]>
git.saurik.com Git - apple/libinfo.git/blob - gen.subproj/getifaddrs.c
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
5 * Copyright (c) 1995, 1999
6 * Berkeley Software Design, Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
29 * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
30 * try-and-error for region size.
32 #include "libinfo_common.h"
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
39 #include <sys/param.h>
40 #include <net/route.h>
41 #include <sys/sysctl.h>
42 #include <net/if_dl.h>
47 #include <netinet/in.h>
53 #define SA_LEN(sa) sizeof(struct sockaddr)
57 #define SA_LEN(sa) (sa)->sa_len
60 #define SALIGN (sizeof(int32_t) - 1)
61 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
65 * On systems with a routing socket, ALIGNBYTES should match the value
66 * that the kernel uses when building the messages.
68 #define ALIGNBYTES XXX
71 #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
74 #if _BSDI_VERSION >= 199701
78 #if _BSDI_VERSION >= 199802
79 /* ifam_data is very specific to recent versions of bsdi */
80 #define HAVE_IFAM_DATA
83 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
91 #define MEMORY_MIN 2048
92 #define MEMORY_MAX 16777216
96 getifaddrs(struct ifaddrs
**pif
)
101 struct ifaddrs
*ifa
, *ift
;
102 struct sockaddr_in6
*sin6
;
109 struct ifaddrs
*cif
= 0;
111 struct rt_msghdr
*rtm
;
112 struct if_msghdr
*ifm
;
113 struct ifa_msghdr
*ifam
;
114 struct sockaddr_dl
*dl
;
117 #else /* NET_RT_IFLIST */
123 #endif /* NET_RT_IFLIST */
132 mib
[2] = 0; /* protocol */
133 mib
[3] = 0; /* wildcard address family */
134 mib
[4] = NET_RT_IFLIST
;
135 mib
[5] = 0; /* no flags */
136 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) return (-1);
138 if (needed
< MEMORY_MIN
) needed
= MEMORY_MIN
;
140 if (needed
> MEMORY_MAX
) needed
= MEMORY_MAX
;
144 while (needed
<= MEMORY_MAX
)
146 buf
= malloc(needed
);
147 if (buf
== NULL
) return (-1);
149 status
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
150 if (status
>= 0) break;
163 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
164 rtm
= (struct rt_msghdr
*)next
;
165 if (rtm
->rtm_version
!= RTM_VERSION
)
167 switch (rtm
->rtm_type
) {
169 ifm
= (struct if_msghdr
*)rtm
;
170 if (ifm
->ifm_addrs
& RTA_IFP
) {
171 index
= ifm
->ifm_index
;
173 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
174 dcnt
+= SA_RLEN((struct sockaddr
*)dl
) +
177 dcnt
+= sizeof(ifm
->ifm_data
);
178 #endif /* HAVE_IFM_DATA */
179 ncnt
+= dl
->sdl_nlen
+ 1;
185 ifam
= (struct ifa_msghdr
*)rtm
;
186 if (index
&& ifam
->ifam_index
!= index
)
187 abort(); /* this cannot happen */
189 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
190 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
192 p
= (char *)(ifam
+ 1);
194 #ifdef HAVE_IFAM_DATA
195 dcnt
+= sizeof(ifam
->ifam_data
) + ALIGNBYTES
;
196 #endif /* HAVE_IFAM_DATA */
197 /* Scan to look for length of address */
199 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
200 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
203 sa
= (struct sockaddr
*)p
;
211 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
212 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
215 sa
= (struct sockaddr
*)p
;
217 if (i
== RTAX_NETMASK
&& SA_LEN(sa
) == 0)
226 #else /* NET_RT_IFLIST */
228 ifc
.ifc_len
= sizeof(buf
);
230 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
235 i
= ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
);
243 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
251 ncnt
+= sizeof(ifr
->ifr_name
) + 1;
253 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
255 #endif /* NET_RT_IFLIST */
257 if (icnt
+ dcnt
+ ncnt
== 1) {
262 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
268 ifa
= (struct ifaddrs
*)data
;
269 data
+= sizeof(struct ifaddrs
) * icnt
;
272 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
277 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
278 rtm
= (struct rt_msghdr
*)next
;
279 if (rtm
->rtm_version
!= RTM_VERSION
)
281 switch (rtm
->rtm_type
) {
283 ifm
= (struct if_msghdr
*)rtm
;
284 if (ifm
->ifm_addrs
& RTA_IFP
) {
285 index
= ifm
->ifm_index
;
286 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
289 ift
->ifa_name
= names
;
290 ift
->ifa_flags
= (int)ifm
->ifm_flags
;
291 memcpy(names
, dl
->sdl_data
, dl
->sdl_nlen
);
292 names
[dl
->sdl_nlen
] = 0;
293 names
+= dl
->sdl_nlen
+ 1;
295 ift
->ifa_addr
= (struct sockaddr
*)data
;
296 memcpy(data
, dl
, SA_LEN((struct sockaddr
*)dl
));
297 data
+= SA_RLEN((struct sockaddr
*)dl
);
300 /* ifm_data needs to be aligned */
301 ift
->ifa_data
= data
= (void *)ALIGN(data
);
302 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
303 data
+= sizeof(ifm
->ifm_data
);
304 #else /* HAVE_IFM_DATA */
305 ift
->ifa_data
= NULL
;
306 #endif /* HAVE_IFM_DATA */
308 ift
= (ift
->ifa_next
= ift
+ 1);
314 ifam
= (struct ifa_msghdr
*)rtm
;
315 if (index
&& ifam
->ifam_index
!= index
)
316 abort(); /* this cannot happen */
318 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
320 ift
->ifa_name
= cif
->ifa_name
;
321 ift
->ifa_flags
= cif
->ifa_flags
;
322 ift
->ifa_data
= NULL
;
323 p
= (char *)(ifam
+ 1);
324 /* Scan to look for length of address */
326 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
327 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
330 sa
= (struct sockaddr
*)p
;
338 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
339 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
342 sa
= (struct sockaddr
*)p
;
346 ift
->ifa_addr
= (struct sockaddr
*)data
;
347 memcpy(data
, p
, len
);
353 (struct sockaddr
*)data
;
354 if (SA_LEN(sa
) == 0) {
355 memset(data
, 0, alen
);
359 memcpy(data
, p
, len
);
365 (struct sockaddr
*)data
;
366 memcpy(data
, p
, len
);
373 #ifdef HAVE_IFAM_DATA
374 /* ifam_data needs to be aligned */
375 ift
->ifa_data
= data
= (void *)ALIGN(data
);
376 memcpy(data
, &ifam
->ifam_data
, sizeof(ifam
->ifam_data
));
377 data
+= sizeof(ifam
->ifam_data
);
378 #endif /* HAVE_IFAM_DATA */
380 ift
= (ift
->ifa_next
= ift
+ 1);
386 #else /* NET_RT_IFLIST */
388 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
393 ift
->ifa_name
= names
;
394 names
[sizeof(ifr
->ifr_name
)] = 0;
395 strncpy(names
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
399 ift
->ifa_addr
= (struct sockaddr
*)data
;
401 memcpy(data
, sa
, SA_LEN(sa
));
404 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
405 ift
= (ift
->ifa_next
= ift
+ 1);
407 #endif /* NET_RT_IFLIST */
409 ift
->ifa_next
= NULL
;
412 for (ift
= ifa
; ift
!= NULL
; ift
= ift
->ifa_next
)
414 if (ift
->ifa_addr
->sa_family
== AF_INET6
)
416 sin6
= (struct sockaddr_in6
*)ift
->ifa_addr
;
417 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
))
419 esid
= ntohs(sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
420 sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
421 if (sin6
->sin6_scope_id
== 0) sin6
->sin6_scope_id
= esid
;
436 freeifaddrs(struct ifaddrs
*ifp
)