VirtualBox

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

Last change on this file since 53390 was 49718, checked in by vboxsync, 11 years ago

Various FreeBSD fixes submitted Bernhard Froehlich

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