[BACK]Return to getifaddrs.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / net

Annotation of src/lib/libc/net/getifaddrs.c, Revision 1.15

1.15    ! christos    1: /*     $NetBSD: getifaddrs.c,v 1.14 2011/02/04 02:01:12 matt Exp $     */
1.1       itojun      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:  *
1.2       itojun     25:  *     BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
1.1       itojun     26:  */
1.4       itojun     27:
                     28: #include <sys/cdefs.h>
                     29: #if defined(LIBC_SCCS) && !defined(lint)
1.15    ! christos   30: __RCSID("$NetBSD: getifaddrs.c,v 1.14 2011/02/04 02:01:12 matt Exp $");
1.4       itojun     31: #endif /* LIBC_SCCS and not lint */
                     32:
1.13      pooka      33: #ifndef RUMP_ACTION
1.3       itojun     34: #include "namespace.h"
1.13      pooka      35: #endif
1.1       itojun     36: #include <sys/types.h>
                     37: #include <sys/ioctl.h>
                     38: #include <sys/socket.h>
                     39: #include <net/if.h>
                     40: #include <sys/param.h>
                     41: #include <net/route.h>
                     42: #include <sys/sysctl.h>
                     43: #include <net/if_dl.h>
                     44:
1.7       lukem      45: #include <assert.h>
1.1       itojun     46: #include <errno.h>
                     47: #include <ifaddrs.h>
                     48: #include <stdlib.h>
                     49: #include <string.h>
1.3       itojun     50:
1.13      pooka      51: #if defined(__weak_alias) && !defined(RUMP_ACTION)
1.3       itojun     52: __weak_alias(getifaddrs,_getifaddrs)
                     53: __weak_alias(freeifaddrs,_freeifaddrs)
                     54: #endif
1.1       itojun     55:
1.13      pooka      56: #ifdef RUMP_ACTION
                     57: #include <rump/rump_syscalls.h>
                     58: #define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f)
                     59: #endif
                     60:
