source: rtems-libbsd/freebsd/lib/libc/net/getifaddrs.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

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