VirtualBox

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

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

IntNet: Added Interface, Interface private data passing for per-interface based VBoxNetFlt.

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