VirtualBox

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

Last change on this file since 33876 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 KB
Line 
1/* $Id: NetIf-darwin.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Darwin implementation.
4 */
5
6/*
7 * Copyright (C) 2008 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 strcpy(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) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
156#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
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 continue;
165
166 sa = (struct sockaddr *)cp;
167
168 pAddresses[i] = sa;
169
170 ADVANCE(cp, sa);
171 }
172}
173
174void extractAddressesToNetInfo(int iAddrMask, caddr_t cp, caddr_t cplim, PNETIFINFO pInfo)
175{
176 struct sockaddr *addresses[RTAX_MAX];
177
178 extractAddresses(iAddrMask, cp, cplim, addresses);
179 switch (addresses[RTAX_IFA]->sa_family)
180 {
181 case AF_INET:
182 if (!pInfo->IPAddress.u)
183 {
184 pInfo->IPAddress.u = ((struct sockaddr_in *)addresses[RTAX_IFA])->sin_addr.s_addr;
185 pInfo->IPNetMask.u = ((struct sockaddr_in *)addresses[RTAX_NETMASK])->sin_addr.s_addr;
186 }
187 break;
188 case AF_INET6:
189 if (!pInfo->IPv6Address.s.Lo && !pInfo->IPv6Address.s.Hi)
190 {
191 memcpy(pInfo->IPv6Address.au8,
192 ((struct sockaddr_in6 *)addresses[RTAX_IFA])->sin6_addr.__u6_addr.__u6_addr8,
193 sizeof(pInfo->IPv6Address));
194 memcpy(pInfo->IPv6NetMask.au8,
195 ((struct sockaddr_in6 *)addresses[RTAX_NETMASK])->sin6_addr.__u6_addr.__u6_addr8,
196 sizeof(pInfo->IPv6NetMask));
197 }
198 break;
199 default:
200 Log(("NetIfList: Unsupported address family: %u\n", addresses[RTAX_IFA]->sa_family));
201 break;
202 }
203}
204
205static int getDefaultIfaceIndex(unsigned short *pu16Index)
206{
207 size_t cbNeeded;
208 char *pBuf, *pNext;
209 int aiMib[6];
210 struct sockaddr *addresses[RTAX_MAX];
211
212 aiMib[0] = CTL_NET;
213 aiMib[1] = PF_ROUTE;
214 aiMib[2] = 0;
215 aiMib[3] = PF_INET; /* address family */
216 aiMib[4] = NET_RT_DUMP;
217 aiMib[5] = 0;
218
219 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
220 {
221 Log(("getDefaultIfaceIndex: Failed to get estimate for list size (errno=%d).\n", errno));
222 return RTErrConvertFromErrno(errno);
223 }
224 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
225 return VERR_NO_MEMORY;
226 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
227 {
228 free(pBuf);
229 Log(("getDefaultIfaceIndex: Failed to retrieve interface table (errno=%d).\n", errno));
230 return RTErrConvertFromErrno(errno);
231 }
232
233 char *pEnd = pBuf + cbNeeded;
234 struct rt_msghdr *pRtMsg;
235 for (pNext = pBuf; pNext < pEnd; pNext += pRtMsg->rtm_msglen)
236 {
237 pRtMsg = (struct rt_msghdr *)pNext;
238
239 if (pRtMsg->rtm_type != RTM_GET)
240 {
241 Log(("getDefaultIfaceIndex: Got message %u while expecting %u.\n",
242 pRtMsg->rtm_type, RTM_GET));
243 //rc = VERR_INTERNAL_ERROR;
244 continue;
245 }
246 if ((char*)(pRtMsg + 1) < pEnd)
247 {
248 /* Extract addresses from the message. */
249 extractAddresses(pRtMsg->rtm_addrs, (char *)(pRtMsg + 1),
250 pRtMsg->rtm_msglen + (char *)pRtMsg, addresses);
251 if ((pRtMsg->rtm_addrs & RTA_DST))
252 {
253 if (addresses[RTAX_DST]->sa_family != AF_INET)
254 continue;
255 struct sockaddr_in *addr = (struct sockaddr_in *)addresses[RTAX_DST];
256 struct sockaddr_in *mask = (struct sockaddr_in *)addresses[RTAX_NETMASK];
257 if ((addr->sin_addr.s_addr == INADDR_ANY) &&
258 mask &&
259 (ntohl(mask->sin_addr.s_addr) == 0L ||
260 mask->sin_len == 0))
261 {
262 *pu16Index = pRtMsg->rtm_index;
263 free(pBuf);
264 return VINF_SUCCESS;
265 }
266 }
267 }
268 }
269 free(pBuf);
270 return 0; /* Failed to find default interface, take the first one in the list. */
271}
272
273int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
274{
275 int rc = VINF_SUCCESS;
276 size_t cbNeeded;
277 char *pBuf, *pNext;
278 int aiMib[6];
279 unsigned short u16DefaultIface = 0; /* initialized to shut up gcc */
280
281 /* Get the index of the interface associated with default route. */
282 rc = getDefaultIfaceIndex(&u16DefaultIface);
283 if (RT_FAILURE(rc))
284 return rc;
285
286 aiMib[0] = CTL_NET;
287 aiMib[1] = PF_ROUTE;
288 aiMib[2] = 0;
289 aiMib[3] = 0; /* address family */
290 aiMib[4] = NET_RT_IFLIST;
291 aiMib[5] = 0;
292
293 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
294 {
295 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
296 return RTErrConvertFromErrno(errno);
297 }
298 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
299 return VERR_NO_MEMORY;
300 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
301 {
302 free(pBuf);
303 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
304 return RTErrConvertFromErrno(errno);
305 }
306
307 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
308 if (sock < 0)
309 {
310 free(pBuf);
311 Log(("NetIfList: socket() -> %d\n", errno));
312 return RTErrConvertFromErrno(errno);
313 }
314
315 PDARWINETHERNIC pNIC;
316 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
317
318 char *pEnd = pBuf + cbNeeded;
319 for (pNext = pBuf; pNext < pEnd;)
320 {
321 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
322
323 if (pIfMsg->ifm_type != RTM_IFINFO)
324 {
325 Log(("NetIfList: Got message %u while expecting %u.\n",
326 pIfMsg->ifm_type, RTM_IFINFO));
327 rc = VERR_INTERNAL_ERROR;
328 break;
329 }
330 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
331
332 size_t cbNameLen = pSdl->sdl_nlen + 1;
333 Assert(pSdl->sdl_nlen < sizeof(pNIC->szBSDName));
334 for (pNIC = pEtherNICs; pNIC; pNIC = pNIC->pNext)
335 if ( !strncmp(pSdl->sdl_data, pNIC->szBSDName, pSdl->sdl_nlen)
336 && pNIC->szBSDName[pSdl->sdl_nlen] == '\0')
337 {
338 cbNameLen = strlen(pNIC->szName) + 1;
339 break;
340 }
341 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
342 if (!pNew)
343 {
344 rc = VERR_NO_MEMORY;
345 break;
346 }
347 memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
348 pNew->enmMediumType = NETIF_T_ETHERNET;
349 Assert(sizeof(pNew->szShortName) > pSdl->sdl_nlen);
350 memcpy(pNew->szShortName, pSdl->sdl_data, RT_MIN(pSdl->sdl_nlen, sizeof(pNew->szShortName) - 1));
351
352 /*
353 * If we found the adapter in the list returned by
354 * DarwinGetEthernetControllers() copy the name and UUID from there.
355 */
356 if (pNIC)
357 {
358 memcpy(pNew->szName, pNIC->szName, cbNameLen);
359 pNew->Uuid = pNIC->Uuid;
360 }
361 else
362 {
363 memcpy(pNew->szName, pSdl->sdl_data, pSdl->sdl_nlen);
364 /* Generate UUID from name and MAC address. */
365 RTUUID uuid;
366 RTUuidClear(&uuid);
367 memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
368 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
369 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
370 memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
371 pNew->Uuid = uuid;
372 }
373
374 pNext += pIfMsg->ifm_msglen;
375 while (pNext < pEnd)
376 {
377 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
378
379 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
380 break;
381 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
382 (char *)(pIfAddrMsg + 1),
383 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
384 pNew);
385 pNext += pIfAddrMsg->ifam_msglen;
386 }
387
388 if (pSdl->sdl_type == IFT_ETHER)
389 {
390 struct ifreq IfReq;
391 strcpy(IfReq.ifr_name, pNew->szShortName);
392 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
393 {
394 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
395 pNew->enmStatus = NETIF_S_UNKNOWN;
396 }
397 else
398 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
399
400 HostNetworkInterfaceType_T enmType;
401 if (strncmp("vboxnet", pNew->szName, 7))
402 enmType = HostNetworkInterfaceType_Bridged;
403 else
404 enmType = HostNetworkInterfaceType_HostOnly;
405
406 ComObjPtr<HostNetworkInterface> IfObj;
407 IfObj.createObject();
408 if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
409 /* Make sure the default interface gets to the beginning. */
410 if (pIfMsg->ifm_index == u16DefaultIface)
411 list.push_front(IfObj);
412 else
413 list.push_back(IfObj);
414 }
415 RTMemFree(pNew);
416 }
417 for (pNIC = pEtherNICs; pNIC;)
418 {
419 void *pvFree = pNIC;
420 pNIC = pNIC->pNext;
421 RTMemFree(pvFree);
422 }
423 close(sock);
424 free(pBuf);
425 return rc;
426}
427
428int NetIfGetConfigByName(PNETIFINFO pInfo)
429{
430 int rc = VINF_SUCCESS;
431 size_t cbNeeded;
432 char *pBuf, *pNext;
433 int aiMib[6];
434
435 aiMib[0] = CTL_NET;
436 aiMib[1] = PF_ROUTE;
437 aiMib[2] = 0;
438 aiMib[3] = 0; /* address family */
439 aiMib[4] = NET_RT_IFLIST;
440 aiMib[5] = 0;
441
442 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
443 {
444 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
445 return RTErrConvertFromErrno(errno);
446 }
447 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
448 return VERR_NO_MEMORY;
449 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
450 {
451 free(pBuf);
452 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
453 return RTErrConvertFromErrno(errno);
454 }
455
456 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
457 if (sock < 0)
458 {
459 free(pBuf);
460 Log(("NetIfList: socket() -> %d\n", errno));
461 return RTErrConvertFromErrno(errno);
462 }
463
464 char *pEnd = pBuf + cbNeeded;
465 for (pNext = pBuf; pNext < pEnd;)
466 {
467 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
468
469 if (pIfMsg->ifm_type != RTM_IFINFO)
470 {
471 Log(("NetIfList: Got message %u while expecting %u.\n",
472 pIfMsg->ifm_type, RTM_IFINFO));
473 rc = VERR_INTERNAL_ERROR;
474 break;
475 }
476 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
477
478 bool fSkip = !!strncmp(pInfo->szShortName, pSdl->sdl_data, pSdl->sdl_nlen)
479 || pInfo->szShortName[pSdl->sdl_nlen] != '\0';
480
481 pNext += pIfMsg->ifm_msglen;
482 while (pNext < pEnd)
483 {
484 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
485
486 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
487 break;
488 if (!fSkip)
489 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
490 (char *)(pIfAddrMsg + 1),
491 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
492 pInfo);
493 pNext += pIfAddrMsg->ifam_msglen;
494 }
495
496 if (!fSkip && pSdl->sdl_type == IFT_ETHER)
497 {
498 size_t cbNameLen = pSdl->sdl_nlen + 1;
499 memcpy(pInfo->MACAddress.au8, LLADDR(pSdl), sizeof(pInfo->MACAddress.au8));
500 pInfo->enmMediumType = NETIF_T_ETHERNET;
501 /* Generate UUID from name and MAC address. */
502 RTUUID uuid;
503 RTUuidClear(&uuid);
504 memcpy(&uuid, pInfo->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
505 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
506 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
507 memcpy(uuid.Gen.au8Node, pInfo->MACAddress.au8, sizeof(uuid.Gen.au8Node));
508 pInfo->Uuid = uuid;
509
510 struct ifreq IfReq;
511 strcpy(IfReq.ifr_name, pInfo->szShortName);
512 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
513 {
514 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
515 pInfo->enmStatus = NETIF_S_UNKNOWN;
516 }
517 else
518 pInfo->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
519
520 return VINF_SUCCESS;
521 }
522 }
523 close(sock);
524 free(pBuf);
525 return rc;
526}
527
528#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