VirtualBox

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

Last change on this file since 86714 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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