1 /* $NetBSD: getifaddrs.c,v 1.11 2007/12/06 22:51:57 dyoung Exp $ */
4 * Copyright (c) 1995, 1999
5 * Berkeley Software Design, Inc. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
28 #include <sys/cdefs.h>
29 #if defined(LIBC_SCCS) && !defined(lint)
30 __RCSID("$NetBSD: getifaddrs.c,v 1.11 2007/12/06 22:51:57 dyoung Exp $");
31 #endif /* LIBC_SCCS and not lint */
33 #include "namespace.h"
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
38 #include <sys/param.h>
39 #include <net/route.h>
40 #include <sys/sysctl.h>
41 #include <net/if_dl.h>
50 __weak_alias(getifaddrs
,_getifaddrs
)
51 __weak_alias(freeifaddrs
,_freeifaddrs
)
54 #define SALIGN (sizeof(long) - 1)
55 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
58 getifaddrs(struct ifaddrs
**pif
)
69 struct rt_msghdr
*rtm
;
70 struct if_msghdr
*ifm
;
71 struct ifa_msghdr
*ifam
;
73 struct ifaddrs
*ifa
, *ift
;
80 _DIAGASSERT(pif
!= NULL
);
84 mib
[2] = 0; /* protocol */
85 mib
[3] = 0; /* wildcard address family */
86 mib
[4] = NET_RT_IFLIST
;
87 mib
[5] = 0; /* no flags */
88 if (sysctl(mib
, __arraycount(mib
), NULL
, &needed
, NULL
, 0) < 0)
90 if ((buf
= malloc(needed
)) == NULL
)
92 if (sysctl(mib
, __arraycount(mib
), buf
, &needed
, NULL
, 0) < 0) {
97 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
98 rtm
= (struct rt_msghdr
*)(void *)next
;
99 if (rtm
->rtm_version
!= RTM_VERSION
)
101 switch (rtm
->rtm_type
) {
103 ifm
= (struct if_msghdr
*)(void *)rtm
;
104 if (ifm
->ifm_addrs
& RTA_IFP
) {
105 const struct sockaddr_dl
*dl
;
107 idx
= ifm
->ifm_index
;
109 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
110 dcnt
+= SA_RLEN((const struct sockaddr
*)(const void *)dl
) +
112 dcnt
+= sizeof(ifm
->ifm_data
);
113 ncnt
+= dl
->sdl_nlen
+ 1;
119 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
120 if (idx
&& ifam
->ifam_index
!= idx
)
121 abort(); /* this cannot happen */
123 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
124 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
126 p
= (char *)(void *)(ifam
+ 1);
128 /* Scan to look for length of address */
130 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
131 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
134 sa
= (struct sockaddr
*)(void *)p
;
142 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
143 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
146 sa
= (struct sockaddr
*)(void *)p
;
148 if (i
== RTAX_NETMASK
&& sa
->sa_len
== 0)
158 if (icnt
+ dcnt
+ ncnt
== 1) {
163 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
169 ifa
= (struct ifaddrs
*)(void *)data
;
170 data
+= sizeof(struct ifaddrs
) * icnt
;
173 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
177 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
178 rtm
= (struct rt_msghdr
*)(void *)next
;
179 if (rtm
->rtm_version
!= RTM_VERSION
)
181 switch (rtm
->rtm_type
) {
183 ifm
= (struct if_msghdr
*)(void *)rtm
;
184 if (ifm
->ifm_addrs
& RTA_IFP
) {
185 const struct sockaddr_dl
*dl
;
187 idx
= ifm
->ifm_index
;
188 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
190 memset(&cif
, 0, sizeof(cif
));
192 cif
.ifa_name
= names
;
193 cif
.ifa_flags
= (int)ifm
->ifm_flags
;
194 memcpy(names
, dl
->sdl_data
,
195 (size_t)dl
->sdl_nlen
);
196 names
[dl
->sdl_nlen
] = 0;
197 names
+= dl
->sdl_nlen
+ 1;
199 cif
.ifa_addr
= (struct sockaddr
*)(void *)data
;
200 memcpy(data
, dl
, (size_t)dl
->sdl_len
);
201 data
+= SA_RLEN((const struct sockaddr
*)(const void *)dl
);
203 /* ifm_data needs to be aligned */
204 cif
.ifa_data
= data
= (void *)ALIGN(data
);
205 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
206 data
+= sizeof(ifm
->ifm_data
);
212 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
213 if (idx
&& ifam
->ifam_index
!= idx
)
214 abort(); /* this cannot happen */
216 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
218 ift
->ifa_name
= cif
.ifa_name
;
219 ift
->ifa_flags
= cif
.ifa_flags
;
220 ift
->ifa_data
= NULL
;
221 p
= (char *)(void *)(ifam
+ 1);
222 /* Scan to look for length of address */
224 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
225 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
228 sa
= (struct sockaddr
*)(void *)p
;
236 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
237 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
240 sa
= (struct sockaddr
*)(void *)p
;
245 (struct sockaddr
*)(void *)data
;
246 memcpy(data
, p
, len
);
248 if (ift
->ifa_addr
->sa_family
== AF_LINK
)
249 ift
->ifa_data
= cif
.ifa_data
;
254 (struct sockaddr
*)(void *)data
;
255 if (sa
->sa_len
== 0) {
256 memset(data
, 0, alen
);
260 memcpy(data
, p
, len
);
266 (struct sockaddr
*)(void *)data
;
267 memcpy(data
, p
, len
);
275 ift
= (ift
->ifa_next
= ift
+ 1);
282 ift
->ifa_next
= NULL
;
292 freeifaddrs(struct ifaddrs
*ifp
)
295 _DIAGASSERT(ifp
!= NULL
);