foo
[glibc.git] / sysdeps / unix / sysv / linux / if_index.c
blob0fac763f9f9a9d272203b49f4f7026a8904740d0
1 /* Copyright (C) 1997-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <alloca.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <net/if.h>
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <bits/libc-lock.h>
28 #include <not-cancel.h>
30 #include "netlinkaccess.h"
33 unsigned int
34 if_nametoindex (const char *ifname)
36 #ifndef SIOCGIFINDEX
37 __set_errno (ENOSYS);
38 return 0;
39 #else
40 struct ifreq ifr;
41 int fd = __opensock ();
43 if (fd < 0)
44 return 0;
46 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
47 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
49 int saved_errno = errno;
50 close_not_cancel_no_status (fd);
51 if (saved_errno == EINVAL)
52 __set_errno (ENOSYS);
53 return 0;
55 close_not_cancel_no_status (fd);
56 return ifr.ifr_ifindex;
57 #endif
59 libc_hidden_def (if_nametoindex)
62 void
63 if_freenameindex (struct if_nameindex *ifn)
65 struct if_nameindex *ptr = ifn;
66 while (ptr->if_name || ptr->if_index)
68 free (ptr->if_name);
69 ++ptr;
71 free (ifn);
73 libc_hidden_def (if_freenameindex)
76 static struct if_nameindex *
77 if_nameindex_netlink (void)
79 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
80 struct if_nameindex *idx = NULL;
82 if (__netlink_open (&nh) < 0)
83 return NULL;
86 /* Tell the kernel that we wish to get a list of all
87 active interfaces. Collect all data for every interface. */
88 if (__netlink_request (&nh, RTM_GETLINK) < 0)
89 goto exit_free;
91 /* Count the interfaces. */
92 unsigned int nifs = 0;
93 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
95 struct nlmsghdr *nlh;
96 size_t size = nlp->size;
98 if (nlp->nlh == NULL)
99 continue;
101 /* Walk through all entries we got from the kernel and look, which
102 message type they contain. */
103 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
105 /* Check if the message is what we want. */
106 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
107 continue;
109 if (nlh->nlmsg_type == NLMSG_DONE)
110 break; /* ok */
112 if (nlh->nlmsg_type == RTM_NEWLINK)
113 ++nifs;
117 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
118 if (idx == NULL)
120 nomem:
121 __set_errno (ENOBUFS);
122 goto exit_free;
125 /* Add the interfaces. */
126 nifs = 0;
127 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
129 struct nlmsghdr *nlh;
130 size_t size = nlp->size;
132 if (nlp->nlh == NULL)
133 continue;
135 /* Walk through all entries we got from the kernel and look, which
136 message type they contain. */
137 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
139 /* Check if the message is what we want. */
140 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
141 continue;
143 if (nlh->nlmsg_type == NLMSG_DONE)
144 break; /* ok */
146 if (nlh->nlmsg_type == RTM_NEWLINK)
148 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
149 struct rtattr *rta = IFLA_RTA (ifim);
150 size_t rtasize = IFLA_PAYLOAD (nlh);
152 idx[nifs].if_index = ifim->ifi_index;
154 while (RTA_OK (rta, rtasize))
156 char *rta_data = RTA_DATA (rta);
157 size_t rta_payload = RTA_PAYLOAD (rta);
159 if (rta->rta_type == IFLA_IFNAME)
161 idx[nifs].if_name = __strndup (rta_data, rta_payload);
162 if (idx[nifs].if_name == NULL)
164 idx[nifs].if_index = 0;
165 if_freenameindex (idx);
166 idx = NULL;
167 goto nomem;
169 break;
172 rta = RTA_NEXT (rta, rtasize);
175 ++nifs;
180 idx[nifs].if_index = 0;
181 idx[nifs].if_name = NULL;
183 exit_free:
184 __netlink_free_handle (&nh);
185 __netlink_close (&nh);
187 return idx;
191 struct if_nameindex *
192 if_nameindex (void)
194 #ifndef SIOCGIFINDEX
195 __set_errno (ENOSYS);
196 return NULL;
197 #else
198 struct if_nameindex *result = if_nameindex_netlink ();
199 return result;
200 #endif
202 libc_hidden_def (if_nameindex)
205 char *
206 if_indextoname (unsigned int ifindex, char *ifname)
208 /* We may be able to do the conversion directly, rather than searching a
209 list. This ioctl is not present in kernels before version 2.1.50. */
210 struct ifreq ifr;
211 int fd;
212 int status;
214 fd = __opensock ();
216 if (fd < 0)
217 return NULL;
219 ifr.ifr_ifindex = ifindex;
220 status = __ioctl (fd, SIOCGIFNAME, &ifr);
222 close_not_cancel_no_status (fd);
224 if (status < 0)
226 if (errno == ENODEV)
227 /* POSIX requires ENXIO. */
228 __set_errno (ENXIO);
230 return NULL;
232 else
233 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
235 libc_hidden_def (if_indextoname)