VirtualBox

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

Last change on this file since 40912 was 40912, checked in by vboxsync, 13 years ago

VBoxNetFlt/FreeBSD: Fix crash on VM shutdown if VIMAGE is enabled (Thanks to Mikolaj Golub and Bernhard Froehlich)

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