Пример #1
0
int           TUNTAP_SetNetMask( char*  pszNetDevName,
                                 char*  pszNetMask )
{
    struct hifr         hifr;
    struct sockaddr_in* sin;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));
    sin = (struct sockaddr_in*)&hifr.hifr_netmask;
    sin->sin_family = AF_INET;
    set_sockaddr_in_sin_len( sin );

    if( !pszNetMask  ||
        !inet_aton( pszNetMask, &sin->sin_addr ) )
    {
        WRMSG( HHC00143, "E", pszNetDevName, !pszNetMask ? "NULL" : pszNetMask );
            return -1;
    }

    return TUNTAP_IOCtl( 0, SIOCSIFNETMASK, (char*)&hifr );
}   // End of function  TUNTAP_SetNetMask()
Пример #2
0
int           TUNTAP_SetMACAddr( char*  pszNetDevName,
                                 char*  pszMACAddr )
{
    struct hifr         hifr;
    struct sockaddr*    addr;
    MAC                 mac;

    if( !pszNetDevName || !*pszNetDevName )
    {
        // "Invalid net device name %s"
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    if( !pszMACAddr || ParseMAC( pszMACAddr, mac ) != 0 )
    {
        // "Net device %s: Invalid MAC address %s"
        WRMSG( HHC00145, "E", pszNetDevName, pszMACAddr ? pszMACAddr : "NULL" );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));
    addr = (struct sockaddr*)&hifr.hifr_hwaddr;
    memcpy( addr->sa_data, mac, IFHWADDRLEN );
    addr->sa_family = 1;    // ARPHRD_ETHER

    return TUNTAP_IOCtl( 0, SIOCSIFHWADDR, (char*)&hifr );

}   // End of function  TUNTAP_SetMACAddr()
Пример #3
0
//
// TUNTAP_SetMTU
//
int             TUNTAP_SetMTU( char*  pszNetDevName,
                               char*  pszMTU )
{
    struct hifr         hifr;
    int                 iMTU;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    if( !pszMTU  || !*pszMTU )
    {
        WRMSG( HHC00144, "E", pszNetDevName, pszMTU ? pszMTU : "NULL" );
        return -1;
    }

    iMTU = atoi( pszMTU );
    if( iMTU < 46 || iMTU > 65536 )
    {
        WRMSG( HHC00144, "E", pszNetDevName, pszMTU );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));
    hifr.hifr_mtu = iMTU;

    return TUNTAP_IOCtl( 0, SIOCSIFMTU, (char*)&hifr );
}   // End of function  TUNTAP_SetMTU()
Пример #4
0
int           TUNTAP_SetBCastAddr( char*  pszNetDevName,
                                   char*  pszBCastAddr )
{
    struct hifr         hifr;
    struct sockaddr_in* sin;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));
    sin = (struct sockaddr_in*)&hifr.hifr_broadaddr;
    sin->sin_family = AF_INET;
    set_sockaddr_in_sin_len( sin );

    if( !pszBCastAddr  ||
        !inet_aton( pszBCastAddr, &sin->sin_addr ) )
    {
        WRMSG( HHC00155, "E", pszNetDevName, !pszBCastAddr ? "NULL" : pszBCastAddr );
            return -1;
    }

    return TUNTAP_IOCtl( 0, SIOCSIFBRDADDR, (char*)&hifr );
}   // End of function  TUNTAP_SetBCastAddr()
Пример #5
0
int           TUNTAP_SetMACAddr( char*   pszNetDevName,
                                 char*   pszMACAddr )
{
    struct hifr         hifr;
    struct sockaddr*    addr;
    MAC                 mac;

    memset( &hifr, 0, sizeof( struct hifr ) );

    addr = (struct sockaddr*)&hifr.hifr_hwaddr;

    addr->sa_family = AF_UNIX;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    strcpy( hifr.hifr_name, pszNetDevName );

    if( !pszMACAddr || ParseMAC( pszMACAddr, mac ) != 0 )
    {
        WRMSG( HHC00145, "E", pszNetDevName, pszMACAddr ? pszMACAddr : "NULL" );
            return -1;
    }

    memcpy( addr->sa_data, mac, IFHWADDRLEN );

    return TUNTAP_IOCtl( 0, SIOCSIFHWADDR, (char*)&hifr );
}   // End of function  TUNTAP_SetMACAddr()
Пример #6
0
int           TUNTAP_DelRoute( char*  pszNetDevName,
                               char*  pszDestAddr,
                               char*  pszNetMask,
                               char*  pszGWAddr,
                               int    iFlags )
{
    struct rtentry      rtentry;
    struct sockaddr_in* sin;

    memset( &rtentry, 0, sizeof( struct rtentry ) );

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    rtentry.rt_dev = pszNetDevName;

    sin = (struct sockaddr_in*)&rtentry.rt_dst;
    sin->sin_family = AF_INET;
    set_sockaddr_in_sin_len( sin );

    if( !pszDestAddr  ||
        !inet_aton( pszDestAddr, &sin->sin_addr ) )
    {
        WRMSG(HHC00142, "E", pszNetDevName, pszDestAddr ? pszDestAddr : "NULL" );
        return -1;
    }

    sin = (struct sockaddr_in*)&rtentry.rt_genmask;
    sin->sin_family = AF_INET;
    set_sockaddr_in_sin_len( sin );

    if( !pszNetMask  ||
        !inet_aton( pszNetMask, &sin->sin_addr ) )
    {
        WRMSG( HHC00143, "E", pszNetDevName, pszNetMask ? pszNetMask : "NULL" );
        return -1;
    }

    sin = (struct sockaddr_in*)&rtentry.rt_gateway;
    sin->sin_family = AF_INET;
    set_sockaddr_in_sin_len( sin );

    if( pszGWAddr )
    {
        if( !inet_aton( pszGWAddr, &sin->sin_addr ) )
        {
            WRMSG( HHC00146, "E", pszNetDevName, pszGWAddr );
            return -1;
        }
    }

    rtentry.rt_flags = iFlags;

    return TUNTAP_IOCtl( 0, SIOCDELRT, (char*)&rtentry );
}   // End of function  TUNTAP_DelRoute()
Пример #7
0
//
// TUNTAP_GetMACAddr
//
int           TUNTAP_GetMACAddr( char*   pszNetDevName,
                                 char**  ppszMACAddr )
{
#if defined(OPTION_TUNTAP_GETMACADDR)
    struct hifr         hifr;
    struct sockaddr*    addr;
    int                 rc;

    if( !pszNetDevName || !*pszNetDevName )
    {
        // "Invalid net device name %s"
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    if( !ppszMACAddr )
    {
        // HHC00136 "Error in function %s: %s"
        WRMSG(HHC00136, "E", "TUNTAP_GetMACAddr", "Invalid parameters" );
        return -1;
    }

    *ppszMACAddr = NULL;

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));
    addr = (struct sockaddr*)&hifr.hifr_hwaddr;
    addr->sa_family = 1;    // ARPHRD_ETHER

