VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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