1 /* $FreeBSD: src/lib/libc/net/getifaddrs.c,v 1.6 2002/07/25 08:08:30 ume Exp $ */
2 /* $DragonFly: src/lib/libc/net/getifaddrs.c,v 1.5 2005/01/31 22:29:33 dillon Exp $ */
3 /* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */
6 * Copyright (c) 1995, 1999
7 * Berkeley Software Design, Inc. All rights reserved.
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.
33 #include "namespace.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>
49 #include "un-namespace.h"
52 #define SA_LEN(sa) sizeof(struct sockaddr)
56 #define SA_LEN(sa) (sa)->sa_len
59 #define SALIGN (sizeof(long) - 1)
60 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
64 * On systems with a routing socket, ALIGNBYTES should match the value
65 * that the kernel uses when building the messages.
67 #define ALIGNBYTES XXX
70 #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
73 #if _BSDI_VERSION >= 199701
77 #if _BSDI_VERSION >= 199802
78 /* ifam_data is very specific to recent versions of bsdi */
79 #define HAVE_IFAM_DATA
82 #if defined(__NetBSD__) || defined(__OpenBSD__) || \
83 defined(__FreeBSD__) || defined(__DragonFly__)
87 #define MAX_SYSCTL_TRY 5
90 getifaddrs(struct ifaddrs
**pif
)
101 struct ifaddrs
*cif
= 0;
103 struct rt_msghdr
*rtm
;
104 struct if_msghdr
*ifm
;
105 struct ifa_msghdr
*ifam
;
106 struct sockaddr_dl
*dl
;
108 struct ifaddrs
*ifa
, *ift
;
110 #else /* NET_RT_IFLIST */
116 #endif /* NET_RT_IFLIST */
125 mib
[2] = 0; /* protocol */
126 mib
[3] = 0; /* wildcard address family */
127 mib
[4] = NET_RT_IFLIST
;
128 mib
[5] = 0; /* no flags */
131 * We'll try to get addresses several times in case that
132 * the number of addresses is unexpectedly increased during
133 * the two sysctl calls. This should rarely happen, but we'll
134 * try to do our best for applications that assume success of
135 * this library (which should usually be the case).
136 * Portability note: since FreeBSD does not add margin of
137 * memory at the first sysctl, the possibility of failure on
138 * the second sysctl call is a bit higher.
141 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
143 if ((buf
= malloc(needed
)) == NULL
)
145 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
146 if (errno
!= ENOMEM
|| ++ntry
>= MAX_SYSCTL_TRY
) {
153 } while (buf
== NULL
);
155 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
156 rtm
= (struct rt_msghdr
*)(void *)next
;
157 if (rtm
->rtm_version
!= RTM_VERSION
)
159 switch (rtm
->rtm_type
) {
161 ifm
= (struct if_msghdr
*)(void *)rtm
;
162 if (ifm
->ifm_addrs
& RTA_IFP
) {
163 idx
= ifm
->ifm_index
;
165 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
166 dcnt
+= SA_RLEN((struct sockaddr
*)(void*)dl
) +
169 dcnt
+= sizeof(ifm
->ifm_data
);
170 #endif /* HAVE_IFM_DATA */
171 ncnt
+= dl
->sdl_nlen
+ 1;
177 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
178 if (idx
&& ifam
->ifam_index
!= idx
)
179 abort(); /* this cannot happen */
181 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
182 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
184 p
= (char *)(void *)(ifam
+ 1);
186 #ifdef HAVE_IFAM_DATA
187 dcnt
+= sizeof(ifam
->ifam_data
) + ALIGNBYTES
;
188 #endif /* HAVE_IFAM_DATA */
189 /* Scan to look for length of address */
191 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
192 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
195 sa
= (struct sockaddr
*)(void *)p
;
203 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
204 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
207 sa
= (struct sockaddr
*)(void *)p
;
209 if (i
== RTAX_NETMASK
&& SA_LEN(sa
) == 0)
218 #else /* NET_RT_IFLIST */
220 ifc
.ifc_len
= sizeof(buf
);
222 if ((sock
= _socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
224 i
= _ioctl(sock
, SIOCGIFCONF
, (char *)&ifc
);
230 lifr
= (struct ifreq
*)&ifc
.ifc_buf
[ifc
.ifc_len
];
238 ncnt
+= sizeof(ifr
->ifr_name
) + 1;
240 if (SA_LEN(sa
) < sizeof(*sa
))
241 ifr
= (struct ifreq
*)(((char *)sa
) + sizeof(*sa
));
243 ifr
= (struct ifreq
*)(((char *)sa
) + SA_LEN(sa
));
245 #endif /* NET_RT_IFLIST */
247 if (icnt
+ dcnt
+ ncnt
== 1) {
252 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
258 ifa
= (struct ifaddrs
*)(void *)data
;
259 data
+= sizeof(struct ifaddrs
) * icnt
;
262 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
267 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
268 rtm
= (struct rt_msghdr
*)(void *)next
;
269 if (rtm
->rtm_version
!= RTM_VERSION
)
271 switch (rtm
->rtm_type
) {
273 ifm
= (struct if_msghdr
*)(void *)rtm
;
274 if (ifm
->ifm_addrs
& RTA_IFP
) {
275 idx
= ifm
->ifm_index
;
276 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
279 ift
->ifa_name
= names
;
280 ift
->ifa_flags
= (int)ifm
->ifm_flags
;
281 memcpy(names
, dl
->sdl_data
,
282 (size_t)dl
->sdl_nlen
);
283 names
[dl
->sdl_nlen
] = 0;
284 names
+= dl
->sdl_nlen
+ 1;
286 ift
->ifa_addr
= (struct sockaddr
*)(void *)data
;
288 (size_t)SA_LEN((struct sockaddr
*)
290 data
+= SA_RLEN((struct sockaddr
*)(void *)dl
);
293 /* ifm_data needs to be aligned */
294 ift
->ifa_data
= data
= (void *)ALIGN(data
);
295 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
296 data
+= sizeof(ifm
->ifm_data
);
297 #else /* HAVE_IFM_DATA */
298 ift
->ifa_data
= NULL
;
299 #endif /* HAVE_IFM_DATA */
301 ift
= (ift
->ifa_next
= ift
+ 1);
307 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
308 if (idx
&& ifam
->ifam_index
!= idx
)
309 abort(); /* this cannot happen */
311 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
313 ift
->ifa_name
= cif
->ifa_name
;
314 ift
->ifa_flags
= cif
->ifa_flags
;
315 ift
->ifa_data
= NULL
;
316 p
= (char *)(void *)(ifam
+ 1);
317 /* Scan to look for length of address */
319 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
320 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
323 sa
= (struct sockaddr
*)(void *)p
;
331 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
332 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
335 sa
= (struct sockaddr
*)(void *)p
;
340 (struct sockaddr
*)(void *)data
;
341 memcpy(data
, p
, len
);
347 (struct sockaddr
*)(void *)data
;
348 if (SA_LEN(sa
) == 0) {
349 memset(data
, 0, alen
);
353 memcpy(data
, p
, len
);
359 (struct sockaddr
*)(void *)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
;
413 freeifaddrs(struct ifaddrs
*ifp
)