VirtualBox

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

Last change on this file since 25414 was 23400, checked in by vboxsync, 15 years ago

Filemuncher fixes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use