Ejemplo n.º 1
0
static uint32_t getInterfaceSpeed(const char *pszName)
{
    /*
     * I wish I could do simple ioctl here, but older kernels require root
     * privileges for any ethtool commands.
     */
    char szBuf[256];
    uint32_t uSpeed = 0;
    /* First, we try to retrieve the speed via sysfs. */
    RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
    FILE *fp = fopen(szBuf, "r");
    if (fp)
    {
        if (fscanf(fp, "%u", &uSpeed) != 1)
            uSpeed = 0;
        fclose(fp);
    }
    if (uSpeed == 10)
    {
        /* Check the cable is plugged in at all */
        unsigned uCarrier = 0;
        RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
        fp = fopen(szBuf, "r");
        if (fp)
        {
            if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
                uSpeed = 0;
            fclose(fp);
        }
    }
    
    if (uSpeed == 0)
    {
        /* Failed to get speed via sysfs, go to plan B. */
        int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
        if (RT_SUCCESS(rc))
            uSpeed = RTStrToUInt32(szBuf);
    }
    return uSpeed;
}
Ejemplo n.º 2
0
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
{
    // Zeroing out pInfo is a bad idea as it should contain both short and long names at
    // this point. So make sure the structure is cleared by the caller if necessary!
    // memset(pInfo, 0, sizeof(*pInfo));
    struct ifreq Req;
    memset(&Req, 0, sizeof(Req));
    strncpy(Req.ifr_name, pszName, sizeof(Req.ifr_name) - 1);
    if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
    {
        switch (Req.ifr_hwaddr.sa_family)
        {
        case ARPHRD_ETHER:
            pInfo->enmMediumType = NETIF_T_ETHERNET;
            break;
        default:
            pInfo->enmMediumType = NETIF_T_UNKNOWN;
            break;
        }
        /* Generate UUID from name and MAC address. */
        RTUUID uuid;
        RTUuidClear(&uuid);
        memcpy(&uuid, Req.ifr_name, RT_MIN(sizeof(Req.ifr_name), sizeof(uuid)));
        uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
        uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
        memcpy(uuid.Gen.au8Node, &Req.ifr_hwaddr.sa_data, sizeof(uuid.Gen.au8Node));
        pInfo->Uuid = uuid;

        memcpy(&pInfo->MACAddress, Req.ifr_hwaddr.sa_data, sizeof(pInfo->MACAddress));

        if (ioctl(iSocket, SIOCGIFADDR, &Req) >= 0)
            memcpy(pInfo->IPAddress.au8,
                   &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
                   sizeof(pInfo->IPAddress.au8));

        if (ioctl(iSocket, SIOCGIFNETMASK, &Req) >= 0)
            memcpy(pInfo->IPNetMask.au8,
                   &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
                   sizeof(pInfo->IPNetMask.au8));

        if (ioctl(iSocket, SIOCGIFFLAGS, &Req) >= 0)
            pInfo->enmStatus = Req.ifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;

        FILE *fp = fopen("/proc/net/if_inet6", "r");
        if (fp)
        {
            RTNETADDRIPV6 IPv6Address;
            unsigned uIndex, uLength, uScope, uTmp;
            char szName[30];
            for (;;)
            {
                memset(szName, 0, sizeof(szName));
                int n = fscanf(fp,
                               "%08x%08x%08x%08x"
                               " %02x %02x %02x %02x %20s\n",
                               &IPv6Address.au32[0], &IPv6Address.au32[1],
                               &IPv6Address.au32[2], &IPv6Address.au32[3],
                               &uIndex, &uLength, &uScope, &uTmp, szName);
                if (n == EOF)
                    break;
                if (n != 9 || uLength > 128)
                {
                    Log(("getInterfaceInfo: Error while reading /proc/net/if_inet6, n=%d uLength=%u\n",
                         n, uLength));
                    break;
                }
                if (!strcmp(Req.ifr_name, szName))
                {
                    pInfo->IPv6Address.au32[0] = htonl(IPv6Address.au32[0]);
                    pInfo->IPv6Address.au32[1] = htonl(IPv6Address.au32[1]);
                    pInfo->IPv6Address.au32[2] = htonl(IPv6Address.au32[2]);
                    pInfo->IPv6Address.au32[3] = htonl(IPv6Address.au32[3]);
                    ASMBitSetRange(&pInfo->IPv6NetMask, 0, uLength);
                }
            }
            fclose(fp);
        }
        /*
         * Don't even try to get speed for non-Ethernet interfaces, it only
         * produces errors.
         */
        pInfo->uSpeedMbits = 0;
        if (pInfo->enmMediumType == NETIF_T_ETHERNET)
        {
            /*
             * I wish I could do simple ioctl here, but older kernels require root
             * privileges for any ethtool commands.
             */
            char szBuf[256];
            /* First, we try to retrieve the speed via sysfs. */
            RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
            fp = fopen(szBuf, "r");
            if (fp)
            {
                if (fscanf(fp, "%u", &pInfo->uSpeedMbits) != 1)
                    pInfo->uSpeedMbits = 0;
                fclose(fp);
            }
            if (pInfo->uSpeedMbits == 10)
            {
                /* Check the cable is plugged in at all */
                unsigned uCarrier = 0;
                RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
                fp = fopen(szBuf, "r");
                if (fp)
                {
                    if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
                        pInfo->uSpeedMbits = 0;
                    fclose(fp);
                }
            }

            if (pInfo->uSpeedMbits == 0)
            {
                /* Failed to get speed via sysfs, go to plan B. */
                int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
                if (RT_SUCCESS(rc))
                    pInfo->uSpeedMbits = RTStrToUInt32(szBuf);
            }
        }
    }
    return VINF_SUCCESS;
}