191
160
vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
194
#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
196
* Reads and retains the host interface handle.
198
* @returns The handle, NULL if detached.
201
DECLINLINE(ifnet_t) vboxNetAdpDarwinRetainIfNet(PVBOXNETADP pThis)
203
if (pThis->u.s.pIface)
204
ifnet_reference(pThis->u.s.pIface);
206
return pThis->u.s.pIface;
211
* Release the host interface handle previously retained
212
* by vboxNetAdpDarwinRetainIfNet.
214
* @param pThis The instance.
215
* @param pIfNet The vboxNetAdpDarwinRetainIfNet return value, NULL is fine.
217
DECLINLINE(void) vboxNetAdpDarwinReleaseIfNet(PVBOXNETADP pThis, ifnet_t pIfNet)
221
ifnet_release(pIfNet);
225
* Internal worker that create a darwin mbuf for a (scatter/)gather list.
227
* Taken from VBoxNetAdp-darwin.cpp.
229
* @returns Pointer to the mbuf.
230
* @param pThis The instance.
231
* @param pSG The (scatter/)gather list.
233
static mbuf_t vboxNetAdpDarwinMBufFromSG(PVBOXNETADP pThis, PINTNETSG pSG)
235
/// @todo future? mbuf_how_t How = preemtion enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
236
mbuf_how_t How = MBUF_WAITOK;
239
* We can't make use of the physical addresses on darwin because the way the
240
* mbuf / cluster stuffe works (see mbuf_data_to_physical and mcl_to_paddr).
241
* So, because we're lazy, we will ASSUME that all SGs coming from INTNET
242
* will only contain one single segment.
244
Assert(pSG->cSegsUsed == 1);
245
Assert(pSG->cbTotal == pSG->aSegs[0].cb);
246
Assert(pSG->cbTotal > 0);
249
* We need some way of getting back to our instance data when
250
* the mbuf is freed, so use pvUserData for this.
251
* -- this is not relevant anylonger! --
253
Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
254
Assert(!pSG->pvUserData2);
255
pSG->pvUserData = pThis;
258
* Allocate a packet and copy over the data.
260
* Using mbuf_attachcluster() here would've been nice but there are two
261
* issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
262
* that it's not supposed to be used for really external buffers. The 2nd
263
* point might be argued against considering that the only m_clattach user
264
* is mallocs memory for the ext mbuf and not doing what's stated in the docs.
265
* However, it's hard to tell if these m_clattach buffers actually makes it
266
* to the NICs or not, and even if they did, the NIC would need the physical
267
* addresses for the pages they contain and might end up copying the data
268
* to a new mbuf anyway.
270
* So, in the end it's better to just do it the simple way that will work
271
* 100%, even if it involes some extra work (alloc + copy) we really wished
275
errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
278
/* Skip zero sized memory buffers (paranoia). */
280
while (pCur && !mbuf_maxlen(pCur))
281
pCur = mbuf_next(pCur);
284
/* Set the required packet header attributes. */
285
mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
286
mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
288
/* Special case the single buffer copy. */
290
&& mbuf_maxlen(pCur) >= pSG->cbTotal)
292
mbuf_setlen(pCur, pSG->cbTotal);
293
memcpy(mbuf_data(pCur), pSG->aSegs[0].pv, pSG->cbTotal);
297
/* Multi buffer copying. */
298
size_t cbSrc = pSG->cbTotal;
299
uint8_t const *pbSrc = (uint8_t const *)pSG->aSegs[0].pv;
300
while (cbSrc > 0 && pCur)
302
size_t cb = mbuf_maxlen(pCur);
305
mbuf_setlen(pCur, cb);
306
memcpy(mbuf_data(pCur), pbSrc, cb);
311
pCur = mbuf_next(pCur);
320
AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
321
pSG->pvUserData = NULL;
328
* Calculates the number of segments required to represent the mbuf.
330
* Taken from VBoxNetAdp-darwin.cpp.
332
* @returns Number of segments.
333
* @param pThis The instance.
334
* @param pMBuf The mbuf.
335
* @param pvFrame The frame pointer, optional.
337
DECLINLINE(unsigned) vboxNetAdpDarwinMBufCalcSGSegs(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame)
342
* Count the buffers in the chain.
345
for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
350
&& (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
353
#ifdef PADD_RUNT_FRAMES_FROM_HOST
355
* Add one buffer if the total is less than the ethernet minimum 60 bytes.
356
* This may allocate a segment too much if the ethernet header is separated,
357
* but that shouldn't harm us much.
359
if (mbuf_pkthdr_len(pMBuf) < 60)
363
#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
364
/* maximize the number of segments. */
365
cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
368
return cSegs ? cSegs : 1;
373
* Initializes a SG list from an mbuf.
375
* Taken from VBoxNetAdp-darwin.cpp.
377
* @returns Number of segments.
378
* @param pThis The instance.
379
* @param pMBuf The mbuf.
381
* @param pvFrame The frame pointer, optional.
382
* @param cSegs The number of segments allocated for the SG.
383
* This should match the number in the mbuf exactly!
384
* @param fSrc The source of the frame.
386
DECLINLINE(void) vboxNetAdpDarwinMBufToSG(PVBOXNETADP pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
390
pSG->pvOwnerData = NULL;
391
pSG->pvUserData = NULL;
392
pSG->pvUserData2 = NULL;
394
pSG->fFlags = INTNETSG_FLAGS_TEMP;
395
pSG->cSegsAlloc = cSegs;
398
* Walk the chain and convert the buffers to segments.
402
for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
404
size_t cbSeg = mbuf_len(pCur);
407
void *pvSeg = mbuf_data(pCur);
409
/* deal with pvFrame */
410
if (!iSeg && pvFrame && pvFrame != pvSeg)
412
void *pvStart = mbuf_datastart(pMBuf);
413
uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
414
uintptr_t offSegEnd = offSeg + cbSeg;
415
Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
416
uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
417
if (RT_LIKELY(offFrame < offSeg))
420
cbSeg += offSeg - offFrame;
423
AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
424
pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
428
AssertBreak(iSeg < cSegs);
429
pSG->cbTotal += cbSeg;
430
pSG->aSegs[iSeg].cb = cbSeg;
431
pSG->aSegs[iSeg].pv = pvSeg;
432
pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
435
/* The pvFrame might be in a now empty buffer. */
438
&& (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
440
cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
441
pSG->cbTotal += cbSeg;
442
pSG->aSegs[iSeg].cb = cbSeg;
443
pSG->aSegs[iSeg].pv = pvFrame;
444
pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
450
Assert(iSeg && iSeg <= cSegs);
451
pSG->cSegsUsed = iSeg;
453
#ifdef PADD_RUNT_FRAMES_FROM_HOST
455
* Add a trailer if the frame is too small.
457
* Since we're getting to the packet before it is framed, it has not
458
* yet been padded. The current solution is to add a segment pointing
459
* to a buffer containing all zeros and pray that works for all frames...
461
if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
463
AssertReturnVoid(iSeg < cSegs);
465
static uint8_t const s_abZero[128] = {0};
466
pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
467
pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
468
pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
474
#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
476
* Redistribute the segments.
478
if (pSG->cSegsUsed < pSG->cSegsAlloc)
480
/* copy the segments to the end. */
481
int iSrc = pSG->cSegsUsed;
482
int iDst = pSG->cSegsAlloc;
487
pSG->aSegs[iDst] = pSG->aSegs[iSrc];
490
/* create small segments from the start. */
491
pSG->cSegsUsed = pSG->cSegsAlloc;
495
&& iDst < pSG->cSegsAlloc)
497
pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
498
pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
499
pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
500
if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
502
pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
503
pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
505
else if (++iSrc >= pSG->cSegsAlloc)
507
pSG->cSegsUsed = iDst + 1;
515
AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
518
#endif /* VBOXANETADP_DO_NOT_USE_NETFLT */
519
163
static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
521
#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
522
PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
524
if (vboxNetAdpPrepareToReceive(pThis))
526
unsigned cSegs = vboxNetAdpDarwinMBufCalcSGSegs(pThis, pMBuf, NULL);
527
if (cSegs < VBOXNETADP_DARWIN_MAX_SEGS)
529
PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
530
vboxNetAdpDarwinMBufToSG(pThis, pMBuf, NULL, pSG, cSegs, INTNETTRUNKDIR_HOST);
531
vboxNetAdpReceive(pThis, pSG);
534
vboxNetAdpCancelReceive(pThis);
536
#endif /* VBOXANETADP_DO_NOT_USE_NETFLT */
537
165
mbuf_freem_list(pMBuf);
588
#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
590
int vboxNetAdpPortOsXmit(PVBOXNETADP pThis, PINTNETSG pSG, uint32_t fDst)
592
int rc = VINF_SUCCESS;
593
ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis); // Really need a wrapper?
597
* Create a mbuf for the gather list and push it onto the host stack.
599
mbuf_t pMBuf = vboxNetAdpDarwinMBufFromSG(pThis, pSG);
602
/* This is what IONetworkInterface::inputPacket does. */
603
unsigned const cbEthHdr = 14;
604
mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
605
mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
606
mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
607
mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */
609
Log(("vboxNetAdpPortOsXmit: calling ifnet_input()\n"));
610
errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
612
rc = RTErrConvertFromErrno(err);
616
Log(("vboxNetAdpPortOsXmit: failed to convert SG to mbuf.\n"));
620
vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
623
Log(("vboxNetAdpPortOsXmit: failed to retain the interface.\n"));
628
bool vboxNetAdpPortOsIsPromiscuous(PVBOXNETADP pThis)
631
ifnet_t pIfNet = vboxNetAdpDarwinRetainIfNet(pThis);
634
/* gather the data */
635
fIf = ifnet_flags(pIfNet);
636
vboxNetAdpDarwinReleaseIfNet(pThis, pIfNet);
638
return fIf & IFF_PROMISC;
642
void vboxNetAdpPortOsGetMacAddress(PVBOXNETADP pThis, PRTMAC pMac)
644
*pMac = pThis->u.s.Mac;
648
bool vboxNetAdpPortOsIsHostMac(PVBOXNETADP pThis, PCRTMAC pMac)
650
/* ASSUMES that the MAC address never changes. */
651
return pThis->u.s.Mac.au16[0] == pMac->au16[0]
652
&& pThis->u.s.Mac.au16[1] == pMac->au16[1]
653
&& pThis->u.s.Mac.au16[2] == pMac->au16[2];
656
int vboxNetAdpOsDisconnectIt(PVBOXNETADP pThis)
658
/* Nothing to do here. */
663
int vboxNetAdpOsConnectIt(PVBOXNETADP pThis)
665
/* Nothing to do here. */
668
#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
669
//VBOXNETADP g_vboxnet0;
670
VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
672
#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
676
216
int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
867
359
static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
869
int rc = VINF_SUCCESS;
870
361
uint32_t cbReq = IOCPARM_LEN(iCmd);
871
362
PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
873
365
Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
874
366
switch (IOCBASECMD(iCmd))
876
368
case IOCBASECMD(VBOXNETADP_CTL_ADD):
877
if ((IOC_DIRMASK & iCmd) == IOC_OUT)
880
rc = vboxNetAdpCreate(&pNew);
883
if (cbReq < sizeof(VBOXNETADPREQ))
885
OSDBGPRINT(("VBoxNetAdpDarwinIOCtl: param len %#x < req size %#x; iCmd=%#lx\n", cbReq, sizeof(VBOXNETADPREQ), iCmd));
888
strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName));
370
if ( (IOC_DIRMASK & iCmd) != IOC_OUT
371
|| cbReq < sizeof(VBOXNETADPREQ))
375
rc = vboxNetAdpCreate(&pNew);
379
Assert(strlen(pReq->szName) < sizeof(pReq->szName));
380
strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
381
pReq->szName[sizeof(pReq->szName) - 1] = '\0';
382
Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
893
386
case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
894
for (unsigned i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
896
PVBOXNETADP pThis = &g_aAdapters[i];
898
if (strncmp(pThis->szName, pReq->szName, VBOXNETADP_MAX_NAME_LEN) == 0)
899
if (ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
901
rc = vboxNetAdpDestroy(pThis);
388
if (!memchr(pReq->szName, '\0', RT_MIN(cbReq, sizeof(pReq->szName))))
391
PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
395
rc = vboxNetAdpDestroy(pAdp);
398
Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
907
403
OSDBGPRINT(("VBoxNetAdpDarwinIOCtl: unknown command %x.\n", IOCBASECMD(iCmd)));
908
rc = VERR_INVALID_PARAMETER;
912
return RT_SUCCESS(rc) ? 0 : EINVAL;
915
410
int vboxNetAdpOsInit(PVBOXNETADP pThis)