diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2002-03-07 22:40:24 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2002-03-07 22:40:24 +0000 |
commit | c372ea7718760b6e392788f1434181dac16ba592 (patch) | |
tree | a0fd9150b1e89206abb55b6ac0d47c4144fc38ad /lib/libc/net/if_nameindex.c | |
parent | 6e30c72c9f734e2d947b28e3ded9e3ba474df78b (diff) |
Replace SIOCGIFCONF-using NRL versions with KAME versions that use
getifaddrs(3). Fixes problems on LP64 platforms.
Diffstat (limited to 'lib/libc/net/if_nameindex.c')
-rw-r--r-- | lib/libc/net/if_nameindex.c | 233 |
1 files changed, 103 insertions, 130 deletions
diff --git a/lib/libc/net/if_nameindex.c b/lib/libc/net/if_nameindex.c index 2b85fbae959..3675a2a4507 100644 --- a/lib/libc/net/if_nameindex.c +++ b/lib/libc/net/if_nameindex.c @@ -1,26 +1,20 @@ -/* - * Copyright (c) 1998-1999, Craig Metz, All rights reserved. +/* $OpenBSD: if_nameindex.c,v 1.9 2002/03/07 22:40:23 millert Exp $ */ +/* $KAME: if_nameindex.c,v 1.7 2000/11/24 08:17:20 itojun Exp $ */ + +/*- + * Copyright (c) 1997, 2000 + * Berkeley Software Design, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Craig Metz and - * by other contributors. - * 4. Neither the name of the author nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -28,140 +22,119 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp */ -#include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> -#include <sys/ioctl.h> -#include <net/if.h> #include <net/if_dl.h> -#include <errno.h> -#include <unistd.h> +#include <net/if.h> +#include <ifaddrs.h> +#include <stdlib.h> #include <string.h> +/* + * From RFC 2553: + * + * 4.3 Return All Interface Names and Indexes + * + * The if_nameindex structure holds the information about a single + * interface and is defined as a result of including the <net/if.h> + * header. + * + * struct if_nameindex { + * unsigned int if_index; + * char *if_name; + * }; + * + * The final function returns an array of if_nameindex structures, one + * structure per interface. + * + * struct if_nameindex *if_nameindex(void); + * + * The end of the array of structures is indicated by a structure with + * an if_index of 0 and an if_name of NULL. The function returns a NULL + * pointer upon an error, and would set errno to the appropriate value. + * + * The memory used for this array of structures along with the interface + * names pointed to by the if_name members is obtained dynamically. + * This memory is freed by the next function. + * + * 4.4. Free Memory + * + * The following function frees the dynamic memory that was allocated by + * if_nameindex(). + * + * #include <net/if.h> + * + * void if_freenameindex(struct if_nameindex *ptr); + * + * The argument to this function must be a pointer that was returned by + * if_nameindex(). + */ + struct if_nameindex * if_nameindex(void) { - int i, j, fd = -1, extra, len = 0; - struct if_nameindex *nameindex = NULL; - struct ifconf ifconf; - char lastname[IFNAMSIZ], *c, *inbuf; - struct if_nameindex *n; - struct sockaddr *sa; - void *p; - - ifconf.ifc_buf = NULL; + struct ifaddrs *ifaddrs, *ifa; + unsigned int ni; + size_t nbytes; + struct if_nameindex *ifni, *ifni2; + char *cp; - if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - goto ret; + if (getifaddrs(&ifaddrs) < 0) + return(NULL); /* - * Try ifc_len == 0 hack first, to get the actual length. - * If that fails, revert to a loop which grows the ifc_buf - * until it is sufficiently large. + * First, find out how many interfaces there are, and how + * much space we need for the string names. */ - extra = sizeof(struct ifreq); - while (1) { - ifconf.ifc_len = len; - if (ioctl(fd, SIOCGIFCONF, (void *) &ifconf) == -1 && - ifconf.ifc_buf) - goto ret; - if (ifconf.ifc_buf && - ifconf.ifc_len + extra < len) - break; - if (ifconf.ifc_buf) { - if (len == 0) - len = 4096; - ifconf.ifc_len = len *= 2; - } else { - len = ifconf.ifc_len; - extra = 0; - } - inbuf = realloc(ifconf.ifc_buf, ifconf.ifc_len); - if (inbuf == NULL) - goto ret; - ifconf.ifc_buf = inbuf; - } - - i = sizeof(struct if_nameindex); - j = 0; - p = ifconf.ifc_buf; - len = ifconf.ifc_len; - lastname[0] = 0; - lastname[sizeof(lastname)-1] = 0; - - while (len > 0) { - if (len < (IFNAMSIZ + sizeof(struct sockaddr))) - goto ret; - if (strncmp(lastname, p, IFNAMSIZ)) { - strlcpy(lastname, p, sizeof(lastname)); - i += sizeof(struct if_nameindex); - j += strlen(lastname) + 1; + ni = 0; + nbytes = 0; + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_LINK) { + nbytes += strlen(ifa->ifa_name) + 1; + ni++; } - len -= IFNAMSIZ; - p += IFNAMSIZ; - sa = p; - - if (sa->sa_len < sizeof(struct sockaddr)) - sa->sa_len = sizeof(struct sockaddr); - - if (len < sa->sa_len) - goto ret; - len -= sa->sa_len; - p += sa->sa_len; - } - - nameindex = malloc(i + j); - if (nameindex == NULL) { - errno = ENOMEM; - goto ret; } - memset(nameindex, 0, i + j); - n = nameindex; - p = ifconf.ifc_buf; - c = (void *) nameindex + i; - i = 0; - len = ifconf.ifc_len; - lastname[0] = 0; - - while (len > 0) { - if (len < IFNAMSIZ + sizeof(struct sockaddr)) - goto ret; - if (strncmp(lastname, p, IFNAMSIZ)) { - if (i) { - if (!n->if_index) - n->if_index = i; - n++; - } - i++; - memcpy(lastname, p, sizeof(lastname)); - strlcpy(c, lastname, sizeof(lastname)); - n->if_name = c; - c += strlen(c) + 1; - } - len -= IFNAMSIZ; - p += IFNAMSIZ; - sa = p; + /* + * Next, allocate a chunk of memory, use the first part + * for the array of structures, and the last part for + * the strings. + */ + cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes); + ifni = (struct if_nameindex *)cp; + if (ifni == NULL) + goto out; + cp += (ni + 1) * sizeof(struct if_nameindex); - if (len < sa->sa_len) - goto ret; - if (sa->sa_family == AF_LINK) { - struct sockaddr_dl *sd = (struct sockaddr_dl *)sa; - n->if_index = sd->sdl_index; + /* + * Now just loop through the list of interfaces again, + * filling in the if_nameindex array and making copies + * of all the strings. + */ + ifni2 = ifni; + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr && + ifa->ifa_addr->sa_family == AF_LINK) { + ifni2->if_index = + ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index; + ifni2->if_name = cp; + nbytes = strlen(ifa->ifa_name) + 1; + memcpy(cp, ifa->ifa_name, nbytes); + ifni2++; + cp += nbytes; } - len -= sa->sa_len; - p += sa->sa_len; } - - if (n->if_index == 0) - n->if_index = i; - -ret: - if (fd != -1) - close(fd); - if (ifconf.ifc_buf) - free(ifconf.ifc_buf); - return (nameindex); + /* + * Finally, don't forget to terminate the array. + */ + ifni2->if_index = 0; + ifni2->if_name = NULL; +out: + freeifaddrs(ifaddrs); + return(ifni); } |