Update copyright notices with scripts/update-copyrights
[glibc.git] / sysdeps / unix / sysv / linux / if_index.c
blobf8948a4176df7381873a51e75b178a2089a8e6e7
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>
29 #include <kernel-features.h>
31 #include "netlinkaccess.h"
34 unsigned int
35 if_nametoindex (const char *ifname)
37 #ifndef SIOCGIFINDEX
38 __set_errno (ENOSYS);
39 return 0;
40 #else
41 struct ifreq ifr;
42 int fd = __opensock ();
44 if (fd < 0)
45 return 0;
47 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
48 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
50 int saved_errno = errno;
51 close_not_cancel_no_status (fd);
52 if (saved_errno == EINVAL)
53 __set_errno (ENOSYS);
54 return 0;
56 close_not_cancel_no_status (fd);
57 return ifr.ifr_ifindex;
58 #endif
60 libc_hidden_def (if_nametoindex)
63 void
64 if_freenameindex (struct if_nameindex *ifn)
66 struct if_nameindex *ptr = ifn;
67 while (ptr->if_name || ptr->if_index)
69 free (ptr->if_name);
70 ++ptr;
72 free (ifn);
74 libc_hidden_def (if_freenameindex)
77 static struct if_nameindex *
78 if_nameindex_netlink (void)
80 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
81 struct if_nameindex *idx = NULL;
83 if (__netlink_open (&nh) < 0)
84 return NULL;
87 /* Tell the kernel that we wish to get a list of all
88 active interfaces. Collect all data for every interface. */
89 if (__netlink_request (&nh, RTM_GETLINK) < 0)
90 goto exit_free;
92 /* Count the interfaces. */
93 unsigned int nifs = 0;
94 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
96 struct nlmsghdr *nlh;
97 size_t size = nlp->size;
99 if (nlp->nlh == NULL)
100 continue;
102 /* Walk through all entries we got from the kernel and look, which
103 message type they contain. */
104 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
106 /* Check if the message is what we want. */
107 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
108 continue;
110 if (nlh->nlmsg_type == NLMSG_DONE)
111 break; /* ok */
113 if (nlh->nlmsg_type == RTM_NEWLINK)
114 ++nifs;
118 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
119 if (idx == NULL)
121 nomem:
122 __set_errno (ENOBUFS);
123 goto exit_free;
126 /* Add the interfaces. */
127 nifs = 0;
128 for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
130 struct nlmsghdr *nlh;
131 size_t size = nlp->size;
133 if (nlp->nlh == NULL)
134 continue;
136 /* Walk through all entries we got from the kernel and look, which
137 message type they contain. */
138 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
140 /* Check if the message is what we want. */
141 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
142 continue;
144 if (nlh->nlmsg_type == NLMSG_DONE)
145 break; /* ok */
147 if (nlh->nlmsg_type == RTM_NEWLINK)
149 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
150 struct rtattr *rta = IFLA_RTA (ifim);
151 size_t rtasize = IFLA_PAYLOAD (nlh);
153 idx[nifs].if_index = ifim->ifi_index;
155 while (RTA_OK (rta, rtasize))
157 char *rta_data = RTA_DATA (rta);
158 size_t rta_payload = RTA_PAYLOAD (rta);
160 if (rta->rta_type == IFLA_IFNAME)
162 idx[nifs].if_name = __strndup (rta_data, rta_payload);
163 if (idx[nifs].if_name == NULL)
165 idx[nifs].if_index = 0;
166 if_freenameindex (idx);
167 idx = NULL;
168 goto nomem;
170 break;
173 rta = RTA_NEXT (rta, rtasize);
176 ++nifs;
181 idx[nifs].if_index = 0;
182 idx[nifs].if_name = NULL;
184 exit_free:
185 __netlink_free_handle (&nh);
186 __netlink_close (&nh);
188 return idx;
192 struct if_nameindex *
193 if_nameindex (void)
195 #ifndef SIOCGIFINDEX
196 __set_errno (ENOSYS);
197 return NULL;
198 #else
199 struct if_nameindex *result = if_nameindex_netlink ();
200 return result;
201 #endif
203 libc_hidden_def (if_nameindex)
206 char *
207 if_indextoname (unsigned int ifindex, char *ifname)
209 /* We may be able to do the conversion directly, rather than searching a
210 list. This ioctl is not present in kernels before version 2.1.50. */
211 struct ifreq ifr;
212 int fd;
213 int status;
215 fd = __opensock ();
217 if (fd < 0)
218 return NULL;
220 ifr.ifr_ifindex = ifindex;
221 status = __ioctl (fd, SIOCGIFNAME, &ifr);
223 close_not_cancel_no_status (fd);
225 if (status < 0)
227 if (errno == ENODEV)
228 /* POSIX requires ENXIO. */
229 __set_errno (ENXIO);
231 return NULL;
233 else
234 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
236 libc_hidden_def (if_indextoname)