source: rtems/cpukit/libnetworking/libc/getifaddrs.c @ ee613aa

4.115
Last change on this file since ee613aa was ee613aa, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/24/11 at 09:36:14

Include <sys/cdefs.h> (Eliminate rtems/bsd/sys/cdefs.h).

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*      $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 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.12 2000/02/23 14:51:59 dab 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
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <sys/cdefs.h>
37
38#include <sys/types.h>
39#include <sys/ioctl.h>
40#include <sys/socket.h>
41#include <net/if.h>
42#ifdef  NET_RT_IFLIST
43#include <sys/param.h>
44#include <net/route.h>
45#include <sys/sysctl.h>
46#include <net/if_dl.h>
47#endif
48
49#include <errno.h>
50#include <ifaddrs.h>
51#include <stdlib.h>
52#include <string.h>
53
54#if !defined(AF_LINK)
55#define SA_LEN(sa)      sizeof(struct sockaddr)
56#endif
57
58#if !defined(SA_LEN)
59#define SA_LEN(sa)      (sa)->sa_len
60#endif
61
62#define SALIGN  (sizeof(long) - 1)
63#define SA_RLEN(sa)     ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
64
65#ifndef ALIGNBYTES
66/*
67 * On systems with a routing socket, ALIGNBYTES should match the value
68 * that the kernel uses when building the messages.
69 */
70#define ALIGNBYTES      XXX
71#endif
72#ifndef ALIGN
73#define ALIGN(p)        (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
74#endif
75
76#if     _BSDI_VERSION >= 199701
77#define HAVE_IFM_DATA
78#endif
79
80#if     _BSDI_VERSION >= 199802
81/* ifam_data is very specific to recent versions of bsdi */
82#define HAVE_IFAM_DATA
83#endif
84
85#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
86#define HAVE_IFM_DATA
87#endif
88
89#define MAX_SYSCTL_TRY 5
90
91int
92getifaddrs(struct ifaddrs **pif)
93{
94        int icnt = 1;
95        int dcnt = 0;
96        int ncnt = 0;
97#ifdef  NET_RT_IFLIST
98        int ntry = 0;
99        int mib[6];
100        size_t needed;
101        char *buf;
102        char *next;
103        struct ifaddrs *cif = 0;
104        char *p, *p0;
105        struct rt_msghdr *rtm;
106        struct if_msghdr *ifm;
107        struct ifa_msghdr *ifam;
108        struct sockaddr_dl *dl;
109        struct sockaddr *sa;
110        struct ifaddrs *ifa, *ift;
111        u_short idx = 0;
112#else   /* NET_RT_IFLIST */
113        char buf[1024];
114        int m, sock;
115        struct ifconf ifc;
116        struct ifreq *ifr;
117        struct ifreq *lifr;
118#endif  /* NET_RT_IFLIST */
119        int i;
120        size_t len, alen;
121        char *data;
122        char *names;
123
124#ifdef  NET_RT_IFLIST
125        mib[0] = CTL_NET;
126        mib[1] = PF_ROUTE;
127        mib[2] = 0;             /* protocol */
128        mib[3] = 0;             /* wildcard address family */
129        mib[4] = NET_RT_IFLIST;
130        mib[5] = 0;             /* no flags */
131        do {
132                /*
133                 * We'll try to get addresses several times in case that
134                 * the number of addresses is unexpectedly increased during
135                 * the two sysctl calls.  This should rarely happen, but we'll
136                 * try to do our best for applications that assume success of
137                 * this library (which should usually be the case).
138                 * Portability note: since FreeBSD does not add margin of
139                 * memory at the first sysctl, the possibility of failure on
140                 * the second sysctl call is a bit higher.
141                 */
142
143                if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
144                        return (-1);
145                if ((buf = malloc(needed)) == NULL)
146                        return (-1);
147                if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
148                        if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
149                                free(buf);
150                                return (-1);
151                        }
152                        free(buf);
153                        buf = NULL;
154                }
155        } while (buf == NULL);
156
157        for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
158                rtm = (struct rt_msghdr *)(void *)next;
159                if (rtm->rtm_version != RTM_VERSION)
160                        continue;
161                switch (rtm->rtm_type) {
162                case RTM_IFINFO:
163                        ifm = (struct if_msghdr *)(void *)rtm;
164                        if (ifm->ifm_addrs & RTA_IFP) {
165                                idx = ifm->ifm_index;
166                                ++icnt;
167                                dl = (struct sockaddr_dl *)(void *)(ifm + 1);
168                                dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
169                                    ALIGNBYTES;
170#ifdef  HAVE_IFM_DATA
171                                dcnt += sizeof(ifm->ifm_data);
172#endif  /* HAVE_IFM_DATA */
173                                ncnt += dl->sdl_nlen + 1;
174                        } else
175                                idx = 0;
176                        break;
177
178                case RTM_NEWADDR:
179                        ifam = (struct ifa_msghdr *)(void *)rtm;
180                        if (idx && ifam->ifam_index != idx)
181                                abort();        /* this cannot happen */
182
183#define RTA_MASKS       (RTA_NETMASK | RTA_IFA | RTA_BRD)
184                        if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
185                                break;
186                        p = (char *)(void *)(ifam + 1);
187                        ++icnt;
188#ifdef  HAVE_IFAM_DATA
189                        dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
190#endif  /* HAVE_IFAM_DATA */
191                        /* Scan to look for length of address */
192                        alen = 0;
193                        for (p0 = p, i = 0; i < RTAX_MAX; i++) {
194                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
195                                    == 0)
196                                        continue;
197                                sa = (struct sockaddr *)(void *)p;
198                                len = SA_RLEN(sa);
199                                if (i == RTAX_IFA) {
200                                        alen = len;
201                                        break;
202                                }
203                                p += len;
204                        }
205                        for (p = p0, i = 0; i < RTAX_MAX; i++) {
206                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
207                                    == 0)
208                                        continue;
209                                sa = (struct sockaddr *)(void *)p;
210                                len = SA_RLEN(sa);
211                                if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
212                                        dcnt += alen;
213                                else
214                                        dcnt += len;
215                                p += len;
216                        }
217                        break;
218                }
219        }
220#else   /* NET_RT_IFLIST */
221        ifc.ifc_buf = buf;
222        ifc.ifc_len = sizeof(buf);
223
224        if ((sock = _socket(AF_INET, SOCK_STREAM, 0)) < 0)
225                return (-1);
226        i =  _ioctl(sock, SIOCGIFCONF, (char *)&ifc);
227        _close(sock);
228        if (i < 0)
229                return (-1);
230
231        ifr = ifc.ifc_req;
232        lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
233
234        while (ifr < lifr) {
235                struct sockaddr *sa;
236
237                sa = &ifr->ifr_addr;
238                ++icnt;
239                dcnt += SA_RLEN(sa);
240                ncnt += sizeof(ifr->ifr_name) + 1;
241               
242                if (SA_LEN(sa) < sizeof(*sa))
243                        ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
244                else
245                        ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
246        }
247#endif  /* NET_RT_IFLIST */
248
249        if (icnt + dcnt + ncnt == 1) {
250                *pif = NULL;
251                free(buf);
252                return (0);
253        }
254        data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
255        if (data == NULL) {
256                free(buf);
257                return(-1);
258        }
259
260        ifa = (struct ifaddrs *)(void *)data;
261        data += sizeof(struct ifaddrs) * icnt;
262        names = data + dcnt;
263
264        memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
265        ift = ifa;
266
267#ifdef  NET_RT_IFLIST
268        idx = 0;
269        for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
270                rtm = (struct rt_msghdr *)(void *)next;
271                if (rtm->rtm_version != RTM_VERSION)
272                        continue;
273                switch (rtm->rtm_type) {
274                case RTM_IFINFO:
275                        ifm = (struct if_msghdr *)(void *)rtm;
276                        if (ifm->ifm_addrs & RTA_IFP) {
277                                idx = ifm->ifm_index;
278                                dl = (struct sockaddr_dl *)(void *)(ifm + 1);
279
280                                cif = ift;
281                                ift->ifa_name = names;
282                                ift->ifa_flags = (int)ifm->ifm_flags;
283                                memcpy(names, dl->sdl_data,
284                                    (size_t)dl->sdl_nlen);
285                                names[dl->sdl_nlen] = 0;
286                                names += dl->sdl_nlen + 1;
287
288                                ift->ifa_addr = (struct sockaddr *)(void *)data;
289                                memcpy(data, dl,
290                                    (size_t)SA_LEN((struct sockaddr *)
291                                    (void *)dl));
292                                data += SA_RLEN((struct sockaddr *)(void *)dl);
293
294#ifdef  HAVE_IFM_DATA
295                                /* ifm_data needs to be aligned */
296                                ift->ifa_data = data = (void *)ALIGN(data);
297                                memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
298                                data += sizeof(ifm->ifm_data);
299#else   /* HAVE_IFM_DATA */
300                                ift->ifa_data = NULL;
301#endif  /* HAVE_IFM_DATA */
302
303                                ift = (ift->ifa_next = ift + 1);
304                        } else
305                                idx = 0;
306                        break;
307
308                case RTM_NEWADDR:
309                        ifam = (struct ifa_msghdr *)(void *)rtm;
310                        if (idx && ifam->ifam_index != idx)
311                                abort();        /* this cannot happen */
312
313                        if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
314                                break;
315                        ift->ifa_name = cif->ifa_name;
316                        ift->ifa_flags = cif->ifa_flags;
317                        ift->ifa_data = NULL;
318                        p = (char *)(void *)(ifam + 1);
319                        /* Scan to look for length of address */
320                        alen = 0;
321                        for (p0 = p, i = 0; i < RTAX_MAX; i++) {
322                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
323                                    == 0)
324                                        continue;
325                                sa = (struct sockaddr *)(void *)p;
326                                len = SA_RLEN(sa);
327                                if (i == RTAX_IFA) {
328                                        alen = len;
329                                        break;
330                                }
331                                p += len;
332                        }
333                        for (p = p0, i = 0; i < RTAX_MAX; i++) {
334                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
335                                    == 0)
336                                        continue;
337                                sa = (struct sockaddr *)(void *)p;
338                                len = SA_RLEN(sa);
339                                switch (i) {
340                                case RTAX_IFA:
341                                        ift->ifa_addr =
342                                            (struct sockaddr *)(void *)data;
343                                        memcpy(data, p, len);
344                                        data += len;
345                                        break;
346
347                                case RTAX_NETMASK:
348                                        ift->ifa_netmask =
349                                            (struct sockaddr *)(void *)data;
350                                        if (SA_LEN(sa) == 0) {
351                                                memset(data, 0, alen);
352                                                data += alen;
353                                                break;
354                                        }
355                                        memcpy(data, p, len);
356                                        data += len;
357                                        break;
358
359                                case RTAX_BRD:
360                                        ift->ifa_broadaddr =
361                                            (struct sockaddr *)(void *)data;
362                                        memcpy(data, p, len);
363                                        data += len;
364                                        break;
365                                }
366                                p += len;
367                        }
368
369#ifdef  HAVE_IFAM_DATA
370                        /* ifam_data needs to be aligned */
371                        ift->ifa_data = data = (void *)ALIGN(data);
372                        memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
373                        data += sizeof(ifam->ifam_data);
374#endif  /* HAVE_IFAM_DATA */
375
376                        ift = (ift->ifa_next = ift + 1);
377                        break;
378                }
379        }
380
381        free(buf);
382#else   /* NET_RT_IFLIST */
383        ifr = ifc.ifc_req;
384        lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
385
386        while (ifr < lifr) {
387                struct sockaddr *sa;
388
389                ift->ifa_name = names;
390                names[sizeof(ifr->ifr_name)] = 0;
391                strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
392                while (*names++)
393                        ;
394
395                ift->ifa_addr = (struct sockaddr *)data;
396                sa = &ifr->ifr_addr;
397                memcpy(data, sa, SA_LEN(sa));
398                data += SA_RLEN(sa);
399               
400                ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
401                ift = (ift->ifa_next = ift + 1);
402        }
403#endif  /* NET_RT_IFLIST */
404        if (--ift >= ifa) {
405                ift->ifa_next = NULL;
406                *pif = ifa;
407        } else {
408                *pif = NULL;
409                free(ifa);
410        }
411        return (0);
412}
413
414void
415freeifaddrs(struct ifaddrs *ifp)
416{
417
418        free(ifp);
419}
Note: See TracBrowser for help on using the repository browser.