blob: 8efcd2a76fbf42983283690db70ff390a44ced5c [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA.
19
20 Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
21 */
22
23#define __FORCE_GLIBC
24#include <features.h>
25#include <string.h>
26#include <alloca.h>
27#include <errno.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <net/if.h>
32#include <sys/socket.h>
33#include <sys/ioctl.h>
34#include <libc-internal.h>
35#include <not-cancel.h>
36
37#include "netlinkaccess.h"
38
39extern int __opensock(void) attribute_hidden;
40
41unsigned int
42if_nametoindex(const char* ifname)
43{
44#ifndef SIOCGIFINDEX
45 __set_errno (ENOSYS);
46 return 0;
47#else
48 struct ifreq ifr;
49 int fd = __opensock();
50
51 if (fd < 0)
52 return 0;
53
54 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
55 if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
56 {
57 /* close never fails here, fd is just a unconnected socket.
58 *int saved_errno = errno; */
59 close_not_cancel_no_status(fd);
60 /*if (saved_errno == EINVAL)
61 * __set_errno(ENOSYS); */
62 return 0;
63 }
64
65 close_not_cancel_no_status(fd);
66 return ifr.ifr_ifindex;
67#endif
68}
69libc_hidden_def(if_nametoindex)
70
71void
72if_freenameindex (struct if_nameindex *ifn)
73{
74 struct if_nameindex *ptr = ifn;
75 while (ptr->if_name || ptr->if_index)
76 {
77 free (ptr->if_name);
78 ++ptr;
79 }
80 free (ifn);
81}
82libc_hidden_def(if_freenameindex)
83
84#if !__ASSUME_NETLINK_SUPPORT
85struct if_nameindex *
86if_nameindex (void)
87{
88#ifndef SIOCGIFINDEX
89 __set_errno (ENOSYS);
90 return NULL;
91#else
92 int fd = __opensock ();
93 struct ifconf ifc;
94 unsigned int nifs, i;
95 int rq_len;
96 struct if_nameindex *idx = NULL;
97# define RQ_IFS 4
98
99 if (fd < 0)
100 return NULL;
101
102 ifc.ifc_buf = NULL;
103
104 /* Guess on the correct buffer size... */
105 rq_len = RQ_IFS * sizeof (struct ifreq);
106
107 /* Read all the interfaces out of the kernel. */
108 /* Note: alloca's in this loop are diff from glibc because it's smaller */
109 do
110 {
111 ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
112 ifc.ifc_len = rq_len;
113
114 if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
115 {
116 close_not_cancel_no_status (fd);
117 return NULL;
118 }
119 }
120 while (ifc.ifc_len == rq_len);
121
122 nifs = ifc.ifc_len / sizeof(struct ifreq);
123
124 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
125 if (idx == NULL)
126 {
127 close_not_cancel_no_status (fd);
128 __set_errno(ENOBUFS);
129 return NULL;
130 }
131
132 for (i = 0; i < nifs; ++i)
133 {
134 struct ifreq *ifr = &ifc.ifc_req[i];
135 idx[i].if_name = strdup (ifr->ifr_name);
136 if (idx[i].if_name == NULL
137 || ioctl (fd, SIOCGIFINDEX, ifr) < 0)
138 {
139 int saved_errno = errno;
140 unsigned int j;
141
142 for (j = 0; j < i; ++j)
143 free (idx[j].if_name);
144 free(idx);
145 close_not_cancel_no_status (fd);
146 if (saved_errno == EINVAL)
147 saved_errno = ENOSYS;
148 else if (saved_errno == ENOMEM)
149 saved_errno = ENOBUFS;
150 __set_errno (saved_errno);
151 return NULL;
152 }
153 idx[i].if_index = ifr->ifr_ifindex;
154 }
155
156 idx[i].if_index = 0;
157 idx[i].if_name = NULL;
158
159 close_not_cancel_no_status (fd);
160 return idx;
161#endif
162}
163#else
164struct if_nameindex *
165if_nameindex (void)
166{
167 unsigned int nifs = 0;
168 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
169 struct if_nameindex *idx = NULL;
170 struct netlink_res *nlp;
171
172 if (__netlink_open (&nh) < 0)
173 return NULL;
174
175
176 /* Tell the kernel that we wish to get a list of all
177 active interfaces. Collect all data for every interface. */
178 if (__netlink_request (&nh, RTM_GETLINK) < 0)
179 goto exit_free;
180
181 /* Count the interfaces. */
182 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
183 {
184 struct nlmsghdr *nlh;
185 size_t size = nlp->size;
186
187 if (nlp->nlh == NULL)
188 continue;
189
190 /* Walk through all entries we got from the kernel and look, which
191 message type they contain. */
192 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
193 {
194 /* Check if the message is what we want. */
195 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
196 continue;
197
198 if (nlh->nlmsg_type == NLMSG_DONE)
199 break; /* ok */
200
201 if (nlh->nlmsg_type == RTM_NEWLINK)
202 ++nifs;
203 }
204 }
205
206 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
207 if (idx == NULL)
208 {
209 nomem:
210 __set_errno (ENOBUFS);
211 goto exit_free;
212 }
213
214 /* Add the interfaces. */
215 nifs = 0;
216 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
217 {
218 struct nlmsghdr *nlh;
219 size_t size = nlp->size;
220
221 if (nlp->nlh == NULL)
222 continue;
223
224 /* Walk through all entries we got from the kernel and look, which
225 message type they contain. */
226 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
227 {
228 /* Check if the message is what we want. */
229 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
230 continue;
231
232 if (nlh->nlmsg_type == NLMSG_DONE)
233 break; /* ok */
234
235 if (nlh->nlmsg_type == RTM_NEWLINK)
236 {
237 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
238 struct rtattr *rta = IFLA_RTA (ifim);
239 size_t rtasize = IFLA_PAYLOAD (nlh);
240
241 idx[nifs].if_index = ifim->ifi_index;
242
243 while (RTA_OK (rta, rtasize))
244 {
245 char *rta_data = RTA_DATA (rta);
246 size_t rta_payload = RTA_PAYLOAD (rta);
247
248 if (rta->rta_type == IFLA_IFNAME)
249 {
250 idx[nifs].if_name = strndup (rta_data, rta_payload);
251 if (idx[nifs].if_name == NULL)
252 {
253 idx[nifs].if_index = 0;
254 if_freenameindex (idx);
255 idx = NULL;
256 goto nomem;
257 }
258 break;
259 }
260
261 rta = RTA_NEXT (rta, rtasize);
262 }
263
264 ++nifs;
265 }
266 }
267 }
268
269 idx[nifs].if_index = 0;
270 idx[nifs].if_name = NULL;
271
272 exit_free:
273 __netlink_free_handle (&nh);
274 __netlink_close (&nh);
275
276 return idx;
277}
278#endif
279libc_hidden_def(if_nameindex)
280
281char *
282if_indextoname (unsigned int ifindex, char *ifname)
283{
284#if !defined SIOCGIFINDEX
285 __set_errno (ENOSYS);
286 return NULL;
287#else
288# ifdef SIOCGIFNAME
289 /* Use ioctl to avoid searching the list. */
290 struct ifreq ifr;
291 int fd;
292
293 fd = __opensock ();
294
295 if (fd < 0)
296 return NULL;
297
298 ifr.ifr_ifindex = ifindex;
299 if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
300 {
301 int serrno = errno;
302 close_not_cancel_no_status (fd);
303 if (serrno == ENODEV)
304 /* POSIX requires ENXIO. */
305 serrno = ENXIO;
306 __set_errno (serrno);
307 return NULL;
308 }
309 close_not_cancel_no_status (fd);
310
311 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
312# else
313 struct if_nameindex *idx;
314 struct if_nameindex *p;
315 char *result = NULL;
316
317 idx = if_nameindex();
318
319 if (idx != NULL)
320 {
321 for (p = idx; p->if_index || p->if_name; ++p)
322 if (p->if_index == ifindex)
323 {
324 result = strncpy (ifname, p->if_name, IFNAMSIZ);
325 break;
326 }
327
328 if_freenameindex (idx);
329
330 if (result == NULL)
331 __set_errno (ENXIO);
332 }
333 return result;
334# endif
335#endif
336}
337