#if defined( OPTION_W32_CTCI )
    rc = TUNTAP_IOCtl( 0, SIOCGIFHWADDR, (char*)&hifr );
#else // (non-Win32 platforms)
    {
        int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
        rc = ioctl( sockfd, SIOCGIFHWADDR, &hifr );
        close( sockfd );
    }
#endif
    if( rc < 0 )
    {
        // HHC00136 "Error in function %s: %s"
        WRMSG( HHC00136, "E", "TUNTAP_GetMACAddr", strerror( errno ));
        return -1;
    }

    return FormatMAC( ppszMACAddr, (BYTE*) addr->sa_data );
#else // defined(OPTION_TUNTAP_GETMACADDR)
    UNREFERENCED(pszNetDevName);
    UNREFERENCED(ppszMACAddr);
    WRMSG(HHC00136, "E", "TUNTAP_GetMACAddr", "Unsupported" );
    return -1; // (unsupported)
#endif // defined(OPTION_TUNTAP_GETMACADDR)
}   // End of function  TUNTAP_GetMACAddr()
Пример #8
0
//
// TUNTAP_GetMTU
//
int             TUNTAP_GetMTU( char*   pszNetDevName,
                               char**  ppszMTU )
{
    struct hifr         hifr;
    int                 rc;
    char                szMTU[8] = {0};

    if( !pszNetDevName || !*pszNetDevName )
    {
        // "Invalid net device name %s"
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    if( !ppszMTU )
    {
        // HHC00136 "Error in function %s: %s"
        WRMSG(HHC00136, "E", "TUNTAP_GetMTU", "Invalid parameters" );
        return -1;
    }

    *ppszMTU = NULL;

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));

