]>
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 4194304
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
;
135 while (needed
<= MEMORY_MAX
)
137 buf
= malloc(needed
);
138 if (buf
== NULL
) return (-1);
140 status
= sysctl(mib
, 6, buf
, &needed
, NULL
, 0);
141 if (status
>= 0) break;
148 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
149 rtm
= (struct rt_msghdr
*)next
;
150 if (rtm
->rtm_version
!= RTM_VERSION
)
152 switch (rtm
->rtm_type
) {
154 ifm
= (struct if_msghdr
*)rtm
;
155 if (ifm
->ifm_addrs
& RTA_IFP
) {
156 index
= ifm
->ifm_index
;
158 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
159 dcnt
+= SA_RLEN((struct sockaddr
*)dl
) +
162 dcnt
+= sizeof(ifm
->ifm_data
);
163 #endif /* HAVE_IFM_DATA */
164 ncnt
+= dl
->sdl_nlen
+ 1;
170 ifam
= (struct ifa_msghdr
*)rtm
;
171 if (index
&& ifam
->ifam_index
!= index
)
172 abort(); /* this cannot happen */
174 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
175 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
177 p
= (char *)(ifam
+ 1);
179 #ifdef HAVE_IFAM_DATA
180 dcnt
+= sizeof(ifam
->ifam_data
) + ALIGNBYTES
;
181 #endif /* HAVE_IFAM_DATA */
182 /* Scan to look for length of address */
184 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
185 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
188 sa
= (struct sockaddr
*)p
;
196 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
197 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
200 sa
= (struct sockaddr
*)p
;
202 if (i
== RTAX_NETMASK
&& SA_LEN(sa
) == 0)
211 #else /* NET_RT_IFLIST */
213 ifc
.ifc_len
= sizeof(buf
);
215 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
220 i
= ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
);
228 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
236 ncnt
+= sizeof(ifr
->ifr_name
) + 1;
238 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
240 #endif /* NET_RT_IFLIST */
242 if (icnt
+ dcnt
+ ncnt
== 1) {
247 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
253 ifa
= (struct ifaddrs
*)data
;
254 data
+= sizeof(struct ifaddrs
) * icnt
;
257 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
262 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
263 rtm
= (struct rt_msghdr
*)next
;
264 if (rtm
->rtm_version
!= RTM_VERSION
)
266 switch (rtm
->rtm_type
) {
268 ifm
= (struct if_msghdr
*)rtm
;
269 if (ifm
->ifm_addrs
& RTA_IFP
) {
270 index
= ifm
->ifm_index
;
271 dl
= (struct sockaddr_dl
*)(ifm
+ 1);
274 ift
->ifa_name
= names
;
275 ift
->ifa_flags
= (int)ifm
->ifm_flags
;
276 memcpy(names
, dl
->sdl_data
, dl
->sdl_nlen
);
277 names
[dl
->sdl_nlen
] = 0;
278 names
+= dl
->sdl_nlen
+ 1;
280 ift
->ifa_addr
= (struct sockaddr
*)data
;
281 memcpy(data
, dl
, SA_LEN((struct sockaddr
*)dl
));
282 data
+= SA_RLEN((struct sockaddr
*)dl
);
285 /* ifm_data needs to be aligned */
286 ift
->ifa_data
= data
= (void *)ALIGN(data
);
287 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
288 data
+= sizeof(ifm
->ifm_data
);
289 #else /* HAVE_IFM_DATA */
290 ift
->ifa_data
= NULL
;
291 #endif /* HAVE_IFM_DATA */
293 ift
= (ift
->ifa_next
= ift
+ 1);
299 ifam
= (struct ifa_msghdr
*)rtm
;
300 if (index
&& ifam
->ifam_index
!= index
)
301 abort(); /* this cannot happen */
303 if (index
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
305 ift
->ifa_name
= cif
->ifa_name
;
306 ift
->ifa_flags
= cif
->ifa_flags
;
307 ift
->ifa_data
= NULL
;
308 p
= (char *)(ifam
+ 1);
309 /* Scan to look for length of address */
311 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
312 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
315 sa
= (struct sockaddr
*)p
;
323 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
324 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
327 sa
= (struct sockaddr
*)p
;
331 ift
->ifa_addr
= (struct sockaddr
*)data
;
332 memcpy(data
, p
, len
);
338 (struct sockaddr
*)data
;
339 if (SA_LEN(sa
) == 0) {
340 memset(data
, 0, alen
);
344 memcpy(data
, p
, len
);
350 (struct sockaddr
*)data
;
351 memcpy(data
, p
, len
);
358 #ifdef HAVE_IFAM_DATA
359 /* ifam_data needs to be aligned */
360 ift
->ifa_data
= data
= (void *)ALIGN(data
);
361 memcpy(data
, &ifam
->ifam_data
, sizeof(ifam
->ifam_data
));
362 data
+= sizeof(ifam
->ifam_data
);
363 #endif /* HAVE_IFAM_DATA */
365 ift
= (ift
->ifa_next
= ift
+ 1);
371 #else /* NET_RT_IFLIST */
373 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
378 ift
->ifa_name
= names
;
379 names
[sizeof(ifr
->ifr_name
)] = 0;
380 strncpy(names
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
384 ift
->ifa_addr
= (struct sockaddr
*)data
;
386 memcpy(data
, sa
, SA_LEN(sa
));
389 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
390 ift
= (ift
->ifa_next
= ift
+ 1);
392 #endif /* NET_RT_IFLIST */
394 ift
->ifa_next
= NULL
;
401 for (ift
= ifa
; ift
!= NULL
; ift
= ift
->ifa_next
)
403 if (ift
->ifa_addr
->sa_family
== AF_INET6
)
405 sin6
= (struct sockaddr_in6
*)ift
->ifa_addr
;
406 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
))
408 esid
= ntohs(sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
409 sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
410 if (sin6
->sin6_scope_id
== 0) sin6
->sin6_scope_id
= esid
;
419 freeifaddrs(struct ifaddrs
*ifp
)