1.14      matt       61: #define        SA_RLEN(sa)     RT_ROUNDUP((sa)->sa_len)
1.1       itojun     62:
                     63: int
                     64: getifaddrs(struct ifaddrs **pif)
                     65: {
1.15    ! christos   66:        size_t icnt = 1;
        !            67:        size_t dcnt = 0;
        !            68:        size_t ncnt = 0;
        !            69:        static const int mib[] = {
        !            70:                CTL_NET,
        !            71:                PF_ROUTE,
        !            72:                0,                      /* protocol */
        !            73:                0,                      /* wildcard address family */
        !            74:                NET_RT_IFLIST,
        !            75:                0                       /* no flags */
        !            76:        };
1.1       itojun     77:        size_t needed;
                     78:        char *buf;
                     79:        char *next;
1.12      dyoung     80:        struct ifaddrs cif;
1.1       itojun     81:        char *p, *p0;
                     82:        struct rt_msghdr *rtm;
                     83:        struct if_msghdr *ifm;
                     84:        struct ifa_msghdr *ifam;
                     85:        struct sockaddr *sa;
                     86:        struct ifaddrs *ifa, *ift;
1.5       christos   87:        u_short idx = 0;
1.1       itojun     88:        int i;
                     89:        size_t len, alen;
                     90:        char *data;
                     91:        char *names;
                     92:
1.7       lukem      93:        _DIAGASSERT(pif != NULL);
                     94:
1.15    ! christos   95:        if (sysctl(mib, (u_int)__arraycount(mib), NULL, &needed, NULL, 0) < 0)
1.1       itojun     96:                return (-1);
                     97:        if ((buf = malloc(needed)) == NULL)
                     98:                return (-1);
1.15    ! christos   99:        if (sysctl(mib, (u_int)__arraycount(mib), buf, &needed, NULL, 0) < 0) {
1.1       itojun    100:                free(buf);
                    101:                return (-1);
                    102:        }
                    103:
                    104:        for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
1.5       christos  105:                rtm = (struct rt_msghdr *)(void *)next;
1.1       itojun    106:                if (rtm->rtm_version != RTM_VERSION)
                    107:                        continue;
                    108:                switch (rtm->rtm_type) {
                    109:                case RTM_IFINFO:
1.5       christos  110:                        ifm = (struct if_msghdr *)(void *)rtm;
1.1       itojun    111:                        if (ifm->ifm_addrs & RTA_IFP) {
1.12      dyoung    112:                                const struct sockaddr_dl *dl;
                    113:
1.5       christos  114:                                idx = ifm->ifm_index;
1.1       itojun    115:                                ++icnt;
1.5       christos  116:                                dl = (struct sockaddr_dl *)(void *)(ifm + 1);
1.12      dyoung    117:                                dcnt += SA_RLEN((const struct sockaddr *)(const void *)dl) +
1.5       christos  118:                                    ALIGNBYTES;
1.1       itojun    119:                                dcnt += sizeof(ifm->ifm_data);
                    120:                                ncnt += dl->sdl_nlen + 1;
                    121:                        } else
1.5       christos  122:                                idx = 0;
1.1       itojun    123:                        break;
                    124:
                    125:                case RTM_NEWADDR:
1.5       christos  126:                        ifam = (struct ifa_msghdr *)(void *)rtm;
                    127:                        if (idx && ifam->ifam_index != idx)
1.1       itojun    128:                                abort();        /* this cannot happen */
                    129:
                    130: #define        RTA_MASKS       (RTA_NETMASK | RTA_IFA | RTA_BRD)
1.5       christos  131:                        if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
1.1       itojun    132:                                break;
1.5       christos  133:                        p = (char *)(void *)(ifam + 1);
1.1       itojun    134:                        ++icnt;
                    135:                        /* Scan to look for length of address */
                    136:                        alen = 0;
                    137:                        for (p0 = p, i = 0; i < RTAX_MAX; i++) {
                    138:                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
                    139:                                    == 0)
                    140:                                        continue;
1.5       christos  141:                                sa = (struct sockaddr *)(void *)p;
1.1       itojun    142:                                len = SA_RLEN(sa);
                    143:                                if (i == RTAX_IFA) {
                    144:                                        alen = len;
                    145:                                        break;
                    146:                                }
                    147:                                p += len;
                    148:                        }
                    149:                        for (p = p0, i = 0; i < RTAX_MAX; i++) {
                    150:                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
                    151:                                    == 0)
                    152:                                        continue;
1.5       christos  153:                                sa = (struct sockaddr *)(void *)p;
1.1       itojun    154:                                len = SA_RLEN(sa);
1.9       itojun    155:                                if (i == RTAX_NETMASK && sa->sa_len == 0)
1.1       itojun    156:                                        dcnt += alen;
                    157:                                else
                    158:                                        dcnt += len;
                    159:                                p += len;
                    160:                        }
                    161:                        break;
                    162:                }
                    163:        }
                    164:
                    165:        if (icnt + dcnt + ncnt == 1) {
                    166:                *pif = NULL;
                    167:                free(buf);
                    168:                return (0);
                    169:        }
                    170:        data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
                    171:        if (data == NULL) {
                    172:                free(buf);
                    173:                return(-1);
                    174:        }
                    175:
1.5       christos  176:        ifa = (struct ifaddrs *)(void *)data;
1.1       itojun    177:        data += sizeof(struct ifaddrs) * icnt;
                    178:        names = data + dcnt;
                    179:
                    180:        memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
                    181:        ift = ifa;
                    182:
1.5       christos  183:        idx = 0;
1.1       itojun    184:        for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
1.5       christos  185:                rtm = (struct rt_msghdr *)(void *)next;
1.1       itojun    186:                if (rtm->rtm_version != RTM_VERSION)
                    187:                        continue;
                    188:                switch (rtm->rtm_type) {
                    189:                case RTM_IFINFO:
1.5       christos  190:                        ifm = (struct if_msghdr *)(void *)rtm;
1.1       itojun    191:                        if (ifm->ifm_addrs & RTA_IFP) {
1.12      dyoung    192:                                const struct sockaddr_dl *dl;
                    193:
1.5       christos  194:                                idx = ifm->ifm_index;
                    195:                                dl = (struct sockaddr_dl *)(void *)(ifm + 1);
1.1       itojun    196:
1.12      dyoung    197:                                memset(&cif, 0, sizeof(cif));
                    198:
                    199:                                cif.ifa_name = names;
                    200:                                cif.ifa_flags = (int)ifm->ifm_flags;
1.5       christos  201:                                memcpy(names, dl->sdl_data,
                    202:                                    (size_t)dl->sdl_nlen);
1.1       itojun    203:                                names[dl->sdl_nlen] = 0;
                    204:                                names += dl->sdl_nlen + 1;
                    205:
1.12      dyoung    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);
1.1       itojun    209:
                    210:                                /* ifm_data needs to be aligned */
1.12      dyoung    211:                                cif.ifa_data = data = (void *)ALIGN(data);
1.1       itojun    212:                                memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
                    213:                                data += sizeof(ifm->ifm_data);
                    214:                        } else
