interface_id.c revision e11c3f44f531fdff80941ce57c065d2ae861cefc
1N/A/*
1N/A * CDDL HEADER START
1N/A *
1N/A * The contents of this file are subject to the terms of the
1N/A * Common Development and Distribution License (the "License").
1N/A * You may not use this file except in compliance with the License.
1N/A *
1N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1N/A * or http://www.opensolaris.org/os/licensing.
1N/A * See the License for the specific language governing permissions
1N/A * and limitations under the License.
1N/A *
1N/A * When distributing Covered Code, include this CDDL HEADER in each
1N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1N/A * If applicable, add the following below this CDDL HEADER, with the
1N/A * fields enclosed by brackets "[]" replaced with your own identifying
1N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1N/A *
1N/A * CDDL HEADER END
1N/A */
1N/A/*
1N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
1N/A * Use is subject to license terms.
1N/A */
1N/A
1N/A#include <stdio.h>
1N/A#include <ctype.h>
1N/A#include <string.h>
1N/A#include <strings.h>
1N/A#include <stdlib.h>
1N/A#include <sys/types.h>
1N/A#include <sys/socket.h>
1N/A#include <inet/common.h>
1N/A#include <net/if.h>
1N/A#include <netinet/in.h>
1N/A#include <sys/sockio.h>
1N/A#include <sys/ioctl.h>
1N/A#include <unistd.h>
1N/A#include <errno.h>
1N/A
1N/A#define IPIF_SEPARATOR_CHAR ":"
1N/A
1N/A/*
1N/A * Given an interface name, this function retrives the associated
1N/A * index value. Returns index value if successful, zero otherwise.
1N/A * The length of the supplied interface name must be at most
1N/A * IF_NAMESIZE-1 bytes
1N/A */
1N/Auint32_t
1N/Aif_nametoindex(const char *ifname)
1N/A{
1N/A int s;
1N/A struct lifreq lifr;
1N/A int save_err;
1N/A size_t size;
1N/A
1N/A
1N/A /* Make sure the given name is not NULL */
1N/A if ((ifname == NULL)||(*ifname == '\0')) {
1N/A errno = ENXIO;
1N/A return (0);
1N/A }
1N/A
1N/A /*
1N/A * Fill up the interface name in the ioctl
1N/A * request message. Make sure that the length of
1N/A * the given interface name <= (IF_NAMESIZE-1)
1N/A */
1N/A size = strlen(ifname);
1N/A if (size > (IF_NAMESIZE - 1)) {
1N/A errno = EINVAL;
1N/A return (0);
1N/A }
1N/A
1N/A strncpy(lifr.lifr_name, ifname, size +1);
1N/A
1N/A /* Check the v4 interfaces first */
1N/A s = socket(AF_INET, SOCK_DGRAM, 0);
1N/A if (s >= 0) {
1N/A if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
1N/A (void) close(s);
1N/A return (lifr.lifr_index);
1N/A }
1N/A (void) close(s);
1N/A }
1N/A
1N/A /* Check the v6 interface list */
1N/A s = socket(AF_INET6, SOCK_DGRAM, 0);
1N/A if (s < 0)
1N/A return (0);
1N/A
1N/A if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
1N/A lifr.lifr_index = 0;
1N/A
1N/A save_err = errno;
1N/A (void) close(s);
1N/A errno = save_err;
1N/A return (lifr.lifr_index);
1N/A}
1N/A
1N/A/*
1N/A * Given an index, this function returns the associated interface
1N/A * name in the supplied buffer ifname.
1N/A * Returns physical interface name if successful, NULL otherwise.
1N/A * The interface name returned will be at most IF_NAMESIZE-1 bytes.
1N/A */
1N/Achar *
1N/Aif_indextoname(uint32_t ifindex, char *ifname)
1N/A{
1N/A int n;
1N/A int s;
1N/A char *buf;
1N/A uint32_t index;
1N/A struct lifnum lifn;
1N/A struct lifconf lifc;
1N/A struct lifreq *lifrp;
1N/A int numifs;
1N/A size_t bufsize;
1N/A boolean_t found;
1N/A uint_t flags;
1N/A
1N/A flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
1N/A
1N/A /* A interface index of 0 is invalid */
1N/A if (ifindex == 0) {
1N/A errno = ENXIO;
1N/A return (NULL);
1N/A }
1N/A
1N/A s = socket(AF_INET6, SOCK_DGRAM, 0);
1N/A if (s < 0) {
1N/A s = socket(AF_INET, SOCK_DGRAM, 0);
1N/A if (s < 0) {
1N/A return (NULL);
1N/A }
1N/A }
1N/A
1N/A /* Prepare to send a SIOCGLIFNUM request message */
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = flags;
if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
/*
* NOTE: "+ 10" sleaze mitigates new IP interfaces showing up between
* the SIOCGLIFNUM and the SIOCGLIFCONF.
*/
numifs = lifn.lifn_count + 10;
/*
* Provide enough buffer to obtain the interface
* list from the kernel as response to a SIOCGLIFCONF
* request
*/
bufsize = numifs * sizeof (struct lifreq);
buf = malloc(bufsize);
if (buf == NULL) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = flags;
lifc.lifc_len = bufsize;
lifc.lifc_buf = buf;
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
free(buf);
return (NULL);
}
lifrp = lifc.lifc_req;
found = B_FALSE;
for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
/*
* Obtain the index value of each interface, and
* match to see if the retrived index value matches
* the given one. If so we have return the corresponding
* device name of that interface.
*/
size_t size;
index = if_nametoindex(lifrp->lifr_name);
if (index == 0)
/* Oops the interface just disappeared */
continue;
if (index == ifindex) {
size = strcspn(lifrp->lifr_name,
(char *)IPIF_SEPARATOR_CHAR);
lifrp->lifr_name[size] = '\0';
found = B_TRUE;
(void) strncpy(ifname, lifrp->lifr_name,
size + 1);
break;
}
}
(void) close(s);
free(buf);
if (!found) {
errno = ENXIO;
return (NULL);
}
return (ifname);
}
/*
* This function returns all the interface names and indexes
*/
struct if_nameindex *
if_nameindex(void)
{
int n;
int s;
boolean_t found;
char *buf;
struct lifnum lifn;
struct lifconf lifc;
struct lifreq *lifrp;
int numifs;
int index;
int i;
int physinterf_num;
size_t bufsize;
struct if_nameindex *interface_list;
struct if_nameindex *interface_entry;
s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return (NULL);
}
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
return (NULL);
numifs = lifn.lifn_count;
bufsize = numifs * sizeof (struct lifreq);
buf = malloc(bufsize);
if (buf == NULL) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
lifc.lifc_len = bufsize;
lifc.lifc_buf = buf;
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
free(buf);
return (NULL);
}
lifrp = lifc.lifc_req;
(void) close(s);
/* Allocate the array of if_nameindex structure */
interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex));
if (!interface_list) {
int save_err = errno;
free(buf);
errno = save_err;
return (NULL);
}
/*
* Make sure that terminator structure automatically
* happens to be all zeroes.
*/
bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex)));
interface_entry = interface_list;
physinterf_num = 0;
for (n = numifs; n > 0; n--, lifrp++) {
size_t size;
size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR);
lifrp->lifr_name[size] = '\0';
found = B_FALSE;
/*
* Search the current array to see if this interface
* already exists
*/
for (i = 0; i < physinterf_num; i++) {
if (strcmp(interface_entry[i].if_name,
lifrp->lifr_name) == 0) {
found = B_TRUE;
break;
}
}
allocate_new:
/* New one. Allocate an array element and fill it */
if (!found) {
if ((interface_entry[physinterf_num].if_name =
strdup(lifrp->lifr_name)) == NULL) {
int save_err;
if_freenameindex(interface_list);
save_err = errno;
free(buf);
errno = save_err;
return (NULL);
}
/*
* Obtain the index value for the interface
*/
interface_entry[physinterf_num].if_index =
if_nametoindex(lifrp->lifr_name);
physinterf_num++;
}
}
/* Create the last one of the array */
interface_entry[physinterf_num].if_name = NULL;
interface_entry[physinterf_num].if_index = 0;
/* Free up the excess array space */
free(buf);
interface_list = realloc(interface_list, ((physinterf_num + 1) *
sizeof (struct if_nameindex)));
return (interface_list);
}
/*
* This function frees the the array that is created while
* the if_nameindex function.
*/
void
if_freenameindex(struct if_nameindex *ptr)
{
if (ptr == NULL)
return;
/* First free the if_name member in each array element */
while (ptr->if_name != NULL) {
free(ptr->if_name);
ptr++;
}
/* Now free up the array space */
free(ptr);
}