#if defined( OPTION_W32_CTCI )
    rc = TUNTAP_IOCtl( 0, SIOCGIFMTU, (char*)&hifr );
#else // (non-Win32 platforms)
    {
        int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
        rc = ioctl( sockfd, SIOCGIFMTU, &hifr );
        close( sockfd );
    }
#endif
    if( rc < 0 )
    {
        // HHC00136 "Error in function %s: %s"
        WRMSG( HHC00136, "E", "TUNTAP_GetMTU", strerror( errno ));
        return -1;
    }

    MSGBUF( szMTU, "%u", hifr.hifr_mtu );
    if (!(*ppszMTU = strdup( szMTU )))
    {
        errno = ENOMEM;
        return -1;
    }

    return 0;
}   // End of function  TUNTAP_GetMTU()
Пример #9
0
int             TUNTAP_SetIPAddr6( char*   pszNetDevName,
                                   char*   pszIPAddr6,
                                   char*   pszPrefixSize6 )
{
    struct hifr         hifr;
    int                 iPfxSiz;

    memset( &hifr, 0, sizeof( struct hifr ) );

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    strcpy( hifr.hifr_name, pszNetDevName );

    if( !pszIPAddr6 )
    {
        WRMSG( HHC00141, "E", pszNetDevName, "NULL" );
        return -1;
    }

    if( hinet_pton( AF_INET6, pszIPAddr6, &hifr.hifr6_addr ) != 1 )
    {
        WRMSG( HHC00141, "E", pszNetDevName, pszIPAddr6 );
        return -1;
    }

    if( !pszPrefixSize6 )
    {
        WRMSG(HHC00153, "E", pszNetDevName, "NULL" );
        return -1;
    }

    iPfxSiz = atoi( pszPrefixSize6 );

    if( iPfxSiz < 0 || iPfxSiz > 128 )
    {
        WRMSG(HHC00153, "E", pszNetDevName, pszPrefixSize6 );
        return -1;
    }

    hifr.hifr6_prefixlen = iPfxSiz;

    hifr.hifr6_ifindex = hif_nametoindex( pszNetDevName );

    hifr.hifr_afamily = AF_INET6;

    return TUNTAP_IOCtl( 0, SIOCSIFADDR, (char*)&hifr );
}   // End of function  TUNTAP_SetIPAddr6()
Пример #10
0
int             TUNTAP_ClrIPAddr( char* pszNetDevName )
{
    struct hifr hifr;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name));

    return TUNTAP_IOCtl( 0, SIOCDIFADDR, (char*)&hifr );
}   // End of function  TUNTAP_ClrIPAddr()
Пример #11
0
int             TUNTAP_SetFlags ( char*  pszNetDevName,
                                  int    iFlags )
{
    struct hifr         hifr;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    memset( &hifr, 0, sizeof( struct hifr ) );
    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name) );
    hifr.hifr_flags = iFlags;

    return TUNTAP_IOCtl( 0, SIOCSIFFLAGS, (char*)&hifr );
}   // End of function  TUNTAP_SetFlags()
Пример #12
0
int      TUNTAP_GetFlags ( char*   pszNetDevName,
                           int*    piFlags )
{
    struct hifr         hifr;
    struct sockaddr_in* sin;
    int                 rc;

    memset( &hifr, 0, sizeof( struct hifr ) );

    sin = (struct sockaddr_in*)&hifr.hifr_addr;

    sin->sin_family = AF_INET;

    if( !pszNetDevName || !*pszNetDevName )
    {
        WRMSG( HHC00140, "E", pszNetDevName ? pszNetDevName : "NULL" );
        return -1;
    }

    strlcpy( hifr.hifr_name, pszNetDevName, sizeof(hifr.hifr_name) );

    // PROGRAMMING NOTE: hercifc can't "get" information,
    // only "set" it. Thus because we normally use hercifc
    // to issue ioctl codes to the interface (on non-Win32)
    // we bypass hercifc altogether and issue the ioctl
    // ourselves directly to the device itself, bypassing
    // hercifc completely. Note that for Win32 however,
    // 'TUNTAP_IOCtl' routes to a TunTap32.DLL call and
    // thus works just fine. We need special handling
    // only for non-Win32 platforms. - Fish

#if defined( OPTION_W32_CTCI )

    rc = TUNTAP_IOCtl( 0, SIOCGIFFLAGS, (char*)&hifr );

#else // (non-Win32 platforms)
    {
        int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
        rc = ioctl( sockfd, SIOCGIFFLAGS, &hifr );
    }
#endif

    *piFlags = hifr.hifr_flags;

    return rc;
}   // End of function  TUNTAP_GetFlags()
Пример #13
0
//
// TUNTAP_SetMode           (TUNTAP_CreateInterface helper)
//
static int TUNTAP_SetMode (int fd, struct hifr *hifr, int iFlags)
{
    int rc;

    /* Try TUNTAP_ioctl first */
    rc = TUNTAP_IOCtl (fd, TUNSETIFF, (char *) hifr);

#if !defined(OPTION_W32_CTCI)
    /* If invalid value, try with the pre-2.4.5 value */
    if (0 > rc && errno == EINVAL)
        rc = TUNTAP_IOCtl (fd, ('T' << 8) | 202, (char *) hifr);

    /* kludge for EPERM and linux 2.6.18 */
    if (0 > rc && errno == EPERM && !(IFF_NO_HERCIFC & iFlags))
    {
        int             ifd[2];
        char           *hercifc;
        pid_t           pid;
        CTLREQ          ctlreq;
        fd_set          selset;
        struct timeval  tv;
        int             sv_err;
        int             status;

        if (socketpair (AF_UNIX, SOCK_STREAM, 0, ifd) < 0)
            return -1;

        if (!(hercifc = getenv ("HERCULES_IFC")))
            hercifc = HERCIFC_CMD;

        pid = fork();

        if (pid < 0)
            return -1;
        else if (pid == 0)
        {
            /* child */
            dup2 (ifd[0], STDIN_FILENO);
            dup2 (STDOUT_FILENO, STDERR_FILENO);
            dup2 (ifd[0], STDOUT_FILENO);
            close (ifd[1]);
            rc = execlp (hercifc, hercifc, NULL );
            return -1;
        }

        /* parent */
        close(ifd[0]);

        /* Request hercifc to issue the TUNSETIFF ioctl */
        memset (&ctlreq, 0, CTLREQ_SIZE);
        ctlreq.iCtlOp = TUNSETIFF;
        ctlreq.iProcID = fd;
        memcpy (&ctlreq.iru.hifr, hifr, sizeof (struct hifr));
        write (ifd[1], &ctlreq, CTLREQ_SIZE);

        /* Get response, if any, from hercifc */
        FD_ZERO (&selset);
        FD_SET (ifd[1], &selset);
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        rc = select (ifd[1]+1, &selset, NULL, NULL, &tv);
        if (rc > 0)
        {
            rc = read (ifd[1], &ctlreq, CTLREQ_SIZE);
            if (rc > 0)
                memcpy (hifr, &ctlreq.iru.hifr, sizeof (struct hifr));
        }
        else if (rc == 0)
        {
            WRMSG (HHC00135, "E", hercifc);
            errno = EPERM;
            rc = -1;
        }

        /* clean-up */
        sv_err = errno;
        close (ifd[1]);
        kill (pid, SIGKILL);
        waitpid (pid, &status, 0);
        errno = sv_err;
    }
#endif /* if !defined(OPTION_W32_CTCI) */

    return rc;
}   // End of function  TUNTAP_SetMode()
Пример #14
0
int  CTCI_Init( DEVBLK* pDEVBLK, int argc, char *argv[] )
{
    PCTCBLK         pWrkCTCBLK = NULL;  // Working CTCBLK
    PCTCBLK         pDevCTCBLK = NULL;  // Device  CTCBLK
    int             rc = 0;             // Return code
    int             nIFType;            // Interface type
    int             nIFFlags;           // Interface flags
    char            thread_name[32];    // CTCI_ReadThread

    nIFType =               // Interface type
        0
        | IFF_TUN           // ("TUN", not "tap")
        | IFF_NO_PI         // (no packet info)
        ;

    nIFFlags =               // Interface flags
        0
        | IFF_UP            // (interface is being enabled)
        | IFF_BROADCAST     // (interface broadcast addr is valid)
        ;

#if defined( TUNTAP_IFF_RUNNING_NEEDED )

    nIFFlags |=             // ADDITIONAL Interface flags
        0
        | IFF_RUNNING       // (interface is ALSO operational)
        ;

#endif /* defined( TUNTAP_IFF_RUNNING_NEEDED ) */

    pDEVBLK->devtype = 0x3088;

    // CTC is a group device
    if(!group_device(pDEVBLK, CTC_DEVICES_IN_GROUP))
        return 0;

    // Housekeeping
    pWrkCTCBLK = malloc( sizeof( CTCBLK ) );

    if( !pWrkCTCBLK )
    {
        logmsg( _("HHCCT037E %4.4X: Unable to allocate CTCBLK\n"),
                pDEVBLK->devnum );
        return -1;
    }

    memset( pWrkCTCBLK, 0, sizeof( CTCBLK ) );

    // Parse configuration file statement
    if( ParseArgs( pDEVBLK, pWrkCTCBLK, argc, (char**)argv ) != 0 )
    {
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }

    // Allocate the device CTCBLK and copy parsed information.

    pDevCTCBLK = malloc( sizeof( CTCBLK ) );

    if( !pDevCTCBLK )
    {
        logmsg( _("HHCCT038E %4.4X: Unable to allocate CTCBLK\n"),
                pDEVBLK->devnum );
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }

    memcpy( pDevCTCBLK, pWrkCTCBLK, sizeof( CTCBLK ) );

    // New format has only one device statement for both addresses
    // We need to dynamically allocate the read device block

    pDevCTCBLK->pDEVBLK[0] = pDEVBLK->group->memdev[0];
    pDevCTCBLK->pDEVBLK[1] = pDEVBLK->group->memdev[1];

    pDevCTCBLK->pDEVBLK[0]->dev_data = pDevCTCBLK;
    pDevCTCBLK->pDEVBLK[1]->dev_data = pDevCTCBLK;

    SetSIDInfo( pDevCTCBLK->pDEVBLK[0], 0x3088, 0x08, 0x3088, 0x01 );
    SetSIDInfo( pDevCTCBLK->pDEVBLK[1], 0x3088, 0x08, 0x3088, 0x01 );

    pDevCTCBLK->pDEVBLK[0]->ctctype  = CTC_CTCI;
    pDevCTCBLK->pDEVBLK[0]->ctcxmode = 1;

    pDevCTCBLK->pDEVBLK[1]->ctctype  = CTC_CTCI;
    pDevCTCBLK->pDEVBLK[1]->ctcxmode = 1;

    pDevCTCBLK->sMTU                = atoi( pDevCTCBLK->szMTU );
    pDevCTCBLK->iMaxFrameBufferSize = sizeof(pDevCTCBLK->bFrameBuffer);

    initialize_lock( &pDevCTCBLK->Lock );
    initialize_lock( &pDevCTCBLK->EventLock );
    initialize_condition( &pDevCTCBLK->Event );

    // Give both Herc devices a reasonable name...

    strlcpy( pDevCTCBLK->pDEVBLK[0]->filename,
             pDevCTCBLK->szTUNCharName,
     sizeof( pDevCTCBLK->pDEVBLK[0]->filename ) );

    strlcpy( pDevCTCBLK->pDEVBLK[1]->filename,
             pDevCTCBLK->szTUNCharName,
     sizeof( pDevCTCBLK->pDEVBLK[1]->filename ) );

    rc = TUNTAP_CreateInterface( pDevCTCBLK->szTUNCharName,
                                 IFF_TUN | IFF_NO_PI,
                                 &pDevCTCBLK->fd,
                                 pDevCTCBLK->szTUNDevName );

    if( rc < 0 )
    {
        free( pWrkCTCBLK );
        pWrkCTCBLK = NULL;
        return -1;
    }
    else
    {
        logmsg(_("HHCCT073I %4.4X: TUN device %s opened\n"),
                  pDevCTCBLK->pDEVBLK[0]->devnum,
                  pDevCTCBLK->szTUNDevName);
    }

#if defined(OPTION_W32_CTCI)

    // Set the specified driver/dll i/o buffer sizes..
    {
        struct tt32ctl tt32ctl;

        memset( &tt32ctl, 0, sizeof(tt32ctl) );
        strlcpy( tt32ctl.tt32ctl_name, pDevCTCBLK->szTUNDevName, sizeof(tt32ctl.tt32ctl_name) );

        tt32ctl.tt32ctl_devbuffsize = pDevCTCBLK->iKernBuff;
        if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SDEVBUFF, (char*)&tt32ctl ) != 0  )
        {
            logmsg( _("HHCCT074W TT32SDEVBUFF failed for device %s: %s.\n"),
                    pDevCTCBLK->szTUNDevName, strerror( errno ) );
        }

        tt32ctl.tt32ctl_iobuffsize = pDevCTCBLK->iIOBuff;
        if( TUNTAP_IOCtl( pDevCTCBLK->fd, TT32SIOBUFF, (char*)&tt32ctl ) != 0  )
        {
            logmsg( _("HHCCT075W TT32SIOBUFF failed for device %s: %s.\n"),
                    pDevCTCBLK->szTUNDevName, strerror( errno ) );
        }
    }
