VirtualBox

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

Last change on this file since 100356 was 77124, checked in by vboxsync, 6 years ago

VBoxNetAdp,VBoxNetFlt: FreeBSD build fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.2 KB
Line 
1/* $Id: VBoxNetFlt-freebsd.c 77124 2019-02-01 15:35: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/*********************************************************************************************************************************
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#if __FreeBSD_version > 1100100
374 taskqueue_enqueue(taskqueue_fast, &pThis->u.s.tskin);
375#else
376 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
377#endif
378 }
379 /*
380 * Handle mbufs on the outgoing hook, frames going to the interface
381 */
382 else if (pThis->u.s.output == hook)
383 {
384 if (mtag != NULL || !fActive)
385 {
386 int rc = ether_output_frame(ifp, m);
387 if (fActive)
388 vboxNetFltRelease(pThis, true /*fBusy*/);
389 VBOXCURVNET_RESTORE();
390 return rc;
391 }
392 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
393 _IF_ENQUEUE(&pThis->u.s.outq, m);
394 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
395#if __FreeBSD_version > 1100100
396 taskqueue_enqueue(taskqueue_fast, &pThis->u.s.tskout);
397#else
398 taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
399#endif
400 }
401 else
402 {
403 m_freem(m);
404 }
405
406 if (fActive)
407 vboxNetFltRelease(pThis, true /*fBusy*/);
408 VBOXCURVNET_RESTORE();
409 return (0);
410}
411
412static int ng_vboxnetflt_shutdown(node_p node)
413{
414 PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
415 bool fActive;
416
417 /* Prevent node shutdown if we're active */
418 if (pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
419 return (EBUSY);
420 NG_NODE_UNREF(node);
421 return (0);
422}
423
424static int ng_vboxnetflt_disconnect(hook_p hook)
425{
426 return (0);
427}
428
429/**
430 * Input processing task, handles incoming frames
431 */
432static void vboxNetFltFreeBSDinput(void *arg, int pending)
433{
434 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
435 struct mbuf *m, *m0;
436 struct ifnet *ifp = pThis->u.s.ifp;
437 unsigned int cSegs = 0;
438 bool fDropIt = false, fActive;
439 PINTNETSG pSG;
440
441 VBOXCURVNET_SET(ifp->if_vnet);
442 vboxNetFltRetain(pThis, true /* fBusy */);
443 for (;;)
444 {
445 mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
446 _IF_DEQUEUE(&pThis->u.s.inq, m);
447 mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
448 if (m == NULL)
449 break;
450
451 for (m0 = m; m0 != NULL; m0 = m0->m_next)
452 if (m0->m_len > 0)
453 cSegs++;
454
455#ifdef PADD_RUNT_FRAMES_FROM_HOST
456 if (m_length(m, NULL) < 60)
457 cSegs++;
458#endif
459
460 /* Create a copy and deliver to the virtual switch */
461 pSG = RTMemTmpAlloc(RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
462 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
463 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE);
464 RTMemTmpFree(pSG);
465 if (fDropIt)
466 m_freem(m);
467 else
468 ether_demux(ifp, m);
469 }
470 vboxNetFltRelease(pThis, true /* fBusy */);
471 VBOXCURVNET_RESTORE();
472}
473
474/**
475 * Output processing task, handles outgoing frames
476 */
477static void vboxNetFltFreeBSDoutput(void *arg, int pending)
478{
479 PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
480 struct mbuf *m, *m0;
481 struct ifnet *ifp = pThis->u.s.ifp;
482 unsigned int cSegs = 0;
483 bool fDropIt = false, fActive;
484 PINTNETSG pSG;
485
486 VBOXCURVNET_SET(ifp->if_vnet);
487 vboxNetFltRetain(pThis, true /* fBusy */);
488 for (;;)
489 {
490 mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
491 _IF_DEQUEUE(&pThis->u.s.outq, m);
492 mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
493 if (m == NULL)
494 break;
495
496 for (m0 = m; m0 != NULL; m0 = m0->m_next)
497 if (m0->m_len > 0)
498 cSegs++;
499
500#ifdef PADD_RUNT_FRAMES_FROM_HOST
501 if (m_length(m, NULL) < 60)
502 cSegs++;
503#endif
504 /* Create a copy and deliver to the virtual switch */
505 pSG = RTMemTmpAlloc(RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
506 vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
507 fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_HOST);
508 RTMemTmpFree(pSG);
509
510 if (fDropIt)
511 m_freem(m);
512 else
513 ether_output_frame(ifp, m);
514 }
515 vboxNetFltRelease(pThis, true /* fBusy */);
516 VBOXCURVNET_RESTORE();
517}
518
519/**
520 * Called to deliver a frame to either the host, the wire or both.
521 */
522int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
523{
524 NOREF(pvIfData);
525
526 void (*input_f)(struct ifnet *, struct mbuf *);
527 struct ifnet *ifp;
528 struct mbuf *m;
529 struct m_tag *mtag;
530 bool fActive;
531 int error;
532
533 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
534 VBOXCURVNET_SET(ifp->if_vnet);
535
536 if (fDst & INTNETTRUNKDIR_WIRE)
537 {
538 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
539 if (m == NULL)
540 return VERR_NO_MEMORY;
541 m = m_pullup(m, ETHER_HDR_LEN);
542 if (m == NULL)
543 return VERR_NO_MEMORY;
544
545 m->m_flags |= M_PKTHDR;
546 ether_output_frame(ifp, m);
547 }
548
549 if (fDst & INTNETTRUNKDIR_HOST)
550 {
551 m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG);
552 if (m == NULL)
553 return VERR_NO_MEMORY;
554 m = m_pullup(m, ETHER_HDR_LEN);
555 if (m == NULL)
556 return VERR_NO_MEMORY;
557 /*
558 * Delivering packets to the host will be captured by the
559 * input hook. Tag the packet with a mbuf tag so that we
560 * can skip re-delivery of the packet to the guest during
561 * input hook processing.
562 */
563 mtag = m_tag_alloc(MTAG_VBOX, PACKET_TAG_VBOX, 0, M_NOWAIT);
564 if (mtag == NULL)
565 {
566 m_freem(m);
567 return VERR_NO_MEMORY;
568 }
569
570 m_tag_init(m);
571 m_tag_prepend(m, mtag);
572 m->m_flags |= M_PKTHDR;
573 m->m_pkthdr.rcvif = ifp;
574 ifp->if_input(ifp, m);
575 }
576 VBOXCURVNET_RESTORE();
577 return VINF_SUCCESS;
578}
579
580static bool vboxNetFltFreeBsdIsPromiscuous(PVBOXNETFLTINS pThis)
581{
582 /** @todo This isn't taking into account that we put the interface in
583 * promiscuous mode. */
584 return (pThis->u.s.flags & IFF_PROMISC) ? true : false;
585}
586
587int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
588{
589 char nam[NG_NODESIZ];
590 struct ifnet *ifp;
591 node_p node;
592
593 VBOXCURVNET_SET_FROM_UCRED();
594 NOREF(pvContext);
595 ifp = ifunit(pThis->szName);
596 if (ifp == NULL)
597 return VERR_INTNET_FLT_IF_NOT_FOUND;
598
599 /* Create a new netgraph node for this instance */
600 if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
601 return VERR_INTERNAL_ERROR;
602
603 RTSpinlockAcquire(pThis->hSpinlock);
604
605 ASMAtomicUoWritePtr(&pThis->u.s.ifp, ifp);
606 pThis->u.s.node = node;
607 bcopy(IF_LLADDR(ifp), &pThis->u.s.MacAddr, ETHER_ADDR_LEN);
608 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
609
610 /* Initialize deferred input queue */
611 bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
612 mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
613 TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
614
615 /* Initialize deferred output queue */
616 bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
617 mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
618 TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
619
620 RTSpinlockRelease(pThis->hSpinlock);
621
622 NG_NODE_SET_PRIVATE(node, pThis);
623
624 /* Attempt to name it vboxnetflt_<ifname> */
625 snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName);
626 ng_name_node(node, nam);
627
628 /* Report MAC address, promiscuous mode and GSO capabilities. */
629 /** @todo keep these reports up to date, either by polling for changes or
630 * intercept some control flow if possible. */
631 if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
632 {
633 Assert(pThis->pSwitchPort);
634 pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
635 pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltFreeBsdIsPromiscuous(pThis));
636 pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
637 pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
638 vboxNetFltRelease(pThis, true /*fBusy*/);
639 }
640 VBOXCURVNET_RESTORE();
641
642 return VINF_SUCCESS;
643}
644
645bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
646{
647 struct ifnet *ifp, *ifp0;
648
649 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
650 VBOXCURVNET_SET(ifp->if_vnet);
651 /*
652 * Attempt to check if the interface is still there and re-initialize if
653 * something has changed.
654 */
655 ifp0 = ifunit(pThis->szName);
656 if (ifp != ifp0)
657 {
658 ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, true);
659 ng_rmnode_self(pThis->u.s.node);
660 pThis->u.s.node = NULL;
661 }
662 VBOXCURVNET_RESTORE();
663
664 if (ifp0 != NULL)
665 {
666 vboxNetFltOsDeleteInstance(pThis);
667 vboxNetFltOsInitInstance(pThis, NULL);
668 }
669
670 return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
671}
672
673void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
674{
675
676 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
677 taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
678
679 mtx_destroy(&pThis->u.s.inq.ifq_mtx);
680 mtx_destroy(&pThis->u.s.outq.ifq_mtx);
681
682 VBOXCURVNET_SET_FROM_UCRED();
683 if (pThis->u.s.node != NULL)
684 ng_rmnode_self(pThis->u.s.node);
685 VBOXCURVNET_RESTORE();
686 pThis->u.s.node = NULL;
687}
688
689int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
690{
691
692 pThis->u.s.ifp = NULL;
693 pThis->u.s.flags = 0;
694 pThis->u.s.node = NULL;
695 return VINF_SUCCESS;
696}
697
698void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
699{
700 struct ifnet *ifp;
701 struct ifreq ifreq;
702 int error;
703 node_p node;
704 struct ng_mesg *msg;
705 struct ngm_connect *con;
706 struct ngm_rmhook *rm;
707 char path[NG_PATHSIZ];
708
709 Log(("%s: fActive:%d\n", __func__, fActive));
710
711 ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
712 VBOXCURVNET_SET(ifp->if_vnet);
713 node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p);
714
715 memset(&ifreq, 0, sizeof(struct ifreq));
716 /* Activate interface */
717 if (fActive)
718 {
719 pThis->u.s.flags = ifp->if_flags;
720 ifpromisc(ifp, 1);
721
722 /* ng_ether nodes are named after the interface name */
723 snprintf(path, sizeof(path), "%s:", ifp->if_xname);
724
725 /*
726 * Send a netgraph connect message to the ng_ether node
727 * assigned to the bridged interface. Connecting
728 * the hooks 'lower' (ng_ether) to out 'input'.
729 */
730 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
731 sizeof(struct ngm_connect), M_NOWAIT);
732 if (msg == NULL)
733 return;
734 con = (struct ngm_connect *)msg->data;
735 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
736 strlcpy(con->ourhook, "lower", NG_HOOKSIZ);
737 strlcpy(con->peerhook, "input", NG_HOOKSIZ);
738 NG_SEND_MSG_PATH(error, node, msg, path, 0);
739
740 /*
741 * Do the same for the hooks 'upper' (ng_ether) and our
742 * 'output' hook.
743 */
744 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
745 sizeof(struct ngm_connect), M_NOWAIT);
746 if (msg == NULL)
747 return;
748 con = (struct ngm_connect *)msg->data;
749 snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:",
750 ifp->if_xname);
751 strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
752 strlcpy(con->peerhook, "output", sizeof(con->peerhook));
753 NG_SEND_MSG_PATH(error, node, msg, path, 0);
754 }
755 else
756 {
757 /* De-activate interface */
758 pThis->u.s.flags = 0;
759 ifpromisc(ifp, 0);
760
761 /* Disconnect msgs are addressed to ourself */
762 snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);
763
764 /*
765 * Send a netgraph message to disconnect our 'input' hook
766 */
767 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
768 sizeof(struct ngm_rmhook), M_NOWAIT);
769 if (msg == NULL)
770 return;
771 rm = (struct ngm_rmhook *)msg->data;
772 strlcpy(rm->ourhook, "input", NG_HOOKSIZ);
773 NG_SEND_MSG_PATH(error, node, msg, path, 0);
774
775 /*
776 * Send a netgraph message to disconnect our 'output' hook
777 */
778 NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
779 sizeof(struct ngm_rmhook), M_NOWAIT);
780 if (msg == NULL)
781 return;
782 rm = (struct ngm_rmhook *)msg->data;
783 strlcpy(rm->ourhook, "output", NG_HOOKSIZ);
784 NG_SEND_MSG_PATH(error, node, msg, path, 0);
785 }
786 VBOXCURVNET_RESTORE();
787}
788
789int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
790{
791 return VINF_SUCCESS;
792}
793
794int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
795{
796 return VINF_SUCCESS;
797}
798
799void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
800{
801 NOREF(pThis); NOREF(pvIfData); NOREF(pMac);
802}
803
804int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
805{
806 /* Nothing to do */
807 NOREF(pThis); NOREF(pvIf); NOREF(ppvIfData);
808 return VINF_SUCCESS;
809}
810
811int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
812{
813 /* Nothing to do */
814 NOREF(pThis); NOREF(pvIfData);
815 return VINF_SUCCESS;
816}
817
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