1 /* $NetBSD: getifaddrs.c,v 1.13 2010/11/05 16:23:56 pooka 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.13 2010/11/05 16:23:56 pooka Exp $");
31 #endif /* LIBC_SCCS and not lint */
34 #include "namespace.h"
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
40 #include <sys/param.h>
41 #include <net/route.h>
42 #include <sys/sysctl.h>
43 #include <net/if_dl.h>
51 #if defined(__weak_alias) && !defined(RUMP_ACTION)
52 __weak_alias(getifaddrs
,_getifaddrs
)
53 __weak_alias(freeifaddrs
,_freeifaddrs
)
57 #include <rump/rump_syscalls.h>
58 #define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f)
61 #define SALIGN (sizeof(long) - 1)
62 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
65 getifaddrs(struct ifaddrs
**pif
)
76 struct rt_msghdr
*rtm
;
77 struct if_msghdr
*ifm
;
78 struct ifa_msghdr
*ifam
;
80 struct ifaddrs
*ifa
, *ift
;
87 _DIAGASSERT(pif
!= NULL
);
91 mib
[2] = 0; /* protocol */
92 mib
[3] = 0; /* wildcard address family */
93 mib
[4] = NET_RT_IFLIST
;
94 mib
[5] = 0; /* no flags */
95 if (sysctl(mib
, __arraycount(mib
), NULL
, &needed
, NULL
, 0) < 0)
97 if ((buf
= malloc(needed
)) == NULL
)
99 if (sysctl(mib
, __arraycount(mib
), buf
, &needed
, NULL
, 0) < 0) {
104 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
105 rtm
= (struct rt_msghdr
*)(void *)next
;
106 if (rtm
->rtm_version
!= RTM_VERSION
)
108 switch (rtm
->rtm_type
) {
110 ifm
= (struct if_msghdr
*)(void *)rtm
;
111 if (ifm
->ifm_addrs
& RTA_IFP
) {
112 const struct sockaddr_dl
*dl
;
114 idx
= ifm
->ifm_index
;
116 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
117 dcnt
+= SA_RLEN((const struct sockaddr
*)(const void *)dl
) +
119 dcnt
+= sizeof(ifm
->ifm_data
);
120 ncnt
+= dl
->sdl_nlen
+ 1;
126 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
127 if (idx
&& ifam
->ifam_index
!= idx
)
128 abort(); /* this cannot happen */
130 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
131 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
133 p
= (char *)(void *)(ifam
+ 1);
135 /* Scan to look for length of address */
137 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
138 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
141 sa
= (struct sockaddr
*)(void *)p
;
149 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
150 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
153 sa
= (struct sockaddr
*)(void *)p
;
155 if (i
== RTAX_NETMASK
&& sa
->sa_len
== 0)
165 if (icnt
+ dcnt
+ ncnt
== 1) {
170 data
= malloc(sizeof(struct ifaddrs
) * icnt
+ dcnt
+ ncnt
);
176 ifa
= (struct ifaddrs
*)(void *)data
;
177 data
+= sizeof(struct ifaddrs
) * icnt
;
180 memset(ifa
, 0, sizeof(struct ifaddrs
) * icnt
);
184 for (next
= buf
; next
< buf
+ needed
; next
+= rtm
->rtm_msglen
) {
185 rtm
= (struct rt_msghdr
*)(void *)next
;
186 if (rtm
->rtm_version
!= RTM_VERSION
)
188 switch (rtm
->rtm_type
) {
190 ifm
= (struct if_msghdr
*)(void *)rtm
;
191 if (ifm
->ifm_addrs
& RTA_IFP
) {
192 const struct sockaddr_dl
*dl
;
194 idx
= ifm
->ifm_index
;
195 dl
= (struct sockaddr_dl
*)(void *)(ifm
+ 1);
197 memset(&cif
, 0, sizeof(cif
));
199 cif
.ifa_name
= names
;
200 cif
.ifa_flags
= (int)ifm
->ifm_flags
;
201 memcpy(names
, dl
->sdl_data
,
202 (size_t)dl
->sdl_nlen
);
203 names
[dl
->sdl_nlen
] = 0;
204 names
+= dl
->sdl_nlen
+ 1;
206 cif
.ifa_addr
= (struct sockaddr
*)(void *)data
;
207 memcpy(data
, dl
, (size_t)dl
->sdl_len
);
208 data
+= SA_RLEN((const struct sockaddr
*)(const void *)dl
);
210 /* ifm_data needs to be aligned */
211 cif
.ifa_data
= data
= (void *)ALIGN(data
);
212 memcpy(data
, &ifm
->ifm_data
, sizeof(ifm
->ifm_data
));
213 data
+= sizeof(ifm
->ifm_data
);
219 ifam
= (struct ifa_msghdr
*)(void *)rtm
;
220 if (idx
&& ifam
->ifam_index
!= idx
)
221 abort(); /* this cannot happen */
223 if (idx
== 0 || (ifam
->ifam_addrs
& RTA_MASKS
) == 0)
225 ift
->ifa_name
= cif
.ifa_name
;
226 ift
->ifa_flags
= cif
.ifa_flags
;
227 ift
->ifa_data
= NULL
;
228 p
= (char *)(void *)(ifam
+ 1);
229 /* Scan to look for length of address */
231 for (p0
= p
, i
= 0; i
< RTAX_MAX
; i
++) {
232 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
235 sa
= (struct sockaddr
*)(void *)p
;
243 for (p
= p0
, i
= 0; i
< RTAX_MAX
; i
++) {
244 if ((RTA_MASKS
& ifam
->ifam_addrs
& (1 << i
))
247 sa
= (struct sockaddr
*)(void *)p
;
252 (struct sockaddr
*)(void *)data
;
253 memcpy(data
, p
, len
);
255 if (ift
->ifa_addr
->sa_family
== AF_LINK
)
256 ift
->ifa_data
= cif
.ifa_data
;
261 (struct sockaddr
*)(void *)data
;
262 if (sa
->sa_len
== 0) {
263 memset(data
, 0, alen
);
267 memcpy(data
, p
, len
);
273 (struct sockaddr
*)(void *)data
;
274 memcpy(data
, p
, len
);
282 ift
= (ift
->ifa_next
= ift
+ 1);
289 ift
->ifa_next
= NULL
;
299 freeifaddrs(struct ifaddrs
*ifp
)
302 _DIAGASSERT(ifp
!= NULL
);