Annotation of embedaddon/libpdel/net/if_iface.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include <sys/types.h>
                     42: #include <sys/param.h>
                     43: #include <sys/socket.h>
                     44: #include <sys/sysctl.h>
                     45: #include <sys/sockio.h>
                     46: 
                     47: #include <net/if.h>
                     48: #include <net/if_dl.h>
                     49: #include <net/route.h>
                     50: 
                     51: #include <netinet/in.h>
                     52: #include <arpa/inet.h>
                     53: 
                     54: #include <stdio.h>
                     55: #include <stdlib.h>
                     56: #include <stdarg.h>
                     57: #include <unistd.h>
                     58: #include <string.h>
                     59: #include <errno.h>
                     60: #include <err.h>
                     61: 
                     62: #include "structs/structs.h"
                     63: #include "structs/type/array.h"
                     64: 
                     65: #include "util/typed_mem.h"
                     66: #include "net/if_util.h"
                     67: 
                     68: #define ROUNDUP(a) \
                     69:        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
                     70: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
                     71: 
                     72: static struct  if_msghdr *if_find(const char *ifname,
                     73:                        u_char **bufp, const char *mtype);
                     74: static int     if_info(u_char **bufp, const char *mtype);
                     75: 
                     76: /*
                     77:  * Get list of IP addresses and netmasks configured on an interface.
                     78:  */
                     79: int
                     80: if_get_ip_addrs(const char *ifname, struct in_addr **iplistp,
                     81:        struct in_addr **nmlistp, const char *mtype)
                     82: {
                     83:        struct if_msghdr *ifm;
                     84:        struct ifa_msghdr *ifam;
                     85:        struct in_addr *iplist = NULL;
                     86:        struct in_addr *nmlist = NULL;
                     87:        int errno_save;
                     88:        int num = 0;
                     89:        u_char *buf;
                     90: 
                     91:        /* Find interface info */
                     92:        if ((ifm = if_find(ifname, &buf, TYPED_MEM_TEMP)) == NULL)
                     93:                return (-1);
                     94: 
                     95:        /* Search for first IP address */
                     96:        for (ifam = (struct ifa_msghdr *)(void *)
                     97:              ((u_char *)ifm + ifm->ifm_msglen);
                     98:            ifam->ifam_type == RTM_NEWADDR;
                     99:            ifam = (struct ifa_msghdr *)(void *)
                    100:              ((u_char *)ifam + ifam->ifam_msglen))
                    101:                num++;
                    102: 
                    103:        /* Allocate arrays */
                    104:        if ((iplist = MALLOC(mtype, num * sizeof(*iplist))) == NULL
                    105:            || (nmlist = MALLOC(mtype, num * sizeof(*nmlist))) == NULL) {
                    106:                errno_save = errno;
                    107:                FREE(mtype, iplist);                            /* ok if NULL */
                    108:                FREE(TYPED_MEM_TEMP, buf);
                    109:                errno = errno_save;
                    110:                return (-1);
                    111:        }
                    112: 
                    113:        /* Search for IP address/netmask combinations */
                    114:        num = 0;
                    115:        for (ifam = (struct ifa_msghdr *)(void *)
                    116:             ((u_char *)ifm + ifm->ifm_msglen);
                    117:            ifam->ifam_type == RTM_NEWADDR;
                    118:            ifam = (struct ifa_msghdr *)(void *)
                    119:              ((u_char *)ifam + ifam->ifam_msglen)) {
                    120:                char *cp = (char *)(ifam + 1);
                    121:                int need = RTA_IFA | RTA_NETMASK;
                    122:                int i;
                    123: 
                    124:                /* Find IP address and netmask, if any */
                    125:                if ((ifam->ifam_addrs & need) != need)
                    126:                        continue;
                    127:                for (i = 1; i != 0 && need != 0; i <<= 1) {
                    128:                        if ((ifam->ifam_addrs & i) == 0)
                    129:                                continue;
                    130:                        if (i == RTA_IFA
                    131:                            && ((struct sockaddr *)(void *)cp)->sa_family
                    132:                              == AF_INET) {
                    133:                                iplist[num] = ((struct sockaddr_in *)
                    134:                                    (void *)cp)->sin_addr;
                    135:                        } else if (i == RTA_NETMASK) {
                    136:                                nmlist[num] = ((struct sockaddr_in *)
                    137:                                    (void *)cp)->sin_addr;
                    138:                        }
                    139:                        need &= ~i;
                    140:                        ADVANCE(cp, (struct sockaddr *)cp);
                    141:                }
                    142:                if (need == 0)
                    143:                        num++;
                    144:        }
                    145: 
                    146:        /* Done */
                    147:        FREE(TYPED_MEM_TEMP, buf);
                    148:        *iplistp = iplist;
                    149:        *nmlistp = nmlist;
                    150:        return (num);
                    151: }
                    152: 
                    153: /*
                    154:  * Get the first IP address on an interface.
                    155:  */
                    156: int
                    157: if_get_ip_addr(const char *ifname, struct in_addr *ipp, struct in_addr *nmp)
                    158: {
                    159:        struct in_addr *iplist;
                    160:        struct in_addr *nmlist;
                    161:        int nip;
                    162: 
                    163:        if ((nip = if_get_ip_addrs(ifname,
                    164:            &iplist, &nmlist, TYPED_MEM_TEMP)) == -1)
                    165:                return (-1);
                    166:        if (nip == 0) {
                    167:                FREE(TYPED_MEM_TEMP, iplist);
                    168:                FREE(TYPED_MEM_TEMP, nmlist);
                    169:                errno = ENOENT;
                    170:                return (-1);
                    171:        }
                    172:        if (ipp != NULL)
                    173:                *ipp = iplist[0];
                    174:        if (nmp != NULL)
                    175:                *nmp = nmlist[0];
                    176:        FREE(TYPED_MEM_TEMP, iplist);
                    177:        FREE(TYPED_MEM_TEMP, nmlist);
                    178:        return (0);
                    179: }
                    180: 
                    181: /*
                    182:  * Get the flags associated with an interface.
                    183:  */
                    184: int
                    185: if_get_flags(const char *ifname)
                    186: {
                    187:        struct if_msghdr *ifm;
                    188:        u_char *buf;
                    189:        int rtn;
                    190: 
                    191:        if ((ifm = if_find(ifname, &buf, TYPED_MEM_TEMP)) == NULL)
                    192:                return (-1);
                    193:        rtn = ifm->ifm_flags;
                    194:        FREE(TYPED_MEM_TEMP, buf);
                    195:        return (rtn);
                    196: }
                    197: 
                    198: /*
                    199:  * Set the flags associated with an interface.
                    200:  */
                    201: int
                    202: if_set_flags(const char *ifname, int flags)
                    203: {
                    204:        struct ifreq ifr;
                    205:        int r;
                    206:        int s;
                    207: 
                    208:        if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
                    209:                return (-1);
                    210:        memset(&ifr, 0, sizeof(ifr));
                    211:        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
                    212:        ifr.ifr_flags = flags;
                    213:        r = ioctl(s, SIOCSIFFLAGS, (char *)&ifr);
                    214:        (void)close(s);
                    215:        return (r);
                    216: }
                    217: 
                    218: /*
                    219:  * Get the MTU associated with an interface.
                    220:  */
                    221: int
                    222: if_get_mtu(const char *ifname)
                    223: {
                    224:        struct if_msghdr *ifm;
                    225:        u_char *buf;
                    226:        int rtn;
                    227: 
                    228:        if ((ifm = if_find(ifname, &buf, TYPED_MEM_TEMP)) == NULL)
                    229:                return (-1);
                    230:        rtn = ifm->ifm_data.ifi_mtu;
                    231:        FREE(TYPED_MEM_TEMP, buf);
                    232:        return (rtn);
                    233: }
                    234: 
                    235: /*
                    236:  * Set the MTU associated with an interface.
                    237:  */
                    238: int
                    239: if_set_mtu(const char *ifname, u_int mtu)
                    240: {
                    241:        struct ifreq ifr;
                    242:        int r;
                    243:        int s;
                    244: 
                    245:        if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
                    246:                return (-1);
                    247:        memset(&ifr, 0, sizeof(ifr));
                    248:        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
                    249:        ifr.ifr_mtu = mtu;
                    250:        r = ioctl(s, SIOCSIFMTU, (char *)&ifr);
                    251:        (void)close(s);
                    252:        return (r);
                    253: }
                    254: 
                    255: /*
                    256:  * Get the interface type.
                    257:  */
                    258: int
                    259: if_get_type(const char *ifname)
                    260: {
                    261:        struct if_msghdr *ifm;
                    262:        u_char *buf;
                    263:        int rtn;
                    264: 
                    265:        if ((ifm = if_find(ifname, &buf, TYPED_MEM_TEMP)) == NULL)
                    266:                return (-1);
                    267:        rtn = ifm->ifm_data.ifi_type;
                    268:        FREE(TYPED_MEM_TEMP, buf);
                    269:        return (rtn);
                    270: }
                    271: 
                    272: /*
                    273:  * Get the link address for an interface.
                    274:  */
                    275: int
                    276: if_get_link_addr(const char *ifname,
                    277:        struct sockaddr_dl **sdlp, const char *mtype)
                    278: {
                    279:        struct if_msghdr *ifm;
                    280:        struct sockaddr_dl *sdl;
                    281:        int errno_save;
                    282:        u_char *buf;
                    283: 
                    284:        if ((ifm = if_find(ifname, &buf, TYPED_MEM_TEMP)) == NULL)
                    285:                return (-1);
                    286:        sdl = (struct sockaddr_dl *)(ifm + 1);
                    287:        if ((*sdlp = MALLOC(mtype, sdl->sdl_len)) == NULL) {
                    288:                errno_save = errno;
                    289:                FREE(TYPED_MEM_TEMP, buf);
                    290:                errno = errno_save;
                    291:                return (-1);
                    292:        }
                    293:        memcpy(*sdlp, sdl, sdl->sdl_len);
                    294:        FREE(TYPED_MEM_TEMP, buf);
                    295:        return (0);
                    296: }
                    297: 
                    298: /*
                    299:  * Gets the names of all system interfaces.
                    300:  */
                    301: int
                    302: if_get_list(char ***listp, const char *mtype)
                    303: {
                    304:        char **list = NULL;
                    305:        int errno_save;
                    306:        int num = 0;
                    307:        u_char *buf;
                    308:        u_char *ptr;
                    309:        int len;
                    310: 
                    311:        /* Get raw data from kernel */
                    312:        if ((len = if_info(&buf, TYPED_MEM_TEMP)) == -1)
                    313:                return (-1);
                    314: 
                    315:        /* Scan interfaces */
                    316:        for (ptr = buf;
                    317:            ptr < buf + len;
                    318:            ptr += ((struct if_msghdr *)(void *)ptr)->ifm_msglen) {
                    319:                struct if_msghdr *const ifm = (struct if_msghdr *)(void *)ptr;
                    320: 
                    321:                /* Sanity check version */
                    322:                if (ifm->ifm_version != RTM_VERSION) {
                    323:                        errno = EIO;
                    324:                        goto fail;
                    325:                }
                    326: 
                    327:                /* Next interface? */
                    328:                if (ifm->ifm_type == RTM_IFINFO) {
                    329:                        struct sockaddr_dl *const sdl
                    330:                            = (struct sockaddr_dl *)(ifm + 1);
                    331:                        char nbuf[IF_NAMESIZE + 1];
                    332:                        void *new_list;
                    333: 
                    334:                        /* Get name */
                    335:                        if (sdl->sdl_nlen > sizeof(nbuf) - 1)
                    336:                                continue;
                    337:                        memcpy(nbuf, sdl->sdl_data, sdl->sdl_nlen);
                    338:                        nbuf[sdl->sdl_nlen] = '\0';
                    339: 
                    340:                        /* Add name to list */
                    341:                        if ((new_list = REALLOC(mtype, list,
                    342:                            (num + 1) * sizeof(*list))) == NULL)
                    343:                                goto fail;
                    344:                        list = new_list;
                    345:                        if ((list[num] = STRDUP(mtype, nbuf)) == NULL)
                    346:                                goto fail;
                    347:                        num++;
                    348:                }
                    349:        }
                    350: 
                    351:        /* Done */
                    352:        FREE(TYPED_MEM_TEMP, buf);
                    353:        *listp = list;
                    354:        return (num);
                    355: 
                    356: fail:
                    357:        errno_save = errno;
                    358:        while (num > 0)
                    359:                FREE(mtype, list[--num]);
                    360:        FREE(mtype, list);
                    361:        FREE(TYPED_MEM_TEMP, buf);
                    362:        errno = errno_save;
                    363:        return (-1);
                    364: }
                    365: 
                    366: /*
                    367:  * Get the flags or type associated with an interface.
                    368:  * Caller must free *bufp.
                    369:  *
                    370:  * Returns -1 and sets errno if there was a problem.
                    371:  */
                    372: static struct if_msghdr *
                    373: if_find(const char *ifname, u_char **bufp, const char *mtype)
                    374: {
                    375:        u_char *buf;
                    376:        u_char *ptr;
                    377:        size_t len;
                    378: 
                    379:        /* Get raw data from kernel */
                    380:        if ((len = if_info(&buf, mtype)) == -1)
                    381:                return (NULL);
                    382: 
                    383:        /* Scan for desired interface */
                    384:        for (ptr = buf;
                    385:            ptr < buf + len;
                    386:            ptr += ((struct if_msghdr *)(void *)ptr)->ifm_msglen) {
                    387:                struct if_msghdr *const ifm = (struct if_msghdr *)(void *)ptr;
                    388:                struct sockaddr_dl *sdl;
                    389: 
                    390:                /* Sanity check version */
                    391:                if (ifm->ifm_version != RTM_VERSION) {
                    392:                        FREE(mtype, buf);
                    393:                        errno = EIO;
                    394:                        return (NULL);
                    395:                }
                    396: 
                    397:                /* Next interface or previous interface address? */
                    398:                if (ifm->ifm_type != RTM_IFINFO)
                    399:                        continue;
                    400: 
                    401:                /* Compare interface name */
                    402:                sdl = (struct sockaddr_dl *)(ifm + 1);
                    403:                if (strlen(ifname) != sdl->sdl_nlen ||
                    404:                    strncmp(ifname, sdl->sdl_data, sdl->sdl_nlen) != 0)
                    405:                        continue;
                    406: 
                    407:                /* Found it */
                    408:                *bufp = buf;
                    409:                return (ifm);
                    410:        }
                    411: 
                    412:        /* Not found */
                    413:        FREE(mtype, buf);
                    414:        errno = ENOENT;
                    415:        return (NULL);
                    416: }
                    417: 
                    418: /*
                    419:  * Get the interface list. Caller must free *bufp.
                    420:  */
                    421: static int
                    422: if_info(u_char **bufp, const char *mtype)
                    423: {
                    424:        int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
                    425:        size_t length;
                    426:        u_char *buf;
                    427: 
                    428:        if (sysctl(mib, 6, NULL, &length, NULL, 0) == -1)
                    429:                return (-1);
                    430:        length += 256;
                    431:        if ((buf = MALLOC(mtype, length)) == NULL)
                    432:                return (-1);
                    433:        if (sysctl(mib, 6, buf, &length, NULL, 0) == -1)
                    434:                return (-1);
                    435:        *bufp = buf;
                    436:        return (length);
                    437: }
                    438: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>