VirtualBox

Changeset 5126 in vbox for trunk/src/VBox/Devices/Network


Ignore:
Timestamp:
Oct 1, 2007 2:52:32 PM (17 years ago)
Author:
vboxsync
Message:

Solaris

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DrvTAP.cpp

    r5013 r5126  
    2222*******************************************************************************/
    2323#define LOG_GROUP LOG_GROUP_DRV_TUN
     24#include <VBox/log.h>
    2425#include <VBox/pdmdrv.h>
    2526
     
    2728#include <iprt/file.h>
    2829#include <iprt/string.h>
     30#include <iprt/path.h>
    2931#ifdef ASYNC_NET
    3032# include <iprt/thread.h>
     
    3638#include <sys/poll.h>
    3739#ifdef RT_OS_SOLARIS
     40# include <sys/stat.h>
     41# include <sys/ethernet.h>
     42# include <sys/sockio.h>
     43# include <netinet/in.h>
     44# include <netinet/in_systm.h>
     45# include <netinet/ip.h>
     46# include <netinet/ip_icmp.h>
     47# include <netinet/udp.h>
     48# include <netinet/tcp.h>
     49# include <net/if.h>
     50# include <stropts.h>
    3851# include <fcntl.h>
     52# include <ctype.h>
     53# include <stdlib.h>
    3954#else
    4055# include <sys/fcntl.h>
     
    7590    /** TAP device file handle. */
    7691    RTFILE                  FileDevice;
     92    /** The configured TAP device name. */
     93    char                   *pszDeviceName;
     94#ifdef RT_OS_SOLARIS
     95    /** The actual TAP device name. */
     96    char                   *pszDeviceNameActual;
     97#endif
     98    /** TAP setup application. */
     99    char                   *pszSetupApplication;
     100    /** TAP terminate application. */
     101    char                   *pszTerminateApplication;
    77102#ifdef ASYNC_NET
    78103    /** The write end of the control pipe. */
     
    119144/** Converts a pointer to TAP::INetworkConnector to a PRDVTAP. */
    120145#define PDMINETWORKCONNECTOR_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConnector)) )
     146
     147
     148/*******************************************************************************
     149*   Internal Functions                                                         *
     150*******************************************************************************/
     151#ifdef RT_OS_SOLARIS
     152static DECLCALLBACK(int) SolarisTAPAttach(PPDMDRVINS pDrvIns);
     153#endif
    121154
    122155
     
    415448
    416449
     450#if defined(RT_OS_SOLARIS)
     451/**
     452 * Calls OS-specific TAP setup application/script.
     453 *
     454 * @returns VBox error code.
     455 * @param   pData           The instance data.
     456 */
     457static int drvTAPSetupApplication(PDRVTAP pData)
     458{
     459    char *pszArgs[3];
     460    pszArgs[0] = pData->pszSetupApplication;
     461    pszArgs[1] = pData->pszDeviceNameActual;
     462    pszArgs[2] = NULL;
     463
     464/** @todo use RTProcCreate */
     465
     466    Log2(("Starting TAP setup application: %s %s\n", pData->pszSetupApplication, pData->pszDeviceNameActual));
     467    pid_t pid = fork();
     468    if (pid < 0)
     469    {
     470        /* Bad. fork() failed! */
     471        LogRel(("TAP#%d: Failed to fork() process for running TAP setup application: %s\n", pDrvIns->iInstance,
     472              pData->pszSetupApplication, strerror(errno)));
     473        return VERR_HOSTIF_INIT_FAILED;
     474    }
     475    if (pid == 0)
     476    {
     477        /* Child process. */
     478        execv(pszArgs[0], pszArgs);
     479        _exit(1);
     480    }
     481
     482    /* Parent process. */
     483    int result;
     484    while (waitpid(pid, &result, 0) < 0)
     485        ;
     486    if (!WIFEXITED(result) || WEXITSTATUS(result) != 0)
     487    {
     488        LogRel(("TAP#%d: Failed to run TAP setup application: %s\n", pDrvIns->iInstance, pData->pszSetupApplication));
     489        return VERR_HOSTIF_INIT_FAILED;
     490    }
     491   
     492    return VINF_SUCCESS;
     493}
     494
     495
     496/**
     497 * Calls OS-specific TAP terminate application/script.
     498 *
     499 * @returns VBox error code.
     500 * @param   pData           The instance data.
     501 */
     502static int drvTAPTerminateApplication(PDRVTAP pData)
     503{
     504    char *pszArgs[3];
     505    pszArgs[0] = pData->pszTerminateApplication;
     506    pszArgs[1] = pData->pszDeviceNameActual;
     507    pszArgs[2] = NULL;
     508
     509/** @todo use RTProcCreate */
     510
     511    Log2(("Starting TAP terminate application: %s %s\n", pData->pszTerminateApplication, pData->pszDeviceNameActual));
     512    pid_t pid = fork();
     513    if (pid < 0)
     514    {
     515        /* Bad. fork() failed! */
     516        LogRel(("TAP#%d: Failed to fork() process for running TAP terminate application: %s\n", pDrvIns->iInstance,
     517              pData->pszTerminateApplication, strerror(errno)));
     518        return VERR_HOSTIF_TERM_FAILED;
     519    }
     520    if (pid == 0)
     521    {
     522        /* Child process. */
     523        execv(pszArgs[0], pszArgs);
     524        _exit(1);
     525    }
     526       
     527    /* Parent process. */
     528    int result;
     529    while (waitpid(pid, &result, 0) < 0)
     530        ;
     531    if (!WIFEXITED(result) || WEXITSTATUS(result) != 0)
     532    {
     533        LogRel(("TAP#%d: Failed to run TAP terminate application: %s\n", pDrvIns->iInstance, pData->pszSetupApplication));
     534        return VERR_HOSTIF_TERM_FAILED;
     535    }
     536   
     537    return VINF_SUCCESS;
     538}
     539
     540#endif /* RT_OS_SOLARIS */
     541
     542
     543#ifdef RT_OS_SOLARIS
     544/** From net/if_tun.h, installed by Universal TUN/TAP driver */
     545# define TUNNEWPPA                   (('T'<<16) | 0x0001)
     546/** Whether to enable ARP for TAP. */
     547# define VBOX_SOLARIS_TAP_ARP        1
     548
     549/**
     550 * Creates/Attaches TAP device to IP.
     551 *
     552 * @returns VBox error code.
     553 * @param   pDrvIns          The driver instance data.
     554 * @param   pszDevName       Pointer to device name.
     555 */
     556static DECLCALLBACK(int) SolarisTAPAttach(PPDMDRVINS pDrvIns)
     557{
     558    PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
     559    LogFlow(("SolarisTapAttach: pData=%p\n", pData));
     560   
     561   
     562    /* Close previously opened file desc., if any. */
     563    static int s_IPFileDes = -1; /** @todo r=bird: what's the point of keeping this open? */
     564    if (s_IPFileDes >= 0)
     565        close(s_IPFileDes);
     566   
     567    s_IPFileDes = open("/dev/udp", O_RDWR, 0);
     568    if (s_IPFileDes < 0)
     569        return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
     570                                   N_("Failed to open /dev/udp. errno=%d"), errno);
     571   
     572    int TapFileDes = open("/dev/tap", O_RDWR, 0);
     573    if (TapFileDes < 0)
     574        return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
     575                                   N_("Failed to open /dev/tap for TAP. errno=%d"), errno);
     576   
     577    /* Use the PPA from the ifname if possible (e.g "tap2", then use 2 as PPA) */
     578    int iPPA = -1;
     579    if (pData->pszDeviceName)
     580    {
     581        size_t cch = strlen(pData->pszDeviceName);
     582        if (cch > 1 && isdigit(pData->pszDeviceName[cch - 1]) != 0)
     583            iPPA = pData->pszDeviceName[cch - 1] - '0';
     584    }
     585   
     586    struct strioctl ioIF;
     587    ioIF.ic_cmd = TUNNEWPPA;
     588    ioIF.ic_len = sizeof(iPPA);
     589    ioIF.ic_dp = (char *)(&iPPA);
     590    ioIF.ic_timout = 0;
     591    iPPA = ioctl(TapFileDes, I_STR, &ioIF);
     592    if (iPPA < 0) /** @todo r=bird: leaving at least one file descriptor open. */
     593        return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
     594                                   N_("Failed to get new interface. errno=%d"), errno);
     595   
     596    int InterfaceFD = open("/dev/tap", O_RDWR, 0);
     597    if (!InterfaceFD)
     598        return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
     599                                   N_("Failed to open interface /dev/tap. errno=%d"), errno);
     600   
     601    if (ioctl(InterfaceFD, I_PUSH, "ip") == -1)
     602    {
     603        close(InterfaceFD);
     604        return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
     605                                   N_("Failed to push IP. errno=%d"), errno);
     606    }
     607   
     608    struct lifreq ifReq;
     609    memset(&ifReq, 0, sizeof(ifReq));
     610    if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
     611        LogRel(("TAP#%d: Failed to get interface flags.\n", pDrvIns->iInstance));
     612
     613    char szTmp[16];
     614    char *pszDevName = pData->pszDeviceName;   
     615    if (!pData->pszDeviceName || !*pData->pszDeviceName)
     616    {
     617        RTStrPrintf(szTmp, sizeof(szTmp), "tap%d", iPPA);
     618        pszDevName = szTmp;
     619    }
     620   
     621    ifReq.lifr_ppa = iPPA;
     622    RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pszDevName);
     623   
     624    if (ioctl(InterfaceFD, SIOCSLIFNAME, &ifReq) == -1)
     625        LogRel(("TAP#%d: Failed to set PPA. errno=%d\n", pDrvIns->iInstance, errno));
     626   
     627    if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
     628        LogRel(("TAP#%d: Failed to get interface flags after setting PPA. errno=%d\n", pDrvIns->iInstance, errno));
     629
     630#ifdef VBOX_SOLARIS_TAP_ARP
     631    /* Interface */
     632    if (ioctl(InterfaceFD, I_PUSH, "arp") == -1)
     633        LogRel(("TAP#%d: Failed to push ARP to Interface FD. errno=%d\n", pDrvIns->iInstance, errno));
     634
     635    /* IP */
     636    if (ioctl(s_IPFileDes, I_POP, NULL) == -1)
     637        LogRel(("TAP#%d: Failed I_POP from IP FD. errno=%d\n", pDrvIns->iInstance, errno));
     638
     639    if (ioctl(s_IPFileDes, I_PUSH, "arp") == -1)
     640        LogRel(("TAP#%d: Failed to push ARP to IP FD. errno=%d\n", pDrvIns->iInstance, errno));
     641   
     642    /* ARP */
     643    int ARPFileDes = open("/dev/tap", O_RDWR, 0);
     644    if (ARPFileDes < 0)
     645        LogRel(("TAP#%d: Failed to open for /dev/tap for ARP. errno=%d", pDrvIns->iInstance, errno));
     646   
     647    if (ioctl(ARPFileDes, I_PUSH, "arp") == -1)
     648        LogRel(("TAP#%d: Failed to push ARP to ARP FD. errno=%d\n", pDrvIns->iInstance, errno));
     649   
     650    ioIF.ic_cmd = SIOCSLIFNAME;
     651    ioIF.ic_timout = 0;
     652    ioIF.ic_len = sizeof(ifReq);
     653    ioIF.ic_dp = (char *)&ifReq;
     654    if (ioctl(ARPFileDes, I_STR, &ioIF) == -1)
     655        LogRel(("TAP#%d: Failed to set interface name to ARP.\n", pDrvIns->iInstance));
     656#endif
     657
     658    /* We must use I_LINK and not I_PLINK as I_PLINK makes the link persistent.
     659     * Then we would not be able unlink the interface if we reuse it.
     660     * Even 'unplumb' won't work after that.
     661     */
     662    int IPMuxID = ioctl(s_IPFileDes, I_LINK, InterfaceFD);
     663    if (IPMuxID == -1)
     664    {
     665        close(InterfaceFD);
     666#ifdef VBOX_SOLARIS_TAP_ARP
     667        close(ARPFileDes);
     668#endif
     669        LogRel(("TAP#%d: Cannot link TAP device to IP.\n", pDrvIns->iInstance));
     670        return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
     671                    N_("Failed to link TAP device to IP. Check TAP interface name. errno=%d"), errno);
     672    }
     673   
     674#ifdef VBOX_SOLARIS_TAP_ARP
     675    int ARPMuxID = ioctl(s_IPFileDes, I_LINK, ARPFileDes);
     676    if (ARPMuxID == -1)
     677        LogRel(("TAP#%d: Failed to link TAP device to ARP\n", pDrvIns->iInstance));
     678   
     679    close(ARPFileDes);
     680#endif
     681    close(InterfaceFD);
     682
     683    /* Reuse ifReq */
     684    memset(&ifReq, 0, sizeof(ifReq));
     685    RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pszDevName);
     686    ifReq.lifr_ip_muxid  = IPMuxID;
     687#ifdef VBOX_SOLARIS_TAP_ARP
     688    ifReq.lifr_arp_muxid = ARPMuxID;
     689#endif
     690
     691    if (ioctl(s_IPFileDes, SIOCSLIFMUXID, &ifReq) == -1)
     692    {
     693#ifdef VBOX_SOLARIS_TAP_ARP
     694        ioctl(IPFileDes, I_PUNLINK, ARPMuxID);
     695#endif
     696        ioctl(IPFileDes, I_PUNLINK, IPMuxID);
     697        close(s_IPFileDes);
     698        s_IPFileDes = -1;
     699        LogRel(("TAP#%d: Failed to set Mux ID.\n", pDrvIns->iInstance));
     700        return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
     701                                   N_("Failed to set Mux ID. Check TAP interface name. errno=%d"), errno);
     702    }
     703
     704    /* what's the point? */
     705    pData->FileDevice = (RTFILE)TapFileDes;
     706    pData->pszDeviceNameActual = RTStrDup(pszDevName);
     707   
     708    return VINF_SUCCESS;
     709}
     710
     711#endif  /* RT_OS_SOLARIS */
     712
     713
    417714/**
    418715 * Queries an interface to the driver.
     
    451748{
    452749    LogFlow(("drvTAPDestruct\n"));
     750    PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
     751
    453752#ifdef ASYNC_NET
    454     PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
    455 
    456753    /*
    457754     * Terminate the Async I/O Thread.
     
    487784    }
    488785#endif
     786
     787#ifdef RT_OS_SOLARIS
     788    if (pData->pszTerminateApplication)
     789        drvTAPTerminateApplication(pData);
     790
     791    RTStrFree(pData->pszDeviceNameActual);
     792#endif
     793    MMR3HeapFree(pData->pszDeviceName);
     794    MMR3HeapFree(pData->pszSetupApplication);
     795    MMR3HeapFree(pData->pszTerminateApplication);
    489796}
    490797
     
    509816    pData->pDrvIns                      = pDrvIns;
    510817    pData->FileDevice                   = NIL_RTFILE;
     818    pData->pszDeviceName                = NULL;
     819#ifdef RT_OS_SOLARIS
     820    pData->pszDeviceNameActual          = NULL;
     821#endif
     822    pData->pszSetupApplication          = NULL;
     823    pData->pszTerminateApplication      = NULL;
    511824#ifdef ASYNC_NET
    512825    pData->Thread                       = NIL_RTTHREAD;
     
    524837     * Validate the config.
    525838     */
    526     if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0InitProg\0TermProg\0FileHandle\0"))
     839    if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0InitProg\0TermProg\0FileHandle\0TAPSetupApplication\0TAPTerminateApplication"))
    527840        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
    528841
     
    546859     * Read the configuration.
    547860     */
     861#if defined(RT_OS_SOLARIS)   /** @todo Other platforms' TAP code should be moved here from ConsoleImpl & VBoxBFE. */
     862    rc = CFGMR3QueryStringAlloc(pCfgHandle, "TAPSetupApplication", &pData->pszSetupApplication);
     863    if (VBOX_SUCCESS(rc))
     864    {
     865        if (!RTPathExists(pData->pszSetupApplication))
     866            return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
     867                                       N_("Invalid TAP setup program path: %s"), pData->pszSetupApplication);
     868    }
     869    else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
     870        return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
     871
     872    rc = CFGMR3QueryStringAlloc(pCfgHandle, "TAPTerminateApplication", &pData->pszTerminateApplication);
     873    if (VBOX_SUCCESS(rc))
     874    {
     875        if (!RTPathExists(pData->pszTerminateApplication))
     876            return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
     877                                       N_("Invalid TAP terminate program path: %s"), pData->pszTerminateApplication);
     878    }
     879    else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
     880        return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
     881
     882   
     883    rc = CFGMR3QueryStringAlloc(pCfgHandle, "Device", &pData->pszDeviceName);
     884    if (VBOX_FAILURE(rc))
     885        return PDMDRV_SET_ERROR(pDrvIns, rc,
     886                                N_("Configuration error: Query for \"Device\" string failed!"));
     887
     888    /*
     889     * Do the setup.
     890     */
     891    rc = SolarisTAPAttach(pDrvIns);
     892    if (VBOX_FAILURE(rc))
     893        return rc;
     894
     895    if (pData->pszSetupApplication)
     896    {
     897        rc = drvTAPSetupApplication(pData);
     898        if (RT_SUCCESS(rc))
     899            return rc;
     900    }
     901
     902#else /* !SOLARIS */
     903
    548904    int32_t iFile;
    549905    rc = CFGMR3QueryS32(pCfgHandle, "FileHandle", &iFile);
     
    555911        return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_HANDLE, RT_SRC_POS,
    556912                                   N_("The TAP file handle %RTfile is not valid!"), pData->FileDevice);
     913#endif /* !SOLARIS */
    557914
    558915    /*
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette