VirtualBox

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

Last change on this file since 73097 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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