xref: /openbsd/lib/libc/net/if_nameindex.c (revision d415bd75)
1 /*	$OpenBSD: if_nameindex.c,v 1.13 2016/12/16 17:44:59 krw Exp $	*/
2 /*	$KAME: if_nameindex.c,v 1.7 2000/11/24 08:17:20 itojun Exp $	*/
3 
4 /*-
5  * Copyright (c) 2015 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 1997, 2000
7  *	Berkeley Software Design, Inc.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
28  */
29 
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/sysctl.h>
33 #include <net/if.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 
38 /*
39  * From RFC 2553:
40  *
41  * 4.3 Return All Interface Names and Indexes
42  *
43  *    The if_nameindex structure holds the information about a single
44  *    interface and is defined as a result of including the <net/if.h>
45  *    header.
46  *
47  *       struct if_nameindex {
48  *         unsigned int   if_index;
49  *         char          *if_name;
50  *       };
51  *
52  *    The final function returns an array of if_nameindex structures, one
53  *    structure per interface.
54  *
55  *       struct if_nameindex  *if_nameindex(void);
56  *
57  *    The end of the array of structures is indicated by a structure with
58  *    an if_index of 0 and an if_name of NULL.  The function returns a NULL
59  *    pointer upon an error, and would set errno to the appropriate value.
60  *
61  *    The memory used for this array of structures along with the interface
62  *    names pointed to by the if_name members is obtained dynamically.
63  *    This memory is freed by the next function.
64  *
65  * 4.4.  Free Memory
66  *
67  *    The following function frees the dynamic memory that was allocated by
68  *    if_nameindex().
69  *
70  *        #include <net/if.h>
71  *
72  *        void  if_freenameindex(struct if_nameindex *ptr);
73  *
74  *    The argument to this function must be a pointer that was returned by
75  *    if_nameindex().
76  */
77 
78 struct if_nameindex *
79 if_nameindex(void)
80 {
81 	struct if_nameindex_msg *ifnm = NULL;
82 	struct if_nameindex *ifni = NULL, *ifni2;
83 	char *cp;
84 	size_t needed;
85 	unsigned int ni, i;
86 	int mib[6];
87 
88 	mib[0] = CTL_NET;
89 	mib[1] = PF_ROUTE;
90 	mib[2] = 0;		/* protocol */
91 	mib[3] = 0;		/* not used */
92 	mib[4] = NET_RT_IFNAMES;
93 	mib[5] = 0;		/* no flags */
94 	while (1) {
95 		struct if_nameindex_msg *buf = NULL;
96 
97 		if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
98 			goto out;
99 		if (needed == 0)
100 			break;
101 		if ((buf = realloc(ifnm, needed)) == NULL)
102 			goto out;
103 		ifnm = buf;
104 		if (sysctl(mib, 6, ifnm, &needed, NULL, 0) == -1) {
105 			if (errno == ENOMEM)
106 				continue;
107 			goto out;
108 		}
109 		break;
110 	}
111 
112 	/*
113 	 * Allocate a chunk of memory, use the first part for the array of
114 	 * structures, and the last part for the strings.
115 	 */
116 	ni = needed / sizeof(*ifnm);
117 	ifni = calloc(ni + 1, sizeof(struct if_nameindex) + IF_NAMESIZE);
118 	if (ifni == NULL)
119 		goto out;
120 	cp = (char *)(ifni + (ni + 1));
121 
122 	ifni2 = ifni;
123 	for (i = 0; i < ni; i++) {
124 		ifni2->if_index = ifnm[i].if_index;
125 		/* don't care about truncation */
126 		strlcpy(cp, ifnm[i].if_name, IF_NAMESIZE);
127 		ifni2->if_name = cp;
128 		ifni2++;
129 		cp += IF_NAMESIZE;
130 	}
131 	/* Finally, terminate the array. */
132 	ifni2->if_index = 0;
133 	ifni2->if_name = NULL;
134 out:
135 	free(ifnm);
136 	return ifni;
137 }
138 
139 void
140 if_freenameindex(struct if_nameindex *ptr)
141 {
142 	free(ptr);
143 }
144 DEF_WEAK(if_nameindex);
145 DEF_WEAK(if_freenameindex);
146