summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server/linux/NetIf-linux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/linux/NetIf-linux.cpp')
-rw-r--r--src/VBox/Main/src-server/linux/NetIf-linux.cpp133
1 files changed, 97 insertions, 36 deletions
diff --git a/src/VBox/Main/src-server/linux/NetIf-linux.cpp b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
index 6fe799cf..2384cc52 100644
--- a/src/VBox/Main/src-server/linux/NetIf-linux.cpp
+++ b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,14 +37,23 @@
#include "netif.h"
#include "Logging.h"
+/**
+ * Obtain the name of the interface used for default routing.
+ *
+ * NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp.
+ *
+ * @returns VBox status code.
+ *
+ * @param pszName The buffer of IFNAMSIZ+1 length where to put the name.
+ */
static int getDefaultIfaceName(char *pszName)
{
FILE *fp = fopen("/proc/net/route", "r");
char szBuf[1024];
char szIfName[17];
- char szAddr[129];
- char szGateway[129];
- char szMask[129];
+ uint32_t uAddr;
+ uint32_t uGateway;
+ uint32_t uMask;
int iTmp;
unsigned uFlags;
@@ -52,13 +61,13 @@ static int getDefaultIfaceName(char *pszName)
{
while (fgets(szBuf, sizeof(szBuf)-1, fp))
{
- int n = sscanf(szBuf, "%16s %128s %128s %X %d %d %d %128s %d %d %d\n",
- szIfName, szAddr, szGateway, &uFlags, &iTmp, &iTmp, &iTmp,
- szMask, &iTmp, &iTmp, &iTmp);
+ int n = sscanf(szBuf, "%16s %x %x %x %d %d %d %x %d %d %d\n",
+ szIfName, &uAddr, &uGateway, &uFlags, &iTmp, &iTmp, &iTmp,
+ &uMask, &iTmp, &iTmp, &iTmp);
if (n < 10 || !(uFlags & RTF_UP))
continue;
- if (strcmp(szAddr, "00000000") == 0 && strcmp(szMask, "00000000") == 0)
+ if (uAddr == 0 && uMask == 0)
{
fclose(fp);
strncpy(pszName, szIfName, 16);
@@ -71,14 +80,55 @@ static int getDefaultIfaceName(char *pszName)
return VERR_INTERNAL_ERROR;
}
+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);
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
{
switch (Req.ifr_hwaddr.sa_family)
@@ -122,7 +172,7 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
char szName[30];
for (;;)
{
- memset(szName, 0, sizeof(szName));
+ RT_ZERO(szName);
int n = fscanf(fp,
"%08x%08x%08x%08x"
" %02x %02x %02x %02x %20s\n",
@@ -152,31 +202,10 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
* 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 == 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);
- }
- }
+ pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
+ else
+ pInfo->uSpeedMbits = 0;
}
return VINF_SUCCESS;
}
@@ -216,7 +245,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
IfObj.createObject();
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", pszName, 7))
+ if (strncmp(pszName, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -251,3 +280,35 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
close(sock);
return rc;
}
+
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
+{
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return VERR_OUT_OF_RESOURCES;
+ struct ifreq Req;
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
+ if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
+ {
+ if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
+ if (Req.ifr_flags & IFF_UP)
+ {
+ close(sock);
+ *puMbits = getInterfaceSpeed(pcszIfName);
+ return VINF_SUCCESS;
+ }
+ }
+ close(sock);
+ *puMbits = 0;
+ return VWRN_NOT_FOUND;
+}