VirtualBox

source: vbox/trunk/src/VBox/Main/freebsd/NetIf-freebsd.cpp@ 28851

Last change on this file since 28851 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: 13.1 KB
Line 
1/* $Id: NetIf-freebsd.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * Main - NetIfList, FreeBSD 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 * Original (C) 2009 Fredrik Lindberg <fli@shapeshifter.se>. Contributed
20 * to VirtualBox under the MIT license by the author.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_MAIN
27#include <sys/types.h>
28
29#include <sys/sysctl.h>
30#include <sys/socket.h>
31#include <sys/sockio.h>
32#include <net/if.h>
33#include <net/if_types.h>
34
35#include <net/route.h>
36/*
37 * route.h includes net/radix.h which for some reason defines Free as a wrapper
38 * around free. This collides with Free defined in xpcom/include/nsIMemory.h
39 * Undefine it and hope for the best
40 */
41#undef Free
42
43#include <net/if_dl.h>
44#include <netinet/in.h>
45
46#include <stdio.h>
47#include <unistd.h>
48#include <errno.h>
49
50#include <list>
51
52#include "HostNetworkInterfaceImpl.h"
53#include "netif.h"
54#include "Logging.h"
55
56#define ROUNDUP(a) \
57 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
58#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
59
60void extractAddresses(int iAddrMask, caddr_t cp, caddr_t cplim, struct sockaddr **pAddresses)
61{
62 struct sockaddr *sa;
63
64 for (int i = 0; i < RTAX_MAX && cp < cplim; i++) {
65 if (!(iAddrMask & (1 << i)))
66 continue;
67
68 sa = (struct sockaddr *)cp;
69
70 pAddresses[i] = sa;
71
72 ADVANCE(cp, sa);
73 }
74}
75
76static int getDefaultIfaceIndex(unsigned short *pu16Index, int family)
77{
78 size_t cbNeeded;
79 char *pBuf, *pNext;
80 int aiMib[6];
81 struct sockaddr *addresses[RTAX_MAX];
82 aiMib[0] = CTL_NET;
83 aiMib[1] = PF_ROUTE;
84 aiMib[2] = 0;
85 aiMib[3] = family; /* address family */
86 aiMib[4] = NET_RT_DUMP;
87 aiMib[5] = 0;
88
89 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
90 {
91 Log(("getDefaultIfaceIndex: Failed to get estimate for list size (errno=%d).\n", errno));
92 return RTErrConvertFromErrno(errno);
93 }
94 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
95 return VERR_NO_MEMORY;
96 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
97 {
98 free(pBuf);
99 Log(("getDefaultIfaceIndex: Failed to retrieve interface table (errno=%d).\n", errno));
100 return RTErrConvertFromErrno(errno);
101 }
102
103 char *pEnd = pBuf + cbNeeded;
104 struct rt_msghdr *pRtMsg;
105 for (pNext = pBuf; pNext < pEnd; pNext += pRtMsg->rtm_msglen)
106 {
107 pRtMsg = (struct rt_msghdr *)pNext;
108
109 if (pRtMsg->rtm_type != RTM_GET)
110 {
111 Log(("getDefaultIfaceIndex: Got message %u while expecting %u.\n",
112 pRtMsg->rtm_type, RTM_GET));
113 //rc = VERR_INTERNAL_ERROR;
114 continue;
115 }
116 if ((char*)(pRtMsg + 1) < pEnd)
117 {
118 /* Extract addresses from the message. */
119 extractAddresses(pRtMsg->rtm_addrs, (char *)(pRtMsg + 1),
120 pRtMsg->rtm_msglen + (char *)pRtMsg, addresses);
121 if ((pRtMsg->rtm_addrs & RTA_DST))
122 {
123 if (addresses[RTAX_DST]->sa_family != AF_INET)
124 continue;
125 struct sockaddr_in *addr = (struct sockaddr_in *)addresses[RTAX_DST];
126 struct sockaddr_in *mask = (struct sockaddr_in *)addresses[RTAX_NETMASK];
127 if ((addr->sin_addr.s_addr == INADDR_ANY) &&
128 mask &&
129 (ntohl(mask->sin_addr.s_addr) == 0L ||
130 mask->sin_len == 0))
131 {
132 *pu16Index = pRtMsg->rtm_index;
133 free(pBuf);
134 return VINF_SUCCESS;
135 }
136 }
137 }
138 }
139 free(pBuf);
140 return VERR_INTERNAL_ERROR;
141
142}
143
144void extractAddressesToNetInfo(int iAddrMask, caddr_t cp, caddr_t cplim, PNETIFINFO pInfo)
145{
146 struct sockaddr *addresses[RTAX_MAX];
147
148 extractAddresses(iAddrMask, cp, cplim, addresses);
149 switch (addresses[RTAX_IFA]->sa_family)
150 {
151 case AF_INET:
152 if (!pInfo->IPAddress.u)
153 {
154 pInfo->IPAddress.u = ((struct sockaddr_in *)addresses[RTAX_IFA])->sin_addr.s_addr;
155 pInfo->IPNetMask.u = ((struct sockaddr_in *)addresses[RTAX_NETMASK])->sin_addr.s_addr;
156 }
157 break;
158 case AF_INET6:
159 if (!pInfo->IPv6Address.s.Lo && !pInfo->IPv6Address.s.Hi)
160 {
161 memcpy(pInfo->IPv6Address.au8,
162 ((struct sockaddr_in6 *)addresses[RTAX_IFA])->sin6_addr.__u6_addr.__u6_addr8,
163 sizeof(pInfo->IPv6Address));
164 memcpy(pInfo->IPv6NetMask.au8,
165 ((struct sockaddr_in6 *)addresses[RTAX_NETMASK])->sin6_addr.__u6_addr.__u6_addr8,
166 sizeof(pInfo->IPv6NetMask));
167 }
168 break;
169 default:
170 Log(("NetIfList: Unsupported address family: %u\n", addresses[RTAX_IFA]->sa_family));
171 break;
172 }
173}
174
175
176int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
177{
178 int rc = VINF_SUCCESS;
179 size_t cbNeeded;
180 char *pBuf, *pNext;
181 int aiMib[6];
182 unsigned short u16DefaultIface;
183
184 /* Get the index of the interface associated with default route. */
185 rc = getDefaultIfaceIndex(&u16DefaultIface, PF_INET);
186 if (RT_FAILURE(rc))
187 return rc;
188
189 aiMib[0] = CTL_NET;
190 aiMib[1] = PF_ROUTE;
191 aiMib[2] = 0;
192 aiMib[3] = 0; /* address family */
193 aiMib[4] = NET_RT_IFLIST;
194 aiMib[5] = 0;
195
196 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
197 {
198 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
199 return RTErrConvertFromErrno(errno);
200 }
201 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
202 return VERR_NO_MEMORY;
203 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
204 {
205 free(pBuf);
206 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
207 return RTErrConvertFromErrno(errno);
208 }
209
210 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
211 if (sock < 0)
212 {
213 free(pBuf);
214 Log(("NetIfList: socket() -> %d\n", errno));
215 return RTErrConvertFromErrno(errno);
216 }
217
218 char *pEnd = pBuf + cbNeeded;
219 for (pNext = pBuf; pNext < pEnd;)
220 {
221 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
222
223 if (pIfMsg->ifm_type != RTM_IFINFO)
224 {
225 Log(("NetIfList: Got message %u while expecting %u.\n",
226 pIfMsg->ifm_type, RTM_IFINFO));
227 rc = VERR_INTERNAL_ERROR;
228 break;
229 }
230 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
231
232 size_t cbNameLen = pSdl->sdl_nlen + 1;
233 PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
234 if (!pNew)
235 {
236 rc = VERR_NO_MEMORY;
237 break;
238 }
239 memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
240 pNew->enmMediumType = NETIF_T_ETHERNET;
241 Assert(sizeof(pNew->szShortName) >= cbNameLen);
242 strlcpy(pNew->szShortName, pSdl->sdl_data, cbNameLen);
243 strlcpy(pNew->szName, pSdl->sdl_data, cbNameLen);
244 /* Generate UUID from name and MAC address. */
245 RTUUID uuid;
246 RTUuidClear(&uuid);
247 memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
248 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
249 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
250 memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
251 pNew->Uuid = uuid;
252
253 pNext += pIfMsg->ifm_msglen;
254 while (pNext < pEnd)
255 {
256 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
257
258 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
259 break;
260 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
261 (char *)(pIfAddrMsg + 1),
262 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
263 pNew);
264 pNext += pIfAddrMsg->ifam_msglen;
265 }
266
267 if (pSdl->sdl_type == IFT_ETHER)
268 {
269 struct ifreq IfReq;
270 strcpy(IfReq.ifr_name, pNew->szShortName);
271 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
272 {
273 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
274 pNew->enmStatus = NETIF_S_UNKNOWN;
275 }
276 else
277 pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
278
279 HostNetworkInterfaceType_T enmType;
280 if (strncmp("vboxnet", pNew->szName, 7))
281 enmType = HostNetworkInterfaceType_Bridged;
282 else
283 enmType = HostNetworkInterfaceType_HostOnly;
284
285 ComObjPtr<HostNetworkInterface> IfObj;
286 IfObj.createObject();
287 if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
288 /* Make sure the default interface gets to the beginning. */
289 if (pIfMsg->ifm_index == u16DefaultIface)
290 list.push_front(IfObj);
291 else
292 list.push_back(IfObj);
293 }
294 RTMemFree(pNew);
295 }
296
297 close(sock);
298 free(pBuf);
299 return rc;
300
301
302}
303
304int NetIfGetConfigByName(PNETIFINFO pInfo)
305{
306 int rc = VINF_SUCCESS;
307 size_t cbNeeded;
308 char *pBuf, *pNext;
309 int aiMib[6];
310
311 aiMib[0] = CTL_NET;
312 aiMib[1] = PF_ROUTE;
313 aiMib[2] = 0;
314 aiMib[3] = 0; /* address family */
315 aiMib[4] = NET_RT_IFLIST;
316 aiMib[5] = 0;
317
318 if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
319 {
320 Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
321 return RTErrConvertFromErrno(errno);
322 }
323 if ((pBuf = (char*)malloc(cbNeeded)) == NULL)
324 return VERR_NO_MEMORY;
325 if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
326 {
327 free(pBuf);
328 Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
329 return RTErrConvertFromErrno(errno);
330 }
331
332 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
333 if (sock < 0)
334 {
335 free(pBuf);
336 Log(("NetIfList: socket() -> %d\n", errno));
337 return RTErrConvertFromErrno(errno);
338 }
339
340 char *pEnd = pBuf + cbNeeded;
341 for (pNext = pBuf; pNext < pEnd;)
342 {
343 struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;
344
345 if (pIfMsg->ifm_type != RTM_IFINFO)
346 {
347 Log(("NetIfList: Got message %u while expecting %u.\n",
348 pIfMsg->ifm_type, RTM_IFINFO));
349 rc = VERR_INTERNAL_ERROR;
350 break;
351 }
352 struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);
353
354 bool fSkip = !!strcmp(pInfo->szShortName, pSdl->sdl_data);
355
356 pNext += pIfMsg->ifm_msglen;
357 while (pNext < pEnd)
358 {
359 struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;
360
361 if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
362 break;
363 if (!fSkip)
364 extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
365 (char *)(pIfAddrMsg + 1),
366 pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
367 pInfo);
368 pNext += pIfAddrMsg->ifam_msglen;
369 }
370
371 if (!fSkip && pSdl->sdl_type == IFT_ETHER)
372 {
373 size_t cbNameLen = pSdl->sdl_nlen + 1;
374 memcpy(pInfo->MACAddress.au8, LLADDR(pSdl), sizeof(pInfo->MACAddress.au8));
375 pInfo->enmMediumType = NETIF_T_ETHERNET;
376 /* Generate UUID from name and MAC address. */
377 RTUUID uuid;
378 RTUuidClear(&uuid);
379 memcpy(&uuid, pInfo->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
380 uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
381 uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
382 memcpy(uuid.Gen.au8Node, pInfo->MACAddress.au8, sizeof(uuid.Gen.au8Node));
383 pInfo->Uuid = uuid;
384
385 struct ifreq IfReq;
386 strcpy(IfReq.ifr_name, pInfo->szShortName);
387 if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
388 {
389 Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
390 pInfo->enmStatus = NETIF_S_UNKNOWN;
391 }
392 else
393 pInfo->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;
394
395 return VINF_SUCCESS;
396 }
397 }
398 close(sock);
399 free(pBuf);
400 return rc;
401}
402
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