2.5-18.1
[glibc.git] / sysdeps / unix / sysv / linux / if_index.c
blob66f0ac131733ff398642e82fac01086228ff4d8d
1 /* 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.
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.
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.
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. */
20 #include <alloca.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <net/if.h>
27 #include <sys/socket.h>
28 #include <sys/ioctl.h>
29 #include <bits/libc-lock.h>
30 #include <not-cancel.h>
32 #include "netlinkaccess.h"
35 /* Variable to signal whether SIOCGIFCONF is not available. */
36 # if __ASSUME_SIOCGIFNAME == 0
37 static int old_siocgifconf;
38 #else
39 # define old_siocgifconf 0
40 #endif
43 unsigned int
44 if_nametoindex (const char *ifname)
46 #ifndef SIOCGIFINDEX
47 __set_errno (ENOSYS);
48 return 0;
49 #else
50 struct ifreq ifr;
51 int fd = __opensock ();
53 if (fd < 0)
54 return 0;
56 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
57 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
59 int saved_errno = errno;
60 close_not_cancel_no_status (fd);
61 if (saved_errno == EINVAL)
62 __set_errno (ENOSYS);
63 return 0;
65 close_not_cancel_no_status (fd);
66 return ifr.ifr_ifindex;
67 #endif
69 libc_hidden_def (if_nametoindex)
72 void
73 if_freenameindex (struct if_nameindex *ifn)
75 struct if_nameindex *ptr = ifn;
76 while (ptr->if_name || ptr->if_index)
78 free (ptr->if_name);
79 ++ptr;
81 free (ifn);
83 libc_hidden_def (if_freenameindex)
86 #if __ASSUME_NETLINK_SUPPORT == 0
87 static struct if_nameindex *
88 if_nameindex_ioctl (void)
90 int fd = __opensock ();
91 struct ifconf ifc;
92 unsigned int nifs, i;
93 int rq_len;
94 struct if_nameindex *idx = NULL;
95 # define RQ_IFS 4
97 if (fd < 0)
98 return NULL;
100 ifc.ifc_buf = NULL;
102 /* We may be able to get the needed buffer size directly, rather than
103 guessing. */
104 if (! old_siocgifconf)
106 ifc.ifc_buf = NULL;
107 ifc.ifc_len = 0;
108 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
110 # if __ASSUME_SIOCGIFNAME == 0
111 old_siocgifconf = 1;
112 # endif
113 rq_len = RQ_IFS * sizeof (struct ifreq);
115 else
116 rq_len = ifc.ifc_len;
118 else
119 rq_len = RQ_IFS * sizeof (struct ifreq);
121 /* Read all the interfaces out of the kernel. */
122 ifc.ifc_buf = alloca (rq_len);
123 ifc.ifc_len = rq_len;
124 while (1)
126 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0)
128 close_not_cancel_no_status (fd);
129 return NULL;
131 if (ifc.ifc_len < rq_len || ! old_siocgifconf)
132 break;
134 ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
135 ifc.ifc_len = rq_len;
138 nifs = ifc.ifc_len / sizeof (struct ifreq);
140 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
141 if (idx == NULL)
143 close_not_cancel_no_status (fd);
144 __set_errno (ENOBUFS);
145 return NULL;
148 for (i = 0; i < nifs; ++i)
150 struct ifreq *ifr = &ifc.ifc_req[i];
151 idx[i].if_name = __strdup (ifr->ifr_name);
152 if (idx[i].if_name == NULL
153 || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
155 int saved_errno = errno;
156 unsigned int j;
158 for (j = 0; j < i; ++j)
159 free (idx[j].if_name);
160 free (idx);
161 close_not_cancel_no_status (fd);
162 if (saved_errno == EINVAL)
163 saved_errno = ENOSYS;
164 else if (saved_errno == ENOMEM)
165 saved_errno = ENOBUFS;
166 __set_errno (saved_errno);
167 return NULL;
169 idx[i].if_index = ifr->ifr_ifindex;
172 idx[i].if_index = 0;
173 idx[i].if_name = NULL;
175 close_not_cancel_no_status (fd);
176 return idx;
178 #endif
181 static struct if_nameindex *
182 if_nameindex_netlink (void)
184 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
185 struct if_nameindex *idx = NULL;
187 if (__no_netlink_support || __netlink_open (&nh) < 0)
188 return NULL;
191 /* Tell the kernel that we wish to get a list of all
192 active interfaces. Collect all data for every interface. */
193 if (__netlink_request (&nh, RTM_GETLINK) < 0)
194 goto exit_free;
196 /* Count the interfaces. */
197 unsigned int nifs = 0;
198 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
200 struct nlmsghdr *nlh;
201 size_t size = nlp->size;
203 if (nlp->nlh == NULL)
204 continue;
206 /* Walk through all entries we got from the kernel and look, which
207 message type they contain. */
208 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
210 /* Check if the message is what we want. */
211 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
212 continue;
214 if (nlh->nlmsg_type == NLMSG_DONE)
215 break; /* ok */
217 if (nlh->nlmsg_type == RTM_NEWLINK)
218 ++nifs;
222 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
223 if (idx == NULL)
225 nomem:
226 __set_errno (ENOBUFS);
227 goto exit_free;
230 /* Add the interfaces. */
231 nifs = 0;
232 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
234 struct nlmsghdr *nlh;
235 size_t size = nlp->size;
237 if (nlp->nlh == NULL)
238 continue;
240 /* Walk through all entries we got from the kernel and look, which
241 message type they contain. */
242 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
244 /* Check if the message is what we want. */
245 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
246 continue;
248 if (nlh->nlmsg_type == NLMSG_DONE)
249 break; /* ok */
251 if (nlh->nlmsg_type == RTM_NEWLINK)
253 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
254 struct rtattr *rta = IFLA_RTA (ifim);
255 size_t rtasize = IFLA_PAYLOAD (nlh);
257 idx[nifs].if_index = ifim->ifi_index;
259 while (RTA_OK (rta, rtasize))
261 char *rta_data = RTA_DATA (rta);
262 size_t rta_payload = RTA_PAYLOAD (rta);
264 if (rta->rta_type == IFLA_IFNAME)
266 idx[nifs].if_name = __strndup (rta_data, rta_payload);
267 if (idx[nifs].if_name == NULL)
269 idx[nifs].if_index = 0;
270 if_freenameindex (idx);
271 idx = NULL;
272 goto nomem;
274 break;
277 rta = RTA_NEXT (rta, rtasize);
280 ++nifs;
285 idx[nifs].if_index = 0;
286 idx[nifs].if_name = NULL;
288 exit_free:
289 __netlink_free_handle (&nh);
290 __netlink_close (&nh);
292 return idx;
296 struct if_nameindex *
297 if_nameindex (void)
299 #ifndef SIOCGIFINDEX
300 __set_errno (ENOSYS);
301 return NULL;
302 #else
303 struct if_nameindex *result = if_nameindex_netlink ();
304 # if __ASSUME_NETLINK_SUPPORT == 0
305 if (__no_netlink_support)
306 result = if_nameindex_ioctl ();
307 # endif
308 return result;
309 #endif
311 libc_hidden_def (if_nameindex)
314 char *
315 if_indextoname (unsigned int ifindex, char *ifname)
317 #if !defined SIOCGIFINDEX && __ASSUME_SIOCGIFNAME == 0
318 __set_errno (ENOSYS);
319 return NULL;
320 #else
321 # if __ASSUME_SIOCGIFNAME == 0
322 struct if_nameindex *idx;
323 struct if_nameindex *p;
324 char *result = NULL;
325 # endif
327 # if defined SIOCGIFNAME || __ASSUME_SIOCGIFNAME > 0
328 /* We may be able to do the conversion directly, rather than searching a
329 list. This ioctl is not present in kernels before version 2.1.50. */
330 struct ifreq ifr;
331 int fd;
332 # if __ASSUME_SIOCGIFNAME == 0
333 static int siocgifname_works_not;
335 if (!siocgifname_works_not)
336 # endif
338 # if __ASSUME_SIOCGIFNAME == 0
339 int serrno = errno;
340 # endif
341 int status;
343 fd = __opensock ();
345 if (fd < 0)
346 return NULL;
348 ifr.ifr_ifindex = ifindex;
349 status = __ioctl (fd, SIOCGIFNAME, &ifr);
351 close_not_cancel_no_status (fd);
353 if (status < 0)
355 # if __ASSUME_SIOCGIFNAME == 0
356 if (errno == EINVAL)
357 siocgifname_works_not = 1; /* Don't make the same mistake twice. */
358 else
359 # endif
361 if (errno == ENODEV)
362 /* POSIX requires ENXIO. */
363 __set_errno (ENXIO);
365 return NULL;
368 else
369 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
371 # if __ASSUME_SIOCGIFNAME == 0
372 __set_errno (serrno);
373 # endif
375 # endif
377 # if __ASSUME_SIOCGIFNAME == 0
378 idx = if_nameindex ();
380 if (idx != NULL)
382 for (p = idx; p->if_index || p->if_name; ++p)
383 if (p->if_index == ifindex)
385 result = strncpy (ifname, p->if_name, IFNAMSIZ);
386 break;
389 if_freenameindex (idx);
391 if (result == NULL)
392 __set_errno (ENXIO);
394 return result;
395 # endif
396 #endif
398 libc_hidden_def (if_indextoname)
401 #if 0
402 void
403 internal_function
404 __protocol_available (int *have_inet, int *have_inet6)
406 int fd = __opensock ();
407 unsigned int nifs;
408 int rq_len;
409 struct ifconf ifc;
410 # define RQ_IFS 4
412 /* Wirst case assumption. */
413 *have_inet = 0;
414 *have_inet6 = 0;
416 if (fd < 0)
417 /* We cannot open the socket. No networking at all? */
418 return;
420 /* We may be able to get the needed buffer size directly, rather than
421 guessing. */
422 if (! old_siocgifconf)
424 ifc.ifc_buf = NULL;
425 ifc.ifc_len = 0;
426 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
428 # if __ASSUME_SIOCGIFNAME == 0
429 old_siocgifconf = 1;
430 # endif
431 rq_len = RQ_IFS * sizeof (struct ifreq);
433 else
434 rq_len = ifc.ifc_len;
436 else
437 rq_len = RQ_IFS * sizeof (struct ifreq);
439 /* Read all the interfaces out of the kernel. */
442 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
443 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0)
445 close_not_cancel_no_status (fd);
446 return;
448 rq_len *= 2;
450 while (ifc.ifc_len == rq_len && old_siocgifconf);
452 nifs = ifc.ifc_len / sizeof (struct ifreq);
454 /* Go through all the interfaces and get the address. */
455 while (nifs-- > 0)
456 if (__ioctl (fd, SIOCGIFADDR, &ifc.ifc_req[nifs]) >= 0)
458 /* We successfully got information about this interface. Now
459 test whether it is an IPv4 or IPv6 address. */
460 if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET)
461 *have_inet = 1;
462 else if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET6)
463 *have_inet6 = 1;
465 /* Note, this is & not &&. It works since the values are always
466 0 or 1. */
467 if (*have_inet & *have_inet6)
468 /* We can stop early. */
469 break;
472 close_not_cancel_no_status (fd);
474 #endif