VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp@ 49686

Last change on this file since 49686 was 49686, checked in by vboxsync, 11 years ago

VBoxNetAdp/Darwin: Submit a dummy packet when host-only interface gets created (#7046)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.0 KB
Line 
1/* $Id: VBoxNetAdp-darwin.cpp 49686 2013-11-27 17:41:15Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21/*
22 * Deal with conflicts first.
23 * PVM - BSD mess, that FreeBSD has correct a long time ago.
24 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
25 */
26#include <iprt/types.h>
27#include <sys/param.h>
28#undef PVM
29
30#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
31#include <VBox/log.h>
32#include <VBox/err.h>
33#include <VBox/version.h>
34#include <iprt/assert.h>
35#include <iprt/initterm.h>
36#include <iprt/semaphore.h>
37#include <iprt/spinlock.h>
38#include <iprt/string.h>
39#include <iprt/uuid.h>
40#include <iprt/alloca.h>
41
42#include <sys/systm.h>
43RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
44#include <sys/kpi_mbuf.h>
45RT_C_DECLS_END
46
47#include <net/ethernet.h>
48#include <net/if_ether.h>
49#include <net/if_types.h>
50#include <sys/socket.h>
51#include <net/if.h>
52#include <net/if_dl.h>
53#include <sys/errno.h>
54#include <sys/param.h>
55#include <sys/conf.h>
56#include <miscfs/devfs/devfs.h>
57extern "C" {
58#include <net/bpf.h>
59}
60
61#define VBOXNETADP_OS_SPECFIC 1
62#include "../VBoxNetAdpInternal.h"
63
64/*******************************************************************************
65* Defined Constants And Macros *
66*******************************************************************************/
67/** The maximum number of SG segments.
68 * Used to prevent stack overflow and similar bad stuff. */
69#define VBOXNETADP_DARWIN_MAX_SEGS 32
70#define VBOXNETADP_DARWIN_MAX_FAMILIES 4
71#define VBOXNETADP_DARWIN_NAME "vboxnet"
72#define VBOXNETADP_DARWIN_MTU 1500
73#define VBOXNETADP_DARWIN_DETACH_TIMEOUT 500
74
75#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
76
77/*******************************************************************************
78* Internal Functions *
79*******************************************************************************/
80RT_C_DECLS_BEGIN
81static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData);
82static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData);
83RT_C_DECLS_END
84
85static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
86static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
87static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
88
89/*******************************************************************************
90* Global Variables *
91*******************************************************************************/
92/**
93 * Declare the module stuff.
94 */
95RT_C_DECLS_BEGIN
96extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
97extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
98
99KMOD_EXPLICIT_DECL(VBoxNetAdp, VBOX_VERSION_STRING, _start, _stop)
100DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetAdpDarwinStart;
101DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetAdpDarwinStop;
102DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
103RT_C_DECLS_END
104
105/**
106 * The (common) global data.
107 */
108static int g_nCtlDev = -1; /* Major dev number */
109static void *g_hCtlDev = 0; /* FS dev handle */
110
111/**
112 * The character device switch table for the driver.
113 */
114static struct cdevsw g_ChDev =
115{
116 /*.d_open = */VBoxNetAdpDarwinOpen,
117 /*.d_close = */VBoxNetAdpDarwinClose,
118 /*.d_read = */eno_rdwrt,
119 /*.d_write = */eno_rdwrt,
120 /*.d_ioctl = */VBoxNetAdpDarwinIOCtl,
121 /*.d_stop = */eno_stop,
122 /*.d_reset = */eno_reset,
123 /*.d_ttys = */NULL,
124 /*.d_select = */eno_select,
125 /*.d_mmap = */eno_mmap,
126 /*.d_strategy = */eno_strat,
127 /*.d_getc = */eno_getc,
128 /*.d_putc = */eno_putc,
129 /*.d_type = */0
130};
131
132
133
134static void vboxNetAdpDarwinComposeUUID(PVBOXNETADP pThis, PRTUUID pUuid)
135{
136 /* Generate UUID from name and MAC address. */
137 RTUuidClear(pUuid);
138 memcpy(pUuid->au8, "vboxnet", 7);
139 pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
140 pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
141 pUuid->Gen.u8ClockSeqLow = pThis->iUnit;
142 vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
143}
144
145static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
146{
147 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
148 Assert(pThis);
149 if (pThis->u.s.nTapMode & BPF_MODE_OUTPUT)
150 {
151 Log2(("vboxnetadp: out len=%d\n%.*Rhxd\n", mbuf_len(pMBuf), 14, mbuf_data(pMBuf)));
152 bpf_tap_out(pIface, DLT_EN10MB, pMBuf, NULL, 0);
153 }
154 mbuf_freem_list(pMBuf);
155 return 0;
156}
157
158static void vboxNetAdpDarwinAttachFamily(PVBOXNETADP pThis, protocol_family_t Family)
159{
160 u_int32_t i;
161 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
162 if (pThis->u.s.aAttachedFamilies[i] == 0)
163 {
164 pThis->u.s.aAttachedFamilies[i] = Family;
165 break;
166 }
167}
168
169static void vboxNetAdpDarwinDetachFamily(PVBOXNETADP pThis, protocol_family_t Family)
170{
171 u_int32_t i;
172 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
173 if (pThis->u.s.aAttachedFamilies[i] == Family)
174 pThis->u.s.aAttachedFamilies[i] = 0;
175}
176
177static errno_t vboxNetAdpDarwinAddProto(ifnet_t pIface, protocol_family_t Family, const struct ifnet_demux_desc *pDemuxDesc, u_int32_t nDesc)
178{
179 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
180 Assert(pThis);
181 vboxNetAdpDarwinAttachFamily(pThis, Family);
182 LogFlow(("vboxNetAdpAddProto: Family=%d.\n", Family));
183 return ether_add_proto(pIface, Family, pDemuxDesc, nDesc);
184}
185
186static errno_t vboxNetAdpDarwinDelProto(ifnet_t pIface, protocol_family_t Family)
187{
188 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
189 Assert(pThis);
190 LogFlow(("vboxNetAdpDelProto: Family=%d.\n", Family));
191 vboxNetAdpDarwinDetachFamily(pThis, Family);
192 return ether_del_proto(pIface, Family);
193}
194
195static void vboxNetAdpDarwinDetach(ifnet_t pIface)
196{
197 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
198 Assert(pThis);
199 Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
200 /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
201 RTSemEventSignal(pThis->u.s.hEvtDetached);
202}
203
204static errno_t vboxNetAdpDarwinDemux(ifnet_t pIface, mbuf_t pMBuf,
205 char *pFrameHeader,
206 protocol_family_t *pProtocolFamily)
207{
208 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
209 Assert(pThis);
210 Log2(("vboxNetAdpDarwinDemux: mode=%d\n", pThis->u.s.nTapMode));
211 if (pThis->u.s.nTapMode & BPF_MODE_INPUT)
212 {
213 Log2(("vboxnetadp: in len=%d\n%.*Rhxd\n", mbuf_len(pMBuf), 14, pFrameHeader));
214 bpf_tap_in(pIface, DLT_EN10MB, pMBuf, pFrameHeader, ETHER_HDR_LEN);
215 }
216 return ether_demux(pIface, pMBuf, pFrameHeader, pProtocolFamily);
217}
218
219static errno_t vboxNetAdpDarwinBpfTap(ifnet_t pIface, u_int32_t uLinkType, bpf_tap_mode nMode)
220{
221 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
222 Assert(pThis);
223 Log2(("vboxNetAdpDarwinBpfTap: mode=%d\n", nMode));
224 pThis->u.s.nTapMode = nMode;
225 return 0;
226}
227
228static errno_t vboxNetAdpDarwinBpfSend(ifnet_t pIface, u_int32_t uLinkType, mbuf_t pMBuf)
229{
230 LogRel(("vboxnetadp: BPF send function is not implemented (dlt=%d)\n", uLinkType));
231 mbuf_freem_list(pMBuf);
232 return 0;
233}
234
235
236/**
237 * Constructs and submits a dummy packet to ifnet_input(). This is a workaround
238 * for "stuck dock icon" issue. When the first packet goes through the interface
239 * DLIL grabs a reference to the thread that submits the packet and holds it
240 * until the interface is destroyed. By submitting this dummy we make DLIL grab
241 * the thread of a non-GUI process.
242 *
243 * Most of this function was copied from vboxNetFltDarwinMBufFromSG().
244 *
245 * @returns VBox status code.
246 * @param pIfNet The interface that will hold the reference to the calling
247 * thread. We submit dummy as if it was coming from this interface.
248 */
249static int vboxNetSendDummy(ifnet_t pIfNet)
250{
251 int rc = 0;
252 size_t cbTotal = 50; /* No Ethernet header */
253 mbuf_how_t How = MBUF_WAITOK;
254
255 mbuf_t pPkt = NULL;
256 errno_t err = mbuf_allocpacket(How, cbTotal, NULL, &pPkt);
257 if (!err)
258 {
259 /* Skip zero sized memory buffers (paranoia). */
260 mbuf_t pCur = pPkt;
261 while (pCur && !mbuf_maxlen(pCur))
262 pCur = mbuf_next(pCur);
263 Assert(pCur);
264
265 /* Set the required packet header attributes. */
266 mbuf_pkthdr_setlen(pPkt, cbTotal);
267 mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
268
269 mbuf_setlen(pCur, cbTotal);
270 memset(mbuf_data(pCur), 0, cbTotal);
271
272 mbuf_pkthdr_setrcvif(pPkt, pIfNet); /* will crash without this. */
273
274 errno_t err = ifnet_input(pIfNet, pPkt, NULL);
275 if (err)
276 {
277 rc = RTErrConvertFromErrno(err);
278 mbuf_freem(pPkt);
279 }
280 }
281 else
282 rc = RTErrConvertFromErrno(err);
283
284 return rc;
285}
286
287int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
288{
289 int rc;
290 struct ifnet_init_params Params;
291 RTUUID uuid;
292 struct sockaddr_dl mac;
293
294 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
295 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
296 if (RT_FAILURE(rc))
297 {
298 printf("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc);
299 return rc;
300 }
301
302 pThis->u.s.nTapMode = BPF_MODE_DISABLED;
303
304 mac.sdl_len = sizeof(mac);
305 mac.sdl_family = AF_LINK;
306 mac.sdl_alen = ETHER_ADDR_LEN;
307 mac.sdl_nlen = 0;
308 mac.sdl_slen = 0;
309 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
310
311 RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->iUnit);
312 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
313 Params.uniqueid = uuid.au8;
314 Params.uniqueid_len = sizeof(uuid);
315 Params.name = VBOXNETADP_NAME;
316 Params.unit = pThis->iUnit;
317 Params.family = IFNET_FAMILY_ETHERNET;
318 Params.type = IFT_ETHER;
319 Params.output = vboxNetAdpDarwinOutput;
320 Params.demux = vboxNetAdpDarwinDemux;
321 Params.add_proto = vboxNetAdpDarwinAddProto;
322 Params.del_proto = vboxNetAdpDarwinDelProto;
323 Params.check_multi = ether_check_multi;
324 Params.framer = ether_frameout;
325 Params.softc = pThis;
326 Params.ioctl = (ifnet_ioctl_func)ether_ioctl;
327 Params.set_bpf_tap = NULL;
328 Params.detach = vboxNetAdpDarwinDetach;
329 Params.event = NULL;
330 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
331 Params.broadcast_len = ETHER_ADDR_LEN;
332
333 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
334 if (!err)
335 {
336 err = ifnet_attach(pThis->u.s.pIface, &mac);
337 if (!err)
338 {
339 err = bpf_attach(pThis->u.s.pIface, DLT_EN10MB, ETHER_HDR_LEN,
340 vboxNetAdpDarwinBpfSend, vboxNetAdpDarwinBpfTap);
341 if (err)
342 {
343 LogRel(("vboxnetadp: bpf_attach failed with %d\n", err));
344 }
345 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
346 if (!err)
347 {
348 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
349 vboxNetSendDummy(pThis->u.s.pIface);
350 return VINF_SUCCESS;
351 }
352 else
353 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
354 ifnet_detach(pThis->u.s.pIface);
355 }
356 else
357 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
358 ifnet_release(pThis->u.s.pIface);
359 }
360 else
361 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
362
363 RTSemEventDestroy(pThis->u.s.hEvtDetached);
364 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
365
366 return RTErrConvertFromErrno(err);
367}
368
369void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
370{
371 u_int32_t i;
372 /* Bring down the interface */
373 int rc = VINF_SUCCESS;
374 errno_t err;
375
376 AssertPtr(pThis->u.s.pIface);
377 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
378
379 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
380 if (err)
381 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
382 "(err=%d).\n", err));
383 /* Detach all protocols. */
384 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
385 if (pThis->u.s.aAttachedFamilies[i])
386 ifnet_detach_protocol(pThis->u.s.pIface, pThis->u.s.aAttachedFamilies[i]);
387 err = ifnet_detach(pThis->u.s.pIface);
388 if (err)
389 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
390 "(err=%d).\n", err));
391 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
392 /* Wait until we get a signal from detach callback. */
393 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
394 if (rc == VERR_TIMEOUT)
395 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
396 VBOXNETADP_NAME, pThis->iUnit));
397 err = ifnet_release(pThis->u.s.pIface);
398 if (err)
399 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
400
401 RTSemEventDestroy(pThis->u.s.hEvtDetached);
402 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
403}
404
405/**
406 * Device open. Called on open /dev/vboxnetctl
407 *
408 * @param pInode Pointer to inode info structure.
409 * @param pFilp Associated file pointer.
410 */
411static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
412{
413 char szName[128];
414 szName[0] = '\0';
415 proc_name(proc_pid(pProcess), szName, sizeof(szName));
416 Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
417 return 0;
418}
419
420/**
421 * Close device.
422 */
423static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
424{
425 Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
426 return 0;
427}
428
429/**
430 * Device I/O Control entry point.
431 *
432 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
433 * @param Dev The device number (major+minor).
434 * @param iCmd The IOCtl command.
435 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
436 * @param fFlags Flag saying we're a character device (like we didn't know already).
437 * @param pProcess The process issuing this request.
438 */
439static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
440{
441 uint32_t cbReq = IOCPARM_LEN(iCmd);
442 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
443 int rc;
444
445 Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
446 switch (IOCBASECMD(iCmd))
447 {
448 case IOCBASECMD(VBOXNETADP_CTL_ADD):
449 {
450 if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
451 || cbReq < sizeof(VBOXNETADPREQ))
452 return EINVAL;
453
454 PVBOXNETADP pNew;
455 Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
456 rc = vboxNetAdpCreate(&pNew,
457 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
458 pReq->szName : NULL);
459 if (RT_FAILURE(rc))
460 return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;
461
462 Assert(strlen(pReq->szName) < sizeof(pReq->szName));
463 strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
464 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
465 Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
466 break;
467 }
468
469 case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
470 {
471 if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
472 return EINVAL;
473
474 PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
475 if (!pAdp)
476 return EINVAL;
477
478 rc = vboxNetAdpDestroy(pAdp);
479 if (RT_FAILURE(rc))
480 return EINVAL;
481 Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
482 break;
483 }
484
485 default:
486 printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
487 return EINVAL;
488 }
489
490 return 0;
491}
492
493int vboxNetAdpOsInit(PVBOXNETADP pThis)
494{
495 /*
496 * Init the darwin specific members.
497 */
498 pThis->u.s.pIface = NULL;
499 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
500 memset(pThis->u.s.aAttachedFamilies, 0, sizeof(pThis->u.s.aAttachedFamilies));
501
502 return VINF_SUCCESS;
503}
504
505/**
506 * Start the kernel module.
507 */
508static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
509{
510 int rc;
511
512 /*
513 * Initialize IPRT and find our module tag id.
514 * (IPRT is shared with VBoxDrv, it creates the loggers.)
515 */
516 rc = RTR0Init(0);
517 if (RT_SUCCESS(rc))
518 {
519 Log(("VBoxNetAdpDarwinStart\n"));
520 rc = vboxNetAdpInit();
521 if (RT_SUCCESS(rc))
522 {
523 g_nCtlDev = cdevsw_add(-1, &g_ChDev);
524 if (g_nCtlDev < 0)
525 {
526 LogRel(("VBoxAdp: failed to register control device."));
527 rc = VERR_CANT_CREATE;
528 }
529 else
530 {
531 g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
532 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
533 if (!g_hCtlDev)
534 {
535 LogRel(("VBoxAdp: failed to create FS node for control device."));
536 rc = VERR_CANT_CREATE;
537 }
538 }
539 }
540
541 if (RT_SUCCESS(rc))
542 {
543 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
544 return KMOD_RETURN_SUCCESS;
545 }
546
547 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
548 RTR0Term();
549 }
550 else
551 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
552
553 return KMOD_RETURN_FAILURE;
554}
555
556
557/**
558 * Stop the kernel module.
559 */
560static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
561{
562 Log(("VBoxNetAdpDarwinStop\n"));
563
564 vboxNetAdpShutdown();
565 /* Remove control device */
566 devfs_remove(g_hCtlDev);
567 cdevsw_remove(g_nCtlDev, &g_ChDev);
568
569 RTR0Term();
570
571 return KMOD_RETURN_SUCCESS;
572}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette