1
/* $Id: NetIf-linux.cpp $ */
3
* Main - NetIfList, Linux implementation.
7
* Copyright (C) 2008-2012 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
/*******************************************************************************
22
*******************************************************************************/
23
#define LOG_GROUP LOG_GROUP_MAIN
27
#include <sys/ioctl.h>
29
#include <net/if_arp.h>
30
#include <net/route.h>
31
#include <netinet/in.h>
36
#include "HostNetworkInterfaceImpl.h"
41
* Obtain the name of the interface used for default routing.
43
* NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp.
45
* @returns VBox status code.
47
* @param pszName The buffer of IFNAMSIZ+1 length where to put the name.
49
static int getDefaultIfaceName(char *pszName)
51
FILE *fp = fopen("/proc/net/route", "r");
62
while (fgets(szBuf, sizeof(szBuf)-1, fp))
64
int n = sscanf(szBuf, "%16s %x %x %x %d %d %d %x %d %d %d\n",
65
szIfName, &uAddr, &uGateway, &uFlags, &iTmp, &iTmp, &iTmp,
66
&uMask, &iTmp, &iTmp, &iTmp);
67
if (n < 10 || !(uFlags & RTF_UP))
70
if (uAddr == 0 && uMask == 0)
73
strncpy(pszName, szIfName, 16);
80
return VERR_INTERNAL_ERROR;
83
static uint32_t getInterfaceSpeed(const char *pszName)
86
* I wish I could do simple ioctl here, but older kernels require root
87
* privileges for any ethtool commands.
91
/* First, we try to retrieve the speed via sysfs. */
92
RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
93
FILE *fp = fopen(szBuf, "r");
96
if (fscanf(fp, "%u", &uSpeed) != 1)
102
/* Check the cable is plugged in at all */
103
unsigned uCarrier = 0;
104
RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
105
fp = fopen(szBuf, "r");
108
if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
116
/* Failed to get speed via sysfs, go to plan B. */
117
int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
119
uSpeed = RTStrToUInt32(szBuf);
124
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
126
// Zeroing out pInfo is a bad idea as it should contain both short and long names at
127
// this point. So make sure the structure is cleared by the caller if necessary!
128
// memset(pInfo, 0, sizeof(*pInfo));
131
RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
132
if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
134
switch (Req.ifr_hwaddr.sa_family)
137
pInfo->enmMediumType = NETIF_T_ETHERNET;
140
pInfo->enmMediumType = NETIF_T_UNKNOWN;
143
/* Generate UUID from name and MAC address. */
146
memcpy(&uuid, Req.ifr_name, RT_MIN(sizeof(Req.ifr_name), sizeof(uuid)));
147
uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
148
uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
149
memcpy(uuid.Gen.au8Node, &Req.ifr_hwaddr.sa_data, sizeof(uuid.Gen.au8Node));
152
memcpy(&pInfo->MACAddress, Req.ifr_hwaddr.sa_data, sizeof(pInfo->MACAddress));
154
if (ioctl(iSocket, SIOCGIFADDR, &Req) >= 0)
155
memcpy(pInfo->IPAddress.au8,
156
&((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
157
sizeof(pInfo->IPAddress.au8));
159
if (ioctl(iSocket, SIOCGIFNETMASK, &Req) >= 0)
160
memcpy(pInfo->IPNetMask.au8,
161
&((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
162
sizeof(pInfo->IPNetMask.au8));
164
if (ioctl(iSocket, SIOCGIFFLAGS, &Req) >= 0)
165
pInfo->enmStatus = Req.ifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;
167
FILE *fp = fopen("/proc/net/if_inet6", "r");
170
RTNETADDRIPV6 IPv6Address;
171
unsigned uIndex, uLength, uScope, uTmp;
178
" %02x %02x %02x %02x %20s\n",
179
&IPv6Address.au32[0], &IPv6Address.au32[1],
180
&IPv6Address.au32[2], &IPv6Address.au32[3],
181
&uIndex, &uLength, &uScope, &uTmp, szName);
184
if (n != 9 || uLength > 128)
186
Log(("getInterfaceInfo: Error while reading /proc/net/if_inet6, n=%d uLength=%u\n",
190
if (!strcmp(Req.ifr_name, szName))
192
pInfo->IPv6Address.au32[0] = htonl(IPv6Address.au32[0]);
193
pInfo->IPv6Address.au32[1] = htonl(IPv6Address.au32[1]);
194
pInfo->IPv6Address.au32[2] = htonl(IPv6Address.au32[2]);
195
pInfo->IPv6Address.au32[3] = htonl(IPv6Address.au32[3]);
196
ASMBitSetRange(&pInfo->IPv6NetMask, 0, uLength);
202
* Don't even try to get speed for non-Ethernet interfaces, it only
205
if (pInfo->enmMediumType == NETIF_T_ETHERNET)
206
pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
208
pInfo->uSpeedMbits = 0;
213
int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
215
char szDefaultIface[256];
216
int rc = getDefaultIfaceName(szDefaultIface);
219
Log(("NetIfList: Failed to find default interface.\n"));
220
szDefaultIface[0] = 0;
222
int sock = socket(AF_INET, SOCK_DGRAM, 0);
225
FILE *fp = fopen("/proc/net/dev", "r");
229
while (fgets(buf, sizeof(buf), fp))
231
char *pszEndOfName = strchr(buf, ':');
235
int iFirstNonWS = strspn(buf, " ");
236
char *pszName = buf+iFirstNonWS;
239
rc = getInterfaceInfo(sock, pszName, &Info);
242
if (Info.enmMediumType == NETIF_T_ETHERNET)
244
ComObjPtr<HostNetworkInterface> IfObj;
245
IfObj.createObject();
247
HostNetworkInterfaceType_T enmType;
248
if (strncmp(pszName, RT_STR_TUPLE("vboxnet")))
249
enmType = HostNetworkInterfaceType_Bridged;
251
enmType = HostNetworkInterfaceType_HostOnly;
253
if (SUCCEEDED(IfObj->init(Bstr(pszName), enmType, &Info)))
255
if (strcmp(pszName, szDefaultIface) == 0)
256
list.push_front(IfObj);
258
list.push_back(IfObj);
268
rc = VERR_INTERNAL_ERROR;
273
int NetIfGetConfigByName(PNETIFINFO pInfo)
275
int rc = VINF_SUCCESS;
276
int sock = socket(AF_INET, SOCK_DGRAM, 0);
278
return VERR_NOT_IMPLEMENTED;
279
rc = getInterfaceInfo(sock, pInfo->szShortName, pInfo);
285
* Retrieve the physical link speed in megabits per second. If the interface is
286
* not up or otherwise unavailable the zero speed is returned.
288
* @returns VBox status code.
290
* @param pcszIfName Interface name.
291
* @param puMbits Where to store the link speed.
293
int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
295
int sock = socket(AF_INET, SOCK_DGRAM, 0);
297
return VERR_OUT_OF_RESOURCES;
300
RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
301
if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
303
if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
304
if (Req.ifr_flags & IFF_UP)
307
*puMbits = getInterfaceSpeed(pcszIfName);
313
return VWRN_NOT_FOUND;