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; }
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; }