#endif

#ifdef OPTION_TUNTAP_CLRIPADDR
    VERIFY( TUNTAP_ClrIPAddr ( pDevCTCBLK->szTUNDevName ) == 0 );
#endif

#ifdef OPTION_TUNTAP_SETMACADDR

    if( !pDevCTCBLK->szMACAddress[0] )   // (if MAC address unspecified)
    {
        in_addr_t  wrk_guest_ip_addr;
        MAC        wrk_guest_mac_addr;

        if ((in_addr_t)-1 != (wrk_guest_ip_addr = inet_addr( pDevCTCBLK->szGuestIPAddr )))
        {
            build_herc_iface_mac ( wrk_guest_mac_addr, (const BYTE*) &wrk_guest_ip_addr );

            snprintf
            (
                pDevCTCBLK->szMACAddress,  sizeof( pDevCTCBLK->szMACAddress ),

                "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"

                ,wrk_guest_mac_addr[0]
                ,wrk_guest_mac_addr[1]
                ,wrk_guest_mac_addr[2]
                ,wrk_guest_mac_addr[3]
                ,wrk_guest_mac_addr[4]
                ,wrk_guest_mac_addr[5]
            );
        }
    }

    TRACE
    (
        "** CTCI_Init: %4.4X (%s): IP \"%s\"  -->  default MAC \"%s\"\n"

        ,pDevCTCBLK->pDEVBLK[0]->devnum
        ,pDevCTCBLK->szTUNDevName
        ,pDevCTCBLK->szGuestIPAddr
        ,pDevCTCBLK->szMACAddress
    );

    VERIFY( TUNTAP_SetMACAddr ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMACAddress  ) == 0 );
