summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/getifaddrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/getifaddrs.c')
-rw-r--r--src/lib/libc/net/getifaddrs.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/src/lib/libc/net/getifaddrs.c b/src/lib/libc/net/getifaddrs.c
new file mode 100644
index 0000000000..9537405667
--- /dev/null
+++ b/src/lib/libc/net/getifaddrs.c
@@ -0,0 +1,373 @@
1/* $OpenBSD: getifaddrs.c,v 1.1 2000/02/23 06:55:58 itojun Exp $ */
2
3/*
4 * Copyright (c) 1995, 1999
5 * Berkeley Software Design, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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
23 * SUCH DAMAGE.
24 *
25 * BSDI getifaddrs.c,v 2.11 1999/03/15 20:57:20 jch Exp
26 */
27/*
28 * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
29 * try-and-error for region size.
30 */
31#include <sys/types.h>
32#include <sys/ioctl.h>
33#include <sys/socket.h>
34#include <net/if.h>
35#ifdef NET_RT_IFLIST
36#include <sys/param.h>
37#include <net/route.h>
38#include <sys/sysctl.h>
39#include <net/if_dl.h>
40#endif
41
42#include <errno.h>
43#include <ifaddrs.h>
44#include <stdlib.h>
45#include <string.h>
46
47#if !defined(AF_LINK)
48#define SA_LEN(sa) sizeof(struct sockaddr)
49#endif
50
51#if !defined(SA_LEN)
52#define SA_LEN(sa) (sa)->sa_len
53#endif
54
55#define SALIGN (sizeof(long) - 1)
56#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
57
58#ifndef ALIGNBYTES
59/*
60 * On systems with a routing socket, ALIGNBYTES should match the value
61 * that the kernel uses when building the messages.
62 */
63#define ALIGNBYTES XXX
64#endif
65#ifndef ALIGN
66#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
67#endif
68
69#if _BSDI_VERSION >= 199701
70#define HAVE_IFM_DATA
71#endif
72
73#if _BSDI_VERSION >= 199802
74#define HAVE_IFAM_DATA
75#endif
76
77int
78getifaddrs(struct ifaddrs **pif)
79{
80 int icnt = 1;
81 int dcnt = 0;
82 int ncnt = 0;
83#ifdef NET_RT_IFLIST
84 int mib[6];
85 size_t needed;
86 char *buf;
87 char *next;
88 struct ifaddrs *cif = 0;
89 char *p, *p0;
90 struct rt_msghdr *rtm;
91 struct if_msghdr *ifm;
92 struct ifa_msghdr *ifam;
93 struct sockaddr_dl *dl;
94 struct sockaddr *sa;
95 struct ifaddrs *ifa, *ift;
96 u_short index = 0;
97#else /* NET_RT_IFLIST */
98 char buf[1024];
99 int m, sock;
100 struct ifconf ifc;
101 struct ifreq *ifr;
102 struct ifreq *lifr;
103#endif /* NET_RT_IFLIST */
104 int i;
105 size_t len, alen;
106 char *data;
107 char *names;
108
109#ifdef NET_RT_IFLIST
110 mib[0] = CTL_NET;
111 mib[1] = PF_ROUTE;
112 mib[2] = 0; /* protocol */
113 mib[3] = 0; /* wildcard address family */
114 mib[4] = NET_RT_IFLIST;
115 mib[5] = 0; /* no flags */
116 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
117 return (-1);
118 if ((buf = malloc(needed)) == NULL)
119 return (-1);
120 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
121 free(buf);
122 return (-1);
123 }
124
125 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
126 rtm = (struct rt_msghdr *)next;
127 if (rtm->rtm_version != RTM_VERSION)
128 continue;
129 switch (rtm->rtm_type) {
130 case RTM_IFINFO:
131 ifm = (struct if_msghdr *)rtm;
132 if (ifm->ifm_addrs & RTA_IFP) {
133 index = ifm->ifm_index;
134 ++icnt;
135 dl = (struct sockaddr_dl *)(ifm + 1);
136 dcnt += SA_RLEN((struct sockaddr *)dl) +
137 ALIGNBYTES;
138#ifdef HAVE_IFM_DATA
139 dcnt += sizeof(ifm->ifm_data);
140#endif /* HAVE_IFM_DATA */
141 ncnt += dl->sdl_nlen + 1;
142 } else
143 index = 0;
144 break;
145
146 case RTM_NEWADDR:
147 ifam = (struct ifa_msghdr *)rtm;
148 if (index && ifam->ifam_index != index)
149 abort(); /* this cannot happen */
150
151#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
152 if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
153 break;
154 p = (char *)(ifam + 1);
155 ++icnt;
156#ifdef HAVE_IFAM_DATA
157 dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
158#endif /* HAVE_IFAM_DATA */
159 /* Scan to look for length of address */
160 alen = 0;
161 for (p0 = p, i = 0; i < RTAX_MAX; i++) {
162 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
163 == 0)
164 continue;
165 sa = (struct sockaddr *)p;
166 len = SA_RLEN(sa);
167 if (i == RTAX_IFA) {
168 alen = len;
169 break;
170 }
171 p += len;
172 }
173 for (p = p0, i = 0; i < RTAX_MAX; i++) {
174 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
175 == 0)
176 continue;
177 sa = (struct sockaddr *)p;
178 len = SA_RLEN(sa);
179 if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
180 dcnt += alen;
181 else
182 dcnt += len;
183 p += len;
184 }
185 break;
186 }
187 }
188#else /* NET_RT_IFLIST */
189 ifc.ifc_buf = buf;
190 ifc.ifc_len = sizeof(buf);
191
192 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
193 return (-1);
194 i = ioctl(sock, SIOCGIFCONF, (char *)&ifc);
195 close(sock);
196 if (i < 0)
197 return (-1);
198
199 ifr = ifc.ifc_req;
200 lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
201
202 while (ifr < lifr) {
203 struct sockaddr *sa;
204
205 sa = &ifr->ifr_addr;
206 ++icnt;
207 dcnt += SA_RLEN(sa);
208 ncnt += sizeof(ifr->ifr_name) + 1;
209
210 ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
211 }
212#endif /* NET_RT_IFLIST */
213
214 if (icnt + dcnt + ncnt == 1) {
215 *pif = NULL;
216 free(buf);
217 return (0);
218 }
219 data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
220 if (data == NULL) {
221 free(buf);
222 return(-1);
223 }
224
225 ifa = (struct ifaddrs *)data;
226 data += sizeof(struct ifaddrs) * icnt;
227 names = data + dcnt;
228
229 memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
230 ift = ifa;
231
232#ifdef NET_RT_IFLIST
233 index = 0;
234 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
235 rtm = (struct rt_msghdr *)next;
236 if (rtm->rtm_version != RTM_VERSION)
237 continue;
238 switch (rtm->rtm_type) {
239 case RTM_IFINFO:
240 ifm = (struct if_msghdr *)rtm;
241 if (ifm->ifm_addrs & RTA_IFP) {
242 index = ifm->ifm_index;
243 dl = (struct sockaddr_dl *)(ifm + 1);
244
245 cif = ift;
246 ift->ifa_name = names;
247 ift->ifa_flags = (int)ifm->ifm_flags;
248 memcpy(names, dl->sdl_data, dl->sdl_nlen);
249 names[dl->sdl_nlen] = 0;
250 names += dl->sdl_nlen + 1;
251
252 ift->ifa_addr = (struct sockaddr *)data;
253 memcpy(data, dl, SA_LEN((struct sockaddr *)dl));
254 data += SA_RLEN((struct sockaddr *)dl);
255
256#ifdef HAVE_IFM_DATA
257 /* ifm_data needs to be aligned */
258 ift->ifa_data = data = (void *)ALIGN(data);
259 memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
260 data += sizeof(ifm->ifm_data);
261#else /* HAVE_IFM_DATA */
262 ift->ifa_data = NULL;
263#endif /* HAVE_IFM_DATA */
264
265 ift = (ift->ifa_next = ift + 1);
266 } else
267 index = 0;
268 break;
269
270 case RTM_NEWADDR:
271 ifam = (struct ifa_msghdr *)rtm;
272 if (index && ifam->ifam_index != index)
273 abort(); /* this cannot happen */
274
275 if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
276 break;
277 ift->ifa_name = cif->ifa_name;
278 ift->ifa_flags = cif->ifa_flags;
279 ift->ifa_data = NULL;
280 p = (char *)(ifam + 1);
281 /* Scan to look for length of address */
282 alen = 0;
283 for (p0 = p, i = 0; i < RTAX_MAX; i++) {
284 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
285 == 0)
286 continue;
287 sa = (struct sockaddr *)p;
288 len = SA_RLEN(sa);
289 if (i == RTAX_IFA) {
290 alen = len;
291 break;
292 }
293 p += len;
294 }
295 for (p = p0, i = 0; i < RTAX_MAX; i++) {
296 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
297 == 0)
298 continue;
299 sa = (struct sockaddr *)p;
300 len = SA_RLEN(sa);
301 switch (i) {
302 case RTAX_IFA:
303 ift->ifa_addr = (struct sockaddr *)data;
304 memcpy(data, p, len);
305 data += len;
306 break;
307
308 case RTAX_NETMASK:
309 ift->ifa_netmask =
310 (struct sockaddr *)data;
311 if (SA_LEN(sa) == 0) {
312 memset(data, 0, alen);
313 data += alen;
314 break;
315 }
316 memcpy(data, p, len);
317 data += len;
318 break;
319
320 case RTAX_BRD:
321 ift->ifa_broadaddr =
322 (struct sockaddr *)data;
323 memcpy(data, p, len);
324 data += len;
325 break;
326 }
327 p += len;
328 }
329
330#ifdef HAVE_IFAM_DATA
331 /* ifam_data needs to be aligned */
332 ift->ifa_data = data = (void *)ALIGN(data);
333 memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
334 data += sizeof(ifam->ifam_data);
335#endif /* HAVE_IFAM_DATA */
336
337 ift = (ift->ifa_next = ift + 1);
338 break;
339 }
340 }
341
342 free(buf);
343#else /* NET_RT_IFLIST */
344 ifr = ifc.ifc_req;
345 lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
346
347 while (ifr < lifr) {
348 struct sockaddr *sa;
349
350 ift->ifa_name = names;
351 names[sizeof(ifr->ifr_name)] = 0;
352 strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
353 while (*names++)
354 ;
355
356 ift->ifa_addr = (struct sockaddr *)data;
357 sa = &ifr->ifr_addr;
358 memcpy(data, sa, SA_LEN(sa));
359 data += SA_RLEN(sa);
360
361 ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
362 ift = (ift->ifa_next = ift + 1);
363 }
364#endif /* NET_RT_IFLIST */
365 if (--ift >= ifa) {
366 ift->ifa_next = NULL;
367 *pif = ifa;
368 } else {
369 *pif = NULL;
370 free(ifa);
371 }
372 return (0);
373}