~ubuntu-branches/ubuntu/trusty/virtualbox-lts-xenial/trusty-updates

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-server/linux/NetIf-linux.cpp

  • Committer: Package Import Robot
  • Author(s): Gianfranco Costamagna
  • Date: 2016-02-23 14:28:26 UTC
  • Revision ID: package-import@ubuntu.com-20160223142826-bdu69el2z6wa2a44
Tags: upstream-4.3.36-dfsg
ImportĀ upstreamĀ versionĀ 4.3.36-dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: NetIf-linux.cpp $ */
 
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
 
 
40
/**
 
41
 * Obtain the name of the interface used for default routing.
 
42
 *
 
43
 * NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp.
 
44
 *
 
45
 * @returns VBox status code.
 
46
 *
 
47
 * @param   pszName     The buffer of IFNAMSIZ+1 length where to put the name.
 
48
 */
 
49
static int getDefaultIfaceName(char *pszName)
 
50
{
 
51
    FILE *fp = fopen("/proc/net/route", "r");
 
52
    char szBuf[1024];
 
53
    char szIfName[17];
 
54
    uint32_t uAddr;
 
55
    uint32_t uGateway;
 
56
    uint32_t uMask;
 
57
    int  iTmp;
 
58
    unsigned uFlags;
 
59
 
 
60
    if (fp)
 
61
    {
 
62
        while (fgets(szBuf, sizeof(szBuf)-1, fp))
 
63
        {
 
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))
 
68
                continue;
 
69
 
 
70
            if (uAddr == 0 && uMask == 0)
 
71
            {
 
72
                fclose(fp);
 
73
                strncpy(pszName, szIfName, 16);
 
74
                pszName[16] = 0;
 
75
                return VINF_SUCCESS;
 
76
            }
 
77
        }
 
78
        fclose(fp);
 
79
    }
 
80
    return VERR_INTERNAL_ERROR;
 
81
}
 
82
 
 
83
static uint32_t getInterfaceSpeed(const char *pszName)
 
84
{
 
85
    /*
 
86
     * I wish I could do simple ioctl here, but older kernels require root
 
87
     * privileges for any ethtool commands.
 
88
     */
 
89
    char szBuf[256];
 
90
    uint32_t uSpeed = 0;
 
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");
 
94
    if (fp)
 
95
    {
 
96
        if (fscanf(fp, "%u", &uSpeed) != 1)
 
97
            uSpeed = 0;
 
98
        fclose(fp);
 
99
    }
 
100
    if (uSpeed == 10)
 
101
    {
 
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");
 
106
        if (fp)
 
107
        {
 
108
            if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
 
109
                uSpeed = 0;
 
110
            fclose(fp);
 
111
        }
 
112
    }
 
113
 
 
114
    if (uSpeed == 0)
 
115
    {
 
116
        /* Failed to get speed via sysfs, go to plan B. */
 
117
        int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
 
118
        if (RT_SUCCESS(rc))
 
119
            uSpeed = RTStrToUInt32(szBuf);
 
120
    }
 
121
    return uSpeed;
 
122
}
 
123
 
 
124
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
 
125
{
 
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));
 
129
    struct ifreq Req;
 
130
    RT_ZERO(Req);
 
131
    RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
 
132
    if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
 
133
    {
 
134
        switch (Req.ifr_hwaddr.sa_family)
 
135
        {
 
136
            case ARPHRD_ETHER:
 
137
                pInfo->enmMediumType = NETIF_T_ETHERNET;
 
138
                break;
 
139
            default:
 
140
                pInfo->enmMediumType = NETIF_T_UNKNOWN;
 
141
                break;
 
142
        }
 
143
        /* Generate UUID from name and MAC address. */
 
144
        RTUUID uuid;
 
145
        RTUuidClear(&uuid);
 
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));
 
150
        pInfo->Uuid = uuid;
 
151
 
 
152
        memcpy(&pInfo->MACAddress, Req.ifr_hwaddr.sa_data, sizeof(pInfo->MACAddress));
 
153
 
 
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));
 
158
 
 
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));
 
163
 
 
164
        if (ioctl(iSocket, SIOCGIFFLAGS, &Req) >= 0)
 
165
            pInfo->enmStatus = Req.ifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;
 
166
 
 
167
        FILE *fp = fopen("/proc/net/if_inet6", "r");
 
168
        if (fp)
 
