1 /* $NetBSD: if_nameindex.c,v 1.7 2012/03/13 21:13:41 christos Exp $ */ 2 /* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */ 3 4 /*- 5 * Copyright (c) 1997, 2000 6 * Berkeley Software Design, Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp 27 */ 28 29 #include <sys/cdefs.h> 30 #if defined(LIBC_SCCS) && !defined(lint) 31 __RCSID("$NetBSD: if_nameindex.c,v 1.7 2012/03/13 21:13:41 christos Exp $"); 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include "namespace.h" 35 #include <sys/types.h> 36 #include <sys/socket.h> 37 #include <net/if_dl.h> 38 #include <net/if.h> 39 #include <ifaddrs.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #ifdef __weak_alias 44 __weak_alias(if_nameindex,_if_nameindex) 45 __weak_alias(if_freenameindex,_if_freenameindex) 46 #endif 47 /* 48 * From RFC 2553: 49 * 50 * 4.3 Return All Interface Names and Indexes 51 * 52 * The if_nameindex structure holds the information about a single 53 * interface and is defined as a result of including the <net/if.h> 54 * header. 55 * 56 * struct if_nameindex { 57 * unsigned int if_index; 58 * char *if_name; 59 * }; 60 * 61 * The final function returns an array of if_nameindex structures, one 62 * structure per interface. 63 * 64 * struct if_nameindex *if_nameindex(void); 65 * 66 * The end of the array of structures is indicated by a structure with 67 * an if_index of 0 and an if_name of NULL. The function returns a NULL 68 * pointer upon an error, and would set errno to the appropriate value. 69 * 70 * The memory used for this array of structures along with the interface 71 * names pointed to by the if_name members is obtained dynamically. 72 * This memory is freed by the next function. 73 * 74 * 4.4. Free Memory 75 * 76 * The following function frees the dynamic memory that was allocated by 77 * if_nameindex(). 78 * 79 * #include <net/if.h> 80 * 81 * void if_freenameindex(struct if_nameindex *ptr); 82 * 83 * The argument to this function must be a pointer that was returned by 84 * if_nameindex(). 85 */ 86 87 struct if_nameindex * 88 if_nameindex(void) 89 { 90 struct ifaddrs *ifaddrs, *ifa; 91 size_t nbytes, ni; 92 struct if_nameindex *ifni, *ifni2; 93 char *cp; 94 95 if (getifaddrs(&ifaddrs) < 0) 96 return(NULL); 97 98 /* 99 * First, find out how many interfaces there are, and how 100 * much space we need for the string names. 101 */ 102 ni = 0; 103 nbytes = 0; 104 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 105 if (ifa->ifa_addr && 106 ifa->ifa_addr->sa_family == AF_LINK) { 107 nbytes += strlen(ifa->ifa_name) + 1; 108 ni++; 109 } 110 } 111 112 /* 113 * Next, allocate a chunk of memory, use the first part 114 * for the array of structures, and the last part for 115 * the strings. 116 */ 117 cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes); 118 ifni = (struct if_nameindex *)(void *)cp; 119 if (ifni == NULL) 120 goto out; 121 cp += (ni + 1) * sizeof(struct if_nameindex); 122 123 /* 124 * Now just loop through the list of interfaces again, 125 * filling in the if_nameindex array and making copies 126 * of all the strings. 127 */ 128 ifni2 = ifni; 129 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 130 if (ifa->ifa_addr && 131 ifa->ifa_addr->sa_family == AF_LINK) { 132 ifni2->if_index = 133 ((struct sockaddr_dl*) 134 (void *)ifa->ifa_addr)->sdl_index; 135 ifni2->if_name = cp; 136 strcpy(cp, ifa->ifa_name); 137 ifni2++; 138 cp += strlen(cp) + 1; 139 } 140 } 141 /* 142 * Finally, don't forget to terminate the array. 143 */ 144 ifni2->if_index = 0; 145 ifni2->if_name = NULL; 146 out: 147 freeifaddrs(ifaddrs); 148 return(ifni); 149 } 150 151 void 152 if_freenameindex(struct if_nameindex *ptr) 153 { 154 free(ptr); 155 } 156