ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * VBoxNetFlt - Network Filter Driver (Host), FreeBSD Specific Code.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Permission is hereby granted, free of charge, to any person
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * obtaining a copy of this software and associated documentation
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * files (the "Software"), to deal in the Software without
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * restriction, including without limitation the rights to use,
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * copy, modify, merge, publish, distribute, sublicense, and/or sell
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * copies of the Software, and to permit persons to whom the
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Software is furnished to do so, subject to the following
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * conditions:
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * The above copyright notice and this permission notice shall be
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * included in all copies or substantial portions of the Software.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * OTHER DEALINGS IN THE SOFTWARE.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/*******************************************************************************
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync* Header Files *
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync*******************************************************************************/
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int vboxnetflt_modevent(struct module *, int, void *);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** Netgraph node type */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** Netgraph message cookie */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** Input netgraph hook name */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** Output netgraph hook name */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** mbuf tag identifier */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync/** mbuf packet tag */
8d73b12275cff467e9a44e417d5bb7a5b7218bfevboxsync#if defined(__FreeBSD_version) && __FreeBSD_version >= 800500
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync# define VBOXCURVNET_SET(arg) CURVNET_SET_QUIET(arg)
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync# define VBOXCURVNET_SET_FROM_UCRED() VBOXCURVNET_SET(CRED_TO_VNET(curthread->td_ucred))
8d73b12275cff467e9a44e417d5bb7a5b7218bfevboxsync#else /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
8d73b12275cff467e9a44e417d5bb7a5b7218bfevboxsync#endif /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Netgraph command list, we don't support any
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * additional commands.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic const struct ng_cmdlist ng_vboxnetflt_cmdlist[] =
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Netgraph type definition
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncNETGRAPH_INIT(vboxnetflt, &ng_vboxnetflt_typestruct);
545f5817b4bf7085bafbc6e5186faa7cabef5102vboxsync * Use vboxnetflt because the kernel module is named vboxnetflt and vboxnetadp
545f5817b4bf7085bafbc6e5186faa7cabef5102vboxsync * depends on this when loading dependencies.
545f5817b4bf7085bafbc6e5186faa7cabef5102vboxsync * NETGRAP_INIT will prefix the given name with ng_ so MODULE_DEPEND needs the
545f5817b4bf7085bafbc6e5186faa7cabef5102vboxsync * prefixed name.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * The (common) global data.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Module event handler, called from netgraph subsystem.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int vboxnetflt_modevent(struct module *pMod, int enmEventType, void *pvArg)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltGlobals);
c366016ffe1788c6847d0a967a954713725cab5evboxsync printf("vboxNetFltInitGlobalsAndIdc failed %d\n", rc);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* No MODULE_VERSION in ng_ether so we can't MODULE_DEPEND it */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltGlobals);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS));
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Convert from mbufs to vbox scatter-gather data structure
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic void vboxNetFltFreeBSDMBufToSG(PVBOXNETFLTINS pThis, struct mbuf *m, PINTNETSG pSG,
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync unsigned int i;
9127c416edfd6f9266e387f7abd7aa9904eecbc9vboxsync IntNetSgInitTempSegs(pSG, m_length(m, NULL), cSegs, 0 /*cSegsUsed*/);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Convert to mbufs from vbox scatter-gather data structure
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic struct mbuf * vboxNetFltFreeBSDSGMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync unsigned int i;
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync error = m_append(m, pSG->aSegs[i].cb, pSG->aSegs[i].pv);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync return (m);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* Nothing to do */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Setup netgraph hooks
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int ng_vboxnetflt_newhook(node_p node, hook_p hook, const char *name)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync return (0);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Netgraph message processing for node specific messages.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * We don't accept any special messages so this is not used.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int ng_vboxnetflt_rcvmsg(node_p node, item_p item, hook_p lasthook)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync if (msg->header.typecookie != NGM_VBOXNETFLT_COOKIE)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Handle data on netgraph hooks.
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * Frames processing is deferred to a taskqueue because this might
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * be called with non-sleepable locks held and code paths inside
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * the virtual switch might sleep.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncstatic int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Locate tag to see if processing should be skipped for this frame */
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * Handle incoming hook. This is connected to the
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * input path of the interface, thus handling incoming frames.
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync return (0);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * Handle mbufs on the outgoing hook, frames going to the interface
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync return (0);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Prevent node shutdown if we're active */
d61e6f5b11d9031623420bd7ed3013477d8f402dvboxsync if (pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync return (0);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync return (0);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * Input processing task, handles incoming frames
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsyncstatic void vboxNetFltFreeBSDinput(void *arg, int pending)
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Create a copy and deliver to the virtual switch */
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
586cf6585d0e6aa3bef888eeff116bf82d18cd83vboxsync fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync * Output processing task, handles outgoing frames
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsyncstatic void vboxNetFltFreeBSDoutput(void *arg, int pending)
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Create a copy and deliver to the virtual switch */
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
0c05664313a83177e156d6deb64c656fbc26608dvboxsync fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_HOST);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Called to deliver a frame to either the host, the wire or both.
586cf6585d0e6aa3bef888eeff116bf82d18cd83vboxsyncint vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
c7ff622115966b69b482bd2896662e40d823b22fvboxsync ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Delivering packets to the host will be captured by the
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * input hook. Tag the packet with a mbuf tag so that we
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * can skip re-delivery of the packet to the guest during
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * input hook processing.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync mtag = m_tag_alloc(MTAG_VBOX, PACKET_TAG_VBOX, 0, M_NOWAIT);
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsyncstatic bool vboxNetFltFreeBsdIsPromiscuous(PVBOXNETFLTINS pThis)
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync /** @todo This isn't taking into account that we put the interface in
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync * promiscuous mode. */
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync return (pThis->u.s.flags & IFF_PROMISC) ? true : false;
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncint vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* Create a new netgraph node for this instance */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync bcopy(IF_LLADDR(ifp), &pThis->u.s.MacAddr, ETHER_ADDR_LEN);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Initialize deferred input queue */
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync /* Initialize deferred output queue */
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* Attempt to name it vboxnetflt_<ifname> */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName);
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync /* Report MAC address, promiscuous mode and GSO capabilities. */
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync /** @todo keep these reports up to date, either by polling for changes or
5f809eed9fe4d8f7f317e8102657eb877fd5fbdavboxsync * intercept some control flow if possible. */
d61e6f5b11d9031623420bd7ed3013477d8f402dvboxsync pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
d61e6f5b11d9031623420bd7ed3013477d8f402dvboxsync pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltFreeBsdIsPromiscuous(pThis));
d61e6f5b11d9031623420bd7ed3013477d8f402dvboxsync pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
d61e6f5b11d9031623420bd7ed3013477d8f402dvboxsync pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncbool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
c7ff622115966b69b482bd2896662e40d823b22fvboxsync ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Attempt to check if the interface is still there and re-initialize if
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * something has changed.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, true);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncvoid vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
e54b16ce4a8dbf2ade96b5d4c9e59ccea044c817vboxsync taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncint vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsyncvoid vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
c7ff622115966b69b482bd2896662e40d823b22fvboxsync ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
c7ff622115966b69b482bd2896662e40d823b22fvboxsync node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* Activate interface */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* ng_ether nodes are named after the interface name */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync snprintf(path, sizeof(path), "%s:", ifp->if_xname);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Send a netgraph connect message to the ng_ether node
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * assigned to the bridged interface. Connecting
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * the hooks 'lower' (ng_ether) to out 'input'.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Do the same for the hooks 'upper' (ng_ether) and our
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * 'output' hook.
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync strlcpy(con->peerhook, "output", sizeof(con->peerhook));
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* De-activate interface */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync /* Disconnect msgs are addressed to ourself */
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Send a netgraph message to disconnect our 'input' hook
ba287763fb250c9244e7a7afc1abff9387b94e43vboxsync * Send a netgraph message to disconnect our 'output' hook
586cf6585d0e6aa3bef888eeff116bf82d18cd83vboxsyncvoid vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
586cf6585d0e6aa3bef888eeff116bf82d18cd83vboxsyncint vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
69c51855f3b700d7b26a81f1d7dfed523097b7e2vboxsync /* Nothing to do */
586cf6585d0e6aa3bef888eeff116bf82d18cd83vboxsyncint vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
69c51855f3b700d7b26a81f1d7dfed523097b7e2vboxsync /* Nothing to do */