10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
58485SPeter.Memishian@Sun.COM * Common Development and Distribution License (the "License").
68485SPeter.Memishian@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*13021SRenee.Sommerfeld@Oracle.COM
220Sstevel@tonic-gate /*
23*13021SRenee.Sommerfeld@Oracle.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <ctype.h>
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <inet/common.h>
340Sstevel@tonic-gate #include <net/if.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <sys/sockio.h>
370Sstevel@tonic-gate #include <sys/ioctl.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate #define IPIF_SEPARATOR_CHAR ":"
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate * Given an interface name, this function retrives the associated
450Sstevel@tonic-gate * index value. Returns index value if successful, zero otherwise.
460Sstevel@tonic-gate * The length of the supplied interface name must be at most
470Sstevel@tonic-gate * IF_NAMESIZE-1 bytes
480Sstevel@tonic-gate */
490Sstevel@tonic-gate uint32_t
if_nametoindex(const char * ifname)500Sstevel@tonic-gate if_nametoindex(const char *ifname)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate int s;
530Sstevel@tonic-gate struct lifreq lifr;
540Sstevel@tonic-gate int save_err;
550Sstevel@tonic-gate size_t size;
560Sstevel@tonic-gate
570Sstevel@tonic-gate
580Sstevel@tonic-gate /* Make sure the given name is not NULL */
590Sstevel@tonic-gate if ((ifname == NULL)||(*ifname == '\0')) {
600Sstevel@tonic-gate errno = ENXIO;
610Sstevel@tonic-gate return (0);
620Sstevel@tonic-gate }
630Sstevel@tonic-gate
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate * Fill up the interface name in the ioctl
660Sstevel@tonic-gate * request message. Make sure that the length of
670Sstevel@tonic-gate * the given interface name <= (IF_NAMESIZE-1)
680Sstevel@tonic-gate */
690Sstevel@tonic-gate size = strlen(ifname);
700Sstevel@tonic-gate if (size > (IF_NAMESIZE - 1)) {
710Sstevel@tonic-gate errno = EINVAL;
720Sstevel@tonic-gate return (0);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate
750Sstevel@tonic-gate strncpy(lifr.lifr_name, ifname, size +1);
760Sstevel@tonic-gate
770Sstevel@tonic-gate /* Check the v4 interfaces first */
780Sstevel@tonic-gate s = socket(AF_INET, SOCK_DGRAM, 0);
790Sstevel@tonic-gate if (s >= 0) {
800Sstevel@tonic-gate if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
810Sstevel@tonic-gate (void) close(s);
820Sstevel@tonic-gate return (lifr.lifr_index);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate (void) close(s);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate
870Sstevel@tonic-gate /* Check the v6 interface list */
880Sstevel@tonic-gate s = socket(AF_INET6, SOCK_DGRAM, 0);
890Sstevel@tonic-gate if (s < 0)
900Sstevel@tonic-gate return (0);
910Sstevel@tonic-gate
920Sstevel@tonic-gate if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
930Sstevel@tonic-gate lifr.lifr_index = 0;
940Sstevel@tonic-gate
950Sstevel@tonic-gate save_err = errno;
960Sstevel@tonic-gate (void) close(s);
970Sstevel@tonic-gate errno = save_err;
980Sstevel@tonic-gate return (lifr.lifr_index);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * Given an index, this function returns the associated interface
1030Sstevel@tonic-gate * name in the supplied buffer ifname.
1040Sstevel@tonic-gate * Returns physical interface name if successful, NULL otherwise.
1050Sstevel@tonic-gate * The interface name returned will be at most IF_NAMESIZE-1 bytes.
1060Sstevel@tonic-gate */
1070Sstevel@tonic-gate char *
if_indextoname(uint32_t ifindex,char * ifname)1080Sstevel@tonic-gate if_indextoname(uint32_t ifindex, char *ifname)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate int n;
1110Sstevel@tonic-gate int s;
1120Sstevel@tonic-gate char *buf;
1130Sstevel@tonic-gate uint32_t index;
1140Sstevel@tonic-gate struct lifnum lifn;
1150Sstevel@tonic-gate struct lifconf lifc;
1160Sstevel@tonic-gate struct lifreq *lifrp;
1170Sstevel@tonic-gate int numifs;
1180Sstevel@tonic-gate size_t bufsize;
1190Sstevel@tonic-gate boolean_t found;
1208485SPeter.Memishian@Sun.COM uint_t flags;
1218485SPeter.Memishian@Sun.COM
1228485SPeter.Memishian@Sun.COM flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /* A interface index of 0 is invalid */
1250Sstevel@tonic-gate if (ifindex == 0) {
1260Sstevel@tonic-gate errno = ENXIO;
1270Sstevel@tonic-gate return (NULL);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate s = socket(AF_INET6, SOCK_DGRAM, 0);
1310Sstevel@tonic-gate if (s < 0) {
1320Sstevel@tonic-gate s = socket(AF_INET, SOCK_DGRAM, 0);
1330Sstevel@tonic-gate if (s < 0) {
1340Sstevel@tonic-gate return (NULL);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /* Prepare to send a SIOCGLIFNUM request message */
1390Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC;
1408485SPeter.Memishian@Sun.COM lifn.lifn_flags = flags;
1410Sstevel@tonic-gate if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
1420Sstevel@tonic-gate int save_err = errno;
1430Sstevel@tonic-gate (void) close(s);
1440Sstevel@tonic-gate errno = save_err;
1450Sstevel@tonic-gate return (NULL);
1460Sstevel@tonic-gate }
1478485SPeter.Memishian@Sun.COM
1488485SPeter.Memishian@Sun.COM /*
1498485SPeter.Memishian@Sun.COM * NOTE: "+ 10" sleaze mitigates new IP interfaces showing up between
1508485SPeter.Memishian@Sun.COM * the SIOCGLIFNUM and the SIOCGLIFCONF.
1518485SPeter.Memishian@Sun.COM */
1528485SPeter.Memishian@Sun.COM numifs = lifn.lifn_count + 10;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * Provide enough buffer to obtain the interface
1560Sstevel@tonic-gate * list from the kernel as response to a SIOCGLIFCONF
1570Sstevel@tonic-gate * request
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq);
1610Sstevel@tonic-gate buf = malloc(bufsize);
1620Sstevel@tonic-gate if (buf == NULL) {
1630Sstevel@tonic-gate int save_err = errno;
1640Sstevel@tonic-gate (void) close(s);
1650Sstevel@tonic-gate errno = save_err;
1660Sstevel@tonic-gate return (NULL);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC;
1698485SPeter.Memishian@Sun.COM lifc.lifc_flags = flags;
1700Sstevel@tonic-gate lifc.lifc_len = bufsize;
1710Sstevel@tonic-gate lifc.lifc_buf = buf;
1720Sstevel@tonic-gate if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
1730Sstevel@tonic-gate int save_err = errno;
1740Sstevel@tonic-gate (void) close(s);
1750Sstevel@tonic-gate errno = save_err;
1760Sstevel@tonic-gate free(buf);
1770Sstevel@tonic-gate return (NULL);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate lifrp = lifc.lifc_req;
1810Sstevel@tonic-gate found = B_FALSE;
1820Sstevel@tonic-gate for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * Obtain the index value of each interface, and
1850Sstevel@tonic-gate * match to see if the retrived index value matches
1869593SAnders.Persson@Sun.COM * the given one. If so we return the corresponding
1870Sstevel@tonic-gate * device name of that interface.
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate size_t size;
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate index = if_nametoindex(lifrp->lifr_name);
1920Sstevel@tonic-gate if (index == 0)
1930Sstevel@tonic-gate /* Oops the interface just disappeared */
1940Sstevel@tonic-gate continue;
1950Sstevel@tonic-gate if (index == ifindex) {
1960Sstevel@tonic-gate size = strcspn(lifrp->lifr_name,
1970Sstevel@tonic-gate (char *)IPIF_SEPARATOR_CHAR);
1980Sstevel@tonic-gate lifrp->lifr_name[size] = '\0';
1990Sstevel@tonic-gate found = B_TRUE;
2009593SAnders.Persson@Sun.COM (void) strncpy(ifname, lifrp->lifr_name, size + 1);
2010Sstevel@tonic-gate break;
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate (void) close(s);
2050Sstevel@tonic-gate free(buf);
2060Sstevel@tonic-gate if (!found) {
2070Sstevel@tonic-gate errno = ENXIO;
2080Sstevel@tonic-gate return (NULL);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate return (ifname);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate * This function returns all the interface names and indexes
2150Sstevel@tonic-gate */
2160Sstevel@tonic-gate struct if_nameindex *
if_nameindex(void)2170Sstevel@tonic-gate if_nameindex(void)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate int n;
2200Sstevel@tonic-gate int s;
2210Sstevel@tonic-gate boolean_t found;
2220Sstevel@tonic-gate char *buf;
2230Sstevel@tonic-gate struct lifnum lifn;
2240Sstevel@tonic-gate struct lifconf lifc;
2250Sstevel@tonic-gate struct lifreq *lifrp;
2260Sstevel@tonic-gate int numifs;
2270Sstevel@tonic-gate int index;
2280Sstevel@tonic-gate int i;
2290Sstevel@tonic-gate int physinterf_num;
2300Sstevel@tonic-gate size_t bufsize;
2310Sstevel@tonic-gate struct if_nameindex *interface_list;
2320Sstevel@tonic-gate struct if_nameindex *interface_entry;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate s = socket(AF_INET6, SOCK_DGRAM, 0);
2350Sstevel@tonic-gate if (s < 0) {
2360Sstevel@tonic-gate s = socket(AF_INET, SOCK_DGRAM, 0);
2370Sstevel@tonic-gate if (s < 0)
2380Sstevel@tonic-gate return (NULL);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC;
2420Sstevel@tonic-gate lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
2430Sstevel@tonic-gate if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
2440Sstevel@tonic-gate return (NULL);
2450Sstevel@tonic-gate numifs = lifn.lifn_count;
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate bufsize = numifs * sizeof (struct lifreq);
2480Sstevel@tonic-gate buf = malloc(bufsize);
2490Sstevel@tonic-gate if (buf == NULL) {
2500Sstevel@tonic-gate int save_err = errno;
2510Sstevel@tonic-gate (void) close(s);
2520Sstevel@tonic-gate errno = save_err;
2530Sstevel@tonic-gate return (NULL);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC;
2560Sstevel@tonic-gate lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
2570Sstevel@tonic-gate lifc.lifc_len = bufsize;
2580Sstevel@tonic-gate lifc.lifc_buf = buf;
2590Sstevel@tonic-gate if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
2600Sstevel@tonic-gate int save_err = errno;
2610Sstevel@tonic-gate (void) close(s);
2620Sstevel@tonic-gate errno = save_err;
2630Sstevel@tonic-gate free(buf);
2640Sstevel@tonic-gate return (NULL);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate lifrp = lifc.lifc_req;
2680Sstevel@tonic-gate (void) close(s);
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /* Allocate the array of if_nameindex structure */
2710Sstevel@tonic-gate interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex));
2720Sstevel@tonic-gate if (!interface_list) {
2730Sstevel@tonic-gate int save_err = errno;
2740Sstevel@tonic-gate free(buf);
2750Sstevel@tonic-gate errno = save_err;
2760Sstevel@tonic-gate return (NULL);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * Make sure that terminator structure automatically
2800Sstevel@tonic-gate * happens to be all zeroes.
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex)));
2830Sstevel@tonic-gate interface_entry = interface_list;
2840Sstevel@tonic-gate physinterf_num = 0;
2850Sstevel@tonic-gate for (n = numifs; n > 0; n--, lifrp++) {
2860Sstevel@tonic-gate size_t size;
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR);
2890Sstevel@tonic-gate found = B_FALSE;
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate * Search the current array to see if this interface
2929593SAnders.Persson@Sun.COM * already exists. Only compare the physical name.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate for (i = 0; i < physinterf_num; i++) {
2959593SAnders.Persson@Sun.COM if (strncmp(interface_entry[i].if_name,
2969593SAnders.Persson@Sun.COM lifrp->lifr_name, size) == 0) {
2970Sstevel@tonic-gate found = B_TRUE;
2980Sstevel@tonic-gate break;
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /* New one. Allocate an array element and fill it */
3030Sstevel@tonic-gate if (!found) {
3049593SAnders.Persson@Sun.COM /*
3059593SAnders.Persson@Sun.COM * Obtain the index value for the interface
3069593SAnders.Persson@Sun.COM */
3079593SAnders.Persson@Sun.COM interface_entry[physinterf_num].if_index =
3089593SAnders.Persson@Sun.COM if_nametoindex(lifrp->lifr_name);
3099593SAnders.Persson@Sun.COM
3109593SAnders.Persson@Sun.COM if (interface_entry[physinterf_num].if_index == 0) {
3119593SAnders.Persson@Sun.COM /* The interface went away. Skip this entry. */
3129593SAnders.Persson@Sun.COM continue;
3139593SAnders.Persson@Sun.COM }
3149593SAnders.Persson@Sun.COM
3159593SAnders.Persson@Sun.COM /*
3169593SAnders.Persson@Sun.COM * Truncate the name to ensure that it represents
3179593SAnders.Persson@Sun.COM * a physical interface.
3189593SAnders.Persson@Sun.COM */
3199593SAnders.Persson@Sun.COM lifrp->lifr_name[size] = '\0';
3200Sstevel@tonic-gate if ((interface_entry[physinterf_num].if_name =
3210Sstevel@tonic-gate strdup(lifrp->lifr_name)) == NULL) {
3220Sstevel@tonic-gate int save_err;
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate if_freenameindex(interface_list);
3250Sstevel@tonic-gate save_err = errno;
3260Sstevel@tonic-gate free(buf);
3270Sstevel@tonic-gate errno = save_err;
3280Sstevel@tonic-gate return (NULL);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3319593SAnders.Persson@Sun.COM physinterf_num++;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate /* Create the last one of the array */
3360Sstevel@tonic-gate interface_entry[physinterf_num].if_name = NULL;
3370Sstevel@tonic-gate interface_entry[physinterf_num].if_index = 0;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /* Free up the excess array space */
3400Sstevel@tonic-gate free(buf);
3410Sstevel@tonic-gate interface_list = realloc(interface_list, ((physinterf_num + 1) *
3420Sstevel@tonic-gate sizeof (struct if_nameindex)));
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate return (interface_list);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /*
3480Sstevel@tonic-gate * This function frees the the array that is created while
3490Sstevel@tonic-gate * the if_nameindex function.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate void
if_freenameindex(struct if_nameindex * ptr)3520Sstevel@tonic-gate if_freenameindex(struct if_nameindex *ptr)
3530Sstevel@tonic-gate {
354*13021SRenee.Sommerfeld@Oracle.COM struct if_nameindex *p;
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate if (ptr == NULL)
3570Sstevel@tonic-gate return;
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /* First free the if_name member in each array element */
360*13021SRenee.Sommerfeld@Oracle.COM for (p = ptr; p->if_name != NULL; p++)
361*13021SRenee.Sommerfeld@Oracle.COM free(p->if_name);
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /* Now free up the array space */
3640Sstevel@tonic-gate free(ptr);
3650Sstevel@tonic-gate }
366