Index: Config.kmk =================================================================== --- Config.kmk (revision 22358) +++ 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= Index: src/VBox/Main/generic/NetIf-generic.cpp =================================================================== --- src/VBox/Main/generic/NetIf-generic.cpp (revision 22358) +++ src/VBox/Main/generic/NetIf-generic.cpp (working copy) @@ -132,7 +132,7 @@ int NetIfCreateHostOnlyNetworkInterface (VirtualBox *pVBox, IHostNetworkInterface **aHostNetworkInterface, IProgress **aProgress) { -#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) +#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) /* create a progress object */ ComObjPtr progress; progress.createObject(); @@ -217,7 +217,7 @@ int NetIfRemoveHostOnlyNetworkInterface (VirtualBox *pVBox, IN_GUID aId, IProgress **aProgress) { -#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) +#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) /* create a progress object */ ComObjPtr progress; progress.createObject(); Index: src/VBox/Main/ConsoleImpl2.cpp =================================================================== --- src/VBox/Main/ConsoleImpl2.cpp (revision 22358) +++ src/VBox/Main/ConsoleImpl2.cpp (working copy) @@ -79,6 +79,14 @@ # include #endif +#if defined(RT_OS_FREEBSD) && defined(VBOX_WITH_NETFLT) +# include +# include +# include +# include +# include +#endif + #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) # include # include @@ -2195,7 +2203,7 @@ case NetworkAttachmentType_Bridged: { -#if !defined(VBOX_WITH_NETFLT) && defined(RT_OS_LINUX) +#if !defined(VBOX_WITH_NETFLT) && (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) Assert ((int)pThis->maTapFD[uInstance] >= 0); if ((int)pThis->maTapFD[uInstance] >= 0) { @@ -2376,7 +2384,7 @@ const char *pszTrunk = szTrunkName; /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */ -# elif defined(RT_OS_LINUX) +# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) /** @todo Check for malformed names. */ const char *pszTrunk = pszHifName; Index: src/VBox/Main/freebsd/NetIf-freebsd.cpp =================================================================== --- src/VBox/Main/freebsd/NetIf-freebsd.cpp (revision 22358) +++ src/VBox/Main/freebsd/NetIf-freebsd.cpp (working copy) @@ -24,14 +24,380 @@ /******************************************************************************* * Header Files * *******************************************************************************/ -#define LOG_GROUP LOG_GROUP_MAIN +#include +#include +#include +#include +#include +#include + +#include +/* + * route.h includes net/radix.h which for some reason defines Free as a wrapper + * around free. This collides with Free defined in xpcom/include/nsIMemory.h + * Undefine it and hope for the best + */ +#undef Free + +#include +#include + +#include +#include +#include + +#include + #include "HostNetworkInterfaceImpl.h" #include "netif.h" #include "Logging.h" +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + +void extractAddresses(int iAddrMask, caddr_t cp, caddr_t cplim, struct sockaddr **pAddresses) +{ + struct sockaddr *sa; + + for (int i = 0; i < RTAX_MAX && cp < cplim; i++) { + if (!(iAddrMask & (1 << i))) + continue; + + sa = (struct sockaddr *)cp; + + pAddresses[i] = sa; + + ADVANCE(cp, sa); + } +} + +static int getDefaultIfaceIndex(unsigned short *pu16Index, int family) +{ + size_t cbNeeded; + char *pBuf, *pNext; + int aiMib[6]; + struct sockaddr *addresses[RTAX_MAX]; + aiMib[0] = CTL_NET; + aiMib[1] = PF_ROUTE; + aiMib[2] = 0; + aiMib[3] = family; /* address family */ + aiMib[4] = NET_RT_DUMP; + aiMib[5] = 0; + + if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0) + { + Log(("getDefaultIfaceIndex: Failed to get estimate for list size (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + if ((pBuf = (char*)malloc(cbNeeded)) == NULL) + return VERR_NO_MEMORY; + if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0) + { + free(pBuf); + Log(("getDefaultIfaceIndex: Failed to retrieve interface table (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + + char *pEnd = pBuf + cbNeeded; + struct rt_msghdr *pRtMsg; + for (pNext = pBuf; pNext < pEnd; pNext += pRtMsg->rtm_msglen) + { + pRtMsg = (struct rt_msghdr *)pNext; + + if (pRtMsg->rtm_type != RTM_GET) + { + Log(("getDefaultIfaceIndex: Got message %u while expecting %u.\n", + pRtMsg->rtm_type, RTM_GET)); + //rc = VERR_INTERNAL_ERROR; + continue; + } + if ((char*)(pRtMsg + 1) < pEnd) + { + /* Extract addresses from the message. */ + extractAddresses(pRtMsg->rtm_addrs, (char *)(pRtMsg + 1), + pRtMsg->rtm_msglen + (char *)pRtMsg, addresses); + if ((pRtMsg->rtm_addrs & RTA_DST)) + { + if (addresses[RTAX_DST]->sa_family != AF_INET) + continue; + struct sockaddr_in *addr = (struct sockaddr_in *)addresses[RTAX_DST]; + struct sockaddr_in *mask = (struct sockaddr_in *)addresses[RTAX_NETMASK]; + if ((addr->sin_addr.s_addr == INADDR_ANY) && + mask && + (ntohl(mask->sin_addr.s_addr) == 0L || + mask->sin_len == 0)) + { + *pu16Index = pRtMsg->rtm_index; + free(pBuf); + return VINF_SUCCESS; + } + } + } + } + free(pBuf); + return VERR_INTERNAL_ERROR; + +} + +void extractAddressesToNetInfo(int iAddrMask, caddr_t cp, caddr_t cplim, PNETIFINFO pInfo) +{ + struct sockaddr *addresses[RTAX_MAX]; + + extractAddresses(iAddrMask, cp, cplim, addresses); + switch (addresses[RTAX_IFA]->sa_family) + { + case AF_INET: + if (!pInfo->IPAddress.u) + { + pInfo->IPAddress.u = ((struct sockaddr_in *)addresses[RTAX_IFA])->sin_addr.s_addr; + pInfo->IPNetMask.u = ((struct sockaddr_in *)addresses[RTAX_NETMASK])->sin_addr.s_addr; + } + break; + case AF_INET6: + if (!pInfo->IPv6Address.s.Lo && !pInfo->IPv6Address.s.Hi) + { + memcpy(pInfo->IPv6Address.au8, + ((struct sockaddr_in6 *)addresses[RTAX_IFA])->sin6_addr.__u6_addr.__u6_addr8, + sizeof(pInfo->IPv6Address)); + memcpy(pInfo->IPv6NetMask.au8, + ((struct sockaddr_in6 *)addresses[RTAX_NETMASK])->sin6_addr.__u6_addr.__u6_addr8, + sizeof(pInfo->IPv6NetMask)); + } + break; + default: + Log(("NetIfList: Unsupported address family: %u\n", addresses[RTAX_IFA]->sa_family)); + break; + } +} + + int NetIfList(std::list > &list) { - /** @todo implement */ - return VERR_NOT_IMPLEMENTED; + int rc = VINF_SUCCESS; + size_t cbNeeded; + char *pBuf, *pNext; + int aiMib[6]; + unsigned short u16DefaultIface; + + /* Get the index of the interface associated with default route. */ + rc = getDefaultIfaceIndex(&u16DefaultIface, PF_INET); + if (RT_FAILURE(rc)) + return rc; + + aiMib[0] = CTL_NET; + aiMib[1] = PF_ROUTE; + aiMib[2] = 0; + aiMib[3] = 0; /* address family */ + aiMib[4] = NET_RT_IFLIST; + aiMib[5] = 0; + + if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0) + { + Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + if ((pBuf = (char*)malloc(cbNeeded)) == NULL) + return VERR_NO_MEMORY; + if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0) + { + free(pBuf); + Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + + int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) + { + free(pBuf); + Log(("NetIfList: socket() -> %d\n", errno)); + return RTErrConvertFromErrno(errno); + } + + char *pEnd = pBuf + cbNeeded; + for (pNext = pBuf; pNext < pEnd;) + { + struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext; + + if (pIfMsg->ifm_type != RTM_IFINFO) + { + Log(("NetIfList: Got message %u while expecting %u.\n", + pIfMsg->ifm_type, RTM_IFINFO)); + rc = VERR_INTERNAL_ERROR; + break; + } + struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1); + + size_t cbNameLen = pSdl->sdl_nlen + 1; + PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen])); + if (!pNew) + { + rc = VERR_NO_MEMORY; + break; + } + memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8)); + pNew->enmMediumType = NETIF_T_ETHERNET; + Assert(sizeof(pNew->szShortName) >= cbNameLen); + memcpy(pNew->szShortName, pSdl->sdl_data, cbNameLen); + + memcpy(pNew->szName, pSdl->sdl_data, cbNameLen); + /* Generate UUID from name and MAC address. */ + RTUUID uuid; + RTUuidClear(&uuid); + memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid))); + uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80; + uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000; + memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node)); + pNew->Uuid = uuid; + + pNext += pIfMsg->ifm_msglen; + while (pNext < pEnd) + { + struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext; + + if (pIfAddrMsg->ifam_type != RTM_NEWADDR) + break; + extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs, + (char *)(pIfAddrMsg + 1), + pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg, + pNew); + pNext += pIfAddrMsg->ifam_msglen; + } + + if (pSdl->sdl_type == IFT_ETHER) + { + struct ifreq IfReq; + strcpy(IfReq.ifr_name, pNew->szShortName); + if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) + { + Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); + pNew->enmStatus = NETIF_S_UNKNOWN; + } + else + pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN; + + HostNetworkInterfaceType_T enmType; + if (strncmp("vboxnet", pNew->szName, 7)) + enmType = HostNetworkInterfaceType_Bridged; + else + enmType = HostNetworkInterfaceType_HostOnly; + + ComObjPtr IfObj; + IfObj.createObject(); + if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew))) + /* Make sure the default interface gets to the beginning. */ + if (pIfMsg->ifm_index == u16DefaultIface) + list.push_front(IfObj); + else + list.push_back(IfObj); + } + RTMemFree(pNew); + } + + close(sock); + free(pBuf); + return rc; + + } + +int NetIfGetConfigByName(PNETIFINFO pInfo) +{ + int rc = VINF_SUCCESS; + size_t cbNeeded; + char *pBuf, *pNext; + int aiMib[6]; + + aiMib[0] = CTL_NET; + aiMib[1] = PF_ROUTE; + aiMib[2] = 0; + aiMib[3] = 0; /* address family */ + aiMib[4] = NET_RT_IFLIST; + aiMib[5] = 0; + + if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0) + { + Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + if ((pBuf = (char*)malloc(cbNeeded)) == NULL) + return VERR_NO_MEMORY; + if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0) + { + free(pBuf); + Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno)); + return RTErrConvertFromErrno(errno); + } + + int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) + { + free(pBuf); + Log(("NetIfList: socket() -> %d\n", errno)); + return RTErrConvertFromErrno(errno); + } + + char *pEnd = pBuf + cbNeeded; + for (pNext = pBuf; pNext < pEnd;) + { + struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext; + + if (pIfMsg->ifm_type != RTM_IFINFO) + { + Log(("NetIfList: Got message %u while expecting %u.\n", + pIfMsg->ifm_type, RTM_IFINFO)); + rc = VERR_INTERNAL_ERROR; + break; + } + struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1); + + bool fSkip = !!strcmp(pInfo->szShortName, pSdl->sdl_data); + + pNext += pIfMsg->ifm_msglen; + while (pNext < pEnd) + { + struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext; + + if (pIfAddrMsg->ifam_type != RTM_NEWADDR) + break; + if (!fSkip) + extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs, + (char *)(pIfAddrMsg + 1), + pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg, + pInfo); + pNext += pIfAddrMsg->ifam_msglen; + } + + if (!fSkip && pSdl->sdl_type == IFT_ETHER) + { + size_t cbNameLen = pSdl->sdl_nlen + 1; + memcpy(pInfo->MACAddress.au8, LLADDR(pSdl), sizeof(pInfo->MACAddress.au8)); + pInfo->enmMediumType = NETIF_T_ETHERNET; + /* Generate UUID from name and MAC address. */ + RTUUID uuid; + RTUuidClear(&uuid); + memcpy(&uuid, pInfo->szShortName, RT_MIN(cbNameLen, sizeof(uuid))); + uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80; + uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000; + memcpy(uuid.Gen.au8Node, pInfo->MACAddress.au8, sizeof(uuid.Gen.au8Node)); + pInfo->Uuid = uuid; + + struct ifreq IfReq; + strcpy(IfReq.ifr_name, pInfo->szShortName); + if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0) + { + Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno)); + pInfo->enmStatus = NETIF_S_UNKNOWN; + } + else + pInfo->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN; + + return VINF_SUCCESS; + } + } + close(sock); + free(pBuf); + return rc; +} + 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,446 @@ +/*- + * 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 + +#define VBOXNETFLT_OS_SPECFIC 1 +#include "../VBoxNetFltInternal.h" + +static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals; + +static int VBoxNetFltFreeBSDModuleEvent(struct module *, int, void *); +static moduledata_t g_VBoxNetFltFreeBSDModule = { + "vboxnetflt", + VBoxNetFltFreeBSDModuleEvent, + NULL +}; + +/** Declare the module as a pseudo device. */ +DECLARE_MODULE(vboxnetflt, g_VBoxNetFltFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(vboxnetflt, 1); +MODULE_DEPEND(vboxdrv, vboxdrv, 1, 1, 1); + +#define MTAG_VBOX 0x56424f58 +#define PACKET_TAG_VBOX 128 + +static int +VBoxNetFltFreeBSDModuleEvent(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(); + 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 void +vboxNetFltFreeBSDinput(struct ifnet *ifp, struct mbuf *m) +{ + PVBOXNETFLTINS pThis; + void (*input_f)(struct ifnet *, struct mbuf *); + unsigned int cSegs = 0; + struct mbuf *m0; + bool fDropIt; + PINTNETSG pSG; + + pThis = ifp->if_pspare[0]; + if (pThis == NULL) { + m_freem(m); + return; + } + + input_f = (void *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_input); + + 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); + + if (fDropIt) { + m_freem(m); + return; + } + input_f(ifp, m); +} + +static int +vboxNetFltFreeBSDtransmit(struct ifnet *ifp, struct mbuf *m) +{ + int (*transmit_f)(struct ifnet *, struct mbuf *); + PVBOXNETFLTINS pThis; + unsigned int cSegs = 0; + struct mbuf *m0; + bool fDropIt; + PINTNETSG pSG; + int error = 0; + struct m_tag *mtag; + + pThis = ifp->if_pspare[0]; + if (pThis == NULL) { + m_freem(m); + return ENXIO; + } + + transmit_f = (void *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_transmit); + /* 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); + + if (fDropIt) { + m_freem(m); + return (0); + } +out: + return transmit_f(ifp, m); +} + +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; + + input_f = (void *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_input); + 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; + + /* + * We send the packet with ether_output_frame to respect L2 firewalling, + * this results in the packet beeing captured by our filtering routine. + * Tag the mbuf to instruct the filter to pass the frame directly + * to the interface. + */ + 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); + ether_output_frame(ifp, m); + } + + if (fDst & INTNETTRUNKDIR_HOST) { + m = vboxNetFltFreeBSDSGMBufFromSG(pThis, pSG); + if (m == NULL) + return VERR_NO_MEMORY; + m->m_flags |= M_PKTHDR; + m->m_pkthdr.rcvif = ifp; + input_f(ifp, m); + } + return VINF_SUCCESS; +} + +int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext) +{ + struct ifnet *ifp; + RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; + + NOREF(pvContext); + + ifp = ifunit_ref(pThis->szName); + if (ifp == NULL) + return VERR_INTNET_FLT_IF_NOT_FOUND; + + RTSpinlockAcquire(pThis->hSpinlock, &Tmp); + ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp); + ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp_input, ifp->if_input); + ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp_transmit, ifp->if_transmit); + ifp->if_pspare[0] = pThis; + bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN); + ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false); + RTSpinlockRelease(pThis->hSpinlock, &Tmp); + + 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); + } + + ifp->if_input = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_input); + ifp->if_transmit = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_transmit); + + if_rele(ifp); + + if (ifp0 != NULL) { + vboxNetFltOsInitInstance(pThis, NULL); + } + + return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost); +} + +void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis) +{ + struct ifnet *ifp; + + ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp); + ifp->if_input = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_input); + ifp->if_transmit = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp_transmit); + ifp->if_pspare[0] = NULL; + if_rele(pThis->u.s.ifp); +} + +int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis) +{ + + pThis->u.s.ifp = NULL; + pThis->u.s.ifp_input = NULL; + pThis->u.s.ifp_transmit = NULL; + pThis->u.s.flags = 0; + return VINF_SUCCESS; +} + +void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) +{ + struct ifnet *ifp; + struct ifreq ifreq; + + Log(("%s: fActive:%d\n", __func__, fActive)); + + ifp = (struct ifnet *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.ifp); + + memset(&ifreq, 0, sizeof(struct ifreq)); + if (fActive) { + pThis->u.s.flags = ifp->if_flags; + ifp->if_input = vboxNetFltFreeBSDinput; + ifp->if_transmit = vboxNetFltFreeBSDtransmit; + ifp->if_flags |= (IFF_UP | IFF_PROMISC); + } + else { + if (!(pThis->u.s.flags & IFF_PROMISC)) + ifp->if_flags &= ~IFF_PROMISC; + pThis->u.s.flags = 0; + ifp->if_input = pThis->u.s.ifp_input; + ifp->if_transmit = pThis->u.s.ifp_transmit; + } + 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 22358) +++ 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 Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h =================================================================== --- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (revision 22358) +++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h (working copy) @@ -189,6 +189,20 @@ /** Mutex protection used for loopback. */ RTSEMFASTMUTEX hFastMtx; /** @} */ +# elif defined(RT_OS_FREEBSD) + /** @name Solaris instance data. + * @{ */ + /** Interface handle */ + struct ifnet *ifp; + /** Original interface input routine */ + void *ifp_input; + /** Original interface transmit routine */ + void *ifp_transmit; + /** 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 22358) +++ 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