1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <inet/common.h> 37 #include <net/if.h> 38 #include <netinet/in.h> 39 #include <sys/sockio.h> 40 #include <sys/ioctl.h> 41 #include <unistd.h> 42 #include <errno.h> 43 44 #define IPIF_SEPARATOR_CHAR ":" 45 46 /* 47 * Given an interface name, this function retrives the associated 48 * index value. Returns index value if successful, zero otherwise. 49 * The length of the supplied interface name must be at most 50 * IF_NAMESIZE-1 bytes 51 */ 52 uint32_t 53 if_nametoindex(const char *ifname) 54 { 55 int s; 56 struct lifreq lifr; 57 int save_err; 58 size_t size; 59 60 61 /* Make sure the given name is not NULL */ 62 if ((ifname == NULL)||(*ifname == '\0')) { 63 errno = ENXIO; 64 return (0); 65 } 66 67 /* 68 * Fill up the interface name in the ioctl 69 * request message. Make sure that the length of 70 * the given interface name <= (IF_NAMESIZE-1) 71 */ 72 size = strlen(ifname); 73 if (size > (IF_NAMESIZE - 1)) { 74 errno = EINVAL; 75 return (0); 76 } 77 78 strncpy(lifr.lifr_name, ifname, size +1); 79 80 /* Check the v4 interfaces first */ 81 s = socket(AF_INET, SOCK_DGRAM, 0); 82 if (s >= 0) { 83 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { 84 (void) close(s); 85 return (lifr.lifr_index); 86 } 87 (void) close(s); 88 } 89 90 /* Check the v6 interface list */ 91 s = socket(AF_INET6, SOCK_DGRAM, 0); 92 if (s < 0) 93 return (0); 94 95 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0) 96 lifr.lifr_index = 0; 97 98 save_err = errno; 99 (void) close(s); 100 errno = save_err; 101 return (lifr.lifr_index); 102 } 103 104 /* 105 * Given an index, this function returns the associated interface 106 * name in the supplied buffer ifname. 107 * Returns physical interface name if successful, NULL otherwise. 108 * The interface name returned will be at most IF_NAMESIZE-1 bytes. 109 */ 110 char * 111 if_indextoname(uint32_t ifindex, char *ifname) 112 { 113 int n; 114 int s; 115 char *buf; 116 uint32_t index; 117 struct lifnum lifn; 118 struct lifconf lifc; 119 struct lifreq *lifrp; 120 int numifs; 121 size_t bufsize; 122 boolean_t found; 123 124 /* A interface index of 0 is invalid */ 125 if (ifindex == 0) { 126 errno = ENXIO; 127 return (NULL); 128 } 129 130 s = socket(AF_INET6, SOCK_DGRAM, 0); 131 if (s < 0) { 132 s = socket(AF_INET, SOCK_DGRAM, 0); 133 if (s < 0) { 134 return (NULL); 135 } 136 } 137 138 /* Prepare to send a SIOCGLIFNUM request message */ 139 lifn.lifn_family = AF_UNSPEC; 140 lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 141 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { 142 int save_err = errno; 143 (void) close(s); 144 errno = save_err; 145 return (NULL); 146 } 147 numifs = lifn.lifn_count; 148 149 /* 150 * Provide enough buffer to obtain the interface 151 * list from the kernel as response to a SIOCGLIFCONF 152 * request 153 */ 154 155 bufsize = numifs * sizeof (struct lifreq); 156 buf = malloc(bufsize); 157 if (buf == NULL) { 158 int save_err = errno; 159 (void) close(s); 160 errno = save_err; 161 return (NULL); 162 } 163 lifc.lifc_family = AF_UNSPEC; 164 lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 165 lifc.lifc_len = bufsize; 166 lifc.lifc_buf = buf; 167 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 168 int save_err = errno; 169 (void) close(s); 170 errno = save_err; 171 free(buf); 172 return (NULL); 173 } 174 175 lifrp = lifc.lifc_req; 176 found = B_FALSE; 177 for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { 178 /* 179 * Obtain the index value of each interface, and 180 * match to see if the retrived index value matches 181 * the given one. If so we have return the corresponding 182 * device name of that interface. 183 */ 184 size_t size; 185 186 index = if_nametoindex(lifrp->lifr_name); 187 if (index == 0) 188 /* Oops the interface just disappeared */ 189 continue; 190 if (index == ifindex) { 191 size = strcspn(lifrp->lifr_name, 192 (char *)IPIF_SEPARATOR_CHAR); 193 lifrp->lifr_name[size] = '\0'; 194 found = B_TRUE; 195 (void) strncpy(ifname, lifrp->lifr_name, 196 size + 1); 197 break; 198 } 199 } 200 (void) close(s); 201 free(buf); 202 if (!found) { 203 errno = ENXIO; 204 return (NULL); 205 } 206 return (ifname); 207 } 208 209 /* 210 * This function returns all the interface names and indexes 211 */ 212 struct if_nameindex * 213 if_nameindex(void) 214 { 215 int n; 216 int s; 217 boolean_t found; 218 char *buf; 219 struct lifnum lifn; 220 struct lifconf lifc; 221 struct lifreq *lifrp; 222 int numifs; 223 int index; 224 int i; 225 int physinterf_num; 226 size_t bufsize; 227 struct if_nameindex *interface_list; 228 struct if_nameindex *interface_entry; 229 230 s = socket(AF_INET6, SOCK_DGRAM, 0); 231 if (s < 0) { 232 s = socket(AF_INET, SOCK_DGRAM, 0); 233 if (s < 0) 234 return (NULL); 235 } 236 237 lifn.lifn_family = AF_UNSPEC; 238 lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 239 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) 240 return (NULL); 241 numifs = lifn.lifn_count; 242 243 bufsize = numifs * sizeof (struct lifreq); 244 buf = malloc(bufsize); 245 if (buf == NULL) { 246 int save_err = errno; 247 (void) close(s); 248 errno = save_err; 249 return (NULL); 250 } 251 lifc.lifc_family = AF_UNSPEC; 252 lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 253 lifc.lifc_len = bufsize; 254 lifc.lifc_buf = buf; 255 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 256 int save_err = errno; 257 (void) close(s); 258 errno = save_err; 259 free(buf); 260 return (NULL); 261 } 262 263 lifrp = lifc.lifc_req; 264 (void) close(s); 265 266 /* Allocate the array of if_nameindex structure */ 267 interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex)); 268 if (!interface_list) { 269 int save_err = errno; 270 free(buf); 271 errno = save_err; 272 return (NULL); 273 } 274 /* 275 * Make sure that terminator structure automatically 276 * happens to be all zeroes. 277 */ 278 bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex))); 279 interface_entry = interface_list; 280 physinterf_num = 0; 281 for (n = numifs; n > 0; n--, lifrp++) { 282 size_t size; 283 284 size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR); 285 lifrp->lifr_name[size] = '\0'; 286 found = B_FALSE; 287 /* 288 * Search the current array to see if this interface 289 * already exists 290 */ 291 292 for (i = 0; i < physinterf_num; i++) { 293 if (strcmp(interface_entry[i].if_name, 294 lifrp->lifr_name) == 0) { 295 found = B_TRUE; 296 break; 297 } 298 } 299 300 allocate_new: 301 /* New one. Allocate an array element and fill it */ 302 if (!found) { 303 if ((interface_entry[physinterf_num].if_name = 304 strdup(lifrp->lifr_name)) == NULL) { 305 int save_err; 306 307 if_freenameindex(interface_list); 308 save_err = errno; 309 free(buf); 310 errno = save_err; 311 return (NULL); 312 } 313 314 /* 315 * Obtain the index value for the interface 316 */ 317 interface_entry[physinterf_num].if_index = 318 if_nametoindex(lifrp->lifr_name); 319 physinterf_num++; 320 } 321 } 322 323 /* Create the last one of the array */ 324 interface_entry[physinterf_num].if_name = NULL; 325 interface_entry[physinterf_num].if_index = 0; 326 327 /* Free up the excess array space */ 328 free(buf); 329 interface_list = realloc(interface_list, ((physinterf_num + 1) * 330 sizeof (struct if_nameindex))); 331 332 return (interface_list); 333 } 334 335 /* 336 * This function frees the the array that is created while 337 * the if_nameindex function. 338 */ 339 void 340 if_freenameindex(struct if_nameindex *ptr) 341 { 342 343 if (ptr == NULL) 344 return; 345 346 347 /* First free the if_name member in each array element */ 348 while (ptr->if_name != NULL) { 349 free(ptr->if_name); 350 ptr++; 351 } 352 353 /* Now free up the array space */ 354 free(ptr); 355 } 356