VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp@ 16805

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

#3419: No promisc for WiFi on Darwin either.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 40.8 KB
Line 
1/* $Id: VBoxNetFlt-darwin.cpp 16195 2009-01-23 11:56:46Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2006-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#include <IOKit/IOLib.h> /* Assert as function */
35
36#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
37#include <VBox/log.h>
38#include <VBox/err.h>
39#include <VBox/version.h>
40#include <iprt/initterm.h>
41#include <iprt/assert.h>
42#include <iprt/spinlock.h>
43#include <iprt/semaphore.h>
44#include <iprt/process.h>
45#include <iprt/alloc.h>
46#include <iprt/alloca.h>
47#include <iprt/time.h>
48#include <iprt/net.h>
49
50#include <mach/kmod.h>
51#include <sys/conf.h>
52#include <sys/errno.h>
53#include <sys/ioccom.h>
54#include <sys/malloc.h>
55#include <sys/proc.h>
56#include <sys/socket.h>
57#include <sys/sockio.h>
58#include <sys/kern_event.h>
59#include <net/kpi_interface.h>
60__BEGIN_DECLS /* Buggy 10.4 headers, fixed in 10.5. */
61#include <sys/kpi_mbuf.h>
62#include <net/kpi_interfacefilter.h>
63__END_DECLS
64#include <net/if.h>
65
66#define VBOXNETFLT_OS_SPECFIC 1
67#include "../VBoxNetFltInternal.h"
68
69
70/*******************************************************************************
71* Defined Constants And Macros *
72*******************************************************************************/
73/** The maximum number of SG segments.
74 * Used to prevent stack overflow and similar bad stuff. */
75#define VBOXNETFLT_DARWIN_MAX_SEGS 32
76
77#if 0
78/** For testing extremely segmented frames. */
79#define VBOXNETFLT_DARWIN_TEST_SEG_SIZE 14
80#endif
81
82
83/*******************************************************************************
84* Internal Functions *
85*******************************************************************************/
86__BEGIN_DECLS
87static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData);
88static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData);
89__END_DECLS
90
91
92/*******************************************************************************
93* Structures and Typedefs *
94*******************************************************************************/
95/**
96 * The mbuf tag data.
97 *
98 * We have to associate the ethernet header with each packet we're sending
99 * because things like icmp will inherit the tag it self so the tag along
100 * isn't sufficent to identify our mbufs. For the icmp scenario the ethernet
101 * header naturarlly changes before the packet is send pack, so let check it.
102 */
103typedef struct VBOXNETFLTTAG
104{
105 /** The ethernet header of the outgoing frame. */
106 RTNETETHERHDR EthHdr;
107} VBOXNETFLTTAG;
108/** Pointer to a VBoxNetFlt mbuf tag. */
109typedef VBOXNETFLTTAG *PVBOXNETFLTTAG;
110/** Pointer to a const VBoxNetFlt mbuf tag. */
111typedef VBOXNETFLTTAG const *PCVBOXNETFLTTAG;
112
113
114/*******************************************************************************
115* Global Variables *
116*******************************************************************************/
117/**
118 * Declare the module stuff.
119 */
120__BEGIN_DECLS
121extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
122extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
123
124KMOD_EXPLICIT_DECL(VBoxNetFlt, VBOX_VERSION_STRING, _start, _stop)
125DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetFltDarwinStart;
126DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetFltDarwinStop;
127DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
128__END_DECLS
129
130
131/**
132 * The (common) global data.
133 */
134static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
135
136/** The unique tag id for this module.
137 * This is basically a unique string hash that lives on untill reboot.
138 * It is used for tagging mbufs. */
139static mbuf_tag_id_t g_idTag;
140
141/** the offset of the struct ifnet::if_pcount variable. */
142static unsigned g_offIfNetPCount = sizeof(void *) * (1 /*if_softc*/ + 1 /*if_name*/ + 2 /*if_link*/ + 2 /*if_addrhead*/ + 1 /*if_check_multi*/)
143 + sizeof(u_long) /*if_refcnt*/;
144/** Macro for accessing ifnet::if_pcount. */
145#define VBOX_GET_PCOUNT(pIfNet) ( *(int *)((uintptr_t)pIfNet + g_offIfNetPCount) )
146
147
148/**
149 * Start the kernel module.
150 */
151static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData)
152{
153 int rc;
154
155 /*
156 * Initialize IPRT and find our module tag id.
157 * (IPRT is shared with VBoxDrv, it creates the loggers.)
158 */
159 rc = RTR0Init(0);
160 if (RT_SUCCESS(rc))
161 {
162 Log(("VBoxNetFltDarwinStart\n"));
163 errno_t err = mbuf_tag_id_find("org.VirtualBox.kext.VBoxFltDrv", &g_idTag);
164 if (!err)
165 {
166 /*
167 * Initialize the globals and connect to the support driver.
168 *
169 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
170 * for establishing the connect to the support driver.
171 */
172 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
173 rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
174 if (RT_SUCCESS(rc))
175 {
176 LogRel(("VBoxFltDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
177 return KMOD_RETURN_SUCCESS;
178 }
179
180 LogRel(("VBoxFltDrv: failed to initialize device extension (rc=%d)\n", rc));
181 }
182 else
183 LogRel(("VBoxFltDrv: mbuf_tag_id_find failed, err=%d\n", err));
184 RTR0Term();
185 }
186 else
187 printf("VBoxFltDrv: failed to initialize IPRT (rc=%d)\n", rc);
188
189 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
190 return KMOD_RETURN_FAILURE;
191}
192
193
194/**
195 * Stop the kernel module.
196 */
197static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData)
198{
199 Log(("VBoxNetFltDarwinStop\n"));
200
201 /*
202 * Refuse to unload if anyone is currently using the filter driver.
203 * This is important as I/O kit / xnu will to be able to do usage
204 * tracking for us!
205 */
206 int rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltGlobals);
207 if (RT_FAILURE(rc))
208 {
209 Log(("VBoxNetFltDarwinStop - failed, busy.\n"));
210 return KMOD_RETURN_FAILURE;
211 }
212
213 /*
214 * Undo the work done during start (in reverse order).
215 */
216 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
217
218 RTR0Term();
219
220 return KMOD_RETURN_SUCCESS;
221}
222
223
224/**
225 * Reads and retains the host interface handle.
226 *
227 * @returns The handle, NULL if detached.
228 * @param pThis
229 */
230DECLINLINE(ifnet_t) vboxNetFltDarwinRetainIfNet(PVBOXNETFLTINS pThis)
231{
232 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
233 ifnet_t pIfNet = NULL;
234
235 /*
236 * Be careful here to avoid problems racing the detached callback.
237 */
238 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
239 if (!ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
240 {
241 pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
242 if (pIfNet)
243 ifnet_reference(pIfNet);
244 }
245 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
246
247 return pIfNet;
248}
249
250
251/**
252 * Release the host interface handle previously retained
253 * by vboxNetFltDarwinRetainIfNet.
254 *
255 * @param pThis The instance.
256 * @param pIfNet The vboxNetFltDarwinRetainIfNet return value, NULL is fine.
257 */
258DECLINLINE(void) vboxNetFltDarwinReleaseIfNet(PVBOXNETFLTINS pThis, ifnet_t pIfNet)
259{
260 NOREF(pThis);
261 if (pIfNet)
262 ifnet_release(pIfNet);
263}
264
265
266/**
267 * Checks whether this is an mbuf created by vboxNetFltDarwinMBufFromSG,
268 * i.e. a buffer which we're pushing and should be ignored by the filter callbacks.
269 *
270 * @returns true / false accordingly.
271 * @param pThis The instance.
272 * @param pMBuf The mbuf.
273 * @param pvFrame The frame pointer, optional.
274 */
275DECLINLINE(bool) vboxNetFltDarwinMBufIsOur(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
276{
277 NOREF(pThis);
278
279 /*
280 * Lookup the tag set by vboxNetFltDarwinMBufFromSG.
281 */
282 PCVBOXNETFLTTAG pTagData;
283 size_t cbTagData;
284 errno_t err = mbuf_tag_find(pMBuf, g_idTag, 0 /* type */, &cbTagData, (void **)&pTagData);
285 if (err)
286 return false;
287 AssertReturn(cbTagData == sizeof(*pTagData), false);
288
289 /*
290 * Dig out the ethernet header from the mbuf.
291 */
292 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
293 if (!pEthHdr)
294 pEthHdr = (PCRTNETETHERHDR)mbuf_pkthdr_header(pMBuf);
295 if (!pEthHdr)
296 pEthHdr = (PCRTNETETHERHDR)mbuf_data(pMBuf);
297 /* ASSUMING that there is enough data to work on! */
298 if ( pEthHdr->DstMac.au8[0] != pTagData->EthHdr.DstMac.au8[0]
299 || pEthHdr->DstMac.au8[1] != pTagData->EthHdr.DstMac.au8[1]
300 || pEthHdr->DstMac.au8[2] != pTagData->EthHdr.DstMac.au8[2]
301 || pEthHdr->DstMac.au8[3] != pTagData->EthHdr.DstMac.au8[3]
302 || pEthHdr->DstMac.au8[4] != pTagData->EthHdr.DstMac.au8[4]
303 || pEthHdr->DstMac.au8[5] != pTagData->EthHdr.DstMac.au8[5]
304 || pEthHdr->SrcMac.au8[0] != pTagData->EthHdr.SrcMac.au8[0]
305 || pEthHdr->SrcMac.au8[1] != pTagData->EthHdr.SrcMac.au8[1]
306 || pEthHdr->SrcMac.au8[2] != pTagData->EthHdr.SrcMac.au8[2]
307 || pEthHdr->SrcMac.au8[3] != pTagData->EthHdr.SrcMac.au8[3]
308 || pEthHdr->SrcMac.au8[4] != pTagData->EthHdr.SrcMac.au8[4]
309 || pEthHdr->SrcMac.au8[5] != pTagData->EthHdr.SrcMac.au8[5]
310 || pEthHdr->EtherType != pTagData->EthHdr.EtherType)
311 {
312 Log3(("tagged, but the ethernet header has changed\n"));
313 return false;
314 }
315
316 return true;
317}
318
319
320/**
321 * Internal worker that create a darwin mbuf for a (scatter/)gather list.
322 *
323 * @returns Pointer to the mbuf.
324 * @param pThis The instance.
325 * @param pSG The (scatter/)gather list.
326 */
327static mbuf_t vboxNetFltDarwinMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
328{
329 /// @todo future? mbuf_how_t How = preemtion enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
330 mbuf_how_t How = MBUF_WAITOK;
331
332 /*
333 * We can't make use of the physical addresses on darwin because the way the
334 * mbuf / cluster stuffe works (see mbuf_data_to_physical and mcl_to_paddr).
335 * So, because we're lazy, we will ASSUME that all SGs coming from INTNET
336 * will only contain one single segment.
337 */
338 Assert(pSG->cSegsUsed == 1);
339 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
340 Assert(pSG->cbTotal > 0);
341
342 /*
343 * We need some way of getting back to our instance data when
344 * the mbuf is freed, so use pvUserData for this.
345 * -- this is not relevant anylonger! --
346 */
347 Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
348 Assert(!pSG->pvUserData2);
349 pSG->pvUserData = pThis;
350
351 /*
352 * Allocate a packet and copy over the data.
353 *
354 * Using mbuf_attachcluster() here would've been nice but there are two
355 * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
356 * that it's not supposed to be used for really external buffers. The 2nd
357 * point might be argued against considering that the only m_clattach user
358 * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
359 * However, it's hard to tell if these m_clattach buffers actually makes it
360 * to the NICs or not, and even if they did, the NIC would need the physical
361 * addresses for the pages they contain and might end up copying the data
362 * to a new mbuf anyway.
363 *
364 * So, in the end it's better to just do it the simple way that will work
365 * 100%, even if it involes some extra work (alloc + copy) we really wished
366 * to avoid.
367 */
368 mbuf_t pPkt = NULL;
369 errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
370 if (!err)
371 {
372 /* Skip zero sized memory buffers (paranoia). */
373 mbuf_t pCur = pPkt;
374 while (pCur && !mbuf_maxlen(pCur))
375 pCur = mbuf_next(pCur);
376 Assert(pCur);
377
378 /* Set the required packet header attributes. */
379 mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
380 mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
381
382 /* Special case the single buffer copy. */
383 if ( mbuf_next(pCur)
384 && mbuf_maxlen(pCur) >= pSG->cbTotal)
385 {
386 mbuf_setlen(pCur, pSG->cbTotal);
387 memcpy(mbuf_data(pCur), pSG->aSegs[0].pv, pSG->cbTotal);
388 }
389 else
390 {
391 /* Multi buffer copying. */
392 size_t cbSrc = pSG->cbTotal;
393 uint8_t const *pbSrc = (uint8_t const *)pSG->aSegs[0].pv;
394 while (cbSrc > 0 && pCur)
395 {
396 size_t cb = mbuf_maxlen(pCur);
397 if (cbSrc < cb)
398 cb = cbSrc;
399 mbuf_setlen(pCur, cb);
400 memcpy(mbuf_data(pCur), pbSrc, cb);
401
402 /* advance */
403 pbSrc += cb;
404 cbSrc -= cb;
405 pCur = mbuf_next(pCur);
406 }
407 }
408 if (!err)
409 {
410 /*
411 * Tag the packet and return successfully.
412 */
413 PVBOXNETFLTTAG pTagData;
414 err = mbuf_tag_allocate(pPkt, g_idTag, 0 /* type */, sizeof(VBOXNETFLTTAG) /* tag len */, How, (void **)&pTagData);
415 if (!err)
416 {
417 Assert(pSG->aSegs[0].cb >= sizeof(pTagData->EthHdr));
418 memcpy(&pTagData->EthHdr, pSG->aSegs[0].pv, sizeof(pTagData->EthHdr));
419 return pPkt;
420 }
421
422 /* bailout: */
423 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
424 }
425
426 mbuf_freem(pPkt);
427 }
428 else
429 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
430 pSG->pvUserData = NULL;
431
432 return NULL;
433}
434
435
436/**
437 * Calculates the number of segments required to represent the mbuf.
438 *
439 * @returns Number of segments.
440 * @param pThis The instance.
441 * @param pMBuf The mbuf.
442 * @param pvFrame The frame pointer, optional.
443 */
444DECLINLINE(unsigned) vboxNetFltDarwinMBufCalcSGSegs(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
445{
446 NOREF(pThis);
447
448 /*
449 * Count the buffers in the chain.
450 */
451 unsigned cSegs = 0;
452 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
453 if (mbuf_len(pCur))
454 cSegs++;
455 else if ( !cSegs
456 && pvFrame
457 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
458 cSegs++;
459
460#ifdef PADD_RUNT_FRAMES_FROM_HOST
461 /*
462 * Add one buffer if the total is less than the ethernet minimum 60 bytes.
463 * This may allocate a segment too much if the ethernet header is separated,
464 * but that shouldn't harm us much.
465 */
466 if (mbuf_pkthdr_len(pMBuf) < 60)
467 cSegs++;
468#endif
469
470#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
471 /* maximize the number of segments. */
472 cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
473#endif
474
475 return cSegs ? cSegs : 1;
476}
477
478
479/**
480 * Initializes a SG list from an mbuf.
481 *
482 * @returns Number of segments.
483 * @param pThis The instance.
484 * @param pMBuf The mbuf.
485 * @param pSG The SG.
486 * @param pvFrame The frame pointer, optional.
487 * @param cSegs The number of segments allocated for the SG.
488 * This should match the number in the mbuf exactly!
489 * @param fSrc The source of the frame.
490 */
491DECLINLINE(void) vboxNetFltDarwinMBufToSG(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
492{
493 NOREF(pThis);
494
495 pSG->pvOwnerData = NULL;
496 pSG->pvUserData = NULL;
497 pSG->pvUserData2 = NULL;
498 pSG->cUsers = 1;
499 pSG->fFlags = INTNETSG_FLAGS_TEMP;
500 pSG->cSegsAlloc = cSegs;
501
502 /*
503 * Walk the chain and convert the buffers to segments.
504 */
505 unsigned iSeg = 0;
506 pSG->cbTotal = 0;
507 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
508 {
509 size_t cbSeg = mbuf_len(pCur);
510 if (cbSeg)
511 {
512 void *pvSeg = mbuf_data(pCur);
513
514 /* deal with pvFrame */
515 if (!iSeg && pvFrame && pvFrame != pvSeg)
516 {
517 void *pvStart = mbuf_datastart(pMBuf);
518 uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
519 uintptr_t offSegEnd = offSeg + cbSeg;
520 Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
521 uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
522 if (RT_LIKELY(offFrame < offSeg))
523 {
524 pvSeg = pvFrame;
525 cbSeg += offSeg - offFrame;
526 }
527 else
528 AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
529 pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
530 pvFrame = NULL;
531 }
532
533 AssertBreak(iSeg < cSegs);
534 pSG->cbTotal += cbSeg;
535 pSG->aSegs[iSeg].cb = cbSeg;
536 pSG->aSegs[iSeg].pv = pvSeg;
537 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
538 iSeg++;
539 }
540 /* The pvFrame might be in a now empty buffer. */
541 else if ( !iSeg
542 && pvFrame
543 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
544 {
545 cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
546 pSG->cbTotal += cbSeg;
547 pSG->aSegs[iSeg].cb = cbSeg;
548 pSG->aSegs[iSeg].pv = pvFrame;
549 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
550 iSeg++;
551 pvFrame = NULL;
552 }
553 }
554
555 Assert(iSeg && iSeg <= cSegs);
556 pSG->cSegsUsed = iSeg;
557
558#ifdef PADD_RUNT_FRAMES_FROM_HOST
559 /*
560 * Add a trailer if the frame is too small.
561 *
562 * Since we're getting to the packet before it is framed, it has not
563 * yet been padded. The current solution is to add a segment pointing
564 * to a buffer containing all zeros and pray that works for all frames...
565 */
566 if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
567 {
568 AssertReturnVoid(iSeg < cSegs);
569
570 static uint8_t const s_abZero[128] = {0};
571 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
572 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
573 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
574 pSG->cbTotal = 60;
575 pSG->cSegsUsed++;
576 }
577#endif
578
579#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
580 /*
581 * Redistribute the segments.
582 */
583 if (pSG->cSegsUsed < pSG->cSegsAlloc)
584 {
585 /* copy the segments to the end. */
586 int iSrc = pSG->cSegsUsed;
587 int iDst = pSG->cSegsAlloc;
588 while (iSrc > 0)
589 {
590 iDst--;
591 iSrc--;
592 pSG->aSegs[iDst] = pSG->aSegs[iSrc];
593 }
594
595 /* create small segments from the start. */
596 pSG->cSegsUsed = pSG->cSegsAlloc;
597 iSrc = iDst;
598 iDst = 0;
599 while ( iDst < iSrc
600 && iDst < pSG->cSegsAlloc)
601 {
602 pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
603 pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
604 pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
605 if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
606 {
607 pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
608 pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
609 }
610 else if (++iSrc >= pSG->cSegsAlloc)
611 {
612 pSG->cSegsUsed = iDst + 1;
613 break;
614 }
615 iDst++;
616 }
617 }
618#endif
619
620 AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
621}
622
623
624/**
625 *
626 * @see iff_detached_func in the darwin kpi.
627 */
628static void vboxNetFltDarwinIffDetached(void *pvThis, ifnet_t pIfNet)
629{
630 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
631 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
632 uint64_t NanoTS = RTTimeSystemNanoTS();
633 LogFlow(("vboxNetFltDarwinIffDetached: pThis=%p NanoTS=%RU64 (%d)\n",
634 pThis, NanoTS, VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
635
636 Assert(!pThis->fDisconnectedFromHost);
637 Assert(!pThis->fRediscoveryPending);
638
639 /*
640 * If we've put it into promiscuous mode, undo that now. If we don't
641 * the if_pcount will go all wrong when it's replugged.
642 */
643 if (ASMAtomicXchgBool(&pThis->u.s.fSetPromiscuous, false))
644 ifnet_set_promiscuous(pIfNet, 0);
645
646 /*
647 * We carefully take the spinlock and increase the interface reference
648 * behind it in order to avoid problematic races with the detached callback.
649 */
650 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
651
652 pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
653 int cPromisc = VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : - 1;
654
655 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfNet, NULL);
656 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, NULL);
657 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
658 pThis->u.s.fSetPromiscuous = false;
659 ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, NanoTS);
660 ASMAtomicUoWriteBool(&pThis->fRediscoveryPending, false);
661 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
662
663 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
664
665 if (pIfNet)
666 ifnet_release(pIfNet);
667 LogRel(("VBoxNetFlt: was detached from '%s' (%d)\n", pThis->szName, cPromisc));
668}
669
670
671/**
672 *
673 * @see iff_ioctl_func in the darwin kpi.
674 */
675static errno_t vboxNetFltDarwinIffIoCtl(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, u_long uCmd, void *pvArg)
676{
677 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
678 LogFlow(("vboxNetFltDarwinIffIoCtl: pThis=%p uCmd=%lx\n", pThis, uCmd));
679
680 /*
681 * Update fOtherPromiscuous.
682 */
683 /** @todo we'll have to find the offset of if_pcount to get this right! */
684 //if (uCmd == SIOCSIFFLAGS)
685 //{
686 //
687 //}
688
689 /*
690 * We didn't handle it, continue processing.
691 */
692 NOREF(pThis);
693 NOREF(eProtocol);
694 NOREF(uCmd);
695 NOREF(pvArg);
696 return EOPNOTSUPP;
697}
698
699
700/**
701 *
702 * @see iff_event_func in the darwin kpi.
703 */
704static void vboxNetFltDarwinIffEvent(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, const struct kev_msg *pEvMsg)
705{
706 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
707 LogFlow(("vboxNetFltDarwinIffEvent: pThis=%p\n", pThis));
708
709 NOREF(pThis);
710 NOREF(pIfNet);
711 NOREF(eProtocol);
712 NOREF(pEvMsg);
713
714 /*
715 * Watch out for the interface going online / offline.
716 */
717 if ( VALID_PTR(pThis)
718 && VALID_PTR(pEvMsg)
719 && pEvMsg->vendor_code == KEV_VENDOR_APPLE
720 && pEvMsg->kev_class == KEV_NETWORK_CLASS
721 && pEvMsg->kev_subclass == KEV_DL_SUBCLASS)
722 {
723 if (pThis->u.s.pIfNet == pIfNet)
724 {
725 if (pEvMsg->event_code == KEV_DL_LINK_ON)
726 {
727 if (ASMAtomicUoReadBool(&pThis->u.s.fNeedSetPromiscuous))
728 {
729 /* failed to bring it online. */
730 errno_t err = ifnet_set_promiscuous(pIfNet, 1);
731 if (!err)
732 {
733 ASMAtomicWriteBool(&pThis->u.s.fSetPromiscuous, true);
734 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
735 Log(("vboxNetFltDarwinIffEvent: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
736 }
737 else
738 Log(("vboxNetFltDarwinIffEvent: ifnet_set_promiscuous failed on %s, err=%d (%d)\n", pThis->szName, err, VBOX_GET_PCOUNT(pIfNet)));
739 }
740 else if ( ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous)
741 && !(ifnet_flags(pIfNet) & IFF_PROMISC))
742 {
743 /* Try fix the inconsistency. */
744 errno_t err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
745 if (!err)
746 err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
747 if (!err && (ifnet_flags(pIfNet) & IFF_PROMISC))
748 Log(("vboxNetFltDarwinIffEvent: fixed IFF_PROMISC on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
749 else
750 Log(("vboxNetFltDarwinIffEvent: failed to fix IFF_PROMISC on %s, err=%d flags=%#x (%d)\n",
751 pThis->szName, err, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
752 }
753 else
754 Log(("vboxNetFltDarwinIffEvent: online, '%s'. flags=%#x (%d)\n", pThis->szName, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
755 }
756 else if (pEvMsg->event_code == KEV_DL_LINK_OFF)
757 Log(("vboxNetFltDarwinIffEvent: %s goes down (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
758 }
759 else
760 Log(("vboxNetFltDarwinIffEvent: pThis->u.s.pIfNet=%p pIfNet=%p (%d)\n", pThis->u.s.pIfNet, pIfNet, VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
761 }
762 else if (VALID_PTR(pEvMsg))
763 Log(("vboxNetFltDarwinIffEvent: vendor_code=%#x kev_class=%#x kev_subclass=%#x event_code=%#x\n",
764 pEvMsg->vendor_code, pEvMsg->kev_class, pEvMsg->kev_subclass, pEvMsg->event_code));
765}
766
767
768/**
769 * Internal worker for vboxNetFltDarwinIffInput and vboxNetFltDarwinIffOutput,
770 *
771 * @returns 0 or EJUSTRETURN.
772 * @param pThis The instance.
773 * @param pMBuf The mbuf.
774 * @param pvFrame The start of the frame, optional.
775 * @param fSrc Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value.
776 * @param eProtocol The protocol.
777 */
778static errno_t vboxNetFltDarwinIffInputOutputWorker(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame,
779 uint32_t fSrc, protocol_family_t eProtocol)
780{
781 /*
782 * Drop it immediately?
783 */
784 Log2(("vboxNetFltDarwinIffInputOutputWorker: pThis=%p pMBuf=%p pvFrame=%p fSrc=%#x cbPkt=%x\n",
785 pThis, pMBuf, pvFrame, fSrc, pMBuf ? mbuf_pkthdr_len(pMBuf) : -1));
786 if (!pMBuf)
787 return 0;
788#if 0 /* debugging lost icmp packets */
789 if (mbuf_pkthdr_len(pMBuf) > 0x300)
790 {
791 uint8_t *pb = (uint8_t *)(pvFrame ? pvFrame : mbuf_data(pMBuf));
792 Log3(("D=%.6Rhxs S=%.6Rhxs T=%04x IFF\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
793 }
794#endif
795 if (vboxNetFltDarwinMBufIsOur(pThis, pMBuf, pvFrame))
796 return 0;
797
798 /*
799 * Active? Retain the instance and increment the busy counter.
800 */
801 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
802 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
803 const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
804 if (fActive)
805 vboxNetFltRetain(pThis, true /* fBusy */);
806 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
807 if (!fActive)
808 return 0;
809
810 /*
811 * Finalize out-bound packets since the stack puts off finalizing
812 * TCP/IP checksums as long as possible.
813 * ASSUMES this only applies to outbound IP packets.
814 */
815 if ( (fSrc & INTNETTRUNKDIR_HOST)
816 && eProtocol == PF_INET)
817 {
818 Assert(!pvFrame);
819 mbuf_outbound_finalize(pMBuf, eProtocol, sizeof(RTNETETHERHDR));
820 }
821
822 /*
823 * Create a (scatter/)gather list for the mbuf and feed it to the internal network.
824 */
825 bool fDropIt = false;
826 unsigned cSegs = vboxNetFltDarwinMBufCalcSGSegs(pThis, pMBuf, pvFrame);
827 if (cSegs < VBOXNETFLT_DARWIN_MAX_SEGS)
828 {
829 PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
830 vboxNetFltDarwinMBufToSG(pThis, pMBuf, pvFrame, pSG, cSegs, fSrc);
831
832 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
833 if (fDropIt)
834 mbuf_freem(pMBuf);
835 }
836
837 vboxNetFltRelease(pThis, true /* fBusy */);
838
839 return fDropIt ? EJUSTRETURN : 0;
840}
841
842
843/**
844 * From the host.
845 *
846 * @see iff_output_func in the darwin kpi.
847 */
848static errno_t vboxNetFltDarwinIffOutput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf)
849{
850 /** @todo there was some note about the ethernet header here or something like that... */
851
852 NOREF(eProtocol);
853 NOREF(pIfNet);
854 return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, NULL, INTNETTRUNKDIR_HOST, eProtocol);
855}
856
857
858/**
859 * From the wire.
860 *
861 * @see iff_input_func in the darwin kpi.
862 */
863static errno_t vboxNetFltDarwinIffInput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf, char **ppchFrame)
864{
865 NOREF(eProtocol);
866 NOREF(pIfNet);
867 return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, *ppchFrame, INTNETTRUNKDIR_WIRE, eProtocol);
868}
869
870
871/**
872 * Internal worker for vboxNetFltOsInitInstance and vboxNetFltOsMaybeRediscovered.
873 *
874 * @returns VBox status code.
875 * @param pThis The instance.
876 * @param fRediscovery If set we're doing a rediscovery attempt, so, don't
877 * flood the release log.
878 */
879static int vboxNetFltDarwinAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery)
880{
881 LogFlow(("vboxNetFltDarwinAttachToInterface: pThis=%p (%s)\n", pThis, pThis->szName));
882
883 /*
884 * Locate the interface first.
885 *
886 * The pIfNet member is updated before iflt_attach is called and used
887 * to deal with the hypothetical case where someone rips out the
888 * interface immediately after our iflt_attach call.
889 */
890 ifnet_t pIfNet = NULL;
891 errno_t err = ifnet_find_by_name(pThis->szName, &pIfNet);
892 if (err)
893 {
894 Assert(err == ENXIO);
895 if (!fRediscovery)
896 LogRel(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
897 else
898 Log(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
899 return VERR_INTNET_FLT_IF_NOT_FOUND;
900 }
901
902 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
903 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
904 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfNet, pIfNet);
905 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
906
907 /*
908 * Get the mac address while we still have a valid ifnet reference.
909 */
910 err = ifnet_lladdr_copy_bytes(pIfNet, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
911 if (!err)
912 {
913 /*
914 * Try attach the filter.
915 */
916 struct iff_filter RegRec;
917 RegRec.iff_cookie = pThis;
918 RegRec.iff_name = "VBoxNetFlt";
919 RegRec.iff_protocol = 0;
920 RegRec.iff_input = vboxNetFltDarwinIffInput;
921 RegRec.iff_output = vboxNetFltDarwinIffOutput;
922 RegRec.iff_event = vboxNetFltDarwinIffEvent;
923 RegRec.iff_ioctl = vboxNetFltDarwinIffIoCtl;
924 RegRec.iff_detached = vboxNetFltDarwinIffDetached;
925 interface_filter_t pIfFilter = NULL;
926 err = iflt_attach(pIfNet, &RegRec, &pIfFilter);
927 Assert(err || pIfFilter);
928
929 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
930 pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
931 if (pIfNet && !err)
932 {
933 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
934 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, pIfFilter);
935 pIfNet = NULL; /* don't dereference it */
936 }
937 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
938 }
939
940 /* Release the interface on failure. */
941 if (pIfNet)
942 ifnet_release(pIfNet);
943
944 int rc = RTErrConvertFromErrno(err);
945 if (RT_SUCCESS(rc))
946 LogRel(("VBoxFltDrv: attached to '%s' / %.*Rhxs\n", pThis->szName, sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
947 else
948 LogRel(("VBoxFltDrv: failed to attach to ifnet '%s' (err=%d)\n", pThis->szName, err));
949 return rc;
950}
951
952
953bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
954{
955 vboxNetFltDarwinAttachToInterface(pThis, true /* fRediscovery */);
956 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
957}
958
959
960int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
961{
962 int rc = VINF_SUCCESS;
963 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
964 if (pIfNet)
965 {
966 /*
967 * Create a mbuf for the gather list and push it onto the wire.
968 */
969 if (fDst & INTNETTRUNKDIR_WIRE)
970 {
971 mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
972 if (pMBuf)
973 {
974 errno_t err = ifnet_output_raw(pIfNet, PF_LINK, pMBuf);
975 if (err)
976 rc = RTErrConvertFromErrno(err);
977 }
978 else
979 rc = VERR_NO_MEMORY;
980 }
981
982 /*
983 * Create a mbuf for the gather list and push it onto the host stack.
984 */
985 if (fDst & INTNETTRUNKDIR_HOST)
986 {
987 mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
988 if (pMBuf)
989 {
990 /* This is what IONetworkInterface::inputPacket does. */
991 unsigned const cbEthHdr = 14;
992 mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
993 mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
994 mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
995 mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */
996
997 errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
998 if (err)
999 rc = RTErrConvertFromErrno(err);
1000 }
1001 else
1002 rc = VERR_NO_MEMORY;
1003 }
1004
1005 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1006 }
1007
1008 return rc;
1009}
1010
1011
1012bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
1013{
1014 bool fRc = false;
1015 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
1016 if (pIfNet)
1017 {
1018 /* gather the data */
1019 uint16_t fIf = ifnet_flags(pIfNet);
1020 unsigned cPromisc = VBOX_GET_PCOUNT(pIfNet);
1021 bool fSetPromiscuous = ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous);
1022 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1023
1024 /* calc the return. */
1025 fRc = (fIf & IFF_PROMISC)
1026 && cPromisc > fSetPromiscuous;
1027 }
1028 return fRc;
1029}
1030
1031
1032void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
1033{
1034 *pMac = pThis->u.s.Mac;
1035}
1036
1037
1038bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
1039{
1040 /* ASSUMES that the MAC address never changes. */
1041 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
1042 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
1043 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
1044}
1045
1046
1047void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
1048{
1049 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
1050 if (pIfNet)
1051 {
1052 /*
1053 * If there is no need to set promiscuous mode the only thing
1054 * we have to do in order to preserve the backward compatibility
1055 * is to try bringing the interface up if it gets activated.
1056 */
1057 if (pThis->fDisablePromiscuous)
1058 {
1059 Log(("vboxNetFltPortOsSetActive: promisc disabled, do nothing.\n"));
1060 if (fActive)
1061 {
1062 /*
1063 * Try bring the interface up and running if it's down.
1064 */
1065 u_int16_t fIf = ifnet_flags(pIfNet);
1066 if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
1067 {
1068 ifnet_set_flags(pIfNet, IFF_UP, IFF_UP);
1069 ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1070 }
1071 }
1072 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1073 return;
1074 }
1075 /*
1076 * This api is a bit weird, the best reference is the code.
1077 *
1078 * Also, we have a bit or race conditions wrt the maintance of
1079 * host the interface promiscuity for vboxNetFltPortOsIsPromiscuous.
1080 */
1081 unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pIfNet);
1082 u_int16_t fIf;
1083 if (fActive)
1084 {
1085 Assert(!pThis->u.s.fSetPromiscuous);
1086 errno_t err = ENETDOWN;
1087 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, true);
1088
1089 /*
1090 * Try bring the interface up and running if it's down.
1091 */
1092 fIf = ifnet_flags(pIfNet);
1093 if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
1094 {
1095 err = ifnet_set_flags(pIfNet, IFF_UP, IFF_UP);
1096 errno_t err2 = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1097 if (!err)
1098 err = err2;
1099 fIf = ifnet_flags(pIfNet);
1100 }
1101
1102 /*
1103 * Is it already up? If it isn't, leave it to the link event or
1104 * we'll upset if_pcount (as stated above, ifnet_set_promiscuous is weird).
1105 */
1106 if ((fIf & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
1107 {
1108 err = ifnet_set_promiscuous(pIfNet, 1);
1109 pThis->u.s.fSetPromiscuous = err == 0;
1110 if (!err)
1111 {
1112 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
1113
1114 /* check if it actually worked, this stuff is not always behaving well. */
1115 if (!(ifnet_flags(pIfNet) & IFF_PROMISC))
1116 {
1117 err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
1118 if (!err)
1119 err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1120 if (!err)
1121 Log(("vboxNetFlt: fixed IFF_PROMISC on %s (%d->%d)\n", pThis->szName, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1122 else
1123 Log(("VBoxNetFlt: failed to fix IFF_PROMISC on %s, err=%d (%d->%d)\n",
1124 pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1125 }
1126 }
1127 else
1128 Log(("VBoxNetFlt: ifnet_set_promiscuous -> err=%d grr! (%d->%d)\n", err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1129 }
1130 else if (!err)
1131 Log(("VBoxNetFlt: Waiting for the link to come up... (%d->%d)\n", cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1132 if (err)
1133 LogRel(("VBoxNetFlt: Failed to put '%s' into promiscuous mode, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1134 }
1135 else
1136 {
1137 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
1138 if (pThis->u.s.fSetPromiscuous)
1139 {
1140 errno_t err = ifnet_set_promiscuous(pIfNet, 0);
1141 AssertMsg(!err, ("%d\n", err)); NOREF(err);
1142 }
1143 pThis->u.s.fSetPromiscuous = false;
1144
1145 fIf = ifnet_flags(pIfNet);
1146 Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1147 }
1148
1149 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1150 }
1151}
1152
1153
1154int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
1155{
1156 /* Nothing to do here. */
1157 return VINF_SUCCESS;
1158}
1159
1160
1161int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
1162{
1163 /* Nothing to do here. */
1164 return VINF_SUCCESS;
1165}
1166
1167
1168void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
1169{
1170 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1171 interface_filter_t pIfFilter;
1172
1173 /*
1174 * Carefully obtain the interface filter reference and detach it.
1175 */
1176 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
1177 pIfFilter = (interface_filter_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfFilter);
1178 if (pIfFilter)
1179 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, NULL);
1180 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
1181
1182 if (pIfFilter)
1183 iflt_detach(pIfFilter);
1184}
1185
1186
1187int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
1188{
1189 return vboxNetFltDarwinAttachToInterface(pThis, false /* fRediscovery */);
1190}
1191
1192
1193int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1194{
1195 /*
1196 * Init the darwin specific members.
1197 */
1198 pThis->u.s.pIfNet = NULL;
1199 pThis->u.s.pIfFilter = NULL;
1200 pThis->u.s.fSetPromiscuous = false;
1201 pThis->u.s.fNeedSetPromiscuous = false;
1202 //pThis->u.s.Mac = {0};
1203
1204 return VINF_SUCCESS;
1205}
1206
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