VirtualBox

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

Last change on this file since 91521 was 90804, checked in by vboxsync, 3 years ago

HostDrivers: More VALID_PTR -> RT_VALID_PTR/AssertPtr.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 60.8 KB
Line 
1/* $Id: VBoxNetFlt-darwin.cpp 90804 2021-08-23 19:08:53Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
32#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
33
34#include <VBox/log.h>
35#include <VBox/err.h>
36#include <VBox/intnetinline.h>
37#include <VBox/version.h>
38#include <iprt/initterm.h>
39#include <iprt/assert.h>
40#include <iprt/spinlock.h>
41#include <iprt/semaphore.h>
42#include <iprt/process.h>
43#include <iprt/alloc.h>
44#include <iprt/alloca.h>
45#include <iprt/time.h>
46#include <iprt/net.h>
47#include <iprt/thread.h>
48
49#include "../../darwin/VBoxNetSend.h"
50
51#include <mach/kmod.h>
52#include <sys/conf.h>
53#include <sys/errno.h>
54#include <sys/ioccom.h>
55#include <sys/filio.h>
56#include <sys/malloc.h>
57#include <sys/proc.h>
58#include <sys/socket.h>
59#include <sys/sockio.h>
60#include <sys/kern_event.h>
61#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 /* The 10.15 SDK has a slightly butchered API deprecation attempt. */
62# pragma clang diagnostic push
63# pragma clang diagnostic ignored "-Wmacro-redefined" /* Each header redefines __NKE_API_DEPRECATED. */
64# pragma clang diagnostic ignored "-Wmissing-declarations" /* Misplaced __NKE_API_DEPRECATED; in kpi_mbuf.h. */
65# include <sys/kpi_socket.h>
66# include <net/kpi_interface.h>
67# include <sys/kpi_mbuf.h>
68# include <net/kpi_interfacefilter.h>
69# pragma clang diagnostic pop
70#else /* < 10.15*/
71# include <sys/kpi_socket.h>
72# include <net/kpi_interface.h>
73RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
74# include <sys/kpi_mbuf.h>
75# include <net/kpi_interfacefilter.h>
76RT_C_DECLS_END
77#endif /* < 10.15*/
78
79
80#include <net/if.h>
81#include <net/if_var.h>
82RT_C_DECLS_BEGIN
83#include <net/bpf.h>
84RT_C_DECLS_END
85#include <netinet/in.h>
86#include <netinet/in_var.h>
87#include <netinet6/in6_var.h>
88
89#define VBOXNETFLT_OS_SPECFIC 1
90#include "../VBoxNetFltInternal.h"
91
92
93/*********************************************************************************************************************************
94* Defined Constants And Macros *
95*********************************************************************************************************************************/
96/** The maximum number of SG segments.
97 * Used to prevent stack overflow and similar bad stuff. */
98#define VBOXNETFLT_DARWIN_MAX_SEGS 32
99
100#if 0
101/** For testing extremely segmented frames. */
102#define VBOXNETFLT_DARWIN_TEST_SEG_SIZE 14
103#endif
104
105/* XXX: hidden undef #ifdef __APPLE__ */
106#define VBOX_IN_LOOPBACK(addr) (((addr) & IN_CLASSA_NET) == 0x7f000000)
107#define VBOX_IN_LINKLOCAL(addr) (((addr) & IN_CLASSB_NET) == 0xa9fe0000)
108
109
110
111/*********************************************************************************************************************************
112* Internal Functions *
113*********************************************************************************************************************************/
114RT_C_DECLS_BEGIN
115static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData);
116static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData);
117
118static void vboxNetFltDarwinSysSockUpcall(socket_t pSysSock, void *pvData, int fWait);
119RT_C_DECLS_END
120
121
122/*********************************************************************************************************************************
123* Structures and Typedefs *
124*********************************************************************************************************************************/
125/**
126 * The mbuf tag data.
127 *
128 * We have to associate the ethernet header with each packet we're sending
129 * because things like icmp will inherit the tag it self so the tag along
130 * isn't sufficient to identify our mbufs. For the icmp scenario the ethernet
131 * header naturally changes before the packet is send pack, so let check it.
132 */
133typedef struct VBOXNETFLTTAG
134{
135 /** The ethernet header of the outgoing frame. */
136 RTNETETHERHDR EthHdr;
137} VBOXNETFLTTAG;
138/** Pointer to a VBoxNetFlt mbuf tag. */
139typedef VBOXNETFLTTAG *PVBOXNETFLTTAG;
140/** Pointer to a const VBoxNetFlt mbuf tag. */
141typedef VBOXNETFLTTAG const *PCVBOXNETFLTTAG;
142
143
144/*********************************************************************************************************************************
145* Global Variables *
146*********************************************************************************************************************************/
147/**
148 * Declare the module stuff.
149 */
150RT_C_DECLS_BEGIN
151extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
152extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
153
154KMOD_EXPLICIT_DECL(VBoxNetFlt, VBOX_VERSION_STRING, _start, _stop)
155DECL_HIDDEN_DATA(kmod_start_func_t *) _realmain = VBoxNetFltDarwinStart;
156DECL_HIDDEN_DATA(kmod_stop_func_t *) _antimain = VBoxNetFltDarwinStop;
157DECL_HIDDEN_DATA(int) _kext_apple_cc = __APPLE_CC__;
158RT_C_DECLS_END
159
160
161/**
162 * The (common) global data.
163 */
164static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
165
166/** The unique tag id for this module.
167 * This is basically a unique string hash that lives on until reboot.
168 * It is used for tagging mbufs. */
169static mbuf_tag_id_t g_idTag;
170
171/** The offset of the struct ifnet::if_pcount variable.
172 * @remarks Initial value is valid for Lion and earlier. We adjust it on attach
173 * for later releases. */
174static unsigned g_offIfNetPCount = sizeof(void *) * (1 /*if_softc*/ + 1 /*if_name*/ + 2 /*if_link*/ + 2 /*if_addrhead*/ + 1 /*if_check_multi*/)
175 + sizeof(u_long) /*if_refcnt*/;
176/** Macro for accessing ifnet::if_pcount. */
177#define VBOX_GET_PCOUNT(pIfNet) ( *(int *)((uintptr_t)pIfNet + g_offIfNetPCount) )
178/** The size of area of ifnet structure we try to locate if_pcount in. */
179#define VBOXNETFLT_DARWIN_IFNET_SIZE 256
180/** Indicates whether g_offIfNetPCount has been adjusted already (no point in
181 * doing it more than once). */
182static bool g_fNetPCountFound = false;
183
184
185/**
186 * Change the promiscuous setting and try spot the changed in @a pIfNet.
187 *
188 * @returns Offset of potential p_count field.
189 * @param pIfNet The interface we're attaching to.
190 * @param iPromisc Whether to enable (1) or disable (0) promiscuous mode.
191 *
192 * @note This implementation relies on if_pcount to be aligned on sizeof(int).
193 */
194static unsigned vboxNetFltDarwinSetAndDiff(ifnet_t pIfNet, int iPromisc)
195{
196 int aiSavedState[VBOXNETFLT_DARWIN_IFNET_SIZE / sizeof(int)];
197 memcpy(aiSavedState, pIfNet, sizeof(aiSavedState));
198
199 ifnet_set_promiscuous(pIfNet, iPromisc);
200
201 int const iDiff = iPromisc ? 1 : -1;
202
203 /*
204 * We assume that ifnet structure will never have less members in front of if_pcount
205 * than it used to have in Lion. If this turns out to be false assumption we will
206 * have to start from zero offset.
207 */
208 for (unsigned i = g_offIfNetPCount / sizeof(int); i < RT_ELEMENTS(aiSavedState); i++)
209 if (((int*)pIfNet)[i] - aiSavedState[i] == iDiff)
210 return i * sizeof(int);
211
212 return 0;
213}
214
215
216/**
217 * Detect and adjust the offset of ifnet::if_pcount.
218 *
219 * @param pIfNet The interface we're attaching to.
220 */
221static void vboxNetFltDarwinDetectPCountOffset(ifnet_t pIfNet)
222{
223 if (g_fNetPCountFound)
224 return;
225
226 /*
227 * It would be nice to use locking at this point, but it is not available via KPI.
228 * This is why we try several times. At each attempt we modify if_pcount four times
229 * to rule out false detections.
230 */
231 unsigned offTry1, offTry2, offTry3, offTry4;
232 for (int iAttempt = 0; iAttempt < 3; iAttempt++)
233 {
234 offTry1 = vboxNetFltDarwinSetAndDiff(pIfNet, 1);
235 offTry2 = vboxNetFltDarwinSetAndDiff(pIfNet, 1);
236 offTry3 = vboxNetFltDarwinSetAndDiff(pIfNet, 0);
237 offTry4 = vboxNetFltDarwinSetAndDiff(pIfNet, 0);
238 if (offTry1 == offTry2 && offTry2 == offTry3 && offTry3 == offTry4)
239 {
240 if (g_offIfNetPCount != offTry1)
241 {
242 Log(("VBoxNetFltDarwinDetectPCountOffset: Adjusted if_pcount offset to %x from %x.\n", offTry1, g_offIfNetPCount));
243 g_offIfNetPCount = offTry1;
244 g_fNetPCountFound = true;
245 }
246 break;
247 }
248 }
249
250 if (g_offIfNetPCount != offTry1)
251 LogRel(("VBoxNetFlt: Failed to detect promiscuous count, all traffic may reach wire (%x != %x).\n", g_offIfNetPCount, offTry1));
252}
253
254
255/**
256 * Start the kernel module.
257 */
258static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData)
259{
260 RT_NOREF(pKModInfo, pvData);
261
262 /*
263 * Initialize IPRT and find our module tag id.
264 * (IPRT is shared with VBoxDrv, it creates the loggers.)
265 */
266 int rc = RTR0Init(0);
267 if (RT_SUCCESS(rc))
268 {
269 Log(("VBoxNetFltDarwinStart\n"));
270 errno_t err = mbuf_tag_id_find("org.VirtualBox.kext.VBoxFltDrv", &g_idTag);
271 if (!err)
272 {
273 /*
274 * Initialize the globals and connect to the support driver.
275 *
276 * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
277 * for establishing the connect to the support driver.
278 */
279 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
280 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltGlobals);
281 if (RT_SUCCESS(rc))
282 {
283 LogRel(("VBoxFltDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
284 return KMOD_RETURN_SUCCESS;
285 }
286
287 LogRel(("VBoxFltDrv: failed to initialize device extension (rc=%d)\n", rc));
288 }
289 else
290 LogRel(("VBoxFltDrv: mbuf_tag_id_find failed, err=%d\n", err));
291 RTR0Term();
292 }
293 else
294 printf("VBoxFltDrv: failed to initialize IPRT (rc=%d)\n", rc);
295
296 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
297 return KMOD_RETURN_FAILURE;
298}
299
300
301/**
302 * Stop the kernel module.
303 */
304static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData)
305{
306 RT_NOREF(pKModInfo, pvData);
307 Log(("VBoxNetFltDarwinStop\n"));
308
309 /*
310 * Refuse to unload if anyone is currently using the filter driver.
311 * This is important as I/O kit / xnu will to be able to do usage
312 * tracking for us!
313 */
314 int rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltGlobals);
315 if (RT_FAILURE(rc))
316 {
317 Log(("VBoxNetFltDarwinStop - failed, busy.\n"));
318 return KMOD_RETURN_FAILURE;
319 }
320
321 /*
322 * Undo the work done during start (in reverse order).
323 */
324 memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
325
326 RTR0Term();
327
328 return KMOD_RETURN_SUCCESS;
329}
330
331
332/**
333 * Reads and retains the host interface handle.
334 *
335 * @returns The handle, NULL if detached.
336 * @param pThis
337 */
338DECLINLINE(ifnet_t) vboxNetFltDarwinRetainIfNet(PVBOXNETFLTINS pThis)
339{
340 ifnet_t pIfNet = NULL;
341
342 /*
343 * Be careful here to avoid problems racing the detached callback.
344 */
345 RTSpinlockAcquire(pThis->hSpinlock);
346 if (!ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
347 {
348 pIfNet = ASMAtomicUoReadPtrT(&pThis->u.s.pIfNet, ifnet_t);
349 if (pIfNet)
350 ifnet_reference(pIfNet);
351 }
352 RTSpinlockRelease(pThis->hSpinlock);
353
354 return pIfNet;
355}
356
357
358/**
359 * Release the host interface handle previously retained
360 * by vboxNetFltDarwinRetainIfNet.
361 *
362 * @param pThis The instance.
363 * @param pIfNet The vboxNetFltDarwinRetainIfNet return value, NULL is fine.
364 */
365DECLINLINE(void) vboxNetFltDarwinReleaseIfNet(PVBOXNETFLTINS pThis, ifnet_t pIfNet)
366{
367 NOREF(pThis);
368 if (pIfNet)
369 ifnet_release(pIfNet);
370}
371
372
373/**
374 * Checks whether this is an mbuf created by vboxNetFltDarwinMBufFromSG,
375 * i.e. a buffer which we're pushing and should be ignored by the filter callbacks.
376 *
377 * @returns true / false accordingly.
378 * @param pThis The instance.
379 * @param pMBuf The mbuf.
380 * @param pvFrame The frame pointer, optional.
381 */
382DECLINLINE(bool) vboxNetFltDarwinMBufIsOur(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
383{
384 NOREF(pThis);
385
386 /*
387 * Lookup the tag set by vboxNetFltDarwinMBufFromSG.
388 */
389 PCVBOXNETFLTTAG pTagData;
390 size_t cbTagData;
391 errno_t err = mbuf_tag_find(pMBuf, g_idTag, 0 /* type */, &cbTagData, (void **)&pTagData);
392 if (err)
393 return false;
394 AssertReturn(cbTagData == sizeof(*pTagData), false);
395
396 /*
397 * Dig out the ethernet header from the mbuf.
398 */
399 PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
400 if (!pEthHdr)
401 pEthHdr = (PCRTNETETHERHDR)mbuf_pkthdr_header(pMBuf);
402 if (!pEthHdr)
403 pEthHdr = (PCRTNETETHERHDR)mbuf_data(pMBuf);
404 /* ASSUMING that there is enough data to work on! */
405 if ( pEthHdr->DstMac.au8[0] != pTagData->EthHdr.DstMac.au8[0]
406 || pEthHdr->DstMac.au8[1] != pTagData->EthHdr.DstMac.au8[1]
407 || pEthHdr->DstMac.au8[2] != pTagData->EthHdr.DstMac.au8[2]
408 || pEthHdr->DstMac.au8[3] != pTagData->EthHdr.DstMac.au8[3]
409 || pEthHdr->DstMac.au8[4] != pTagData->EthHdr.DstMac.au8[4]
410 || pEthHdr->DstMac.au8[5] != pTagData->EthHdr.DstMac.au8[5]
411 || pEthHdr->SrcMac.au8[0] != pTagData->EthHdr.SrcMac.au8[0]
412 || pEthHdr->SrcMac.au8[1] != pTagData->EthHdr.SrcMac.au8[1]
413 || pEthHdr->SrcMac.au8[2] != pTagData->EthHdr.SrcMac.au8[2]
414 || pEthHdr->SrcMac.au8[3] != pTagData->EthHdr.SrcMac.au8[3]
415 || pEthHdr->SrcMac.au8[4] != pTagData->EthHdr.SrcMac.au8[4]
416 || pEthHdr->SrcMac.au8[5] != pTagData->EthHdr.SrcMac.au8[5]
417 || pEthHdr->EtherType != pTagData->EthHdr.EtherType)
418 {
419 Log3(("tagged, but the ethernet header has changed\n"));
420 return false;
421 }
422
423 return true;
424}
425
426
427/**
428 * Internal worker that create a darwin mbuf for a (scatter/)gather list.
429 *
430 * @returns Pointer to the mbuf.
431 * @param pThis The instance.
432 * @param pSG The (scatter/)gather list.
433 */
434static mbuf_t vboxNetFltDarwinMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
435{
436 /// @todo future? mbuf_how_t How = preemption enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
437 mbuf_how_t How = MBUF_WAITOK;
438
439 /*
440 * We need some way of getting back to our instance data when
441 * the mbuf is freed, so use pvUserData for this.
442 * -- this is not relevant anylonger! --
443 */
444 Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
445 Assert(!pSG->pvUserData2);
446 pSG->pvUserData = pThis;
447
448 /*
449 * Allocate a packet and copy over the data.
450 *
451 * Using mbuf_attachcluster() here would've been nice but there are two
452 * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
453 * that it's not supposed to be used for really external buffers. The 2nd
454 * point might be argued against considering that the only m_clattach user
455 * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
456 * However, it's hard to tell if these m_clattach buffers actually makes it
457 * to the NICs or not, and even if they did, the NIC would need the physical
458 * addresses for the pages they contain and might end up copying the data
459 * to a new mbuf anyway.
460 *
461 * So, in the end it's better to just do it the simple way that will work
462 * 100%, even if it involves some extra work (alloc + copy) we really wished
463 * to avoid.
464 *
465 * Note. We can't make use of the physical addresses on darwin because the
466 * way the mbuf / cluster stuff works (see mbuf_data_to_physical and
467 * mcl_to_paddr).
468 */
469 mbuf_t pPkt = NULL;
470 errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
471 if (!err)
472 {
473 /* Skip zero sized memory buffers (paranoia). */
474 mbuf_t pCur = pPkt;
475 while (pCur && !mbuf_maxlen(pCur))
476 pCur = mbuf_next(pCur);
477 Assert(pCur);
478
479 /* Set the required packet header attributes. */
480 mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
481 mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
482
483 /* Special case the single buffer copy. */
484 if ( mbuf_next(pCur)
485 && mbuf_maxlen(pCur) >= pSG->cbTotal)
486 {
487 mbuf_setlen(pCur, pSG->cbTotal);
488 IntNetSgRead(pSG, mbuf_data(pCur));
489 }
490 else
491 {
492 /* Multi buffer copying. */
493 size_t cbLeft = pSG->cbTotal;
494 size_t offSrc = 0;
495 while (cbLeft > 0 && pCur)
496 {
497 size_t cb = mbuf_maxlen(pCur);
498 if (cb > cbLeft)
499 cb = cbLeft;
500 mbuf_setlen(pCur, cb);
501 IntNetSgReadEx(pSG, offSrc, cb, mbuf_data(pCur));
502
503 /* advance */
504 offSrc += cb;
505 cbLeft -= cb;
506 pCur = mbuf_next(pCur);
507 }
508 Assert(cbLeft == 0);
509 }
510 if (!err)
511 {
512 /*
513 * Tag the packet and return successfully.
514 */
515 PVBOXNETFLTTAG pTagData;
516 err = mbuf_tag_allocate(pPkt, g_idTag, 0 /* type */, sizeof(VBOXNETFLTTAG) /* tag len */, How, (void **)&pTagData);
517 if (!err)
518 {
519 Assert(pSG->aSegs[0].cb >= sizeof(pTagData->EthHdr));
520 memcpy(&pTagData->EthHdr, pSG->aSegs[0].pv, sizeof(pTagData->EthHdr));
521 return pPkt;
522 }
523
524 /* bailout: */
525 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
526 }
527
528 mbuf_freem(pPkt);
529 }
530 else
531 AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
532 pSG->pvUserData = NULL;
533
534 return NULL;
535}
536
537
538/**
539 * Calculates the number of segments required to represent the mbuf.
540 *
541 * @returns Number of segments.
542 * @param pThis The instance.
543 * @param pMBuf The mbuf.
544 * @param pvFrame The frame pointer, optional.
545 */
546DECLINLINE(unsigned) vboxNetFltDarwinMBufCalcSGSegs(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
547{
548 NOREF(pThis);
549
550 /*
551 * Count the buffers in the chain.
552 */
553 unsigned cSegs = 0;
554 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
555 if (mbuf_len(pCur))
556 cSegs++;
557 else if ( !cSegs
558 && pvFrame
559 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
560 cSegs++;
561
562#ifdef PADD_RUNT_FRAMES_FROM_HOST
563 /*
564 * Add one buffer if the total is less than the ethernet minimum 60 bytes.
565 * This may allocate a segment too much if the ethernet header is separated,
566 * but that shouldn't harm us much.
567 */
568 if (mbuf_pkthdr_len(pMBuf) < 60)
569 cSegs++;
570#endif
571
572#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
573 /* maximize the number of segments. */
574 cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
575#endif
576
577 return cSegs ? cSegs : 1;
578}
579
580
581/**
582 * Initializes a SG list from an mbuf.
583 *
584 * @returns Number of segments.
585 * @param pThis The instance.
586 * @param pMBuf The mbuf.
587 * @param pSG The SG.
588 * @param pvFrame The frame pointer, optional.
589 * @param cSegs The number of segments allocated for the SG.
590 * This should match the number in the mbuf exactly!
591 * @param fSrc The source of the frame.
592 */
593DECLINLINE(void) vboxNetFltDarwinMBufToSG(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs,
594 uint32_t fSrc)
595{
596 RT_NOREF(pThis, fSrc);
597
598 /*
599 * Walk the chain and convert the buffers to segments. Works INTNETSG::cbTotal.
600 */
601 unsigned iSeg = 0;
602 IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
603 for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
604 {
605 size_t cbSeg = mbuf_len(pCur);
606 if (cbSeg)
607 {
608 void *pvSeg = mbuf_data(pCur);
609
610 /* deal with pvFrame */
611 if (!iSeg && pvFrame && pvFrame != pvSeg)
612 {
613 void *pvStart = mbuf_datastart(pMBuf);
614 uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
615 uintptr_t offSegEnd = offSeg + cbSeg;
616 Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
617 uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
618 if (RT_LIKELY(offFrame < offSeg))
619 {
620 pvSeg = pvFrame;
621 cbSeg += offSeg - offFrame;
622 }
623 else
624 AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
625 pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
626 pvFrame = NULL;
627 }
628
629 AssertBreak(iSeg < cSegs);
630 pSG->cbTotal += cbSeg;
631 pSG->aSegs[iSeg].cb = cbSeg;
632 pSG->aSegs[iSeg].pv = pvSeg;
633 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
634 iSeg++;
635 }
636 /* The pvFrame might be in a now empty buffer. */
637 else if ( !iSeg
638 && pvFrame
639 && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
640 {
641 cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
642 pSG->cbTotal += cbSeg;
643 pSG->aSegs[iSeg].cb = cbSeg;
644 pSG->aSegs[iSeg].pv = pvFrame;
645 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
646 iSeg++;
647 pvFrame = NULL;
648 }
649 }
650
651 Assert(iSeg && iSeg <= cSegs);
652 pSG->cSegsUsed = iSeg;
653
654#ifdef PADD_RUNT_FRAMES_FROM_HOST
655 /*
656 * Add a trailer if the frame is too small.
657 *
658 * Since we're getting to the packet before it is framed, it has not
659 * yet been padded. The current solution is to add a segment pointing
660 * to a buffer containing all zeros and pray that works for all frames...
661 */
662 if (pSG->cbTotal < 60 && (fSrc == INTNETTRUNKDIR_HOST))
663 {
664 AssertReturnVoid(iSeg < cSegs);
665
666 static uint8_t const s_abZero[128] = {0};
667 pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
668 pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
669 pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
670 pSG->cbTotal = 60;
671 pSG->cSegsUsed++;
672 }
673#endif
674
675#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
676 /*
677 * Redistribute the segments.
678 */
679 if (pSG->cSegsUsed < pSG->cSegsAlloc)
680 {
681 /* copy the segments to the end. */
682 int iSrc = pSG->cSegsUsed;
683 int iDst = pSG->cSegsAlloc;
684 while (iSrc > 0)
685 {
686 iDst--;
687 iSrc--;
688 pSG->aSegs[iDst] = pSG->aSegs[iSrc];
689 }
690
691 /* create small segments from the start. */
692 pSG->cSegsUsed = pSG->cSegsAlloc;
693 iSrc = iDst;
694 iDst = 0;
695 while ( iDst < iSrc
696 && iDst < pSG->cSegsAlloc)
697 {
698 pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
699 pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
700 pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
701 if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
702 {
703 pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
704 pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
705 }
706 else if (++iSrc >= pSG->cSegsAlloc)
707 {
708 pSG->cSegsUsed = iDst + 1;
709 break;
710 }
711 iDst++;
712 }
713 }
714#endif
715
716 AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
717}
718
719
720/**
721 * Helper for determining whether the host wants the interface to be
722 * promiscuous.
723 */
724static bool vboxNetFltDarwinIsPromiscuous(PVBOXNETFLTINS pThis)
725{
726 bool fRc = false;
727 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
728 if (pIfNet)
729 {
730 /* gather the data */
731 uint16_t fIf = ifnet_flags(pIfNet);
732 unsigned cPromisc = VBOX_GET_PCOUNT(pIfNet);
733 bool fSetPromiscuous = ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous);
734 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
735
736 /* calc the return. */
737 fRc = (fIf & IFF_PROMISC)
738 && cPromisc > fSetPromiscuous;
739 }
740 return fRc;
741}
742
743
744
745/**
746 *
747 * @see iff_detached_func in the darwin kpi.
748 */
749static void vboxNetFltDarwinIffDetached(void *pvThis, ifnet_t pIfNet)
750{
751 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
752 uint64_t NanoTS = RTTimeSystemNanoTS();
753 LogFlow(("vboxNetFltDarwinIffDetached: pThis=%p NanoTS=%RU64 (%d)\n",
754 pThis, NanoTS, RT_VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
755
756 Assert(!pThis->fDisconnectedFromHost);
757 Assert(!pThis->fRediscoveryPending);
758
759 /*
760 * If we've put it into promiscuous mode, undo that now. If we don't
761 * the if_pcount will go all wrong when it's replugged.
762 */
763 if (ASMAtomicXchgBool(&pThis->u.s.fSetPromiscuous, false))
764 ifnet_set_promiscuous(pIfNet, 0);
765
766 /*
767 * We carefully take the spinlock and increase the interface reference
768 * behind it in order to avoid problematic races with the detached callback.
769 */
770 RTSpinlockAcquire(pThis->hSpinlock);
771
772 pIfNet = ASMAtomicUoReadPtrT(&pThis->u.s.pIfNet, ifnet_t);
773 int cPromisc = RT_VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : - 1;
774
775 ASMAtomicUoWriteNullPtr(&pThis->u.s.pIfNet);
776 ASMAtomicUoWriteNullPtr(&pThis->u.s.pIfFilter);
777 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
778 pThis->u.s.fSetPromiscuous = false;
779 ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, NanoTS);
780 ASMAtomicUoWriteBool(&pThis->fRediscoveryPending, false);
781 ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
782
783 RTSpinlockRelease(pThis->hSpinlock);
784
785 if (pIfNet)
786 ifnet_release(pIfNet);
787 LogRel(("VBoxNetFlt: was detached from '%s' (%d)\n", pThis->szName, cPromisc));
788}
789
790
791/**
792 *
793 * @see iff_ioctl_func in the darwin kpi.
794 */
795static errno_t vboxNetFltDarwinIffIoCtl(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, u_long uCmd, void *pvArg)
796{
797 RT_NOREF(pIfNet);
798 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
799 LogFlow(("vboxNetFltDarwinIffIoCtl: pThis=%p uCmd=%lx\n", pThis, uCmd));
800
801 /*
802 * Update fOtherPromiscuous.
803 */
804 /** @todo we'll have to find the offset of if_pcount to get this right! */
805 //if (uCmd == SIOCSIFFLAGS)
806 //{
807 //
808 //}
809
810 /*
811 * We didn't handle it, continue processing.
812 */
813 NOREF(pThis);
814 NOREF(eProtocol);
815 NOREF(uCmd);
816 NOREF(pvArg);
817 return EOPNOTSUPP;
818}
819
820
821/**
822 *
823 * @see iff_event_func in the darwin kpi.
824 */
825static void vboxNetFltDarwinIffEvent(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, const struct kev_msg *pEvMsg)
826{
827 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
828 LogFlow(("vboxNetFltDarwinIffEvent: pThis=%p\n", pThis));
829
830 NOREF(pThis);
831 NOREF(pIfNet);
832 NOREF(eProtocol);
833 NOREF(pEvMsg);
834
835 /*
836 * Watch out for the interface going online / offline.
837 */
838 if ( RT_VALID_PTR(pThis)
839 && RT_VALID_PTR(pEvMsg)
840 && pEvMsg->vendor_code == KEV_VENDOR_APPLE
841 && pEvMsg->kev_class == KEV_NETWORK_CLASS
842 && pEvMsg->kev_subclass == KEV_DL_SUBCLASS)
843 {
844 if (pThis->u.s.pIfNet == pIfNet)
845 {
846 if (pEvMsg->event_code == KEV_DL_LINK_ON)
847 {
848 if (ASMAtomicUoReadBool(&pThis->u.s.fNeedSetPromiscuous))
849 {
850 /* failed to bring it online. */
851 errno_t err = ifnet_set_promiscuous(pIfNet, 1);
852 if (!err)
853 {
854 ASMAtomicWriteBool(&pThis->u.s.fSetPromiscuous, true);
855 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
856 Log(("vboxNetFltDarwinIffEvent: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
857 }
858 else
859 Log(("vboxNetFltDarwinIffEvent: ifnet_set_promiscuous failed on %s, err=%d (%d)\n", pThis->szName, err, VBOX_GET_PCOUNT(pIfNet)));
860 }
861 else if ( ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous)
862 && !(ifnet_flags(pIfNet) & IFF_PROMISC))
863 {
864 /* Try fix the inconsistency. */
865 errno_t err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
866 if (!err)
867 err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
868 if (!err && (ifnet_flags(pIfNet) & IFF_PROMISC))
869 Log(("vboxNetFltDarwinIffEvent: fixed IFF_PROMISC on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
870 else
871 Log(("vboxNetFltDarwinIffEvent: failed to fix IFF_PROMISC on %s, err=%d flags=%#x (%d)\n",
872 pThis->szName, err, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
873 }
874 else
875 Log(("vboxNetFltDarwinIffEvent: online, '%s'. flags=%#x (%d)\n", pThis->szName, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
876 }
877 else if (pEvMsg->event_code == KEV_DL_LINK_OFF)
878 Log(("vboxNetFltDarwinIffEvent: %s goes down (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
879/** @todo KEV_DL_LINK_ADDRESS_CHANGED -> pfnReportMacAddress */
880/** @todo KEV_DL_SIFFLAGS -> pfnReportPromiscuousMode */
881 }
882 else
883 Log(("vboxNetFltDarwinIffEvent: pThis->u.s.pIfNet=%p pIfNet=%p (%d)\n", pThis->u.s.pIfNet, pIfNet, RT_VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
884 }
885 else if (RT_VALID_PTR(pEvMsg))
886 Log(("vboxNetFltDarwinIffEvent: vendor_code=%#x kev_class=%#x kev_subclass=%#x event_code=%#x\n",
887 pEvMsg->vendor_code, pEvMsg->kev_class, pEvMsg->kev_subclass, pEvMsg->event_code));
888}
889
890
891/**
892 * Internal worker for vboxNetFltDarwinIffInput and vboxNetFltDarwinIffOutput,
893 *
894 * @returns 0 or EJUSTRETURN.
895 * @param pThis The instance.
896 * @param pMBuf The mbuf.
897 * @param pvFrame The start of the frame, optional.
898 * @param fSrc Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value.
899 * @param eProtocol The protocol.
900 */
901static errno_t vboxNetFltDarwinIffInputOutputWorker(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame,
902 uint32_t fSrc, protocol_family_t eProtocol)
903{
904 /*
905 * Drop it immediately?
906 */
907 Log2(("vboxNetFltDarwinIffInputOutputWorker: pThis=%p pMBuf=%p pvFrame=%p fSrc=%#x cbPkt=%x\n",
908 pThis, pMBuf, pvFrame, fSrc, pMBuf ? mbuf_pkthdr_len(pMBuf) : -1));
909 if (!pMBuf)
910 return 0;
911#if 0 /* debugging lost icmp packets */
912 if (mbuf_pkthdr_len(pMBuf) > 0x300)
913 {
914 uint8_t *pb = (uint8_t *)(pvFrame ? pvFrame : mbuf_data(pMBuf));
915 Log3(("D=%.6Rhxs S=%.6Rhxs T=%04x IFF\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
916 }
917#endif
918 if (vboxNetFltDarwinMBufIsOur(pThis, pMBuf, pvFrame))
919 return 0;
920
921 /*
922 * Active? Retain the instance and increment the busy counter.
923 */
924 if (!vboxNetFltTryRetainBusyActive(pThis))
925 return 0;
926
927 /*
928 * Finalize out-bound packets since the stack puts off finalizing
929 * TCP/IP checksums as long as possible.
930 * ASSUMES this only applies to outbound IP packets.
931 */
932 if (fSrc == INTNETTRUNKDIR_HOST)
933 {
934 Assert(!pvFrame);
935 mbuf_outbound_finalize(pMBuf, eProtocol, sizeof(RTNETETHERHDR));
936 }
937
938 /*
939 * Create a (scatter/)gather list for the mbuf and feed it to the internal network.
940 */
941 bool fDropIt = false;
942 unsigned cSegs = vboxNetFltDarwinMBufCalcSGSegs(pThis, pMBuf, pvFrame);
943 if (cSegs < VBOXNETFLT_DARWIN_MAX_SEGS)
944 {
945 PINTNETSG pSG = (PINTNETSG)alloca(RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
946 vboxNetFltDarwinMBufToSG(pThis, pMBuf, pvFrame, pSG, cSegs, fSrc);
947
948 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
949 if (fDropIt)
950 {
951 /*
952 * If the interface is in promiscuous mode we should let
953 * all inbound packets (this one was for a bridged guest)
954 * reach the driver as it passes them to tap callbacks in
955 * order for BPF to work properly.
956 */
957 if ( fSrc == INTNETTRUNKDIR_WIRE
958 && vboxNetFltDarwinIsPromiscuous(pThis))
959 {
960 fDropIt = false;
961 }
962
963 /*
964 * A packet from the host to a guest. As we won't pass it
965 * to the drvier/wire we need to feed it to bpf ourselves.
966 *
967 * XXX: TODO: bpf should be done before; use pfnPreRecv?
968 */
969 if (fSrc == INTNETTRUNKDIR_HOST)
970 {
971 bpf_tap_out(pThis->u.s.pIfNet, DLT_EN10MB, pMBuf, NULL, 0);
972 ifnet_stat_increment_out(pThis->u.s.pIfNet, 1, mbuf_len(pMBuf), 0);
973 }
974 }
975 }
976
977 vboxNetFltRelease(pThis, true /* fBusy */);
978
979 if (fDropIt)
980 {
981 mbuf_freem(pMBuf);
982 return EJUSTRETURN;
983 }
984 return 0;
985}
986
987
988/**
989 * From the host.
990 *
991 * @see iff_output_func in the darwin kpi.
992 */
993static errno_t vboxNetFltDarwinIffOutput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf)
994{
995 /** @todo there was some note about the ethernet header here or something like that... */
996
997 NOREF(eProtocol);
998 NOREF(pIfNet);
999 return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, NULL, INTNETTRUNKDIR_HOST, eProtocol);
1000}
1001
1002
1003/**
1004 * From the wire.
1005 *
1006 * @see iff_input_func in the darwin kpi.
1007 */
1008static errno_t vboxNetFltDarwinIffInput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf, char **ppchFrame)
1009{
1010 RT_NOREF(eProtocol, pIfNet);
1011 return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, *ppchFrame, INTNETTRUNKDIR_WIRE, eProtocol);
1012}
1013
1014
1015/** A worker thread for vboxNetFltSendDummy(). */
1016static DECLCALLBACK(int) vboxNetFltSendDummyWorker(RTTHREAD hThreadSelf, void *pvUser)
1017{
1018 RT_NOREF(hThreadSelf);
1019 Assert(pvUser);
1020 ifnet_t pIfNet = (ifnet_t)pvUser;
1021 return VBoxNetSendDummy(pIfNet);
1022}
1023
1024
1025/**
1026 * Prevent GUI icon freeze issue when VirtualBoxVM process terminates.
1027 *
1028 * This function is a workaround for stuck-in-dock issue. The idea here is to
1029 * send a dummy packet to an interface from the context of a kernel thread.
1030 * Therefore, an XNU's receive thread (which is created as a result if we are
1031 * the first who is communicating with the interface) will be associated with
1032 * the kernel thread instead of VirtualBoxVM process.
1033 *
1034 * @param pIfNet Interface to be used to send data.
1035 */
1036static void vboxNetFltSendDummy(ifnet_t pIfNet)
1037{
1038 RTTHREAD hThread;
1039 int rc = RTThreadCreate(&hThread, vboxNetFltSendDummyWorker, (void *)pIfNet, 0,
1040 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "DummyThread");
1041 if (RT_SUCCESS(rc))
1042 {
1043 RTThreadWait(hThread, RT_INDEFINITE_WAIT, NULL);
1044 LogFlow(("vboxNetFltSendDummy: a dummy packet has been successfully sent in order to prevent stuck-in-dock issue\n"));
1045 }
1046 else
1047 LogFlow(("vboxNetFltSendDummy: unable to send dummy packet in order to prevent stuck-in-dock issue\n"));
1048}
1049
1050
1051/**
1052 * Internal worker for vboxNetFltOsInitInstance and vboxNetFltOsMaybeRediscovered.
1053 *
1054 * @returns VBox status code.
1055 * @param pThis The instance.
1056 * @param fRediscovery If set we're doing a rediscovery attempt, so, don't
1057 * flood the release log.
1058 */
1059static int vboxNetFltDarwinAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery)
1060{
1061 LogFlow(("vboxNetFltDarwinAttachToInterface: pThis=%p (%s)\n", pThis, pThis->szName));
1062 IPRT_DARWIN_SAVE_EFL_AC();
1063
1064 /*
1065 * Locate the interface first.
1066 *
1067 * The pIfNet member is updated before iflt_attach is called and used
1068 * to deal with the hypothetical case where someone rips out the
1069 * interface immediately after our iflt_attach call.
1070 */
1071 ifnet_t pIfNet = NULL;
1072 errno_t err = ifnet_find_by_name(pThis->szName, &pIfNet);
1073 if (err)
1074 {
1075 Assert(err == ENXIO);
1076 if (!fRediscovery)
1077 LogRel(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
1078 else
1079 Log(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
1080 IPRT_DARWIN_RESTORE_EFL_AC();
1081 return VERR_INTNET_FLT_IF_NOT_FOUND;
1082 }
1083
1084 AssertCompileMemberAlignment(VBOXNETFLTINS, u.s.pIfNet, ARCH_BITS / 8);
1085 AssertMsg(!((uintptr_t)&pThis->u.s.pIfNet & (ARCH_BITS / 8 - 1)), ("pThis=%p\n", pThis));
1086 RTSpinlockAcquire(pThis->hSpinlock);
1087 ASMAtomicUoWritePtr(&pThis->u.s.pIfNet, pIfNet);
1088 RTSpinlockRelease(pThis->hSpinlock);
1089
1090 /* Adjust g_offIfNetPCount as it varies for different versions of xnu. */
1091 vboxNetFltDarwinDetectPCountOffset(pIfNet);
1092
1093 /* Prevent stuck-in-dock issue by associating interface receive thread with kernel thread. */
1094 vboxNetFltSendDummy(pIfNet);
1095
1096 /*
1097 * Get the mac address while we still have a valid ifnet reference.
1098 */
1099 err = ifnet_lladdr_copy_bytes(pIfNet, &pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr));
1100 if (!err)
1101 {
1102 /*
1103 * Try attach the filter.
1104 */
1105 struct iff_filter RegRec;
1106 RegRec.iff_cookie = pThis;
1107 RegRec.iff_name = "VBoxNetFlt";
1108 RegRec.iff_protocol = 0;
1109 RegRec.iff_input = vboxNetFltDarwinIffInput;
1110 RegRec.iff_output = vboxNetFltDarwinIffOutput;
1111 RegRec.iff_event = vboxNetFltDarwinIffEvent;
1112 RegRec.iff_ioctl = vboxNetFltDarwinIffIoCtl;
1113 RegRec.iff_detached = vboxNetFltDarwinIffDetached;
1114 interface_filter_t pIfFilter = NULL;
1115 err = iflt_attach(pIfNet, &RegRec, &pIfFilter);
1116 Assert(err || pIfFilter);
1117
1118 RTSpinlockAcquire(pThis->hSpinlock);
1119 pIfNet = ASMAtomicUoReadPtrT(&pThis->u.s.pIfNet, ifnet_t);
1120 if (pIfNet && !err)
1121 {
1122 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
1123 ASMAtomicUoWritePtr(&pThis->u.s.pIfFilter, pIfFilter);
1124 pIfNet = NULL; /* don't dereference it */
1125 }
1126 RTSpinlockRelease(pThis->hSpinlock);
1127
1128 /* Report capabilities. */
1129 if ( !pIfNet
1130 && vboxNetFltTryRetainBusyNotDisconnected(pThis))
1131 {
1132 Assert(pThis->pSwitchPort);
1133 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
1134#if 0
1135 /*
1136 * XXX: Don't tell SrvIntNetR0 if the interface is
1137 * promiscuous, because there's no code yet to update that
1138 * information and we don't want it stuck, spamming all
1139 * traffic to the host.
1140 */
1141 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltDarwinIsPromiscuous(pThis));
1142#endif
1143 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
1144 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
1145 vboxNetFltRelease(pThis, true /*fBusy*/);
1146 }
1147 }
1148
1149 /* Release the interface on failure. */
1150 if (pIfNet)
1151 ifnet_release(pIfNet);
1152
1153 int rc = RTErrConvertFromErrno(err);
1154 if (RT_SUCCESS(rc))
1155 LogRel(("VBoxFltDrv: attached to '%s' / %RTmac\n", pThis->szName, &pThis->u.s.MacAddr));
1156 else
1157 LogRel(("VBoxFltDrv: failed to attach to ifnet '%s' (err=%d)\n", pThis->szName, err));
1158 IPRT_DARWIN_RESTORE_EFL_AC();
1159 return rc;
1160}
1161
1162
1163bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
1164{
1165 vboxNetFltDarwinAttachToInterface(pThis, true /* fRediscovery */);
1166 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
1167}
1168
1169
1170int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
1171{
1172 IPRT_DARWIN_SAVE_EFL_AC();
1173 NOREF(pvIfData);
1174
1175 int rc = VINF_SUCCESS;
1176 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
1177 if (pIfNet)
1178 {
1179 /*
1180 * Create a mbuf for the gather list and push it onto the wire.
1181 * BPF tap and stats will be taken care of by the driver.
1182 */
1183 if (fDst & INTNETTRUNKDIR_WIRE)
1184 {
1185 mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
1186 if (pMBuf)
1187 {
1188 errno_t err = ifnet_output_raw(pIfNet, PF_LINK, pMBuf);
1189 if (err)
1190 rc = RTErrConvertFromErrno(err);
1191 }
1192 else
1193 rc = VERR_NO_MEMORY;
1194 }
1195
1196 /*
1197 * Create a mbuf for the gather list and push it onto the host stack.
1198 * BPF tap and stats are on us.
1199 */
1200 if (fDst & INTNETTRUNKDIR_HOST)
1201 {
1202 mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
1203 if (pMBuf)
1204 {
1205 void *pvEthHdr = mbuf_data(pMBuf);
1206 unsigned const cbEthHdr = 14;
1207 struct ifnet_stat_increment_param stats;
1208
1209 RT_ZERO(stats);
1210 stats.packets_in = 1;
1211 stats.bytes_in = mbuf_len(pMBuf); /* full ethernet frame */
1212
1213 mbuf_pkthdr_setrcvif(pMBuf, pIfNet);
1214 mbuf_pkthdr_setheader(pMBuf, pvEthHdr); /* link-layer header */
1215 mbuf_adj(pMBuf, cbEthHdr); /* move to payload */
1216
1217#if 0 /* XXX: disabled since we don't request promiscuous from intnet */
1218 /*
1219 * TODO: Since intnet knows whether it forwarded us
1220 * this packet because it's for us or because we are
1221 * promiscuous, it can perhaps set a flag for us in
1222 * INTNETSG::fFlags so that we don't have to re-check
1223 * it here.
1224 */
1225 PCRTNETETHERHDR pcEthHdr = (PCRTNETETHERHDR)pvEthHdr;
1226 if ( (pcEthHdr->DstMac.au8[0] & 1) == 0 /* unicast? */
1227 && memcmp(&pcEthHdr->DstMac, &pThis->u.s.MacAddr, sizeof(RTMAC)) != 0)
1228 {
1229 mbuf_setflags_mask(pMBuf, MBUF_PROMISC, MBUF_PROMISC);
1230 }
1231#endif
1232
1233 bpf_tap_in(pIfNet, DLT_EN10MB, pMBuf, pvEthHdr, cbEthHdr);
1234 errno_t err = ifnet_input(pIfNet, pMBuf, &stats);
1235 if (err)
1236 rc = RTErrConvertFromErrno(err);
1237 }
1238 else
1239 rc = VERR_NO_MEMORY;
1240 }
1241
1242 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1243 }
1244
1245 IPRT_DARWIN_RESTORE_EFL_AC();
1246 return rc;
1247}
1248
1249
1250void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
1251{
1252 IPRT_DARWIN_SAVE_EFL_AC();
1253 ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
1254 if (pIfNet)
1255 {
1256 if (pThis->fDisablePromiscuous)
1257 {
1258 /*
1259 * Promiscuous mode should not be used (wireless), we just need to
1260 * make sure the interface is up.
1261 */
1262 if (fActive)
1263 {
1264 u_int16_t fIf = ifnet_flags(pIfNet);
1265 if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
1266 {
1267 ifnet_set_flags(pIfNet, IFF_UP, IFF_UP);
1268 ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1269 }
1270 }
1271 }
1272 else
1273 {
1274 /*
1275 * This api is a bit weird, the best reference is the code.
1276 *
1277 * Also, we have a bit or race conditions wrt the maintenance of
1278 * host the interface promiscuity for vboxNetFltPortOsIsPromiscuous.
1279 */
1280 unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pIfNet);
1281 u_int16_t fIf;
1282 if (fActive)
1283 {
1284 Assert(!pThis->u.s.fSetPromiscuous);
1285 errno_t err = ENETDOWN;
1286 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, true);
1287
1288 /*
1289 * Try bring the interface up and running if it's down.
1290 */
1291 fIf = ifnet_flags(pIfNet);
1292 if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
1293 {
1294 err = ifnet_set_flags(pIfNet, IFF_UP, IFF_UP);
1295 errno_t err2 = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1296 if (!err)
1297 err = err2;
1298 fIf = ifnet_flags(pIfNet);
1299 }
1300
1301 /*
1302 * Is it already up? If it isn't, leave it to the link event or
1303 * we'll upset if_pcount (as stated above, ifnet_set_promiscuous is weird).
1304 */
1305 if ((fIf & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
1306 {
1307 err = ifnet_set_promiscuous(pIfNet, 1);
1308 pThis->u.s.fSetPromiscuous = err == 0;
1309 if (!err)
1310 {
1311 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
1312
1313 /* check if it actually worked, this stuff is not always behaving well. */
1314 if (!(ifnet_flags(pIfNet) & IFF_PROMISC))
1315 {
1316 err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
1317 if (!err)
1318 err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
1319 if (!err)
1320 Log(("vboxNetFlt: fixed IFF_PROMISC on %s (%d->%d)\n", pThis->szName, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1321 else
1322 Log(("VBoxNetFlt: failed to fix IFF_PROMISC on %s, err=%d (%d->%d)\n",
1323 pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1324 }
1325 }
1326 else
1327 Log(("VBoxNetFlt: ifnet_set_promiscuous -> err=%d grr! (%d->%d)\n", err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1328 }
1329 else if (!err)
1330 Log(("VBoxNetFlt: Waiting for the link to come up... (%d->%d)\n", cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1331 if (err)
1332 LogRel(("VBoxNetFlt: Failed to put '%s' into promiscuous mode, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1333 }
1334 else
1335 {
1336 ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
1337 if (pThis->u.s.fSetPromiscuous)
1338 {
1339 errno_t err = ifnet_set_promiscuous(pIfNet, 0);
1340 AssertMsg(!err, ("%d\n", err)); NOREF(err);
1341 }
1342 pThis->u.s.fSetPromiscuous = false;
1343
1344 fIf = ifnet_flags(pIfNet);
1345 Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
1346 }
1347 }
1348
1349 vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
1350 }
1351 IPRT_DARWIN_RESTORE_EFL_AC();
1352}
1353
1354
1355int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
1356{
1357 /* Nothing to do here. */
1358 RT_NOREF(pThis);
1359 return VINF_SUCCESS;
1360}
1361
1362
1363int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
1364{
1365 /* Nothing to do here. */
1366 RT_NOREF(pThis);
1367 return VINF_SUCCESS;
1368}
1369
1370
1371void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
1372{
1373 IPRT_DARWIN_SAVE_EFL_AC();
1374
1375 /*
1376 * Carefully obtain the interface filter reference and detach it.
1377 */
1378 RTSpinlockAcquire(pThis->hSpinlock);
1379 interface_filter_t pIfFilter = ASMAtomicUoReadPtrT(&pThis->u.s.pIfFilter, interface_filter_t);
1380 if (pIfFilter)
1381 ASMAtomicUoWriteNullPtr(&pThis->u.s.pIfFilter);
1382 RTSpinlockRelease(pThis->hSpinlock);
1383
1384 if (pIfFilter)
1385 iflt_detach(pIfFilter);
1386
1387 if (pThis->u.s.pSysSock != NULL)
1388 {
1389 RT_GCC_NO_WARN_DEPRECATED_BEGIN
1390
1391 sock_close(pThis->u.s.pSysSock);
1392 pThis->u.s.pSysSock = NULL;
1393
1394 RT_GCC_NO_WARN_DEPRECATED_END
1395 }
1396
1397 IPRT_DARWIN_RESTORE_EFL_AC();
1398}
1399
1400
1401int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
1402{
1403 NOREF(pvContext);
1404
1405 int rc = vboxNetFltDarwinAttachToInterface(pThis, false /* fRediscovery */);
1406 if (RT_FAILURE(rc))
1407 return rc;
1408
1409 if (pThis->pSwitchPort->pfnNotifyHostAddress == NULL)
1410 return rc;
1411
1412 /*
1413 * XXX: uwe
1414 *
1415 * Learn host's IP addresses and set up notifications for changes.
1416 * To avoid racing, set up notifications first.
1417 *
1418 * XXX: This should probably be global, since the only thing
1419 * specific to ifnet here is its IPv6 link-local address.
1420 */
1421 IPRT_DARWIN_SAVE_EFL_AC();
1422 errno_t error;
1423
1424 /** @todo Figure out how to replace the socket stuff we use to detect
1425 * addresses here as 10.5 deprecates it. */
1426 RT_GCC_NO_WARN_DEPRECATED_BEGIN
1427
1428 /** @todo reorg code to not have numerous returns with duplicate code... */
1429 /** @todo reorg code to not have numerous returns with duplicate code... */
1430 /** @todo reorg code to not have numerous returns with duplicate code... */
1431 /** @todo reorg code to not have numerous returns with duplicate code... */
1432 /** @todo reorg code to not have numerous returns with duplicate code... */
1433 /** @todo reorg code to not have numerous returns with duplicate code... */
1434 /** @todo reorg code to not have numerous returns with duplicate code... */
1435 /** @todo reorg code to not have numerous returns with duplicate code... */
1436 /** @todo reorg code to not have numerous returns with duplicate code... */
1437
1438 error = sock_socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT,
1439 vboxNetFltDarwinSysSockUpcall, pThis,
1440 &pThis->u.s.pSysSock);
1441 if (error != 0)
1442 {
1443 LogRel(("sock_socket(SYSPROTO_EVENT): error %d\n", error));
1444 IPRT_DARWIN_RESTORE_EFL_AC();
1445 return rc;
1446 }
1447
1448 int nbio = 1;
1449 error = sock_ioctl(pThis->u.s.pSysSock, FIONBIO, &nbio);
1450 if (error != 0)
1451 {
1452 LogRel(("FIONBIO: error %d\n", error));
1453 sock_close(pThis->u.s.pSysSock);
1454 IPRT_DARWIN_RESTORE_EFL_AC();
1455 return rc;
1456 }
1457
1458 if (!sock_isnonblocking(pThis->u.s.pSysSock))
1459 {
1460 LogRel(("FIONBIO ok, but socket is blocking?!\n"));
1461 sock_close(pThis->u.s.pSysSock);
1462 IPRT_DARWIN_RESTORE_EFL_AC();
1463 return rc;
1464 }
1465
1466 struct kev_request req;
1467 req.vendor_code = KEV_VENDOR_APPLE;
1468 req.kev_class = KEV_NETWORK_CLASS;
1469 req.kev_subclass = KEV_ANY_SUBCLASS; /* need both INET and INET6, so have to request all */
1470
1471 error = sock_ioctl(pThis->u.s.pSysSock, SIOCSKEVFILT, &req);
1472 if (error != 0)
1473 {
1474 LogRel(("SIOCSKEVFILT: error %d\n", error));
1475 sock_close(pThis->u.s.pSysSock);
1476 IPRT_DARWIN_RESTORE_EFL_AC();
1477 return rc;
1478 }
1479 RT_GCC_NO_WARN_DEPRECATED_END
1480
1481 ifnet_t pIfNet = pThis->u.s.pIfNet; /* already retained */
1482
1483 ifaddr_t *pIfAddrList;
1484 error = ifnet_get_address_list(/* all interfaces*/ NULL, &pIfAddrList);
1485 if (error != 0)
1486 {
1487 LogRel(("ifnet_get_address_list: error %d\n", error));
1488 IPRT_DARWIN_RESTORE_EFL_AC();
1489 return rc;
1490 }
1491
1492 for (ifaddr_t *pIfAddr = pIfAddrList; *pIfAddr != NULL; ++pIfAddr)
1493 {
1494 ifaddr_t ifa = *pIfAddr;
1495 sa_family_t family = ifaddr_address_family(ifa);
1496 struct sockaddr_storage ss;
1497
1498 error = ifaddr_address(ifa, (struct sockaddr *)&ss, sizeof(ss));
1499 if (error != 0)
1500 {
1501 LogRel(("getting address family %d: error %d\n", family, error));
1502 continue;
1503 }
1504
1505 if (family == AF_INET)
1506 {
1507 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
1508 u_int32_t u32Addr = ntohl(sin->sin_addr.s_addr);
1509
1510 if (VBOX_IN_LOOPBACK(u32Addr))
1511 continue;
1512
1513 if (ifaddr_ifnet(ifa) != pIfNet && VBOX_IN_LINKLOCAL(u32Addr))
1514 continue;
1515
1516 Log(("> inet %RTnaipv4\n", sin->sin_addr.s_addr));
1517 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort,
1518 /* :fAdded */ true, kIntNetAddrType_IPv4, &sin->sin_addr);
1519 }
1520 else if (family == AF_INET6)
1521 {
1522 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
1523
1524 if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
1525 continue;
1526
1527 /* link-local from other interfaces are out of scope */
1528 if (ifaddr_ifnet(ifa) != pIfNet && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1529 continue;
1530
1531 Log(("> inet6 %RTnaipv6\n", &sin6->sin6_addr));
1532 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort,
1533 /* :fAdded */ true, kIntNetAddrType_IPv6, &sin6->sin6_addr);
1534 }
1535 }
1536
1537 ifnet_free_address_list(pIfAddrList);
1538
1539 /*
1540 * Now that we've got current addresses, check for events that
1541 * might have happened while we were working.
1542 */
1543 vboxNetFltDarwinSysSockUpcall(pThis->u.s.pSysSock, pThis, MBUF_DONTWAIT);
1544
1545 IPRT_DARWIN_RESTORE_EFL_AC();
1546 return rc;
1547}
1548
1549
1550static void vboxNetFltDarwinSysSockUpcall(socket_t pSysSock, void *pvData, int fWait)
1551{
1552 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
1553 errno_t error;
1554
1555 NOREF(fWait);
1556
1557 if (RT_UNLIKELY(pSysSock != pThis->u.s.pSysSock))
1558 {
1559 Log(("vboxNetFltDarwinSysSockUpcall: %p != %p?\n", pSysSock, pThis->u.s.pSysSock));
1560 return;
1561 }
1562
1563 ifnet_t pIfNet = pThis->u.s.pIfNet; /* XXX: retain? */
1564 ifnet_family_t if_family = ifnet_family(pIfNet);
1565 u_int32_t if_unit = ifnet_unit(pIfNet);
1566
1567 for (;;)
1568 {
1569 mbuf_t m;
1570 size_t len = sizeof(struct kern_event_msg) - sizeof(u_int32_t) + sizeof(struct kev_in6_data);
1571
1572 RT_GCC_NO_WARN_DEPRECATED_BEGIN
1573 error = sock_receivembuf(pSysSock, NULL, &m, 0, &len);
1574 RT_GCC_NO_WARN_DEPRECATED_END
1575 if (error != 0)
1576 {
1577 if (error == EWOULDBLOCK)
1578 {
1579 Log(("vboxNetFltDarwinSysSockUpcall: EWOULDBLOCK - we are done\n"));
1580 error = 0;
1581 }
1582 else
1583 Log(("sock_receivembuf: error %d\n", error));
1584 break;
1585 }
1586
1587 if (len < sizeof(struct kern_event_msg) - sizeof(u_int32_t))
1588 {
1589 Log(("vboxNetFltDarwinSysSockUpcall: %u bytes is too short\n", (unsigned int)len));
1590 mbuf_freem(m);
1591 return;
1592 }
1593
1594 struct kern_event_msg *msg = (struct kern_event_msg *)mbuf_data(m);
1595 if (msg->kev_subclass == KEV_INET_SUBCLASS)
1596 {
1597 if (len - (sizeof(struct kern_event_msg) - sizeof(u_int32_t)) < sizeof(struct kev_in_data))
1598 {
1599 Log(("vboxNetFltDarwinSysSockUpcall: %u bytes is too short for KEV_INET_SUBCLASS\n", (unsigned int)len));
1600 mbuf_freem(m);
1601 return;
1602 }
1603
1604 struct kev_in_data *iev = (struct kev_in_data *)msg->event_data;
1605 struct net_event_data *link = &iev->link_data;
1606 PCRTNETADDRU pAddr = (PCRTNETADDRU)&iev->ia_addr;
1607 u_int32_t u32Addr = ntohl(pAddr->IPv4.u);
1608
1609 if (VBOX_IN_LOOPBACK(u32Addr))
1610 {
1611 mbuf_freem(m);
1612 continue;
1613 }
1614
1615 if ( (link->if_family != if_family || link->if_unit != if_unit)
1616 && VBOX_IN_LINKLOCAL(u32Addr))
1617 {
1618 mbuf_freem(m);
1619 continue;
1620 }
1621
1622 switch (msg->event_code)
1623 {
1624 case KEV_INET_NEW_ADDR:
1625 Log(("KEV_INET_NEW_ADDR %.*s%d: %RTnaipv4\n", IFNAMSIZ, link->if_name, link->if_unit, pAddr->IPv4.u));
1626 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, true /*fAdded*/, kIntNetAddrType_IPv4, pAddr);
1627 break;
1628
1629 case KEV_INET_ADDR_DELETED:
1630 Log(("KEV_INET_ADDR_DELETED %.*s%d: %RTnaipv4\n", IFNAMSIZ, link->if_name, link->if_unit, pAddr->IPv4.u));
1631 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, false /*fAdded*/, kIntNetAddrType_IPv4, pAddr);
1632 break;
1633
1634 default:
1635 Log(("KEV INET event %u %.*s%d: addr %RTnaipv4\n",
1636 msg->event_code, IFNAMSIZ, link->if_name, link->if_unit, pAddr->IPv4.u));
1637 break;
1638 }
1639 }
1640 else if (msg->kev_subclass == KEV_INET6_SUBCLASS)
1641 {
1642 if (len - (sizeof(struct kern_event_msg) - sizeof(u_int32_t)) < sizeof(struct kev_in6_data))
1643 {
1644 Log(("vboxNetFltDarwinSysSockUpcall: %u bytes is too short for KEV_INET6_SUBCLASS\n",
1645 (unsigned int)len));
1646 mbuf_freem(m);
1647 return;
1648 }
1649
1650 struct kev_in6_data *iev6 = (struct kev_in6_data *)msg->event_data;
1651 struct net_event_data *link = &iev6->link_data;
1652 PCRTNETADDRU pAddr = (PCRTNETADDRU)&iev6->ia_addr.sin6_addr;
1653
1654 if (IN6_IS_ADDR_LOOPBACK(&iev6->ia_addr.sin6_addr))
1655 {
1656 mbuf_freem(m);
1657 continue;
1658 }
1659
1660 if ( (link->if_family != if_family || link->if_unit != if_unit)
1661 && IN6_IS_ADDR_LINKLOCAL(&iev6->ia_addr.sin6_addr))
1662 {
1663 mbuf_freem(m);
1664 continue;
1665 }
1666
1667 switch (msg->event_code)
1668 {
1669 case KEV_INET6_NEW_USER_ADDR:
1670 Log(("KEV_INET6_NEW_USER_ADDR %.*s%d: %RTnaipv6\n",
1671 IFNAMSIZ, link->if_name, link->if_unit, pAddr));
1672 goto kev_inet6_new;
1673
1674 case KEV_INET6_NEW_LL_ADDR:
1675 Log(("KEV_INET6_NEW_LL_ADDR %.*s%d: %RTnaipv6\n",
1676 IFNAMSIZ, link->if_name, link->if_unit, pAddr));
1677 goto kev_inet6_new;
1678
1679 case KEV_INET6_NEW_RTADV_ADDR:
1680 Log(("KEV_INET6_NEW_RTADV_ADDR %.*s%d: %RTnaipv6\n",
1681 IFNAMSIZ, link->if_name, link->if_unit, pAddr));
1682 goto kev_inet6_new;
1683
1684 kev_inet6_new:
1685 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, true /*fAdded*/, kIntNetAddrType_IPv6, pAddr);
1686 break;
1687
1688 case KEV_INET6_ADDR_DELETED:
1689 Log(("KEV_INET6_ADDR_DELETED %.*s%d: %RTnaipv6\n",
1690 IFNAMSIZ, link->if_name, link->if_unit, pAddr));
1691
1692 pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, false /*fAdded*/, kIntNetAddrType_IPv6, pAddr);
1693 break;
1694
1695 default:
1696 Log(("KEV INET6 event %u %.*s%d: addr %RTnaipv6\n",
1697 msg->event_code, IFNAMSIZ, link->if_name, link->if_unit, pAddr));
1698 break;
1699 }
1700 }
1701 else
1702 Log(("vboxNetFltDarwinSysSockUpcall: subclass %u ignored\n", (unsigned)msg->kev_subclass));
1703
1704 mbuf_freem(m);
1705 }
1706}
1707
1708
1709int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
1710{
1711 /*
1712 * Init the darwin specific members.
1713 */
1714 pThis->u.s.pIfNet = NULL;
1715 pThis->u.s.pIfFilter = NULL;
1716 pThis->u.s.fSetPromiscuous = false;
1717 pThis->u.s.fNeedSetPromiscuous = false;
1718 //pThis->u.s.MacAddr = {0};
1719 pThis->u.s.pSysSock = NULL;
1720
1721 return VINF_SUCCESS;
1722}
1723
1724
1725void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
1726{
1727 NOREF(pThis); NOREF(pvIfData); NOREF(pMac);
1728}
1729
1730
1731int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
1732{
1733 /* Nothing to do */
1734 NOREF(pThis); NOREF(pvIf); NOREF(ppvIfData);
1735 return VINF_SUCCESS;
1736}
1737
1738
1739int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
1740{
1741 /* Nothing to do */
1742 NOREF(pThis); NOREF(pvIfData);
1743 return VINF_SUCCESS;
1744}
1745
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