VirtualBox

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

最後變更 在這個檔案從16976是 16976,由 vboxsync 提交於 16 年 前

VboxNetAdp: Made it build on 10.6.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 24.0 KB
 
1/* $Id: VBoxNetAdp-darwin.cpp 16976 2009-02-20 16:58:33Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25/*
26 * Deal with conflicts first.
27 * PVM - BSD mess, that FreeBSD has correct a long time ago.
28 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
29 */
30#include <iprt/types.h>
31#include <sys/param.h>
32#undef PVM
33
34#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
35#include <VBox/log.h>
36#include <VBox/err.h>
37#include <VBox/version.h>
38#include <iprt/assert.h>
39#include <iprt/initterm.h>
40#include <iprt/semaphore.h>
41#include <iprt/spinlock.h>
42#include <iprt/uuid.h>
43
44#include <sys/systm.h>
45__BEGIN_DECLS /* Buggy 10.4 headers, fixed in 10.5. */
46#include <sys/kpi_mbuf.h>
47__END_DECLS
48
49#include <net/ethernet.h>
50#include <net/if_ether.h>
51#include <net/if_types.h>
52#include <sys/socket.h>
53#include <net/if.h>
54#include <net/if_dl.h>
55#include <sys/errno.h>
56#include <sys/param.h>
57
58#define VBOXNETADP_OS_SPECFIC 1
59#include "../VBoxNetAdpInternal.h"
60
61/*******************************************************************************
62* Defined Constants And Macros *
63*******************************************************************************/
64#define VBOXNETADP_MAX_FAMILIES 4
65#define VBOXNETADP_NAME "vboxnet"
66#define VBOXNETADP_MTU 1500
67#define VBOXNETADP_DETACH_TIMEOUT 500
68
69#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
70
71/*******************************************************************************
72* Internal Functions *
73*******************************************************************************/
74__BEGIN_DECLS
75static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData);
76static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData);
77__END_DECLS
78
79/*******************************************************************************
80* Global Variables *
81*******************************************************************************/
82/**
83 * Declare the module stuff.
84 */
85__BEGIN_DECLS
86extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
87extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
88
89KMOD_EXPLICIT_DECL(VBoxNetAdp, VBOX_VERSION_STRING, _start, _stop)
90DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetAdpDarwinStart;
91DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetAdpDarwinStop;
92DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
93__END_DECLS
94
95/**
96 * The (common) global data.
97 */
98static VBOXNETADPGLOBALS g_VBoxNetAdpGlobals;
99
100
101
102
103static void vboxNetAdpDarwinComposeUUID(PVBOXNETADP pThis, PRTUUID pUuid)
104{
105 /* Generate UUID from name and MAC address. */
106 RTUuidClear(pUuid);
107 memcpy(pUuid->au8, "vboxnet", 7);
108 pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
109 pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
110 pUuid->Gen.u8ClockSeqLow = pThis->uUnit;
111 vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
112}
113
114/**
115 * Reads and retains the host interface handle.
116 *
117 * @returns The handle, NULL if detached.
118 * @param pThis
119 */
120DECLINLINE(ifnet_t) vboxNetAdpDarwinRetainIfNet(PVBOXNETADP pThis)
121{
122 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
123 ifnet_t pIfNet = NULL;
124
125 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
126 if (pThis->enmState >= kVBoxNetAdpState_Connected)
127 ifnet_reference(pThis->u.s.pIface);
128 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
129
130 return pIfNet;
131}
132
133
134/**
135 * Release the host interface handle previously retained
136 * by vboxNetAdpDarwinRetainIfNet.
137 *
138 * @param pThis The instance.
139 * @param pIfNet The vboxNetAdpDarwinRetainIfNet return value, NULL is fine.
140 */
141DECLINLINE(void) vboxNetAdpDarwinReleaseIfNet(PVBOXNETADP pThis, ifnet_t pIfNet)
142{
143 NOREF(pThis);
144 if (pIfNet)
145 ifnet_release(pIfNet);
146}
147
148
149
150static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
151{
152 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
153 Assert(pThis);
154 if (vboxNetAdpPrepareToReceive(pThis))
155 {
156 if (/* converted to SG */0)
157 vboxNetAdpReceive(pThis, NULL);
158 else
159 vboxNetAdpCancelReceive(pThis);
160 }
161 mbuf_freem_list(pMBuf);
162 return 0;
163}
164
165static void vboxNetAdpDarwinAttachFamily(PVBOXNETADP pThis, protocol_family_t Family)
166{
167 u_int32_t i;
168 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
169 if (pThis->u.s.aAttachedFamilies[i] == 0)
170 {
171 pThis->u.s.aAttachedFamilies[i] = Family;
172 break;
173 }
174}
175
176static void vboxNetAdpDarwinDetachFamily(PVBOXNETADP pThis, protocol_family_t Family)
177{
178 u_int32_t i;
179 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
180 if (pThis->u.s.aAttachedFamilies[i] == Family)
181 pThis->u.s.aAttachedFamilies[i] = 0;
182}
183
184static errno_t vboxNetAdpDarwinAddProto(ifnet_t pIface, protocol_family_t Family, const struct ifnet_demux_desc *pDemuxDesc, u_int32_t nDesc)
185{
186 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
187 Assert(pThis);
188 vboxNetAdpDarwinAttachFamily(pThis, Family);
189 LogFlow(("vboxNetAdpAddProto: Family=%d.\n", Family));
190 return ether_add_proto(pIface, Family, pDemuxDesc, nDesc);
191}
192
193static errno_t vboxNetAdpDarwinDelProto(ifnet_t pIface, protocol_family_t Family)
194{
195 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
196 Assert(pThis);
197 LogFlow(("vboxNetAdpDelProto: Family=%d.\n", Family));
198 vboxNetAdpDarwinDetachFamily(pThis, Family);
199 return ether_del_proto(pIface, Family);
200}
201
202static void vboxNetAdpDarwinDetach(ifnet_t pIface)
203{
204 PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
205 Assert(pThis);
206 Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
207 /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
208 RTSemEventSignal(pThis->u.s.hEvtDetached);
209}
210
211/**
212 * Internal worker that create a darwin mbuf for a (scatter/)gather list.
213 *
214 * Taken from VBoxNetAdp-darwin.cpp.
215 *
216 * @returns Pointer to the mbuf.
217 * @param pThis The instance.
218 * @param pSG The (scatter/)gather list.
219 */
220static mbuf_t vboxNetAdpDarwinMBufFromSG(PVBOXNETADP pThis, PINTNETSG pSG)
221{
222 /// @todo future? mbuf_how_t How = preemtion enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
223 mbuf_how_t How = MBUF_WAITOK;
224
225 /*
226 * We can't make use of the physical addresses on darwin because the way the
227 * mbuf / cluster stuffe works (see mbuf_data_to_physical and mcl_to_paddr).
228 * So, because we're lazy, we will ASSUME that all SGs coming from INTNET
229 * will only contain one single segment.
230 */
231 Assert(pSG->cSegsUsed == 1);
232 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
233 Assert(pSG->cbTotal > 0);
234
235 /*
236 * We need some way of getting back to our instance data when
237 * the mbuf is freed, so use pvUserData for this.
238 * -- this is not relevant anylonger! --
239 */
240 Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
241 Assert(!pSG->pvUserData2);
242 pSG->pvUserData = pThis;
243
244 /*
245 * Allocate a packet and copy over the data.
246 *
247 * Using mbuf_attachcluster() here would've been nice but there are two
248 * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
249 * that it's not supposed to be used for really external buffers. The 2nd
250 * point might be argued against considering that the only m_clattach user
251 * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
252 * However, it's hard to tell if these m_clattach buffers actually makes it
253 * to the NICs or not, and even if they did, the NIC would need the physical
254 * addresses for the pages they contain and might end up copying the data
255 * to a new mbuf anyway.
256 *
257 * So, in the end it's better to just do it the simple way that will work
258 * 100%, even if it involes some extra work (alloc + copy) we really wished
259 * to avoid.
260 */
261 mbuf_t pPkt = NULL;
262 errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
263 if (!err)
264 {
265 /* Skip zero sized memory buffers (paranoia). */
266 mbuf_t pCur = pPkt;
267 while (pCur && !mbuf_maxlen(pCur))
268 pCur = mbuf_next(pCur);
269 Assert(pCur);
270
271 /* Set the required packet header attributes. */
272 mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
273 mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
274
275 /* Special case the single buffer copy. */
276 if ( mbuf_next(pCur)
277 && mbuf_maxlen(pCur) >= pSG->cbTotal)
278 {
279 mbuf_setlen(pCur, pSG->cbTotal);
280 memcpy(mbuf_data(pCur), pSG->aSegs[0].pv, pSG->cbTotal);
281 }
282 else
283 {
284 /* Multi buffer copying. */
285 size_t cbSrc = pSG->cbTotal;
286 uint8_t const *pbSrc = (uint8_t const *)pSG->aSegs[0].pv;
287 while (cbSrc > 0 && pCur)
288 {
289 size_t cb = mbuf_maxlen(pCur);
290 if (cbSrc < cb)
291 cb = cbSrc;
292 mbuf_setlen(pCur, cb);
293 memcpy(mbuf_data(pCur), pbSrc, cb);
294
295 /* advance */
296 pbSrc += cb;
297 cbSrc -= cb;
298 pCur = mbuf_next(pCur);
299 }
300 }
301 if (!err)
302 return pPkt;
303
304 mbuf_freem(pPkt);
305 }
306 else
307 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
308 pSG->pvUserData = NULL;
309
310 return NULL;
311}
312
313
314/**
315 * Calculates the number of segments required to represent the mbuf.
316 *
317 * Taken from VBoxNetAdp-darwin.cpp.
318 *
319 * @returns Number of segments.
320 * @param pThis The instance.
321 * @param pMBuf The mbuf.
322 * @param pvFrame The frame pointer, optional.
323 */
324DECLINLINE(unsigned) vboxNetAdpDarwinMBufCalcSGSegs(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame)
325{
326 NOREF(pThis);
327
328 /*
329 * Count the buffers in the chain.
330 */
331 unsigned cSegs = 0;
332 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
333 if (mbuf_len(pCur))
334 cSegs++;
335 else if ( !cSegs
336 && pvFrame
337 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
338 cSegs++;
339
340#ifdef PADD_RUNT_FRAMES_FROM_HOST
341 /*
342 * Add one buffer if the total is less than the ethernet minimum 60 bytes.
343 * This may allocate a segment too much if the ethernet header is separated,
344 * but that shouldn't harm us much.
345 */
346 if (mbuf_pkthdr_len(pMBuf) < 60)
347 cSegs++;
348#endif
349
350#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
351 /* maximize the number of segments. */
352 cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
353#endif
354
355 return cSegs ? cSegs : 1;
356}
357
358
359/**
360 * Initializes a SG list from an mbuf.
361 *
362 * Taken from VBoxNetAdp-darwin.cpp.
363 *
364 * @returns Number of segments.
365 * @param pThis The instance.
366 * @param pMBuf The mbuf.
367 * @param pSG The SG.
368 * @param pvFrame The frame pointer, optional.
369 * @param cSegs The number of segments allocated for the SG.
370 * This should match the number in the mbuf exactly!
371 * @param fSrc The source of the frame.
372 */
373DECLINLINE(void) vboxNetAdpDarwinMBufToSG(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
374{
375 NOREF(pThis);
376
377 pSG->pvOwnerData = NULL;
378 pSG->pvUserData = NULL;
379 pSG->pvUserData2 = NULL;
380 pSG->cUsers = 1;
381 pSG->fFlags = INTNETSG_FLAGS_TEMP;
382 pSG->cSegsAlloc = cSegs;
383
384 /*
385 * Walk the chain and convert the buffers to segments.
386 */
387 unsigned iSeg = 0;
388 pSG->cbTotal = 0;
389 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
390 {
391 size_t cbSeg = mbuf_len(pCur);
392 if (cbSeg)
393 {
394 void *pvSeg = mbuf_data(pCur);
395
396 /* deal with pvFrame */
397 if (!iSeg && pvFrame && pvFrame != pvSeg)
398 {
399 void *pvStart = mbuf_datastart(pMBuf);
400 uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
401 uintptr_t offSegEnd = offSeg + cbSeg;
402 Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
403 uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
404 if (RT_LIKELY(offFrame < offSeg))
405 {
406 pvSeg = pvFrame;
407 cbSeg += offSeg - offFrame;
408 }
409 else
410 AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
411 pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
412 pvFrame = NULL;
413 }
414
415 AssertBreak(iSeg < cSegs);
416 pSG->cbTotal += cbSeg;
417 pSG->aSegs[iSeg].cb = cbSeg;
418 pSG->aSegs[iSeg].pv = pvSeg;
419 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
420 iSeg++;
421 }
422 /* The pvFrame might be in a now empty buffer. */
423 else if ( !iSeg
424 && pvFrame
425 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
426 {
427 cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
428 pSG->cbTotal += cbSeg;
429 pSG->aSegs[iSeg].cb = cbSeg;
430 pSG->aSegs[iSeg].pv = pvFrame;
431 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
432 iSeg++;
433 pvFrame = NULL;
434 }
435 }
436
437 Assert(iSeg && iSeg <= cSegs);
438 pSG->cSegsUsed = iSeg;
439
440#ifdef PADD_RUNT_FRAMES_FROM_HOST
441 /*
442 * Add a trailer if the frame is too small.
443 *
444 * Since we're getting to the packet before it is framed, it has not
445 * yet been padded. The current solution is to add a segment pointing
446 * to a buffer containing all zeros and pray that works for all frames...
447 */
448 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
449 {
450 AssertReturnVoid(iSeg < cSegs);
451
452 static uint8_t const s_abZero[128] = {0};
453 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
454 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
455 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
456 pSG->cbTotal = 60;
457 pSG->cSegsUsed++;
458 }
459#endif
460
461#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
462 /*
463 * Redistribute the segments.
464 */
465 if (pSG->cSegsUsed < pSG->cSegsAlloc)
466 {
467 /* copy the segments to the end. */
468 int iSrc = pSG->cSegsUsed;
469 int iDst = pSG->cSegsAlloc;
470 while (iSrc > 0)
471 {
472 iDst--;
473 iSrc--;
474 pSG->aSegs[iDst] = pSG->aSegs[iSrc];
475 }
476
477 /* create small segments from the start. */
478 pSG->cSegsUsed = pSG->cSegsAlloc;
479 iSrc = iDst;
480 iDst = 0;
481 while ( iDst < iSrc
482 && iDst < pSG->cSegsAlloc)
483 {
484 pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
485 pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
486 pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
487 if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
488 {
489 pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
490 pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
491 }
492 else if (++iSrc >= pSG->cSegsAlloc)
493 {
494 pSG->cSegsUsed = iDst + 1;
495 break;
496 }
497 iDst++;
498 }
499 }
500#endif
501
502 AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
503}
504
505int vboxNetAdpPortOsXmit(PVBOXNETADP pThis, PINTNETSG pSG, uint32_t fDst)
506{
507 int rc = VINF_SUCCESS;
508 ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis); // Really need a wrapper?
509 if (pIfNet)
510 {
511 /*
512 * Create a mbuf for the gather list and push it onto the host stack.
513 */
514 if (fDst & INTNETTRUNKDIR_HOST)
515 {
516 mbuf_t pMBuf = vboxNetAdpDarwinMBufFromSG(pThis, pSG);
517 if (pMBuf)
518 {
519 /* This is what IONetworkInterface::inputPacket does. */
520 unsigned const cbEthHdr = 14;
521 mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
522 mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
523 mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
524 mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */
525
526 errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
527 if (err)
528 rc = RTErrConvertFromErrno(err);
529 }
530 else
531 rc = VERR_NO_MEMORY;
532 }
533
534 vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
535 }
536
537 return rc;
538}
539
540bool vboxNetAdpPortOsIsPromiscuous(PVBOXNETADP pThis)
541{
542 uint16_t fIf = 0;
543 ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis);
544 if (pIfNet)
545 {
546 /* gather the data */
547 fIf = ifnet_flags(pIfNet);
548 vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
549 }
550 return fIf & IFF_PROMISC;
551}
552
553
554void vboxNetAdpPortOsGetMacAddress(PVBOXNETADP pThis, PRTMAC pMac)
555{
556 *pMac = pThis->u.s.Mac;
557}
558
559
560bool vboxNetAdpPortOsIsHostMac(PVBOXNETADP pThis, PCRTMAC pMac)
561{
562 /* ASSUMES that the MAC address never changes. */
563 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
564 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
565 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
566}
567
568int vboxNetAdpOsDisconnectIt(PVBOXNETADP pThis)
569{
570 /* Nothing to do here. */
571 return VINF_SUCCESS;
572}
573
574
575int vboxNetAdpOsConnectIt(PVBOXNETADP pThis)
576{
577 /* Nothing to do here. */
578 return VINF_SUCCESS;
579}
580
581
582int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
583{
584 int rc;
585 struct ifnet_init_params Params;
586 RTUUID uuid;
587 struct sockaddr_dl mac;
588
589 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
590 rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
591 if (RT_FAILURE(rc))
592 return rc;
593
594 mac.sdl_len = sizeof(mac);
595 mac.sdl_family = AF_LINK;
596 mac.sdl_alen = ETHER_ADDR_LEN;
597 mac.sdl_nlen = 0;
598 mac.sdl_slen = 0;
599 memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
600
601 vboxNetAdpDarwinComposeUUID(pThis, &uuid);
602 Params.uniqueid = uuid.au8;
603 Params.uniqueid_len = sizeof(uuid);
604 Params.name = VBOXNETADP_NAME;
605 Params.unit = pThis->uUnit;
606 Params.family = IFNET_FAMILY_ETHERNET;
607 Params.type = IFT_ETHER;
608 Params.output = vboxNetAdpDarwinOutput;
609 Params.demux = ether_demux;
610 Params.add_proto = vboxNetAdpDarwinAddProto;
611 Params.del_proto = vboxNetAdpDarwinDelProto;
612 Params.check_multi = ether_check_multi;
613 Params.framer = ether_frameout;
614 Params.softc = pThis;
615 Params.ioctl = (ifnet_ioctl_func)ether_ioctl;
616 Params.set_bpf_tap = NULL;
617 Params.detach = vboxNetAdpDarwinDetach;
618 Params.event = NULL;
619 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
620 Params.broadcast_len = ETHER_ADDR_LEN;
621
622 errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
623 if (!err)
624 {
625 err = ifnet_attach(pThis->u.s.pIface, &mac);
626 if (!err)
627 {
628 err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
629 if (!err)
630 {
631 ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
632 return VINF_SUCCESS;
633 }
634 else
635 Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
636 ifnet_detach(pThis->u.s.pIface);
637 }
638 else
639 Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
640 ifnet_release(pThis->u.s.pIface);
641 }
642 else
643 Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
644
645 return RTErrConvertFromErrno(err);
646}
647
648void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
649{
650 u_int32_t i;
651 /* Bring down the interface */
652 int rc = VINF_SUCCESS;
653 errno_t err;
654
655 AssertPtr(pThis->u.s.pIface);
656 Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
657
658 err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
659 if (err)
660 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
661 "(err=%d).\n", err));
662 /* Detach all protocols. */
663 for (i = 0; i < VBOXNETADP_MAX_FAMILIES; i++)
664 if (pThis->u.s.aAttachedFamilies[i])
665 ifnet_detach_protocol(pThis->u.s.pIface, pThis->u.s.aAttachedFamilies[i]);
666 err = ifnet_detach(pThis->u.s.pIface);
667 if (err)
668 Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
669 "(err=%d).\n", err));
670 Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
671 /* Wait until we get a signal from detach callback. */
672 rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
673 if (rc == VERR_TIMEOUT)
674 LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
675 VBOXNETADP_NAME, pThis->uUnit));
676 err = ifnet_release(pThis->u.s.pIface);
677 if (err)
678 Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
679
680 RTSemEventDestroy(pThis->u.s.hEvtDetached);
681 pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
682}
683
684/**
685 * Start the kernel module.
686 */
687static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
688{
689 int rc;
690
691 /*
692 * Initialize IPRT and find our module tag id.
693 * (IPRT is shared with VBoxDrv, it creates the loggers.)
694 */
695 rc = RTR0Init(0);
696 if (RT_SUCCESS(rc))
697 {
698 Log(("VBoxNetAdpDarwinStart\n"));
699 /*
700 * Initialize the globals and connect to the support driver.
701 *
702 * This will call back vboxNetAdpOsOpenSupDrv (and maybe vboxNetAdpOsCloseSupDrv)
703 * for establishing the connect to the support driver.
704 */
705 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
706 rc = vboxNetAdpInitGlobals(&g_VBoxNetAdpGlobals);
707 if (RT_SUCCESS(rc))
708 {
709 LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
710 return KMOD_RETURN_SUCCESS;
711 }
712
713 LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
714 RTR0Term();
715 }
716 else
717 printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
718
719 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
720 return KMOD_RETURN_FAILURE;
721}
722
723
724/**
725 * Stop the kernel module.
726 */
727static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
728{
729 Log(("VBoxNetAdpDarwinStop\n"));
730
731 /*
732 * Refuse to unload if anyone is currently using the filter driver.
733 * This is important as I/O kit / xnu will to be able to do usage
734 * tracking for us!
735 */
736 int rc = vboxNetAdpTryDeleteGlobals(&g_VBoxNetAdpGlobals);
737 if (RT_FAILURE(rc))
738 {
739 Log(("VBoxNetAdpDarwinStop - failed, busy.\n"));
740 return KMOD_RETURN_FAILURE;
741 }
742
743 /*
744 * Undo the work done during start (in reverse order).
745 */
746 memset(&g_VBoxNetAdpGlobals, 0, sizeof(g_VBoxNetAdpGlobals));
747
748 RTR0Term();
749
750 return KMOD_RETURN_SUCCESS;
751}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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