VirtualBox

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

Last change on this file since 32740 was 30111, checked in by vboxsync, 14 years ago

iprt/asm.h,*: Revised the ASMAtomic*Ptr functions and macros. The new saves lots of unsafe (void * volatile *) casts as well as adding some type safety when using GCC (typeof rulez).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 KB
Line 
1/* $Id: VBoxNetFlt-freebsd.c 30111 2010-06-09 12:14: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 <VBox/intnetinline.h>
64#include <iprt/initterm.h>
65#include <iprt/string.h>
66#include <iprt/spinlock.h>
67#include <iprt/process.h>
68#include <iprt/assert.h>
69#include <iprt/uuid.h>
70#include <iprt/alloc.h>
71#include <iprt/err.h>
72
73#define VBOXNETFLT_OS_SPECFIC 1
74#include "../VBoxNetFltInternal.h"
75
76static int vboxnetflt_modevent(struct module *, int, void *);
77static ng_constructor_t ng_vboxnetflt_constructor;
78static ng_rcvmsg_t ng_vboxnetflt_rcvmsg;
79static ng_shutdown_t ng_vboxnetflt_shutdown;
80static ng_newhook_t ng_vboxnetflt_newhook;
81static ng_rcvdata_t ng_vboxnetflt_rcvdata;
82static ng_disconnect_t ng_vboxnetflt_disconnect;
83static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
84
85/** Netgraph node type */
86#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt"
87/** Netgraph message cookie */
88#define NGM_VBOXNETFLT_COOKIE 0x56424f58
89
90/** Input netgraph hook name */
91#define NG_VBOXNETFLT_HOOK_IN "input"
92/** Output netgraph hook name */
93#define NG_VBOXNETFLT_HOOK_OUT "output"
94
95/** mbuf tag identifier */
96#define MTAG_VBOX 0x56424f58
97/** mbuf packet tag */
98#define PACKET_TAG_VBOX 128
99
100/*
101 * Netgraph command list, we don't support any
102 * additional commands.
103 */
104static const struct ng_cmdlist ng_vboxnetflt_cmdlist[] =
105{
106 { 0 }
107};
108
109/*
110 * Netgraph type definition
111 */
112static struct ng_type ng_vboxnetflt_typestruct =
113{
114 .version = NG_ABI_VERSION,
115 .name = NG_VBOXNETFLT_NODE_TYPE,
116 .mod_event = vboxnetflt_modevent,
117 .constructor = ng_vboxnetflt_constructor,
118 .rcvmsg = ng_vboxnetflt_rcvmsg,
119 .shutdown = ng_vboxnetflt_shutdown,
120 .newhook = ng_vboxnetflt_newhook,
121 .rcvdata = ng_vboxnetflt_rcvdata,
122 .disconnect = ng_vboxnetflt_disconnect,
123 .cmdlist = ng_vboxnetflt_cmdlist,
124};
125NETGRAPH_INIT(vboxnetflt, &ng_vboxnetflt_typestruct);
126
127/*
128 * Use vboxnetflt because the kernel module is named vboxnetflt and vboxnetadp
129 * depends on this when loading dependencies.
130 * NETGRAP_INIT will prefix the given name with ng_ so MODULE_DEPEND needs the
131 * prefixed name.
132 */
133MODULE_VERSION(vboxnetflt, 1);
134MODULE_DEPEND(ng_vboxnetflt, vboxdrv, 1, 1, 1);
135
136/**
137 * The (common) global data.
138 */
139static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
140
141/**
142 * Module event handler, called from netgraph subsystem.
143 */
144static int vboxnetflt_modevent(struct module *pMod, int enmEventType, void *pvArg)
145{
146 int rc;
147
148 Log(("VBoxNetFltFreeBSDModuleEvent\n"));
149
150 switch (enmEventType)
151 {
152 case MOD_LOAD:
153 rc = RTR0Init(0);
154 if (RT_FAILURE(rc))
155 {
156 printf("RTR0Init failed %d\n", rc);
157 return RTErrConvertToErrno(rc);
158 }
159
160 memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
161 rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltGlobals);
162 if (RT_FAILURE(rc))
163 {
164 printf("vboxNetFltInitGlobalsAndIdc failed %d\n", rc);
165 return RTErrConvertToErrno(rc);
166 }
167 /* No MODULE_VERSION in ng_ether so we can't MODULE_DEPEND it */
168 kern_kldload(curthread, "ng_ether", NULL);
169 break;
170
171 case MOD_UNLOAD:
172 rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltGlobals);
173 memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
174 RTR0Term();
175 break;
176
177 case MOD_SHUTDOWN:
178 case MOD_QUIESCE:
179 default:
180 return EOPNOTSUPP;
181 }
182
183 if (RT_SUCCESS(rc))
184 return 0;
185 return RTErrConvertToErrno(rc);
186}
187
188/*
189 * Convert from mbufs to vbox scatter-gather data structure
190 */
191static void vboxNetFltFreeBSDMBufToSG(PVBOXNETFLTINS pThis, struct mbuf *m, PINTNETSG pSG,
192 unsigned int cSegs, unsigned int segOffset)
193{
194 static uint8_t const s_abZero[128] = {0};
195 unsigned int i;
196 struct mbuf *m0;
197
198 IntNetSgInitTempSegs(pSG, m_length(m, NULL), cSegs, 0 /*cSegsUsed*/);
199
200 for (m0 = m, i = segOffset; m0; m0 = m0->m_next)
201 {
202 if (m0->m_len == 0)
203 continue;
204
205 pSG->aSegs[i].cb = m0->m_len;
206 pSG->aSegs[i].pv = mtod(m0, uint8_t *);
207 pSG->aSegs[i].Phys = NIL_RTHCPHYS;
208 i++;
209 }
210
211#ifdef PADD_RUNT_FRAMES_FROM_HOST
212 if (pSG->cbTotal < 60)
213 {
214 pSG->aSegs[i].Phys = NIL_RTHCPHYS;
215 pSG->aSegs[i].pv = (void *)&s_abZero[0];
216 pSG->aSegs[i].cb = 60 - pSG->cbTotal;
217 pSG->cbTotal = 60;
218 i++;
219 }
220#endif
221
222 pSG->cSegsUsed = i;
223}
224
225/*
226 * Convert to mbufs from vbox scatter-gather data structure
227 */
228static struct mbuf * vboxNetFltFreeBSDSGMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
229{
230 struct mbuf *m;
231 int error;
232 unsigned int i;
233
234 if (pSG->cbTotal == 0)
235 return (NULL);
236
237 m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
238 if (m == NULL)
239 return (NULL);
240
241 m->m_pkthdr.len = m->m_len = 0;
242 m->m_pkthdr.rcvif = NULL;
243
244 for (i = 0; i < pSG->cSegsUsed; i++)
245 {
246 error = m_append(m, pSG->aSegs[i].cb, pSG->aSegs[i].pv);
247 if (error == 0)
248 {
249 m_freem(m);
250 return (NULL);
251 }
252 }
253 return (m);
254}
255
256
257static int ng_vboxnetflt_constructor(node_p node)
258{
259 /* Nothing to do */
260 return (EINVAL);
261}
262
263/*
264 * Setup netgraph hooks
265 */
266static int ng_vboxnetflt_newhook(node_p node, hook_p hook, const char *name)
267{
268 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
269
270 if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
271 {
272#if __FreeBSD_version >= 800000
273 NG_HOOK_SET_TO_INBOUND(hook);
274#endif
275 pThis->u.s.input = hook;
276 }
277 else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
278 {
279 pThis->u.s.output = hook;
280 }
281 else
282 return (EINVAL);
283
284 NG_HOOK_HI_STACK(hook);
285 return (0);
286}
287
288/**
289 * Netgraph message processing for node specific messages.
290 * We don't accept any special messages so this is not used.
291 */
292static int ng_vboxnetflt_rcvmsg(node_p node, item_p item, hook_p lasthook)
293{
294 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
295 struct ng_mesg *msg;
296 int error = 0;
297
298 NGI_GET_MSG(item, msg);
299 if (msg->header.typecookie != NGM_VBOXNETFLT_COOKIE)
300 return (EINVAL);
301
302 switch (msg->header.cmd)
303 {
304 default:
305 error = EINVAL;
306 }
307 return (error);
308}
309
310/**
311 * Handle data on netgraph hooks.
312 * Frames processing is deferred to a taskqueue because this might
313 * be called with non-sleepable locks held and code paths inside
314 * the virtual switch might sleep.
315 */
316static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
317{
318 const node_p node = NG_HOOK_NODE(hook);
319 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
320 struct ifnet *ifp = pThis->u.s.ifp;
321 struct mbuf *m;
322 struct m_tag *mtag;
323 bool fActive;
324
325 fActive = vboxNetFltTryRetainBusyActive(pThis);
326
327 NGI_GET_M(item, m);
328 NG_FREE_ITEM(item);
329
330 /* Locate tag to see if processing should be skipped for this frame */
331 mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
332 if (mtag != NULL)
333 {
334 m_tag_unlink(m, mtag);
335 m_tag_free(mtag);
336 }
337
338 /*
339 * Handle incoming hook. This is connected to the
340 * input path of the interface, thus handling incoming frames.
341 */
342 if (pThis->u.s.input == hook)
343 {
344 if (mtag != NULL || !fActive)
345 {
346 ether_demux(ifp, m);
347 if (fActive)
348 vboxNetFltRelease(pThis, true /*fBusy*/);
349 return (0);
350 }
351 mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
352 _IF_ENQUEUE(&pThis->u.s.inq, m);
353 mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
354 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
355 }
356 /*
357 * Handle mbufs on the outgoing hook, frames going to the interface
358 */
359 else if (pThis->u.s.output == hook)
360 {
361 if (mtag != NULL || !fActive)
362 {
363 int rc = ether_output_frame(ifp, m);
364 if (fActive)
365 vboxNetFltRelease(pThis, true /*fBusy*/);
366 return rc;
367 }
368 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
369 _IF_ENQUEUE(&pThis->u.s.outq, m);
370 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
371 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
372 }
373 else
374 {
375 m_freem(m);
376 }
377
378 if (fActive)
379 vboxNetFltRelease(pThis, true /*fBusy*/);
380 return (0);
381}
382
383static int ng_vboxnetflt_shutdown(node_p node)
384{
385 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
386 bool fActive;
387
388 /* Prevent node shutdown if we're active */
389 if (pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
390 return (EBUSY);
391 NG_NODE_UNREF(node);
392 return (0);
393}
394
395static int ng_vboxnetflt_disconnect(hook_p hook)
396{
397 return (0);
398}
399
400/**
401 * Input processing task, handles incoming frames
402 */
403static void vboxNetFltFreeBSDinput(void *arg, int pending)
404{
405 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
406 struct mbuf *m, *m0;
407 struct ifnet *ifp = pThis->u.s.ifp;
408 unsigned int cSegs = 0;
409 bool fDropIt = false, fActive;
410 PINTNETSG pSG;
411
412 vboxNetFltRetain(pThis, true /* fBusy */);
413 for (;;)
414 {
415 mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
416 _IF_DEQUEUE(&pThis->u.s.inq, m);
417 mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
418 if (m == NULL)
419 break;
420
421 for (m0 = m; m0 != NULL; m0 = m0->m_next)
422 if (m0->m_len > 0)
423 cSegs++;
424
425#ifdef PADD_RUNT_FRAMES_FROM_HOST
426 if (m_length(m, NULL) < 60)
427 cSegs++;
428#endif
429
430 /* Create a copy and deliver to the virtual switch */
431 pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
432 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
433 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE);
434 RTMemTmpFree(pSG);
435 if (fDropIt)
436 m_freem(m);
437 else
438 ether_demux(ifp, m);
439 }
440 vboxNetFltRelease(pThis, true /* fBusy */);
441}
442
443/**
444 * Output processing task, handles outgoing frames
445 */
446static void vboxNetFltFreeBSDoutput(void *arg, int pending)
447{
448 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
449 struct mbuf *m, *m0;
450 struct ifnet *ifp = pThis->u.s.ifp;
451 unsigned int cSegs = 0;
452 bool fDropIt = false, fActive;
453 PINTNETSG pSG;
454
455 vboxNetFltRetain(pThis, true /* fBusy */);
456 for (;;)
457 {
458 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
459 _IF_DEQUEUE(&pThis->u.s.outq, m);
460 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
461 if (m == NULL)
462 break;
463
464 for (m0 = m; m0 != NULL; m0 = m0->m_next)
465 if (m0->m_len > 0)
466 cSegs++;
467
468#ifdef PADD_RUNT_FRAMES_FROM_HOST
469 if (m_length(m, NULL) < 60)
470 cSegs++;
471#endif
472 /* Create a copy and deliver to the virtual switch */
473 pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
474 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
475 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_HOST);
476 RTMemTmpFree(pSG);
477
478 if (fDropIt)
479 m_freem(m);
480 else
481 ether_output_frame(ifp, m);
482 }
483 vboxNetFltRelease(pThis, true /* fBusy */);
484}
485
486/**
487 * Called to deliver a frame to either the host, the wire or both.
488 */
489int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
490{
491 NOREF(pvIfData);
492
493 void (*input_f)(struct ifnet *, struct mbuf *);
494 struct ifnet *ifp;
495 struct mbuf *m;
496 struct m_tag *mtag;
497 bool fActive;
498 int error;
499
500 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
501
502 if (fDst & INTNETTRUNKDIR_WIRE)
503 {
504 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
505 if (m == NULL)
506 return VERR_NO_MEMORY;
507 m = m_pullup(m, ETHER_HDR_LEN);
508 if (m == NULL)
509 return VERR_NO_MEMORY;
510
511 m->m_flags |= M_PKTHDR;
512 ether_output_frame(ifp, m);
513 }
514
515 if (fDst & INTNETTRUNKDIR_HOST)
516 {
517 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
518 if (m == NULL)
519 return VERR_NO_MEMORY;
520 m = m_pullup(m, ETHER_HDR_LEN);
521 if (m == NULL)
522 return VERR_NO_MEMORY;
523 /*
524 * Delivering packets to the host will be captured by the
525 * input hook. Tag the packet with a mbuf tag so that we
526 * can skip re-delivery of the packet to the guest during
527 * input hook processing.
528 */
529 mtag = m_tag_alloc(MTAG_VBOX, PACKET_TAG_VBOX, 0, M_NOWAIT);
530 if (mtag == NULL)
531 {
532 m_freem(m);
533 return VERR_NO_MEMORY;
534 }
535
536 m_tag_init(m);
537 m_tag_prepend(m, mtag);
538 m->m_flags |= M_PKTHDR;
539 m->m_pkthdr.rcvif = ifp;
540 ifp->if_input(ifp, m);
541 }
542 return VINF_SUCCESS;
543}
544
545static bool vboxNetFltFreeBsdIsPromiscuous(PVBOXNETFLTINS pThis)
546{
547 /** @todo This isn't taking into account that we put the interface in
548 * promiscuous mode. */
549 return (pThis->u.s.flags & IFF_PROMISC) ? true : false;
550}
551
552int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
553{
554 char nam[NG_NODESIZ];
555 struct ifnet *ifp;
556 node_p node;
557 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
558
559 NOREF(pvContext);
560 ifp = ifunit(pThis->szName);
561 if (ifp == NULL)
562 return VERR_INTNET_FLT_IF_NOT_FOUND;
563
564 /* Create a new netgraph node for this instance */
565 if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
566 return VERR_INTERNAL_ERROR;
567
568 RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
569
570 ASMAtomicUoWritePtr(&pThis->u.s.ifp, ifp);
571 pThis->u.s.node = node;
572 bcopy(IF_LLADDR(ifp), &pThis->u.s.MacAddr, ETHER_ADDR_LEN);
573 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
574
575 /* Initialize deferred input queue */
576 bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
577 mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
578 TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
579
580 /* Initialize deferred output queue */
581 bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
582 mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
583 TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
584
585 RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
586
587 NG_NODE_SET_PRIVATE(node, pThis);
588
589 /* Attempt to name it vboxnetflt_<ifname> */
590 snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName);
591 ng_name_node(node, nam);
592
593 /* Report MAC address, promiscuous mode and GSO capabilities. */
594 /** @todo keep these reports up to date, either by polling for changes or
595 * intercept some control flow if possible. */
596 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
597 {
598 Assert(pThis->pSwitchPort);
599 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
600 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltFreeBsdIsPromiscuous(pThis));
601 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
602 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
603 vboxNetFltRelease(pThis, true /*fBusy*/);
604 }
605
606 return VINF_SUCCESS;
607}
608
609bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
610{
611 struct ifnet *ifp, *ifp0;
612
613 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
614 /*
615 * Attempt to check if the interface is still there and re-initialize if
616 * something has changed.
617 */
618 ifp0 = ifunit(pThis->szName);
619 if (ifp != ifp0)
620 {
621 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, true);
622 ng_rmnode_self(pThis->u.s.node);
623 pThis->u.s.node = NULL;
624 }
625
626 if (ifp0 != NULL)
627 {
628 vboxNetFltOsDeleteInstance(pThis);
629 vboxNetFltOsInitInstance(pThis, NULL);
630 }
631
632 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
633}
634
635void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
636{
637
638 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
639 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
640
641 mtx_destroy(&pThis->u.s.inq.ifq_mtx);
642 mtx_destroy(&pThis->u.s.outq.ifq_mtx);
643
644 if (pThis->u.s.node != NULL)
645 ng_rmnode_self(pThis->u.s.node);
646 pThis->u.s.node = NULL;
647}
648
649int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
650{
651
652 pThis->u.s.ifp = NULL;
653 pThis->u.s.flags = 0;
654 pThis->u.s.node = NULL;
655 return VINF_SUCCESS;
656}
657
658void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
659{
660 struct ifnet *ifp;
661 struct ifreq ifreq;
662 int error;
663 node_p node;
664 struct ng_mesg *msg;
665 struct ngm_connect *con;
666 struct ngm_rmhook *rm;
667 char path[NG_PATHSIZ];
668
669 Log(("%s: fActive:%d\n", __func__, fActive));
670
671 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
672 node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p);
673
674 memset(&ifreq, 0, sizeof(struct ifreq));
675 /* Activate interface */
676 if (fActive)
677 {
678 pThis->u.s.flags = ifp->if_flags;
679 ifpromisc(ifp, 1);
680
681 /* ng_ether nodes are named after the interface name */
682 snprintf(path, sizeof(path), "%s:", ifp->if_xname);
683
684 /*
685 * Send a netgraph connect message to the ng_ether node
686 * assigned to the bridged interface. Connecting
687 * the hooks 'lower' (ng_ether) to out 'input'.
688 */
689 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
690 sizeof(struct ngm_connect), M_NOWAIT);
691 if (msg == NULL)
692 return;
693 con = (struct ngm_connect *)msg->data;
694 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
695 strlcpy(con->ourhook, "lower", NG_HOOKSIZ);
696 strlcpy(con->peerhook, "input", NG_HOOKSIZ);
697 NG_SEND_MSG_PATH(error, node, msg, path, 0);
698
699 /*
700 * Do the same for the hooks 'upper' (ng_ether) and our
701 * 'output' hook.
702 */
703 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
704 sizeof(struct ngm_connect), M_NOWAIT);
705 if (msg == NULL)
706 return;
707 con = (struct ngm_connect *)msg->data;
708 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:",
709 ifp->if_xname);
710 strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
711 strlcpy(con->peerhook, "output", sizeof(con->peerhook));
712 NG_SEND_MSG_PATH(error, node, msg, path, 0);
713 }
714 else
715 {
716 /* De-activate interface */
717 pThis->u.s.flags = 0;
718 ifpromisc(ifp, 0);
719
720 /* Disconnect msgs are addressed to ourself */
721 snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);
722
723 /*
724 * Send a netgraph message to disconnect our 'input' hook
725 */
726 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
727 sizeof(struct ngm_rmhook), M_NOWAIT);
728 if (msg == NULL)
729 return;
730 rm = (struct ngm_rmhook *)msg->data;
731 strlcpy(rm->ourhook, "input", NG_HOOKSIZ);
732 NG_SEND_MSG_PATH(error, node, msg, path, 0);
733
734 /*
735 * Send a netgraph message to disconnect our 'output' hook
736 */
737 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
738 sizeof(struct ngm_rmhook), M_NOWAIT);
739 if (msg == NULL)
740 return;
741 rm = (struct ngm_rmhook *)msg->data;
742 strlcpy(rm->ourhook, "output", NG_HOOKSIZ);
743 NG_SEND_MSG_PATH(error, node, msg, path, 0);
744 }
745}
746
747int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
748{
749 return VINF_SUCCESS;
750}
751
752int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
753{
754 return VINF_SUCCESS;
755}
756
757void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
758{
759 NOREF(pThis); NOREF(pvIfData); NOREF(pMac);
760}
761
762int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
763{
764 /* Nothing to do */
765 NOREF(pThis); NOREF(pvIf); NOREF(ppvIfData);
766 return VINF_SUCCESS;
767}
768
769int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
770{
771 /* Nothing to do */
772 NOREF(pThis); NOREF(pvIfData);
773 return VINF_SUCCESS;
774}
775
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