#endif

    VERIFY( TUNTAP_SetIPAddr  ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szDriveIPAddr ) == 0 );

    VERIFY( TUNTAP_SetDestAddr( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szGuestIPAddr ) == 0 );

#ifdef OPTION_TUNTAP_SETNETMASK
    VERIFY( TUNTAP_SetNetMask ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szNetMask     ) == 0 );
#endif

    VERIFY( TUNTAP_SetMTU     ( pDevCTCBLK->szTUNDevName, pDevCTCBLK->szMTU         ) == 0 );

    VERIFY( TUNTAP_SetFlags   ( pDevCTCBLK->szTUNDevName, nIFFlags                  ) == 0 );

    // Copy the fd to make panel.c happy
    pDevCTCBLK->pDEVBLK[0]->fd =
    pDevCTCBLK->pDEVBLK[1]->fd = pDevCTCBLK->fd;

    snprintf(thread_name,sizeof(thread_name),"CTCI %4.4X ReadThread",pDEVBLK->devnum);
    thread_name[sizeof(thread_name)-1]=0;
    create_thread( &pDevCTCBLK->tid, JOINABLE, CTCI_ReadThread, pDevCTCBLK, thread_name );

    pDevCTCBLK->pDEVBLK[0]->tid = pDevCTCBLK->tid;
    pDevCTCBLK->pDEVBLK[1]->tid = pDevCTCBLK->tid;

    free( pWrkCTCBLK );
    pWrkCTCBLK = NULL;

    return 0;
}