summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsocket/inet/interface_id.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsocket/inet/interface_id.c')
-rw-r--r--usr/src/lib/libsocket/inet/interface_id.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/usr/src/lib/libsocket/inet/interface_id.c b/usr/src/lib/libsocket/inet/interface_id.c
new file mode 100644
index 0000000000..2a512b025f
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/interface_id.c
@@ -0,0 +1,355 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <inet/common.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define IPIF_SEPARATOR_CHAR ":"
+
+/*
+ * Given an interface name, this function retrives the associated
+ * index value. Returns index value if successful, zero otherwise.
+ * The length of the supplied interface name must be at most
+ * IF_NAMESIZE-1 bytes
+ */
+uint32_t
+if_nametoindex(const char *ifname)
+{
+ int s;
+ struct lifreq lifr;
+ int save_err;
+ size_t size;
+
+
+ /* Make sure the given name is not NULL */
+ if ((ifname == NULL)||(*ifname == '\0')) {
+ errno = ENXIO;
+ return (0);
+ }
+
+ /*
+ * Fill up the interface name in the ioctl
+ * request message. Make sure that the length of
+ * the given interface name <= (IF_NAMESIZE-1)
+ */
+ size = strlen(ifname);
+ if (size > (IF_NAMESIZE - 1)) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ strncpy(lifr.lifr_name, ifname, size +1);
+
+ /* Check the v4 interfaces first */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
+ (void) close(s);
+ return (lifr.lifr_index);
+ }
+ (void) close(s);
+ }
+
+ /* Check the v6 interface list */
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+
+ if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
+ lifr.lifr_index = 0;
+
+ save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (lifr.lifr_index);
+}
+
+/*
+ * Given an index, this function returns the associated interface
+ * name in the supplied buffer ifname.
+ * Returns physical interface name if successful, NULL otherwise.
+ * The interface name returned will be at most IF_NAMESIZE-1 bytes.
+ */
+char *
+if_indextoname(uint32_t ifindex, char *ifname)
+{
+ int n;
+ int s;
+ char *buf;
+ uint32_t index;
+ struct lifnum lifn;
+ struct lifconf lifc;
+ struct lifreq *lifrp;
+ int numifs;
+ size_t bufsize;
+ boolean_t found;
+
+ /* A interface index of 0 is invalid */
+ if (ifindex == 0) {
+ errno = ENXIO;
+ return (NULL);
+ }
+
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return (NULL);
+ }
+ }
+
+ /* Prepare to send a SIOCGLIFNUM request message */
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (NULL);
+ }
+ numifs = lifn.lifn_count;
+
+ /*
+ * 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 = 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;
+ 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);
+}