VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/darwin/NetIf-darwin.cpp@ 57823

Last change on this file since 57823 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 KB
Line 
1/* $Id: NetIf-darwin.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Darwin implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2011 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/*
24 * Deal with conflicts first.
25 * PVM - BSD mess, that FreeBSD has correct a long time ago.
26 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
27 */
28#include <iprt/types.h>
29#include <sys/param.h>
30#undef PVM
31
32#define LOG_GROUP LOG_GROUP_MAIN
33
34#include <iprt/err.h>
35#include <iprt/alloc.h>
36
37#include <string.h>
38#include <sys/socket.h>
39#include <sys/ioctl.h>
40#include <sys/sysctl.h>
41#include <netinet/in.h>
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <net/if_types.h>
45#include <net/route.h>
46#include <ifaddrs.h>
47#include <errno.h>
48#include <unistd.h>
49#include <list>
50
51#include "HostNetworkInterfaceImpl.h"
52#include "netif.h"
53#include "iokit.h"
54#include "Logging.h"
55
56#if 0
57int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
58{
59 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
60 if (sock < 0)
61 {
62 Log(("NetIfList: socket() -> %d\n", errno));
63 return NULL;
64 }
65 struct ifaddrs *IfAddrs, *pAddr;
66 int rc = getifaddrs(&IfAddrs);
67 if (rc)
68 {
69 close(sock);
70 Log(("NetIfList: getifaddrs() -> %d\n", rc));
71 return VERR_INTERNAL_ERROR;
72 }
73
74 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
75 while (pEtherNICs)
76 {
77 size_t cbNameLen = strlen(pEtherNICs->szName) + 1;
78 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
79 pNew->MACAddress = pEtherNICs->Mac;
80 pNew->enmMediumType = NETIF_T_ETHERNET;
81 pNew->Uuid = pEtherNICs->Uuid;
82 Assert(sizeof(pNew->szShortName) > sizeof(pEtherNICs->szBSDName));
83 memcpy(pNew->szShortName, pEtherNICs->szBSDName, sizeof(pEtherNICs->szBSDName));
84 pNew->szShortName[sizeof(pEtherNICs->szBSDName)] = '\0';
85 memcpy(pNew->szName, pEtherNICs->szName, cbNameLen);
86
87 struct ifreq IfReq;
88 RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
89 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
90 {
91 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
92 pNew->enmStatus = NETIF_S_UNKNOWN;
93 }
94 else
95 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
96
97 for (pAddr = IfAddrs; pAddr != NULL; pAddr = pAddr->ifa_next)
98 {
99 if (strcmp(pNew->szShortName, pAddr->ifa_name))
100 continue;
101
102 struct sockaddr_in *pIPAddr, *pIPNetMask;
103 struct sockaddr_in6 *pIPv6Addr, *pIPv6NetMask;
104
105 switch (pAddr->ifa_addr->sa_family)
106 {
107 case AF_INET:
108 if (pNew->IPAddress.u)
109 break;
110 pIPAddr = (struct sockaddr_in *)pAddr->ifa_addr;
111 Assert(sizeof(pNew->IPAddress) == sizeof(pIPAddr->sin_addr));
112 pNew->IPAddress.u = pIPAddr->sin_addr.s_addr;
113 pIPNetMask = (struct sockaddr_in *)pAddr->ifa_netmask;
114 Assert(pIPNetMask->sin_family == AF_INET);
115 Assert(sizeof(pNew->IPNetMask) == sizeof(pIPNetMask->sin_addr));
116 pNew->IPNetMask.u = pIPNetMask->sin_addr.s_addr;
117 break;
118 case AF_INET6:
119 if (pNew->IPv6Address.s.Lo || pNew->IPv6Address.s.Hi)
120 break;
121 pIPv6Addr = (struct sockaddr_in6 *)pAddr->ifa_addr;
122 Assert(sizeof(pNew->IPv6Address) == sizeof(pIPv6Addr->sin6_addr));
123 memcpy(pNew->IPv6Address.au8,
124 pIPv6Addr->sin6_addr.__u6_addr.__u6_addr8,
125 sizeof(pNew->IPv6Address));
126 pIPv6NetMask = (struct sockaddr_in6 *)pAddr->ifa_netmask;
127 Assert(pIPv6NetMask->sin6_family == AF_INET6);
128 Assert(sizeof(pNew->IPv6NetMask) == sizeof(pIPv6NetMask->sin6_addr));
129 memcpy(pNew->IPv6NetMask.au8,
130 pIPv6NetMask->sin6_addr.__u6_addr.__u6_addr8,
131 sizeof(pNew->IPv6NetMask));
132 break;
133 }
134 }
135
136 ComObjPtr<HostNetworkInterface> IfObj;
137 IfObj.createObject();
138 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), HostNetworkInterfaceType_Bridged, pNew)))
139 list.push_back(IfObj);
140 RTMemFree(pNew);
141
142 /* next, free current */
143 void *pvFree = pEtherNICs;
144 pEtherNICs = pEtherNICs->pNext;
145 RTMemFree(pvFree);
146 }
147
148 freeifaddrs(IfAddrs);
149 close(sock);
150 return VINF_SUCCESS;
151}
152#else
153
154#define ROUNDUP(a) \
155 (((a) & (sizeof(u_long) - 1)) ? (1 + ((a) | (sizeof(u_long) - 1))) : (a))
156#define ADVANCE(x, n) (x += (n)->sa_len ? ROUNDUP((n)->sa_len) : sizeof(u_long))
157
158void extractAddresses(int iAddrMask, caddr_t cp, caddr_t cplim, struct sockaddr **pAddresses)
159{
160 struct sockaddr *sa;
161
162 for (int i = 0; i < RTAX_MAX && cp < cplim; i++) {
163 if (iAddrMask & (1 << i))
164 {
165 sa = (struct sockaddr *)cp;
166
167 pAddresses[i] = sa;
168
169 ADVANCE(cp, sa);
170 }
171 else
172 pAddresses[i] = NULL;
173 }
174}
175
176void extractAddressesToNetInfo(int iAddrMask, caddr_t cp, caddr_t cplim, PNETIFINFO pInfo)
177{
178 struct sockaddr *addresses[RTAX_MAX];
179
180 extractAddresses(iAddrMask, cp, cplim, addresses);
181 switch (addresses[RTAX_IFA]->sa_family)
182 {
183 case AF_INET:
184 if (!pInfo->IPAddress.u)
185 {
186 pInfo->IPAddress.u = ((struct sockaddr_in *)addresses[RTAX_IFA])->sin_addr.s_addr;
187 pInfo->IPNetMask.u = ((struct sockaddr_in *)addresses[RTAX_NETMASK])->sin_addr.s_addr;
188 }
189 break;
190 case AF_INET6:
191 if (!pInfo->IPv6Address.s.Lo && !pInfo->IPv6Address.s.Hi)
192 {
193 memcpy(pInfo->IPv6Address.au8,
194 ((struct sockaddr_in6 *)addresses[RTAX_IFA])->sin6_addr.__u6_addr.__u6_addr8,
195 sizeof(pInfo->IPv6Address));
196 memcpy(pInfo->IPv6NetMask.au8,
197 ((struct sockaddr_in6 *)addresses[RTAX_NETMASK])->sin6_addr.__u6_addr.__u6_addr8,
198 sizeof(pInfo->IPv6NetMask));
199 }
200 break;
201 default:
202 Log(("NetIfList: Unsupported address family: %u\n", addresses[RTAX_IFA]->sa_family));
203 break;
204 }
205}
206
207static int getDefaultIfaceIndex(unsigned short *pu16Index)
208{
209 size_t cbNeeded;
210 char *pBuf, *pNext;
211 int aiMib[6];
212 struct sockaddr *addresses[RTAX_MAX];
213
214 aiMib[0] = CTL_NET;
215 aiMib[1] = PF_ROUTE;
216 aiMib[2] = 0;
217 aiMib[3] = PF_INET; /* address family */
218 aiMib[4] = NET_RT_DUMP;
219 aiMib[5] = 0;
220
221 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
222 {
223 Log(("getDefaultIfaceIndex: Failed to get estimate for list size (errno=%d).\n", errno));
224 return RTErrConvertFromErrno(errno);
225 }
226 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
227 return VERR_NO_MEMORY;
228 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
229 {
230 free(pBuf);
231 Log(("getDefaultIfaceIndex: Failed to retrieve interface table (errno=%d).\n", errno));
232 return RTErrConvertFromErrno(errno);
233 }
234
235 char *pEnd = pBuf + cbNeeded;
236 struct rt_msghdr *pRtMsg;
237 for (pNext = pBuf; pNext < pEnd; pNext += pRtMsg->rtm_msglen)
238 {
239 pRtMsg = (struct rt_msghdr *)pNext;
240
241 if (pRtMsg->rtm_type != RTM_GET)
242 {
243 Log(("getDefaultIfaceIndex: Got message %u while expecting %u.\n",
244 pRtMsg->rtm_type, RTM_GET));
245 //rc = VERR_INTERNAL_ERROR;
246 continue;
247 }
248 if ((char*)(pRtMsg + 1) < pEnd)
249 {
250 /* Extract addresses from the message. */
251 extractAddresses(pRtMsg->rtm_addrs, (char *)(pRtMsg + 1),
252 pRtMsg->rtm_msglen + 1 + (char *)pRtMsg, addresses);
253 if ((pRtMsg->rtm_addrs & RTA_DST)
254 && (pRtMsg->rtm_addrs & RTA_NETMASK))
255 {
256 if (addresses[RTAX_DST]->sa_family != AF_INET)
257 continue;
258 struct sockaddr_in *addr = (struct sockaddr_in *)addresses[RTAX_DST];
259 struct sockaddr_in *mask = (struct sockaddr_in *)addresses[RTAX_NETMASK];
260 if ((addr->sin_addr.s_addr == INADDR_ANY) &&
261 mask &&
262 (ntohl(mask->sin_addr.s_addr) == 0L ||
263 mask->sin_len == 0))
264 {
265 *pu16Index = pRtMsg->rtm_index;
266 free(pBuf);
267 return VINF_SUCCESS;
268 }
269 }
270 }
271 }
272 free(pBuf);
273 return 0; /* Failed to find default interface, take the first one in the list. */
274}
275
276int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
277{
278 int rc = VINF_SUCCESS;
279 size_t cbNeeded;
280 char *pBuf, *pNext;
281 int aiMib[6];
282 unsigned short u16DefaultIface = 0; /* initialized to shut up gcc */
283
284 /* Get the index of the interface associated with default route. */
285 rc = getDefaultIfaceIndex(&u16DefaultIface);
286 if (RT_FAILURE(rc))
287 return rc;
288
289 aiMib[0] = CTL_NET;
290 aiMib[1] = PF_ROUTE;
291 aiMib[2] = 0;
292 aiMib[3] = 0; /* address family */
293 aiMib[4] = NET_RT_IFLIST;
294 aiMib[5] = 0;
295
296 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
297 {
298 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
299 return RTErrConvertFromErrno(errno);
300 }
301 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
302 return VERR_NO_MEMORY;
303 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
304 {
305 free(pBuf);
306 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
307 return RTErrConvertFromErrno(errno);
308 }
309
310 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
311 if (sock < 0)
312 {
313 free(pBuf);
314 Log(("NetIfList: socket() -> %d\n", errno));
315 return RTErrConvertFromErrno(errno);
316 }
317
318 PDARWINETHERNIC pNIC;
319 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
320
321 char *pEnd = pBuf + cbNeeded;
322 for (pNext = pBuf; pNext < pEnd;)
323 {
324 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
325
326 if (pIfMsg->ifm_type != RTM_IFINFO)
327 {
328 Log(("NetIfList: Got message %u while expecting %u.\n",
329 pIfMsg->ifm_type, RTM_IFINFO));
330 rc = VERR_INTERNAL_ERROR;
331 break;
332 }
333 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
334
335 size_t cbNameLen = pSdl->sdl_nlen + 1;
336 Assert(pSdl->sdl_nlen < sizeof(pNIC->szBSDName));
337 for (pNIC = pEtherNICs; pNIC; pNIC = pNIC->pNext)
338 if ( !strncmp(pSdl->sdl_data, pNIC->szBSDName, pSdl->sdl_nlen)
339 && pNIC->szBSDName[pSdl->sdl_nlen] == '\0')
340 {
341 cbNameLen = strlen(pNIC->szName) + 1;
342 break;
343 }
344 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
345 if (!pNew)
346 {
347 rc = VERR_NO_MEMORY;
348 break;
349 }
350 memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
351 pNew->enmMediumType = NETIF_T_ETHERNET;
352 Assert(sizeof(pNew->szShortName) > pSdl->sdl_nlen);
353 memcpy(pNew->szShortName, pSdl->sdl_data, RT_MIN(pSdl->sdl_nlen, sizeof(pNew->szShortName) - 1));
354
355 /*
356 * If we found the adapter in the list returned by
357 * DarwinGetEthernetControllers() copy the name and UUID from there.
358 */
359 if (pNIC)
360 {
361 memcpy(pNew->szName, pNIC->szName, cbNameLen);
362 pNew->Uuid = pNIC->Uuid;
363 }
364 else
365 {
366 memcpy(pNew->szName, pSdl->sdl_data, pSdl->sdl_nlen);
367 /* Generate UUID from name and MAC address. */
368 RTUUID uuid;
369 RTUuidClear(&uuid);
370 memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
371 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
372 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
373 memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
374 pNew->Uuid = uuid;
375 }
376
377 pNext += pIfMsg->ifm_msglen;
378 while (pNext < pEnd)
379 {
380 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
381
382 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
383 break;
384 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
385 (char *)(pIfAddrMsg + 1),
386 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
387 pNew);
388 pNext += pIfAddrMsg->ifam_msglen;
389 }
390
391 if (pSdl->sdl_type == IFT_ETHER)
392 {
393 struct ifreq IfReq;
394 RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
395 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
396 {
397 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
398 pNew->enmStatus = NETIF_S_UNKNOWN;
399 }
400 else
401 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
402
403 HostNetworkInterfaceType_T enmType;
404 if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet")))
405 enmType = HostNetworkInterfaceType_Bridged;
406 else
407 enmType = HostNetworkInterfaceType_HostOnly;
408
409 ComObjPtr<HostNetworkInterface> IfObj;
410 IfObj.createObject();
411 if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
412 {
413 /* Make sure the default interface gets to the beginning. */
414 if (pIfMsg->ifm_index == u16DefaultIface)
415 list.push_front(IfObj);
416 else
417 list.push_back(IfObj);
418 }
419 }
420 RTMemFree(pNew);
421 }
422 for (pNIC = pEtherNICs; pNIC;)
423 {
424 void *pvFree = pNIC;
425 pNIC = pNIC->pNext;
426 RTMemFree(pvFree);
427 }
428 close(sock);
429 free(pBuf);
430 return rc;
431}
432
433int NetIfGetConfigByName(PNETIFINFO pInfo)
434{
435 int rc = VINF_SUCCESS;
436 size_t cbNeeded;
437 char *pBuf, *pNext;
438 int aiMib[6];
439
440 aiMib[0] = CTL_NET;
441 aiMib[1] = PF_ROUTE;
442 aiMib[2] = 0;
443 aiMib[3] = 0; /* address family */
444 aiMib[4] = NET_RT_IFLIST;
445 aiMib[5] = 0;
446
447 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
448 {
449 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
450 return RTErrConvertFromErrno(errno);
451 }
452 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
453 return VERR_NO_MEMORY;
454 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
455 {
456 free(pBuf);
457 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
458 return RTErrConvertFromErrno(errno);
459 }
460
461 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
462 if (sock < 0)
463 {
464 free(pBuf);
465 Log(("NetIfList: socket() -> %d\n", errno));
466 return RTErrConvertFromErrno(errno);
467 }
468
469 char *pEnd = pBuf + cbNeeded;
470 for (pNext = pBuf; pNext < pEnd;)
471 {
472 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
473
474 if (pIfMsg->ifm_type != RTM_IFINFO)
475 {
476 Log(("NetIfList: Got message %u while expecting %u.\n",
477 pIfMsg->ifm_type, RTM_IFINFO));
478 rc = VERR_INTERNAL_ERROR;
479 break;
480 }
481 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
482
483 bool fSkip = !!strncmp(pInfo->szShortName, pSdl->sdl_data, pSdl->sdl_nlen)
484 || pInfo->szShortName[pSdl->sdl_nlen] != '\0';
485
486 pNext += pIfMsg->ifm_msglen;
487 while (pNext < pEnd)
488 {
489 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
490
491 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
492 break;
493 if (!fSkip)
494 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
495 (char *)(pIfAddrMsg + 1),
496 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
497 pInfo);
498 pNext += pIfAddrMsg->ifam_msglen;
499 }
500
501 if (!fSkip && pSdl->sdl_type == IFT_ETHER)
502 {
503 size_t cbNameLen = pSdl->sdl_nlen + 1;
504 memcpy(pInfo->MACAddress.au8, LLADDR(pSdl), sizeof(pInfo->MACAddress.au8));
505 pInfo->enmMediumType = NETIF_T_ETHERNET;
506 /* Generate UUID from name and MAC address. */
507 RTUUID uuid;
508 RTUuidClear(&uuid);
509 memcpy(&uuid, pInfo->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
510 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
511 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
512 memcpy(uuid.Gen.au8Node, pInfo->MACAddress.au8, sizeof(uuid.Gen.au8Node));
513 pInfo->Uuid = uuid;
514
515 struct ifreq IfReq;
516 RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pInfo->szShortName);
517 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
518 {
519 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
520 pInfo->enmStatus = NETIF_S_UNKNOWN;
521 }
522 else
523 pInfo->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
524
525 return VINF_SUCCESS;
526 }
527 }
528 close(sock);
529 free(pBuf);
530 return rc;
531}
532
533/**
534 * Retrieve the physical link speed in megabits per second. If the interface is
535 * not up or otherwise unavailable the zero speed is returned.
536 *
537 * @returns VBox status code.
538 *
539 * @param pcszIfName Interface name.
540 * @param puMbits Where to store the link speed.
541 */
542int NetIfGetLinkSpeed(const char * /*pcszIfName*/, uint32_t * /*puMbits*/)
543{
544 return VERR_NOT_IMPLEMENTED;
545}
546#endif
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