Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c =================================================================== --- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 0) +++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c (revision 0) @@ -0,0 +1,606 @@ +/*- + * Copyright (c) 2009 Fredrik Lindberg + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#undef PVM +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VBOXNETFLT_OS_SPECFIC 1 +#include "../VBoxNetFltInternal.h" + +static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals; + +static int vboxnetflt_modevent(struct module *, int, void *); +static ng_constructor_t ng_vboxnetflt_constructor; +static ng_rcvmsg_t ng_vboxnetflt_rcvmsg; +static ng_shutdown_t ng_vboxnetflt_shutdown; +static ng_newhook_t ng_vboxnetflt_newhook; +static ng_rcvdata_t ng_vboxnetflt_rcvdata; +static ng_disconnect_t ng_vboxnetflt_disconnect; +static int ng_vboxnetflt_mod_event(module_t mod, int event, void *data); +static int ng_vboxnetflt_rcv_in(hook_p node, item_p item); +static int ng_vboxnetflt_rcv_out(hook_p node, item_p item); + +#define NG_VBOXNETFLT_NODE_TYPE "vboxnetflt" +#define NGM_VBOXNETFLT_COOKIE 0x56424f58 + +#define NG_VBOXNETFLT_HOOK_IN "input" +#define NG_VBOXNETFLT_HOOK_OUT "output" + +#define MTAG_VBOX 0x56424f58 +#define PACKET_TAG_VBOX 128 + +static const struct ng_cmdlist ng_vboxnetflt_cmdlist[] = { + { 0 } +}; + +static struct ng_type ng_vboxnetflt_typestruct = { + .version = NG_ABI_VERSION, + .name = NG_VBOXNETFLT_NODE_TYPE, + .mod_event = vboxnetflt_modevent, + .constructor = ng_vboxnetflt_constructor, + .rcvmsg = ng_vboxnetflt_rcvmsg, + .shutdown = ng_vboxnetflt_shutdown, + .newhook = ng_vboxnetflt_newhook, + .rcvdata = ng_vboxnetflt_rcvdata, + .disconnect = ng_vboxnetflt_disconnect, + .cmdlist = ng_vboxnetflt_cmdlist, +}; +NETGRAPH_INIT(vboxnetflt, &ng_vboxnetflt_typestruct); +MODULE_DEPEND(ng_vboxnetflt, vboxdrv, 1, 1, 1); + +static int vboxnetflt_modevent(struct module *pMod, int enmEventType, void *pvArg) +{ + int rc; + + Log(("VBoxNetFltFreeBSDModuleEvent\n")); + + switch (enmEventType) { + case MOD_LOAD: + rc = RTR0Init(0); + if (!RT_SUCCESS(rc)) { + Log(("RTR0Init failed %d\n", rc)); + return RTErrConvertToErrno(rc); + } + + memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS)); + rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltGlobals); + if (!RT_SUCCESS(rc)) { + Log(("vboxNetFltInitGlobalsAndIdc failed %d\n", rc)); + return RTErrConvertToErrno(rc); + } + RTR0Term(); + kern_kldload(curthread, "ng_ether", NULL); + break; + + case MOD_UNLOAD: + rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltGlobals); + memset(&g_VBoxNetFltGlobals, 0, sizeof(VBOXNETFLTGLOBALS)); + break; + + case MOD_SHUTDOWN: + case MOD_QUIESCE: + default: + return EOPNOTSUPP; + } + + if (RT_SUCCESS(rc)) + return 0; + return RTErrConvertToErrno(rc); +} + +static void +vboxNetFltFreeBSDMBufToSG(PVBOXNETFLTINS pThis, struct mbuf *m, PINTNETSG pSG, + unsigned int cSegs, unsigned int segOffset) +{ + static uint8_t const s_abZero[128] = {0}; + unsigned int i; + struct mbuf *m0; + + pSG->cbTotal = m_length(m, NULL); + pSG->pvOwnerData = NULL; + pSG->pvUserData = NULL; + pSG->pvUserData2 = NULL; + pSG->cUsers = 1; + pSG->fFlags = INTNETSG_FLAGS_TEMP; + pSG->cSegsAlloc = cSegs; + + for (m0 = m, i = segOffset; m0; m0 = m0->m_next) { + if (m0->m_len == 0) + continue; + + pSG->aSegs[i].cb = m0->m_len; + pSG->aSegs[i].pv = mtod(m0, uint8_t *); + pSG->aSegs[i].Phys = NIL_RTHCPHYS; + i++; + } + +#ifdef PADD_RUNT_FRAMES_FROM_HOST + if (pSG->cbTotal < 60) { + pSG->aSegs[i].Phys = NIL_RTHCPHYS; + pSG->aSegs[i].pv = (void *)&s_abZero[0]; + pSG->aSegs[i].cb = 60 - pSG->cbTotal; + pSG->cbTotal = 60; + i++; + } +#endif + pSG->cSegsUsed = i; +} + +static struct mbuf * +vboxNetFltFreeBSDSGMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG) +{ + struct mbuf *m; + int error; + unsigned int i; + + if (pSG->cbTotal == 0 || pSG->aSegs[0].cb == 0) + return (NULL); + + m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); + if (m == NULL) + return (NULL); + + m->m_pkthdr.len = m->m_len = 0; + m->m_pkthdr.rcvif = NULL; + + for (i = 0; i < pSG->cSegsUsed; i++) { + error = m_append(m, pSG->aSegs[i].cb, pSG->aSegs[i].pv); + if (error == 0) { + m_freem(m); + return (NULL); + } + } + return (m); +} + + +static int ng_vboxnetflt_constructor(node_p node) +{ + + return (EINVAL); +} + +static int ng_vboxnetflt_newhook(node_p node, hook_p hook, const char *name) +{ + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + + if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0) { +#if __FreeBSD_version >= 800000 + NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in); + NG_HOOK_SET_TO_INBOUND(hook); +#endif + pThis->u.s.input = hook; + } else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0) { +#if __FreeBSD_version >= 800000 + NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out); +#endif + pThis->u.s.output = hook; + } else { + return (EINVAL); + } + + NG_HOOK_HI_STACK(hook); + return (0); +} + +static int ng_vboxnetflt_rcvmsg(node_p node, item_p item, hook_p lasthook) +{ + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + struct ng_mesg *msg; + int error = 0; + + NGI_GET_MSG(item, msg); + if (msg->header.typecookie != NGM_VBOXNETFLT_COOKIE) + return (EINVAL); + + switch (msg->header.cmd) { + default: + error = EINVAL; + } + return (error); +} + +static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item) +{ + const node_p node = NG_HOOK_NODE(hook); + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + struct mbuf *m; + + if (pThis->u.s.input == hook) + return ng_vboxnetflt_rcv_in(hook, item); + else if (pThis->u.s.output == hook) + return ng_vboxnetflt_rcv_out(hook, item); + else { + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + } + return (0); +} + +/* Handle mbuf on incoming hook, from interface */ +static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item) +{ + struct mbuf *m, *m0; + struct m_tag *mtag; + const node_p node = NG_HOOK_NODE(hook); + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + struct ifnet *ifp = pThis->u.s.ifp; + bool fActive, fDropIt = false; + unsigned int cSegs = 0; + PINTNETSG pSG; + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + fActive = ASMAtomicUoReadBool(&pThis->fActive); + if (!fActive) + goto out; + + mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL); + if (mtag != NULL) { + m_tag_unlink(m, mtag); + m_tag_free(mtag); + goto out; + } + vboxNetFltRetain(pThis, true /* fBusy */); + + for (m0 = m; m0 != NULL; m0 = m0->m_next) { + if (m0->m_len > 0) + cSegs++; + } + +#ifdef PADD_RUNT_FRAMES_FROM_HOST + if (m_length(m, NULL) < 60) + cSegs++; +#endif + + pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); + vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0); + fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE); + RTMemTmpFree(pSG); + vboxNetFltRelease(pThis, true /* fBusy */); + +out: + if (fDropIt) { + m_freem(m); + return (0); + } + ether_demux(ifp, m); + return (0); +} + +/* Handle mbuf on outgoing hook, to interface */ +static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item) +{ + struct mbuf *m, *m0; + struct m_tag *mtag; + const node_p node = NG_HOOK_NODE(hook); + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + struct ifnet *ifp = pThis->u.s.ifp; + unsigned int cSegs = 0; + bool fDropIt = false, fActive; + PINTNETSG pSG; + + NGI_GET_M(item, m); + NG_FREE_ITEM(item); + + fActive = ASMAtomicUoReadBool(&pThis->fActive); + if (!fActive) + return ether_output_frame(ifp, m); + + vboxNetFltRetain(pThis, true /* fBusy */); + /* Pass directly to interface if the packet originated from us */ + mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL); + if (mtag != NULL) { + m_tag_unlink(m, mtag); + m_tag_free(mtag); + goto out; + } + + for (m0 = m; m0 != NULL; m0 = m0->m_next) { + if (m0->m_len > 0) + cSegs++; + } + +#ifdef PADD_RUNT_FRAMES_FROM_HOST + if (m_length(m, NULL) < 60) + cSegs++; +#endif + + pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); + vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0); + fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST); + RTMemTmpFree(pSG); + +out: + vboxNetFltRelease(pThis, true /* fBusy */); + if (fDropIt) { + m_freem(m); + return (0); + } + return ether_output_frame(ifp, m); +} + +static int ng_vboxnetflt_shutdown(node_p node) +{ + PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); + bool fActive; + + fActive = ASMAtomicUoReadBool(&pThis->fActive); + if (fActive) + return (EBUSY); + NG_NODE_UNREF(node); + return (0); +} + +static int ng_vboxnetflt_disconnect(hook_p hook) +{ + + return (0); +} + +int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst) +{ + void (*input_f)(struct ifnet *, struct mbuf *); + struct ifnet *ifp; + struct mbuf *m; + struct m_tag *mtag; + bool fActive; + + ifp = (void *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp); + + if (fDst & INTNETTRUNKDIR_WIRE) { + m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); + if (m == NULL) + return VERR_NO_MEMORY; + m = m_pullup(m, ETHER_HDR_LEN); + if (m == NULL) + return VERR_NO_MEMORY; + + m->m_flags |= M_PKTHDR; + ether_output_frame(ifp, m); + } + + if (fDst & INTNETTRUNKDIR_HOST) { + m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); + if (m == NULL) + return VERR_NO_MEMORY; + m = m_pullup(m, ETHER_HDR_LEN); + if (m == NULL) + return VERR_NO_MEMORY; + + mtag = m_tag_alloc(MTAG_VBOX, PACKET_TAG_VBOX, 0, M_NOWAIT); + if (mtag == NULL) { + m_freem(m); + return VERR_NO_MEMORY; + } + + m_tag_init(m); + m_tag_prepend(m, mtag); + m->m_flags |= M_PKTHDR; + m->m_pkthdr.rcvif = ifp; + ifp->if_input(ifp, m); + } + return VINF_SUCCESS; +} + +int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext) +{ + char nam[NG_NODESIZ]; + struct ifnet *ifp; + node_p node; + RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; + + NOREF(pvContext); + ifp = ifunit(pThis->szName); + if (ifp == NULL) + return VERR_INTNET_FLT_IF_NOT_FOUND; + + if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0) + return VERR_INTERNAL_ERROR; + + RTSpinlockAcquire(pThis->hSpinlock, &Tmp); + ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp); + pThis->u.s.node = node; + bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN); + ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false); + RTSpinlockRelease(pThis->hSpinlock, &Tmp); + + NG_NODE_SET_PRIVATE(node, pThis); + snprintf(nam, NG_NODESIZ, "vboxnetflt_%s", pThis->szName); + ng_name_node(node, nam); + + return VINF_SUCCESS; +} + +bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis) +{ + struct ifnet *ifp, *ifp0; + + ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp); + ifp0 = ifunit(pThis->szName); + if (ifp != ifp0) { + ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, true); + ng_rmnode_self(pThis->u.s.node); + pThis->u.s.node = NULL; + } + + if (ifp0 != NULL) + vboxNetFltOsInitInstance(pThis, NULL); + + return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost); +} + +void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) +{ + + if (pThis->u.s.node != NULL) + ng_rmnode_self(pThis->u.s.node); + pThis->u.s.node = NULL; +} + +int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis) +{ + + pThis->u.s.ifp = NULL; + pThis->u.s.flags = 0; + pThis->u.s.node = NULL; + return VINF_SUCCESS; +} + +void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) +{ + struct ifnet *ifp; + struct ifreq ifreq; + int error; + node_p node; + struct ng_mesg *msg; + struct ngm_connect *con; + struct ngm_rmhook *rm; + char path[NG_PATHSIZ]; + + Log(("%s: fActive:%d\n", __func__, fActive)); + + ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp); + node = (node_p)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.node); + + memset(&ifreq, 0, sizeof(struct ifreq)); + if (fActive) { + pThis->u.s.flags = ifp->if_flags; + ifp->if_flags |= (IFF_UP | IFF_PROMISC); + + snprintf(path, sizeof(path), "%s:", ifp->if_xname); + + NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, + sizeof(struct ngm_connect), M_NOWAIT); + if (msg == NULL) + return; + con = (struct ngm_connect *)msg->data; + snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname); + strlcpy(con->ourhook, "lower", NG_HOOKSIZ); + strlcpy(con->peerhook, "input", NG_HOOKSIZ); + NG_SEND_MSG_PATH(error, node, msg, path, 0); + + NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, + sizeof(struct ngm_connect), M_NOWAIT); + if (msg == NULL) + return; + con = (struct ngm_connect *)msg->data; + snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", + ifp->if_xname); + strlcpy(con->ourhook, "upper", sizeof(con->ourhook)); + strlcpy(con->peerhook, "output", sizeof(con->peerhook)); + NG_SEND_MSG_PATH(error, node, msg, path, 0); + } + else { + if (!(pThis->u.s.flags & IFF_PROMISC)) + ifp->if_flags &= ~IFF_PROMISC; + pThis->u.s.flags = 0; + + snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname); + + NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, + sizeof(struct ngm_rmhook), M_NOWAIT); + if (msg == NULL) + return; + rm = (struct ngm_rmhook *)msg->data; + strlcpy(rm->ourhook, "input", NG_HOOKSIZ); + NG_SEND_MSG_PATH(error, node, msg, path, 0); + + NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK, + sizeof(struct ngm_rmhook), M_NOWAIT); + if (msg == NULL) + return; + rm = (struct ngm_rmhook *)msg->data; + strlcpy(rm->ourhook, "output", NG_HOOKSIZ); + NG_SEND_MSG_PATH(error, node, msg, path, 0); + } + ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifreq); +} + +bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis) +{ + + return (pThis->u.s.flags & IFF_PROMISC) ? true : false; +} + +void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac) +{ + + *pMac = pThis->u.s.Mac; +} + +bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac) +{ + return pThis->u.s.Mac.au16[0] == pMac->au16[0] + && pThis->u.s.Mac.au16[1] == pMac->au16[1] + && pThis->u.s.Mac.au16[2] == pMac->au16[2]; +} + +int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis) +{ + + return VINF_SUCCESS; +} + +int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis) +{ + + return VINF_SUCCESS; +} + + Index: src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk =================================================================== --- src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk (revision 22586) +++ src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk (working copy) @@ -298,7 +298,7 @@ endif #ifeq ($(KBUILD_TARGET), win) -else if1of ($(KBUILD_TARGET), linux solaris) ## @todo merge this with the mixed case stuff. +else if1of ($(KBUILD_TARGET), linux solaris freebsd) ## @todo merge this with the mixed case stuff. # # vboxnetflt(.ko/.o/) - The lower case driver. # Note! On Solaris the name has to be <= 8 chars long. @@ -327,6 +327,7 @@ # $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB) vboxnetflt_SOURCES.linux = linux/VBoxNetFlt-linux.c vboxnetflt_SOURCES.solaris = solaris/VBoxNetFlt-solaris.c +vboxnetflt_SOURCES.freebsd = freebsd/VBoxNetFlt-freebsd.c vboxnetflt_SOURCES = VBoxNetFlt.c endif @@ -393,6 +394,14 @@ endif # linux +# Gross hack for FreeBSD 7, should figure this out properly +## @todo Properly generate opt_netgraph.h +ifeq ($(KBUILD_TARGET),freebsd) +vboxnetflt_DEPS.freebsd += $(PATH_OUT)/opt_netgraph.h +$(PATH_OUT)/opt_netgraph.h: + echo > $(PATH_OUT)/opt_netgraph.h +endif # freebsd + include $(KBUILD_PATH)/subfooter.kmk Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h =================================================================== --- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 22586) +++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy) @@ -189,6 +189,22 @@ /** Mutex protection used for loopback. */ RTSEMFASTMUTEX hFastMtx; /** @} */ +# elif defined(RT_OS_FREEBSD) + /** @name Solaris instance data. + * @{ */ + /** Interface handle */ + struct ifnet *ifp; + /** Netgraph node handle */ + node_p node; + /** Input hook */ + hook_p input; + /** Output hook */ + hook_p output; + /** Original interface flags */ + unsigned int flags; + /** The MAC address of the interface. */ + RTMAC Mac; + /** @} */ # elif defined(RT_OS_WINDOWS) /** @name Windows instance data. * @{ */ Index: src/VBox/HostDrivers/Makefile.kmk =================================================================== --- src/VBox/HostDrivers/Makefile.kmk (revision 22586) +++ src/VBox/HostDrivers/Makefile.kmk (working copy) @@ -29,7 +29,7 @@ ifdef VBOX_WITH_USB include $(PATH_SUB_CURRENT)/VBoxUSB/Makefile.kmk endif - if1of ($(KBUILD_TARGET), darwin solaris win linux) + if1of ($(KBUILD_TARGET), darwin solaris win linux freebsd) ifdef VBOX_WITH_NETFLT include $(PATH_SUB_CURRENT)/VBoxNetFlt/Makefile.kmk endif Index: Config.kmk =================================================================== --- Config.kmk (revision 22586) +++ Config.kmk (working copy) @@ -668,7 +668,7 @@ VBOX_WITH_USB= VBOX_WITH_EHCI= VBOX_WITH_VMI= - ifn1of ($(KBUILD_TARGET), darwin linux solaris win) + ifn1of ($(KBUILD_TARGET), darwin linux solaris win freebsd) VBOX_WITH_NETFLT= endif VBOX_WITH_DEBUGGER=