]>
git.saurik.com Git - apple/libinfo.git/blob - gen.subproj/getifaddrs.c
2 * Copyright (c) 1995, 1999
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
12 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
15 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
26 * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
27 * try-and-error for region size.
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <net/route.h>
36 #include <sys/sysctl.h>
37 #include <net/if_dl.h>
42 #include <netinet/in.h>
48 #define SA_LEN(sa) sizeof(struct sockaddr)
52 #define SA_LEN(sa) (sa)->sa_len
55 #define SALIGN (sizeof(int32_t) - 1)
56 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
60 * On systems with a routing socket, ALIGNBYTES should match the value
61 * that the kernel uses when building the messages.
63 #define ALIGNBYTES XXX
66 #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
69 #if _BSDI_VERSION >= 199701
73 #if _BSDI_VERSION >= 199802
74 /* ifam_data is very specific to recent versions of bsdi */
75 #define HAVE_IFAM_DATA
78 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
86 #define MEMORY_MIN 2048
87 #define MEMORY_MAX 16777216
90 getifaddrs(struct ifaddrs
**pif
)
95 struct ifaddrs
*ifa
, *ift
;
96 struct sockaddr_in6
*sin6
;
103 struct ifaddrs
*cif
= 0;
105 struct rt_msghdr
*rtm
;
106 struct if_msghdr
*ifm
;
107 struct ifa_msghdr
*ifam
;
108 struct sockaddr_dl
*dl
;
111 #else /* NET_RT_IFLIST */
117 #endif /* NET_RT_IFLIST */
126 mib
[2] = 0; /* protocol */
127 mib
[3] = 0; /* wildcard address family */
128 mib
[4] = NET_RT_IFLIST
;
129 mib
[5] = 0; /* no flags */
130 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) return (-1);
132 if (needed
< MEMORY_MIN
) needed
= MEMORY_MIN
;
134 if (needed
> MEMORY_MAX
) needed
= MEMORY_MAX
;
138 while (needed
<= MEMORY_MAX
)
140 buf
= malloc(needed
);
141 if (buf
== NULL
) return (-1);
143 status
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
144 if (status
>= 0) break;
157 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
158 rtm
= (struct rt_msghdr
*)next
;
159 if (rtm
->rtm_version
!= RTM_VERSION
)
161 switch (rtm
->rtm_type
) {
163 ifm
= (struct if_msghdr
*)rtm
;
164 if (ifm
->ifm_addrs
& RTA_IFP
) {
165 index
= ifm
->ifm_index
;
167 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
168 dcnt
+= SA_RLEN((struct sockaddr
*)dl
) +
171 dcnt
+= sizeof(ifm
->ifm_data
);
172 #endif /* HAVE_IFM_DATA */
173 ncnt
+= dl
->sdl_nlen
+ 1;
179 ifam
= (struct ifa_msghdr
*)rtm
;
180 if (index
&& ifam
->ifam_index
!= index
)
181 abort(); /* this cannot happen */
183 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
184 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
186 p
= (char *)(ifam
+ 1);
188 #ifdef HAVE_IFAM_DATA
189 dcnt
+= sizeof(ifam
->ifam_data
) + ALIGNBYTES
;
190 #endif /* HAVE_IFAM_DATA */
191 /* Scan to look for length of address */
193 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
194 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
197 sa
= (struct sockaddr
*)p
;
205 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
206 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
209 sa
= (struct sockaddr
*)p
;
211 if (i
== RTAX_NETMASK
&& SA_LEN(sa
) == 0)
220 #else /* NET_RT_IFLIST */
222 ifc
.ifc_len
= sizeof(buf
);
224 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
229 i
= ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
);
237 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
245 ncnt
+= sizeof(ifr
->ifr_name
) + 1;
247 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
249 #endif /* NET_RT_IFLIST */
251 if (icnt
+ dcnt
+ ncnt
== 1) {
256 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
262 ifa
= (struct ifaddrs
*)data
;
263 data
+= sizeof(struct ifaddrs
) * icnt
;
266 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
271 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
272 rtm
= (struct rt_msghdr
*)next
;
273 if (rtm
->rtm_version
!= RTM_VERSION
)
275 switch (rtm
->rtm_type
) {
277 ifm
= (struct if_msghdr
*)rtm
;
278 if (ifm
->ifm_addrs
& RTA_IFP
) {
279 index
= ifm
->ifm_index
;
280 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
283 ift
->ifa_name
= names
;
284 ift
->ifa_flags
= (int)ifm
->ifm_flags
;
285 memcpy(names
, dl
->sdl_data
, dl
->sdl_nlen
);
286 names
[dl
->sdl_nlen
] = 0;
287 names
+= dl
->sdl_nlen
+ 1;
289 ift
->ifa_addr
= (struct sockaddr
*)data
;
290 memcpy(data
, dl
, SA_LEN((struct sockaddr
*)dl
));
291 data
+= SA_RLEN((struct sockaddr
*)dl
);
294 /* ifm_data needs to be aligned */
295 ift
->ifa_data
= data
= (void *)ALIGN(data
);
296 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
297 data
+= sizeof(ifm
->ifm_data
);
298 #else /* HAVE_IFM_DATA */
299 ift
->ifa_data
= NULL
;
300 #endif /* HAVE_IFM_DATA */
302 ift
= (ift
->ifa_next
= ift
+ 1);
308 ifam
= (struct ifa_msghdr
*)rtm
;
309 if (index
&& ifam
->ifam_index
!= index
)
310 abort(); /* this cannot happen */
312 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
314 ift
->ifa_name
= cif
->ifa_name
;
315 ift
->ifa_flags
= cif
->ifa_flags
;
316 ift
->ifa_data
= NULL
;
317 p
= (char *)(ifam
+ 1);
318 /* Scan to look for length of address */
320 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
321 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
324 sa
= (struct sockaddr
*)p
;
332 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
333 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
336 sa
= (struct sockaddr
*)p
;
340 ift
->ifa_addr
= (struct sockaddr
*)data
;
341 memcpy(data
, p
, len
);
347 (struct sockaddr
*)data
;
348 if (SA_LEN(sa
) == 0) {
349 memset(data
, 0, alen
);
353 memcpy(data
, p
, len
);
359 (struct sockaddr
*)data
;
360 memcpy(data
, p
, len
);
367 #ifdef HAVE_IFAM_DATA
368 /* ifam_data needs to be aligned */
369 ift
->ifa_data
= data
= (void *)ALIGN(data
);
370 memcpy(data
, &ifam
->ifam_data
, sizeof(ifam
->ifam_data
));
371 data
+= sizeof(ifam
->ifam_data
);
372 #endif /* HAVE_IFAM_DATA */
374 ift
= (ift
->ifa_next
= ift
+ 1);
380 #else /* NET_RT_IFLIST */
382 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
387 ift
->ifa_name
= names
;
388 names
[sizeof(ifr
->ifr_name
)] = 0;
389 strncpy(names
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
393 ift
->ifa_addr
= (struct sockaddr
*)data
;
395 memcpy(data
, sa
, SA_LEN(sa
));
398 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
399 ift
= (ift
->ifa_next
= ift
+ 1);
401 #endif /* NET_RT_IFLIST */
403 ift
->ifa_next
= NULL
;
410 for (ift
= ifa
; ift
!= NULL
; ift
= ift
->ifa_next
)
412 if (ift
->ifa_addr
->sa_family
== AF_INET6
)
414 sin6
= (struct sockaddr_in6
*)ift
->ifa_addr
;
415 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
))
417 esid
= ntohs(sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
418 sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
419 if (sin6
->sin6_scope_id
== 0) sin6
->sin6_scope_id
= esid
;
428 freeifaddrs(struct ifaddrs
*ifp
)