VirtualBox

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

Last change on this file since 18803 was 18803, checked in by vboxsync, 16 years ago

Backed out r45795.

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

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