1 /* $KAME: getifaddrs.c,v 1.9 2005/11/14 16:53:20 sonic Exp $ */
4 * Copyright (c) 1995, 1999
5 * Berkeley Software Design, Inc. All rights reserved.
6 * Copyright (c) 2005 - 2006
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
30 * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
31 * try-and-error for region size.
35 #include <sys/cdefs.h>
36 #include <sys/types.h>
37 #include <sys/sockio.h>
38 #include <sys/socket.h>
44 #include <sys/param.h>
45 #include <net/route.h>
46 #include <sys/sysctl.h>
47 #include <net/if_dl.h>
51 #include <api/amiga_api.h>
52 #include <api/ifaddrs.h>
58 #define SA_LEN(sa) sizeof(struct sockaddr)
62 #define SA_LEN(sa) (sa)->sa_len
65 #define SALIGN (sizeof(long) - 1)
66 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
70 * On systems with a routing socket, ALIGNBYTES should match the value
71 * that the kernel uses when building the messages.
73 #define ALIGNBYTES XXX
76 #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
79 #if _BSDI_VERSION >= 199701
83 #if _BSDI_VERSION >= 199802
84 /* ifam_data is very specific to recent versions of bsdi */
85 #define HAVE_IFAM_DATA
88 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
92 #define MAX_SYSCTL_TRY 5
95 getifaddrs(struct ifaddrs
**pif
, struct SocketBase
*SocketBase
)
106 struct ifaddrs
*cif
= 0;
108 struct rt_msghdr
*rtm
;
109 struct if_msghdr
*ifm
;
110 struct ifa_msghdr
*ifam
;
111 struct sockaddr_dl
*dl
;
115 #else /* NET_RT_IFLIST */
122 #endif /* NET_RT_IFLIST */
123 struct ifaddrs
*ifa
, *ift
;
125 __unused
size_t len
, alen
;
132 mib
[2] = 0; /* protocol */
133 mib
[3] = 0; /* wildcard address family */
134 mib
[4] = NET_RT_IFLIST
;
135 mib
[5] = 0; /* no flags */
138 * We'll try to get addresses several times in case that
139 * the number of addresses is unexpectedly increased during
140 * the two sysctl calls. This should rarely happen, but we'll
141 * try to do our best for applications that assume success of
142 * this library (which should usually be the case).
143 * Portability note: since FreeBSD does not add margin of
144 * memory at the first sysctl, the possibility of failure on
145 * the second sysctl call is a bit higher.
148 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
150 if ((buf
= bsd_malloc(needed
, NULL
, NULL
)) == NULL
)
152 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
153 errno
= readErrnoValue(SocketBase
);
154 if (errno
!= ENOMEM
|| ++ntry
>= MAX_SYSCTL_TRY
) {
161 } while (buf
== NULL
);
163 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
164 rtm
= (struct rt_msghdr
*)(void *)next
;
165 if (rtm
->rtm_version
!= RTM_VERSION
)
167 switch (rtm
->rtm_type
) {
169 ifm
= (struct if_msghdr
*)(void *)rtm
;
170 if (ifm
->ifm_addrs
& RTA_IFP
) {
171 idx
= ifm
->ifm_index
;
173 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
174 dcnt
+= SA_RLEN((struct sockaddr
*)(void*)dl
) +
177 dcnt
+= sizeof(ifm
->ifm_data
);
178 #endif /* HAVE_IFM_DATA */
179 ncnt
+= dl
->sdl_nlen
+ 1;
185 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
186 if (idx
&& ifam
->ifam_index
!= idx
)
187 abort(); /* this cannot happen */
189 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
190 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
192 p
= (char *)(void *)(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
*)(void *)p
;
211 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
212 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
215 sa
= (struct sockaddr
*)(void *)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, SocketBase
)) < 0)
232 i
= __IoctlSocket(sock
, SIOCGIFCONF
, (char *)&ifc
, SocketBase
);
233 __CloseSocket(sock
, SocketBase
);
238 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
246 ncnt
+= sizeof(ifr
->ifr_name
) + 1;
248 if (SA_LEN(sa
) < sizeof(*sa
))
249 ifr
= (struct ifreq
*)(((char *)sa
) + sizeof(*sa
));
251 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
253 #endif /* NET_RT_IFLIST */
255 if (icnt
+ dcnt
+ ncnt
== 1) {
260 data
= bsd_malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
, NULL
, NULL
);
266 ifa
= (struct ifaddrs
*)(void *)data
;
267 data
+= sizeof(struct ifaddrs
) * icnt
;
270 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
275 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
276 rtm
= (struct rt_msghdr
*)(void *)next
;
277 if (rtm
->rtm_version
!= RTM_VERSION
)
279 switch (rtm
->rtm_type
) {
281 ifm
= (struct if_msghdr
*)(void *)rtm
;
282 if (ifm
->ifm_addrs
& RTA_IFP
) {
283 idx
= ifm
->ifm_index
;
284 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
287 ift
->ifa_name
= names
;
288 ift
->ifa_flags
= (int)ifm
->ifm_flags
;
289 memcpy(names
, dl
->sdl_data
,
290 (size_t)dl
->sdl_nlen
);
291 names
[dl
->sdl_nlen
] = 0;
292 names
+= dl
->sdl_nlen
+ 1;
294 ift
->ifa_addr
= (struct sockaddr
*)(void *)data
;
296 (size_t)SA_LEN((struct sockaddr
*)
298 data
+= SA_RLEN((struct sockaddr
*)(void *)dl
);
301 /* ifm_data needs to be aligned */
302 ift
->ifa_data
= data
= (void *)ALIGN(data
);
303 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
304 data
+= sizeof(ifm
->ifm_data
);
305 #else /* HAVE_IFM_DATA */
306 ift
->ifa_data
= NULL
;
307 #endif /* HAVE_IFM_DATA */
309 ift
= (ift
->ifa_next
= ift
+ 1);
315 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
316 if (idx
&& ifam
->ifam_index
!= idx
)
317 abort(); /* this cannot happen */
319 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
321 ift
->ifa_name
= cif
->ifa_name
;
322 ift
->ifa_flags
= cif
->ifa_flags
;
323 ift
->ifa_data
= NULL
;
324 p
= (char *)(void *)(ifam
+ 1);
325 /* Scan to look for length of address */
327 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
328 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
331 sa
= (struct sockaddr
*)(void *)p
;
339 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
340 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
343 sa
= (struct sockaddr
*)(void *)p
;
348 (struct sockaddr
*)(void *)data
;
349 memcpy(data
, p
, len
);
355 (struct sockaddr
*)(void *)data
;
356 if (SA_LEN(sa
) == 0) {
357 memset(data
, 0, alen
);
361 memcpy(data
, p
, len
);
367 (struct sockaddr
*)(void *)data
;
368 memcpy(data
, p
, len
);
375 #ifdef HAVE_IFAM_DATA
376 /* ifam_data needs to be aligned */
377 ift
->ifa_data
= data
= (void *)ALIGN(data
);
378 memcpy(data
, &ifam
->ifam_data
, sizeof(ifam
->ifam_data
));
379 data
+= sizeof(ifam
->ifam_data
);
380 #endif /* HAVE_IFAM_DATA */
382 ift
= (ift
->ifa_next
= ift
+ 1);
388 #else /* NET_RT_IFLIST */
390 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
395 ift
->ifa_name
= names
;
396 names
[sizeof(ifr
->ifr_name
)] = 0;
397 strncpy(names
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
401 ift
->ifa_addr
= (struct sockaddr
*)data
;
403 memcpy(data
, sa
, SA_LEN(sa
));
406 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
407 ift
= (ift
->ifa_next
= ift
+ 1);
409 #endif /* NET_RT_IFLIST */
411 ift
->ifa_next
= NULL
;
421 freeifaddrs(struct ifaddrs
*ifp
)