1.5       christos  215:                                idx = 0;
1.1       itojun    216:                        break;
                    217:
                    218:                case RTM_NEWADDR:
1.5       christos  219:                        ifam = (struct ifa_msghdr *)(void *)rtm;
                    220:                        if (idx && ifam->ifam_index != idx)
1.1       itojun    221:                                abort();        /* this cannot happen */
                    222:
1.5       christos  223:                        if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
1.1       itojun    224:                                break;
1.12      dyoung    225:                        ift->ifa_name = cif.ifa_name;
                    226:                        ift->ifa_flags = cif.ifa_flags;
1.1       itojun    227:                        ift->ifa_data = NULL;
1.5       christos  228:                        p = (char *)(void *)(ifam + 1);
1.1       itojun    229:                        /* Scan to look for length of address */
                    230:                        alen = 0;
                    231:                        for (p0 = p, i = 0; i < RTAX_MAX; i++) {
                    232:                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
                    233:                                    == 0)
                    234:                                        continue;
1.5       christos  235:                                sa = (struct sockaddr *)(void *)p;
1.1       itojun    236:                                len = SA_RLEN(sa);
                    237:                                if (i == RTAX_IFA) {
                    238:                                        alen = len;
                    239:                                        break;
                    240:                                }
                    241:                                p += len;
                    242:                        }
                    243:                        for (p = p0, i = 0; i < RTAX_MAX; i++) {
                    244:                                if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
                    245:                                    == 0)
                    246:                                        continue;
1.5       christos  247:                                sa = (struct sockaddr *)(void *)p;
1.1       itojun    248:                                len = SA_RLEN(sa);
                    249:                                switch (i) {
                    250:                                case RTAX_IFA:
1.5       christos  251:                                        ift->ifa_addr =
                    252:                                            (struct sockaddr *)(void *)data;
1.1       itojun    253:                                        memcpy(data, p, len);
                    254:                                        data += len;
1.12      dyoung    255:                                        if (ift->ifa_addr->sa_family == AF_LINK)
                    256:                                                ift->ifa_data = cif.ifa_data;
1.1       itojun    257:                                        break;
                    258:
                    259:                                case RTAX_NETMASK:
                    260:                                        ift->ifa_netmask =
1.5       christos  261:                                            (struct sockaddr *)(void *)data;
1.9       itojun    262:                                        if (sa->sa_len == 0) {
1.1       itojun    263:                                                memset(data, 0, alen);
                    264:                                                data += alen;
                    265:                                                break;
                    266:                                        }
                    267:                                        memcpy(data, p, len);
                    268:                                        data += len;
                    269:                                        break;
                    270:
                    271:                                case RTAX_BRD:
                    272:                                        ift->ifa_broadaddr =
1.5       christos  273:                                            (struct sockaddr *)(void *)data;
1.1       itojun    274:                                        memcpy(data, p, len);
                    275:                                        data += len;
                    276:                                        break;
                    277:                                }
                    278:                                p += len;
                    279:                        }
                    280:
                    281:
                    282:                        ift = (ift->ifa_next = ift + 1);
                    283:                        break;
                    284:                }
                    285:        }
                    286:
                    287:        free(buf);
                    288:        if (--ift >= ifa) {
                    289:                ift->ifa_next = NULL;
                    290:                *pif = ifa;
                    291:        } else {
                    292:                *pif = NULL;
                    293:                free(ifa);
                    294:        }
                    295:        return (0);
1.2       itojun    296: }
                    297:
                    298: void
                    299: freeifaddrs(struct ifaddrs *ifp)
                    300: {
1.7       lukem     301:
                    302:        _DIAGASSERT(ifp != NULL);
                    303:
1.2       itojun    304:        free(ifp);
1.1       itojun    305: }

CVSweb <webmaster@jp.NetBSD.org>