169
        {
 
170
            RTNETADDRIPV6 IPv6Address;
 
171
            unsigned uIndex, uLength, uScope, uTmp;
 
172
            char szName[30];
 
173
            for (;;)
 
174
            {
 
175
                RT_ZERO(szName);
 
176
                int n = fscanf(fp,
 
177
                               "%08x%08x%08x%08x"
 
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);
 
182
                if (n == EOF)
 
183
                    break;
 
184
                if (n != 9 || uLength > 128)
 
185
                {
 
186
                    Log(("getInterfaceInfo: Error while reading /proc/net/if_inet6, n=%d uLength=%u\n",
 
187
                         n, uLength));
 
188
                    break;
 
189
                }
 
190
                if (!strcmp(Req.ifr_name, szName))
 
191
                {
 
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);
 
197
                }
 
198
            }
 
199
            fclose(fp);
 
200
        }
 
201
        /*
 
202
         * Don't even try to get speed for non-Ethernet interfaces, it only
 
203
         * produces errors.
 
204
         */
 
205
        if (pInfo->enmMediumType == NETIF_T_ETHERNET)
 
206
            pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
 
207
        else
 
208
            pInfo->uSpeedMbits = 0;
 
209
    }
 
210
    return VINF_SUCCESS;
 
211
}
 
212
 
 
213
int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
 
214
{
 
215
    char szDefaultIface[256];
 
216
    int rc = getDefaultIfaceName(szDefaultIface);
 
217
    if (RT_FAILURE(rc))
 
218
    {
 
219
        Log(("NetIfList: Failed to find default interface.\n"));
 
220
        szDefaultIface[0] = 0;
 
221
    }
 
222
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
 
223
    if (sock >= 0)
 
224
    {
 
225
        FILE *fp = fopen("/proc/net/dev", "r");
 
226
        if (fp)
 
227
        {
 
228
            char buf[256];
 
229
            while (fgets(buf, sizeof(buf), fp))
 
230
            {
 
231
                char *pszEndOfName = strchr(buf, ':');
 
232
                if (!pszEndOfName)
 
233
                    continue;
 
234
                *pszEndOfName = 0;
 
235
                int iFirstNonWS = strspn(buf, " ");
 
236
                char *pszName = buf+iFirstNonWS;
 
237
                NETIFINFO Info;
 
238
                RT_ZERO(Info);
 
239
                rc = getInterfaceInfo(sock, pszName, &Info);
 
240
                if (RT_FAILURE(rc))
 
241
                    break;
 
242
                if (Info.enmMediumType == NETIF_T_ETHERNET)
 
243
                {
 
244
                    ComObjPtr<HostNetworkInterface> IfObj;
 
245
                    IfObj.createObject();
 
246
 
 
247
                    HostNetworkInterfaceType_T enmType;
 
248
                    if (strncmp(pszName, RT_STR_TUPLE("vboxnet")))
 
249
                        enmType = HostNetworkInterfaceType_Bridged;
 
250
                    else
 
251
                        enmType = HostNetworkInterfaceType_HostOnly;
 
252
 
 
253
                    if (SUCCEEDED(IfObj->init(Bstr(pszName), enmType, &Info)))
 
254
                    {
 
255
                        if (strcmp(pszName, szDefaultIface) == 0)
 
256
                            list.push_front(IfObj);
 
257
                        else
 
258
                            list.push_back(IfObj);
 
259
                    }
 
260
                }
 
261
 
 
262
            }
 
263
            fclose(fp);
 
264
        }
 
265
        close(sock);
 
266
    }
 
267
    else
 
268
        rc = VERR_INTERNAL_ERROR;
 
269
 
 
270
    return rc;
 
271
}
 
272
 
 
273
int NetIfGetConfigByName(PNETIFINFO pInfo)
 
274
{
 
275
    int rc = VINF_SUCCESS;
 
276
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
 
277
    if (sock < 0)
 
278
        return VERR_NOT_IMPLEMENTED;
 
279
    rc = getInterfaceInfo(sock, pInfo->szShortName, pInfo);
 
280
    close(sock);
 
281
    return rc;
 
282
}
 
283
 
 
284
/**
 
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.
 
287
 *
 
288
 * @returns VBox status code.
 
289
 *
 
290
 * @param   pcszIfName  Interface name.
 
291
 * @param   puMbits     Where to store the link speed.
 
292
 */
 
293
int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
 
294
{
 
295
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
 
296
    if (sock < 0)
 
297
        return VERR_OUT_OF_RESOURCES;
 
298
    struct ifreq Req;
 
299
    RT_ZERO(Req);
 
300
    RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
 
301
    if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
 
302
    {
 
303
        if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
 
304
            if (Req.ifr_flags & IFF_UP)
 
305
            {
 
306
                close(sock);
 
307
                *puMbits = getInterfaceSpeed(pcszIfName);
 
308
                return VINF_SUCCESS;
 
309
            }
 
310
    }
 
311
    close(sock);
 
312
    *puMbits = 0;
 
313
    return VWRN_NOT_FOUND;
 
314
}