xref: /openbsd/lib/libc/net/if_nameindex.c (revision 3d8817e4)
1 /*	$OpenBSD: if_nameindex.c,v 1.10 2010/09/24 13:29:29 claudio Exp $	*/
2 /*	$KAME: if_nameindex.c,v 1.7 2000/11/24 08:17:20 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/types.h>
30 #include <sys/socket.h>
31 #include <net/if_dl.h>
32 #include <net/if.h>
33 #include <ifaddrs.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 /*
38  * From RFC 2553:
39  *
40  * 4.3 Return All Interface Names and Indexes
41  *
42  *    The if_nameindex structure holds the information about a single
43  *    interface and is defined as a result of including the <net/if.h>
44  *    header.
45  *
46  *       struct if_nameindex {
47  *         unsigned int   if_index;
48  *         char          *if_name;
49  *       };
50  *
51  *    The final function returns an array of if_nameindex structures, one
52  *    structure per interface.
53  *
54  *       struct if_nameindex  *if_nameindex(void);
55  *
56  *    The end of the array of structures is indicated by a structure with
57  *    an if_index of 0 and an if_name of NULL.  The function returns a NULL
58  *    pointer upon an error, and would set errno to the appropriate value.
59  *
60  *    The memory used for this array of structures along with the interface
61  *    names pointed to by the if_name members is obtained dynamically.
62  *    This memory is freed by the next function.
63  *
64  * 4.4.  Free Memory
65  *
66  *    The following function frees the dynamic memory that was allocated by
67  *    if_nameindex().
68  *
69  *        #include <net/if.h>
70  *
71  *        void  if_freenameindex(struct if_nameindex *ptr);
72  *
73  *    The argument to this function must be a pointer that was returned by
74  *    if_nameindex().
75  */
76 
77 struct if_nameindex *
78 if_nameindex(void)
79 {
80 	struct ifaddrs *ifaddrs, *ifa;
81 	unsigned int ni;
82 	size_t nbytes;
83 	struct if_nameindex *ifni, *ifni2;
84 	char *cp;
85 
86 	if (getifaddrs(&ifaddrs) < 0)
87 		return(NULL);
88 
89 	/*
90 	 * First, find out how many interfaces there are, and how
91 	 * much space we need for the string names.
92 	 */
93 	ni = 0;
94 	nbytes = 0;
95 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
96 		if (ifa->ifa_addr &&
97 		    ifa->ifa_addr->sa_family == AF_LINK) {
98 			nbytes += strlen(ifa->ifa_name) + 1;
99 			ni++;
100 		}
101 	}
102 
103 	/*
104 	 * Next, allocate a chunk of memory, use the first part
105 	 * for the array of structures, and the last part for
106 	 * the strings.
107 	 */
108 	cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes);
109 	ifni = (struct if_nameindex *)cp;
110 	if (ifni == NULL)
111 		goto out;
112 	cp += (ni + 1) * sizeof(struct if_nameindex);
113 
114 	/*
115 	 * Now just loop through the list of interfaces again,
116 	 * filling in the if_nameindex array and making copies
117 	 * of all the strings.
118 	 */
119 	ifni2 = ifni;
120 	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
121 		if (ifa->ifa_addr &&
122 		    ifa->ifa_addr->sa_family == AF_LINK) {
123 			ifni2->if_index =
124 			    ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
125 			ifni2->if_name = cp;
126 			nbytes = strlen(ifa->ifa_name) + 1;
127 			memcpy(cp, ifa->ifa_name, nbytes);
128 			ifni2++;
129 			cp += nbytes;
130 		}
131 	}
132 	/*
133 	 * Finally, don't forget to terminate the array.
134 	 */
135 	ifni2->if_index = 0;
136 	ifni2->if_name = NULL;
137 out:
138 	freeifaddrs(ifaddrs);
139 	return(ifni);
140 }
141 
142 void
143 if_freenameindex(struct if_nameindex *ptr)
144 {
145 	free(ptr);
146 }
147