VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c@ 24123

Last change on this file since 24123 was 24123, checked in by vboxsync, 15 years ago

VBoxNetFlt/FreeBSD: Fix locking problems. Contributed by Fredrik Lindberg

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1/* $Id: VBoxNetFlt-freebsd.c 24123 2009-10-28 02:46:59Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), FreeBSD Specific Code.
4 */
5
6/*
7 * Copyright (c) 2009 Fredrik Lindberg <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <sys/param.h>
35#undef PVM
36#include <sys/types.h>
37#include <sys/module.h>
38#include <sys/systm.h>
39#include <sys/errno.h>
40#include <sys/kernel.h>
41#include <sys/fcntl.h>
42#include <sys/conf.h>
43#include <sys/socket.h>
44#include <sys/sockio.h>
45#include <sys/syscallsubr.h>
46#include <sys/queue.h>
47#include <sys/taskqueue.h>
48
49#include <net/if.h>
50#include <net/if_var.h>
51#include <net/if_dl.h>
52#include <net/if_types.h>
53#include <net/ethernet.h>
54
55#include <netgraph/ng_message.h>
56#include <netgraph/netgraph.h>
57#include <netgraph/ng_parse.h>
58
59#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
60#include <VBox/version.h>
61#include <VBox/err.h>
62#include <VBox/log.h>
63#include <iprt/initterm.h>
64#include <iprt/string.h>
65#include <iprt/spinlock.h>
66#include <iprt/process.h>
67#include <iprt/assert.h>
68#include <iprt/uuid.h>
69#include <iprt/alloc.h>
70#include <iprt/err.h>
71
72#define VBOXNETFLT_OS_SPECFIC 1
73#include "../VBoxNetFltInternal.h"
74
75static int vboxnetflt_modevent(struct module *, int, void *);
76static ng_constructor_t ng_vboxnetflt_constructor;
77static ng_rcvmsg_t ng_vboxnetflt_rcvmsg;
78static ng_shutdown_t ng_vboxnetflt_shutdown;
79static ng_newhook_t ng_vboxnetflt_newhook;
80static ng_rcvdata_t ng_vboxnetflt_rcvdata;
81static ng_disconnect_t ng_vboxnetflt_disconnect;
82static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
83
84/** Netgraph node type */
85#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
86/** Netgraph message cookie */
87#define NGM_VBOXNETFLT_COOKIE 0x56424f58
88
89/** Input netgraph hook name */
90#define NG_VBOXNETFLT_HOOK_IN "input"
91/** Output netgraph hook name */
92#define NG_VBOXNETFLT_HOOK_OUT "output"
93
94/** mbuf tag identifier */
95#define MTAG_VBOX 0x56424f58
96/** mbuf packet tag */
97#define PACKET_TAG_VBOX 128
98
99/*
100 * Netgraph command list, we don't support any
101 * additional commands.
102 */
103static const struct ng_cmdlist ng_vboxnetflt_cmdlist[] =
104{
105 { 0 }
106};
107
108/*
109 * Netgraph type definition
110 */
111static struct ng_type ng_vboxnetflt_typestruct =
112{
113 .version = NG_ABI_VERSION,
114 .name = NG_VBOXNETFLT_NODE_TYPE,
115 .mod_event = vboxnetflt_modevent,
116 .constructor = ng_vboxnetflt_constructor,
117 .rcvmsg = ng_vboxnetflt_rcvmsg,
118 .shutdown = ng_vboxnetflt_shutdown,
119 .newhook = ng_vboxnetflt_newhook,
120 .rcvdata = ng_vboxnetflt_rcvdata,
121 .disconnect = ng_vboxnetflt_disconnect,
122 .cmdlist = ng_vboxnetflt_cmdlist,
123};
124NETGRAPH_INIT(vboxnetflt, &ng_vboxnetflt_typestruct);
125MODULE_VERSION(ng_vboxnetflt, 1);
126MODULE_DEPEND(ng_vboxnetflt, vboxdrv, 1, 1, 1);
127
128/**
129 * The (common) global data.
130 */
131static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
132
133/**
134 * Module event handler, called from netgraph subsystem.
135 */
136static int vboxnetflt_modevent(struct module *pMod, int enmEventType, void *pvArg)
137{
138 int rc;
139
140 Log(("VBoxNetFltFreeBSDModuleEvent\n"));
141
142 switch (enmEventType)
143 {
144 case MOD_LOAD:
145 rc = RTR0Init(0);
146 if (RT_FAILURE(rc))
147 {
148 printf("RTR0Init failed %d\n", rc);
149 return RTErrConvertToErrno(rc);
150 }
151
152 memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
153 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltGlobals);
154 if (RT_FAILURE(rc))
155 {
156 printf("vboxNetFltInitGlobalsAndIdc failed %d\n", rc);
157 return RTErrConvertToErrno(rc);
158 }
159 /* No MODULE_VERSION in ng_ether so we can't MODULE_DEPEND it */
160 kern_kldload(curthread, "ng_ether", NULL);
161 break;
162
163 case MOD_UNLOAD:
164 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltGlobals);
165 memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
166 RTR0Term();
167 break;
168
169 case MOD_SHUTDOWN:
170 case MOD_QUIESCE:
171 default:
172 return EOPNOTSUPP;
173 }
174
175 if (RT_SUCCESS(rc))
176 return 0;
177 return RTErrConvertToErrno(rc);
178}
179
180/*
181 * Convert from mbufs to vbox scatter-gather data structure
182 */
183static void vboxNetFltFreeBSDMBufToSG(PVBOXNETFLTINS pThis, struct mbuf *m, PINTNETSG pSG,
184 unsigned int cSegs, unsigned int segOffset)
185{
186 static uint8_t const s_abZero[128] = {0};
187 unsigned int i;
188 struct mbuf *m0;
189
190 pSG->cbTotal = m_length(m, NULL);
191 pSG->pvOwnerData = NULL;
192 pSG->pvUserData = NULL;
193 pSG->pvUserData2 = NULL;
194 pSG->cUsers = 1;
195 pSG->fFlags = INTNETSG_FLAGS_TEMP;
196 pSG->cSegsAlloc = cSegs;
197
198 for (m0 = m, i = segOffset; m0; m0 = m0->m_next)
199 {
200 if (m0->m_len == 0)
201 continue;
202
203 pSG->aSegs[i].cb = m0->m_len;
204 pSG->aSegs[i].pv = mtod(m0, uint8_t *);
205 pSG->aSegs[i].Phys = NIL_RTHCPHYS;
206 i++;
207 }
208
209#ifdef PADD_RUNT_FRAMES_FROM_HOST
210 if (pSG->cbTotal < 60)
211 {
212 pSG->aSegs[i].Phys = NIL_RTHCPHYS;
213 pSG->aSegs[i].pv = (void *)&s_abZero[0];
214 pSG->aSegs[i].cb = 60 - pSG->cbTotal;
215 pSG->cbTotal = 60;
216 i++;
217 }
218#endif
219 pSG->cSegsUsed = i;
220}
221
222/*
223 * Convert to mbufs from vbox scatter-gather data structure
224 */
225static struct mbuf * vboxNetFltFreeBSDSGMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
226{
227 struct mbuf *m;
228 int error;
229 unsigned int i;
230
231 if (pSG->cbTotal == 0 || pSG->aSegs[0].cb == 0)
232 return (NULL);
233
234 m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
235 if (m == NULL)
236 return (NULL);
237
238 m->m_pkthdr.len = m->m_len = 0;
239 m->m_pkthdr.rcvif = NULL;
240
241 for (i = 0; i < pSG->cSegsUsed; i++)
242 {
243 error = m_append(m, pSG->aSegs[i].cb, pSG->aSegs[i].pv);
244 if (error == 0)
245 {
246 m_freem(m);
247 return (NULL);
248 }
249 }
250 return (m);
251}
252
253
254static int ng_vboxnetflt_constructor(node_p node)
255{
256 /* Nothing to do */
257 return (EINVAL);
258}
259
260/*
261 * Setup netgraph hooks
262 */
263static int ng_vboxnetflt_newhook(node_p node, hook_p hook, const char *name)
264{
265 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
266
267 if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
268 {
269#if __FreeBSD_version >= 800000
270 NG_HOOK_SET_TO_INBOUND(hook);
271#endif
272 pThis->u.s.input = hook;
273 }
274 else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
275 {
276 pThis->u.s.output = hook;
277 }
278 else
279 return (EINVAL);
280
281 NG_HOOK_HI_STACK(hook);
282 return (0);
283}
284
285/**
286 * Netgraph message processing for node specific messages.
287 * We don't accept any special messages so this is not used.
288 */
289static int ng_vboxnetflt_rcvmsg(node_p node, item_p item, hook_p lasthook)
290{
291 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
292 struct ng_mesg *msg;
293 int error = 0;
294
295 NGI_GET_MSG(item, msg);
296 if (msg->header.typecookie != NGM_VBOXNETFLT_COOKIE)
297 return (EINVAL);
298
299 switch (msg->header.cmd)
300 {
301 default:
302 error = EINVAL;
303 }
304 return (error);
305}
306
307/**
308 * Handle data on netgraph hooks.
309 * Frames processing is deferred to a taskqueue because this might
310 * be called with non-sleepable locks held and code paths inside
311 * the virtual switch might sleep.
312 */
313static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
314{
315 const node_p node = NG_HOOK_NODE(hook);
316 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
317 struct ifnet *ifp = pThis->u.s.ifp;
318 struct mbuf *m;
319 struct m_tag *mtag;
320 bool fActive;
321
322 fActive = ASMAtomicUoReadBool(&pThis->fActive);
323
324 NGI_GET_M(item, m);
325 NG_FREE_ITEM(item);
326
327 /* Locate tag to see if processing should be skipped for this frame */
328 mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
329 if (mtag != NULL)
330 {
331 m_tag_unlink(m, mtag);
332 m_tag_free(mtag);
333 }
334
335 /*
336 * Handle incoming hook. This is connected to the
337 * input path of the interface, thus handling incoming frames.
338 */
339 if (pThis->u.s.input == hook)
340 {
341 if (mtag != NULL || !fActive)
342 {
343 ether_demux(ifp, m);
344 return (0);
345 }
346 mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
347 _IF_ENQUEUE(&pThis->u.s.inq, m);
348 mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
349 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
350 }
351 /**
352 * Handle mbufs on the outgoing hook, frames going to the interface
353 */
354 else if (pThis->u.s.output == hook)
355 {
356 if (mtag != NULL || !fActive)
357 return ether_output_frame(ifp, m);
358 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
359 _IF_ENQUEUE(&pThis->u.s.outq, m);
360 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
361 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
362 }
363 else
364 {
365 m_freem(m);
366 }
367 return (0);
368}
369
370static int ng_vboxnetflt_shutdown(node_p node)
371{
372 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
373 bool fActive;
374
375 /* Prevent node shutdown if we're active */
376 fActive = ASMAtomicUoReadBool(&pThis->fActive);
377 if (fActive)
378 return (EBUSY);
379 NG_NODE_UNREF(node);
380 return (0);
381}
382
383static int ng_vboxnetflt_disconnect(hook_p hook)
384{
385 return (0);
386}
387
388/**
389 * Input processing task, handles incoming frames
390 */
391static void vboxNetFltFreeBSDinput(void *arg, int pending)
392{
393 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
394 struct mbuf *m, *m0;
395 struct ifnet *ifp = pThis->u.s.ifp;
396 unsigned int cSegs = 0;
397 bool fDropIt = false, fActive;
398 PINTNETSG pSG;
399
400 vboxNetFltRetain(pThis, true /* fBusy */);
401 for (;;)
402 {
403 mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
404 _IF_DEQUEUE(&pThis->u.s.inq, m);
405 mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
406 if (m == NULL)
407 break;
408
409 for (m0 = m; m0 != NULL; m0 = m0->m_next)
410 if (m0->m_len > 0)
411 cSegs++;
412
413#ifdef PADD_RUNT_FRAMES_FROM_HOST
414 if (m_length(m, NULL) < 60)
415 cSegs++;
416#endif
417
418 /* Create a copy and deliver to the virtual switch */
419 pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
420 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
421 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
422 RTMemTmpFree(pSG);
423 if (fDropIt)
424 m_freem(m);
425 else
426 ether_demux(ifp, m);
427 }
428 vboxNetFltRelease(pThis, true /* fBusy */);
429}
430
431/**
432 * Output processing task, handles outgoing frames
433 */
434static void vboxNetFltFreeBSDoutput(void *arg, int pending)
435{
436 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
437 struct mbuf *m, *m0;
438 struct ifnet *ifp = pThis->u.s.ifp;
439 unsigned int cSegs = 0;
440 bool fDropIt = false, fActive;
441 PINTNETSG pSG;
442
443 vboxNetFltRetain(pThis, true /* fBusy */);
444 for (;;)
445 {
446 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
447 _IF_DEQUEUE(&pThis->u.s.outq, m);
448 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
449 if (m == NULL)
450 break;
451
452 for (m0 = m; m0 != NULL; m0 = m0->m_next)
453 if (m0->m_len > 0)
454 cSegs++;
455
456#ifdef PADD_RUNT_FRAMES_FROM_HOST
457 if (m_length(m, NULL) < 60)
458 cSegs++;
459#endif
460 /* Create a copy and deliver to the virtual switch */
461 pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
462 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
463 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
464 RTMemTmpFree(pSG);
465
466 if (fDropIt)
467 m_freem(m);
468 else
469 ether_output_frame(ifp, m);
470 }
471 vboxNetFltRelease(pThis, true /* fBusy */);
472}
473
474/**
475 * Called to deliver a frame to either the host, the wire or both.
476 */
477int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
478{
479 void (*input_f)(struct ifnet *, struct mbuf *);
480 struct ifnet *ifp;
481 struct mbuf *m;
482 struct m_tag *mtag;
483 bool fActive;
484 int error;
485
486 ifp = (void *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp);
487
488 if (fDst & INTNETTRUNKDIR_WIRE)
489 {
490 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
491 if (m == NULL)
492 return VERR_NO_MEMORY;
493 m = m_pullup(m, ETHER_HDR_LEN);
494 if (m == NULL)
495 return VERR_NO_MEMORY;
496
497 m->m_flags |= M_PKTHDR;
498 ether_output_frame(ifp, m);
499 }
500
501 if (fDst & INTNETTRUNKDIR_HOST)
502 {
503 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
504 if (m == NULL)
505 return VERR_NO_MEMORY;
506 m = m_pullup(m, ETHER_HDR_LEN);
507 if (m == NULL)
508 return VERR_NO_MEMORY;
509 /*
510 * Delivering packets to the host will be captured by the
511 * input hook. Tag the packet with a mbuf tag so that we
512 * can skip re-delivery of the packet to the guest during
513 * input hook processing.
514 */
515 mtag = m_tag_alloc(MTAG_VBOX, PACKET_TAG_VBOX, 0, M_NOWAIT);
516 if (mtag == NULL)
517 {
518 m_freem(m);
519 return VERR_NO_MEMORY;
520 }
521
522 m_tag_init(m);
523 m_tag_prepend(m, mtag);
524 m->m_flags |= M_PKTHDR;
525 m->m_pkthdr.rcvif = ifp;
526 ifp->if_input(ifp, m);
527 }
528 return VINF_SUCCESS;
529}
530
531int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
532{
533 char nam[NG_NODESIZ];
534 struct ifnet *ifp;
535 node_p node;
536 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
537
538 NOREF(pvContext);
539 ifp = ifunit(pThis->szName);
540 if (ifp == NULL)
541 return VERR_INTNET_FLT_IF_NOT_FOUND;
542
543 /* Create a new netgraph node for this instance */
544 if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
545 return VERR_INTERNAL_ERROR;
546
547 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
548 ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
549 pThis->u.s.node = node;
550 bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
551 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
552 /* Initialize deferred input queue */
553 bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
554 mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
555 TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
556
557 /* Initialize deferred output queue */
558 bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
559 mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
560 TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
561
562 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
563
564 NG_NODE_SET_PRIVATE(node, pThis);
565 /* Attempt to name it vboxnetflt_<ifname> */
566 snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName);
567 ng_name_node(node, nam);
568
569 return VINF_SUCCESS;
570}
571
572bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
573{
574 struct ifnet *ifp, *ifp0;
575
576 ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp);
577 /*
578 * Attempt to check if the interface is still there and re-initialize if
579 * something has changed.
580 */
581 ifp0 = ifunit(pThis->szName);
582 if (ifp != ifp0)
583 {
584 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, true);
585 ng_rmnode_self(pThis->u.s.node);
586 pThis->u.s.node = NULL;
587 }
588
589 if (ifp0 != NULL)
590 {
591 vboxNetFltOsDeleteInstance(pThis);
592 vboxNetFltOsInitInstance(pThis, NULL);
593 }
594
595 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
596}
597
598void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
599{
600
601 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
602 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
603
604 mtx_destroy(&pThis->u.s.inq.ifq_mtx);
605 mtx_destroy(&pThis->u.s.outq.ifq_mtx);
606
607 if (pThis->u.s.node != NULL)
608 ng_rmnode_self(pThis->u.s.node);
609 pThis->u.s.node = NULL;
610}
611
612int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
613{
614
615 pThis->u.s.ifp = NULL;
616 pThis->u.s.flags = 0;
617 pThis->u.s.node = NULL;
618 return VINF_SUCCESS;
619}
620
621void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
622{
623 struct ifnet *ifp;
624 struct ifreq ifreq;
625 int error;
626 node_p node;
627 struct ng_mesg *msg;
628 struct ngm_connect *con;
629 struct ngm_rmhook *rm;
630 char path[NG_PATHSIZ];
631
632 Log(("%s: fActive:%d\n", __func__, fActive));
633
634 ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp);
635 node = (node_p)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.node);
636
637 memset(&ifreq, 0, sizeof(struct ifreq));
638 /* Activate interface */
639 if (fActive)
640 {
641 pThis->u.s.flags = ifp->if_flags;
642 ifpromisc(ifp, 1);
643
644 /* ng_ether nodes are named after the interface name */
645 snprintf(path, sizeof(path), "%s:", ifp->if_xname);
646
647 /*
648 * Send a netgraph connect message to the ng_ether node
649 * assigned to the bridged interface. Connecting
650 * the hooks 'lower' (ng_ether) to out 'input'.
651 */
652 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
653 sizeof(struct ngm_connect), M_NOWAIT);
654 if (msg == NULL)
655 return;
656 con = (struct ngm_connect *)msg->data;
657 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
658 strlcpy(con->ourhook, "lower", NG_HOOKSIZ);
659 strlcpy(con->peerhook, "input", NG_HOOKSIZ);
660 NG_SEND_MSG_PATH(error, node, msg, path, 0);
661
662 /*
663 * Do the same for the hooks 'upper' (ng_ether) and our
664 * 'output' hook.
665 */
666 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
667 sizeof(struct ngm_connect), M_NOWAIT);
668 if (msg == NULL)
669 return;
670 con = (struct ngm_connect *)msg->data;
671 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:",
672 ifp->if_xname);
673 strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
674 strlcpy(con->peerhook, "output", sizeof(con->peerhook));
675 NG_SEND_MSG_PATH(error, node, msg, path, 0);
676 }
677 else
678 {
679 /* De-activate interface */
680 pThis->u.s.flags = 0;
681 ifpromisc(ifp, 0);
682
683 /* Disconnect msgs are addressed to ourself */
684 snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);
685
686 /*
687 * Send a netgraph message to disconnect our 'input' hook
688 */
689 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
690 sizeof(struct ngm_rmhook), M_NOWAIT);
691 if (msg == NULL)
692 return;
693 rm = (struct ngm_rmhook *)msg->data;
694 strlcpy(rm->ourhook, "input", NG_HOOKSIZ);
695 NG_SEND_MSG_PATH(error, node, msg, path, 0);
696
697 /*
698 * Send a netgraph message to disconnect our 'output' hook
699 */
700 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
701 sizeof(struct ngm_rmhook), M_NOWAIT);
702 if (msg == NULL)
703 return;
704 rm = (struct ngm_rmhook *)msg->data;
705 strlcpy(rm->ourhook, "output", NG_HOOKSIZ);
706 NG_SEND_MSG_PATH(error, node, msg, path, 0);
707 }
708}
709
710bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
711{
712 return (pThis->u.s.flags & IFF_PROMISC) ? true : false;
713}
714
715void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
716{
717 *pMac = pThis->u.s.Mac;
718}
719
720bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
721{
722 return pThis->u.s.Mac.au16[0] == pMac->au16[0]
723 && pThis->u.s.Mac.au16[1] == pMac->au16[1]
724 && pThis->u.s.Mac.au16[2] == pMac->au16[2];
725}
726
727int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
728{
729 return VINF_SUCCESS;
730}
731
732int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
733{
734 return VINF_SUCCESS;
735}
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