VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/linux/NetIf-linux.cpp@ 47117

Last change on this file since 47117 was 47117, checked in by vboxsync, 11 years ago

Main: RT_ZERO() / RTStrCopy()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/* $Id: NetIf-linux.cpp 47117 2013-07-12 12:48:17Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Linux implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2012 Oracle Corporation
8 *
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.
16 */
17
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_MAIN
24
25#include <iprt/err.h>
26#include <list>
27#include <sys/ioctl.h>
28#include <net/if.h>
29#include <net/if_arp.h>
30#include <net/route.h>
31#include <netinet/in.h>
32#include <stdio.h>
33#include <unistd.h>
34#include <iprt/asm.h>
35
36#include "HostNetworkInterfaceImpl.h"
37#include "netif.h"
38#include "Logging.h"
39
40static int getDefaultIfaceName(char *pszName)
41{
42 FILE *fp = fopen("/proc/net/route", "r");
43 char szBuf[1024];
44 char szIfName[17];
45 char szAddr[129];
46 char szGateway[129];
47 char szMask[129];
48 int iTmp;
49 unsigned uFlags;
50
51 if (fp)
52 {
53 while (fgets(szBuf, sizeof(szBuf)-1, fp))
54 {
55 int n = sscanf(szBuf, "%16s %128s %128s %X %d %d %d %128s %d %d %d\n",
56 szIfName, szAddr, szGateway, &uFlags, &iTmp, &iTmp, &iTmp,
57 szMask, &iTmp, &iTmp, &iTmp);
58 if (n < 10 || !(uFlags & RTF_UP))
59 continue;
60
61 if (strcmp(szAddr, "00000000") == 0 && strcmp(szMask, "00000000") == 0)
62 {
63 fclose(fp);
64 strncpy(pszName, szIfName, 16);
65 pszName[16] = 0;
66 return VINF_SUCCESS;
67 }
68 }
69 fclose(fp);
70 }
71 return VERR_INTERNAL_ERROR;
72}
73
74static uint32_t getInterfaceSpeed(const char *pszName)
75{
76 /*
77 * I wish I could do simple ioctl here, but older kernels require root
78 * privileges for any ethtool commands.
79 */
80 char szBuf[256];
81 uint32_t uSpeed = 0;
82 /* First, we try to retrieve the speed via sysfs. */
83 RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
84 FILE *fp = fopen(szBuf, "r");
85 if (fp)
86 {
87 if (fscanf(fp, "%u", &uSpeed) != 1)
88 uSpeed = 0;
89 fclose(fp);
90 }
91 if (uSpeed == 10)
92 {
93 /* Check the cable is plugged in at all */
94 unsigned uCarrier = 0;
95 RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
96 fp = fopen(szBuf, "r");
97 if (fp)
98 {
99 if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
100 uSpeed = 0;
101 fclose(fp);
102 }
103 }
104
105 if (uSpeed == 0)
106 {
107 /* Failed to get speed via sysfs, go to plan B. */
108 int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
109 if (RT_SUCCESS(rc))
110 uSpeed = RTStrToUInt32(szBuf);
111 }
112 return uSpeed;
113}
114
115static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
116{
117 // Zeroing out pInfo is a bad idea as it should contain both short and long names at
118 // this point. So make sure the structure is cleared by the caller if necessary!
119 // memset(pInfo, 0, sizeof(*pInfo));
120 struct ifreq Req;
121 RT_ZERO(Req);
122 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
123 if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
124 {
125 switch (Req.ifr_hwaddr.sa_family)
126 {
127 case ARPHRD_ETHER:
128 pInfo->enmMediumType = NETIF_T_ETHERNET;
129 break;
130 default:
131 pInfo->enmMediumType = NETIF_T_UNKNOWN;
132 break;
133 }
134 /* Generate UUID from name and MAC address. */
135 RTUUID uuid;
136 RTUuidClear(&uuid);
137 memcpy(&uuid, Req.ifr_name, RT_MIN(sizeof(Req.ifr_name), sizeof(uuid)));
138 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
139 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
140 memcpy(uuid.Gen.au8Node, &Req.ifr_hwaddr.sa_data, sizeof(uuid.Gen.au8Node));
141 pInfo->Uuid = uuid;
142
143 memcpy(&pInfo->MACAddress, Req.ifr_hwaddr.sa_data, sizeof(pInfo->MACAddress));
144
145 if (ioctl(iSocket, SIOCGIFADDR, &Req) >= 0)
146 memcpy(pInfo->IPAddress.au8,
147 &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
148 sizeof(pInfo->IPAddress.au8));
149
150 if (ioctl(iSocket, SIOCGIFNETMASK, &Req) >= 0)
151 memcpy(pInfo->IPNetMask.au8,
152 &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
153 sizeof(pInfo->IPNetMask.au8));
154
155 if (ioctl(iSocket, SIOCGIFFLAGS, &Req) >= 0)
156 pInfo->enmStatus = Req.ifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;
157
158 FILE *fp = fopen("/proc/net/if_inet6", "r");
159 if (fp)
160 {
161 RTNETADDRIPV6 IPv6Address;
162 unsigned uIndex, uLength, uScope, uTmp;
163 char szName[30];
164 for (;;)
165 {
166 RT_ZERO(szName);
167 int n = fscanf(fp,
168 "%08x%08x%08x%08x"
169 " %02x %02x %02x %02x %20s\n",
170 &IPv6Address.au32[0], &IPv6Address.au32[1],
171 &IPv6Address.au32[2], &IPv6Address.au32[3],
172 &uIndex, &uLength, &uScope, &uTmp, szName);
173 if (n == EOF)
174 break;
175 if (n != 9 || uLength > 128)
176 {
177 Log(("getInterfaceInfo: Error while reading /proc/net/if_inet6, n=%d uLength=%u\n",
178 n, uLength));
179 break;
180 }
181 if (!strcmp(Req.ifr_name, szName))
182 {
183 pInfo->IPv6Address.au32[0] = htonl(IPv6Address.au32[0]);
184 pInfo->IPv6Address.au32[1] = htonl(IPv6Address.au32[1]);
185 pInfo->IPv6Address.au32[2] = htonl(IPv6Address.au32[2]);
186 pInfo->IPv6Address.au32[3] = htonl(IPv6Address.au32[3]);
187 ASMBitSetRange(&pInfo->IPv6NetMask, 0, uLength);
188 }
189 }
190 fclose(fp);
191 }
192 /*
193 * Don't even try to get speed for non-Ethernet interfaces, it only
194 * produces errors.
195 */
196 if (pInfo->enmMediumType == NETIF_T_ETHERNET)
197 pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
198 else
199 pInfo->uSpeedMbits = 0;
200 }
201 return VINF_SUCCESS;
202}
203
204int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
205{
206 char szDefaultIface[256];
207 int rc = getDefaultIfaceName(szDefaultIface);
208 if (RT_FAILURE(rc))
209 {
210 Log(("NetIfList: Failed to find default interface.\n"));
211 szDefaultIface[0] = 0;
212 }
213 int sock = socket(AF_INET, SOCK_DGRAM, 0);
214 if (sock >= 0)
215 {
216 FILE *fp = fopen("/proc/net/dev", "r");
217 if (fp)
218 {
219 char buf[256];
220 while (fgets(buf, sizeof(buf), fp))
221 {
222 char *pszEndOfName = strchr(buf, ':');
223 if (!pszEndOfName)
224 continue;
225 *pszEndOfName = 0;
226 int iFirstNonWS = strspn(buf, " ");
227 char *pszName = buf+iFirstNonWS;
228 NETIFINFO Info;
229 RT_ZERO(Info);
230 rc = getInterfaceInfo(sock, pszName, &Info);
231 if (RT_FAILURE(rc))
232 break;
233 if (Info.enmMediumType == NETIF_T_ETHERNET)
234 {
235 ComObjPtr<HostNetworkInterface> IfObj;
236 IfObj.createObject();
237
238 HostNetworkInterfaceType_T enmType;
239 if (strncmp("vboxnet", pszName, 7))
240 enmType = HostNetworkInterfaceType_Bridged;
241 else
242 enmType = HostNetworkInterfaceType_HostOnly;
243
244 if (SUCCEEDED(IfObj->init(Bstr(pszName), enmType, &Info)))
245 {
246 if (strcmp(pszName, szDefaultIface) == 0)
247 list.push_front(IfObj);
248 else
249 list.push_back(IfObj);
250 }
251 }
252
253 }
254 fclose(fp);
255 }
256 close(sock);
257 }
258 else
259 rc = VERR_INTERNAL_ERROR;
260
261 return rc;
262}
263
264int NetIfGetConfigByName(PNETIFINFO pInfo)
265{
266 int rc = VINF_SUCCESS;
267 int sock = socket(AF_INET, SOCK_DGRAM, 0);
268 if (sock < 0)
269 return VERR_NOT_IMPLEMENTED;
270 rc = getInterfaceInfo(sock, pInfo->szShortName, pInfo);
271 close(sock);
272 return rc;
273}
274
275/**
276 * Retrieve the physical link speed in megabits per second. If the interface is
277 * not up or otherwise unavailable the zero speed is returned.
278 *
279 * @returns VBox status code.
280 *
281 * @param pcszIfName Interface name.
282 * @param puMbits Where to store the link speed.
283 */
284int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
285{
286 int sock = socket(AF_INET, SOCK_DGRAM, 0);
287 if (sock < 0)
288 return VERR_OUT_OF_RESOURCES;
289 struct ifreq Req;
290 RT_ZERO(Req);
291 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
292 if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
293 {
294 if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
295 if (Req.ifr_flags & IFF_UP)
296 {
297 close(sock);
298 *puMbits = getInterfaceSpeed(pcszIfName);
299 return VINF_SUCCESS;
300 }
301 }
302 close(sock);
303 *puMbits = 0;
304 return VWRN_NOT_FOUND;
305}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette