or1k: add clone() from old GNU libc implementation
[uclibc-ng.git] / libc / inet / if_index.c
blob2d7ab27fafe5b6eb7b8cd050ae867dffd0fb8296
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; see the file COPYING.LIB. If
17 not, see <http://www.gnu.org/licenses/>.
19 Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
22 #include <string.h>
23 #include <alloca.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <net/if.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <not-cancel.h>
33 #include "netlinkaccess.h"
35 extern int __opensock(void) attribute_hidden;
37 unsigned int
38 if_nametoindex(const char* ifname)
40 #ifndef SIOCGIFINDEX
41 __set_errno (ENOSYS);
42 return 0;
43 #else
44 struct ifreq ifr;
45 int fd = __opensock();
47 if (fd < 0)
48 return 0;
50 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
51 if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
53 /* close never fails here, fd is just a unconnected socket.
54 *int saved_errno = errno; */
55 close_not_cancel_no_status(fd);
56 /*if (saved_errno == EINVAL)
57 * __set_errno(ENOSYS); */
58 return 0;
61 close_not_cancel_no_status(fd);
62 return ifr.ifr_ifindex;
63 #endif
65 libc_hidden_def(if_nametoindex)
67 void
68 if_freenameindex (struct if_nameindex *ifn)
70 struct if_nameindex *ptr = ifn;
71 while (ptr->if_name || ptr->if_index)
73 free (ptr->if_name);
74 ++ptr;
76 free (ifn);
78 libc_hidden_def(if_freenameindex)
80 #if !__ASSUME_NETLINK_SUPPORT
81 struct if_nameindex *
82 if_nameindex (void)
84 #ifndef SIOCGIFINDEX
85 __set_errno (ENOSYS);
86 return NULL;
87 #else
88 int fd = __opensock ();
89 struct ifconf ifc;
90 unsigned int nifs, i;
91 int rq_len;
92 struct if_nameindex *idx = NULL;
93 # define RQ_IFS 4
95 if (fd < 0)
96 return NULL;
98 ifc.ifc_buf = NULL;
100 /* Guess on the correct buffer size... */
101 rq_len = RQ_IFS * sizeof (struct ifreq);
103 /* Read all the interfaces out of the kernel. */
104 /* Note: alloca's in this loop are diff from glibc because it's smaller */
107 ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
108 ifc.ifc_len = rq_len;
110 if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
112 close_not_cancel_no_status (fd);
113 return NULL;
116 while (ifc.ifc_len == rq_len);
118 nifs = ifc.ifc_len / sizeof(struct ifreq);
120 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
121 if (idx == NULL)
123 close_not_cancel_no_status (fd);
124 __set_errno(ENOBUFS);
125 return NULL;
128 for (i = 0; i < nifs; ++i)
130 struct ifreq *ifr = &ifc.ifc_req[i];
131 idx[i].if_name = strdup (ifr->ifr_name);
132 if (idx[i].if_name == NULL
133 || ioctl (fd, SIOCGIFINDEX, ifr) < 0)
135 int saved_errno = errno;
136 unsigned int j;
138 for (j = 0; j < i; ++j)
139 free (idx[j].if_name);
140 free(idx);
141 close_not_cancel_no_status (fd);
142 if (saved_errno == EINVAL)
143 saved_errno = ENOSYS;
144 else if (saved_errno == ENOMEM)
145 saved_errno = ENOBUFS;
146 __set_errno (saved_errno);
147 return NULL;
149 idx[i].if_index = ifr->ifr_ifindex;
152 idx[i].if_index = 0;
153 idx[i].if_name = NULL;
155 close_not_cancel_no_status (fd);
156 return idx;
157 #endif
159 #else
160 struct if_nameindex *
161 if_nameindex (void)
163 unsigned int nifs = 0;
164 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
165 struct if_nameindex *idx = NULL;
166 struct netlink_res *nlp;
168 if (__netlink_open (&nh) < 0)
169 return NULL;
172 /* Tell the kernel that we wish to get a list of all
173 active interfaces. Collect all data for every interface. */
174 if (__netlink_request (&nh, RTM_GETLINK) < 0)
175 goto exit_free;
177 /* Count the interfaces. */
178 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
180 struct nlmsghdr *nlh;
181 size_t size = nlp->size;
183 if (nlp->nlh == NULL)
184 continue;
186 /* Walk through all entries we got from the kernel and look, which
187 message type they contain. */
188 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
190 /* Check if the message is what we want. */
191 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
192 continue;
194 if (nlh->nlmsg_type == NLMSG_DONE)
195 break; /* ok */
197 if (nlh->nlmsg_type == RTM_NEWLINK)
198 ++nifs;
202 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
203 if (idx == NULL)
205 nomem:
206 __set_errno (ENOBUFS);
207 goto exit_free;
210 /* Add the interfaces. */
211 nifs = 0;
212 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
214 struct nlmsghdr *nlh;
215 size_t size = nlp->size;
217 if (nlp->nlh == NULL)
218 continue;
220 /* Walk through all entries we got from the kernel and look, which
221 message type they contain. */
222 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
224 /* Check if the message is what we want. */
225 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
226 continue;
228 if (nlh->nlmsg_type == NLMSG_DONE)
229 break; /* ok */
231 if (nlh->nlmsg_type == RTM_NEWLINK)
233 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
234 struct rtattr *rta = IFLA_RTA (ifim);
235 size_t rtasize = IFLA_PAYLOAD (nlh);
237 idx[nifs].if_index = ifim->ifi_index;
239 while (RTA_OK (rta, rtasize))
241 char *rta_data = RTA_DATA (rta);
242 size_t rta_payload = RTA_PAYLOAD (rta);
244 if (rta->rta_type == IFLA_IFNAME)
246 idx[nifs].if_name = strndup (rta_data, rta_payload);
247 if (idx[nifs].if_name == NULL)
249 idx[nifs].if_index = 0;
250 if_freenameindex (idx);
251 idx = NULL;
252 goto nomem;
254 break;
257 rta = RTA_NEXT (rta, rtasize);
260 ++nifs;
265 idx[nifs].if_index = 0;
266 idx[nifs].if_name = NULL;
268 exit_free:
269 __netlink_free_handle (&nh);
270 __netlink_close (&nh);
272 return idx;
274 #endif
275 libc_hidden_def(if_nameindex)
277 char *
278 if_indextoname (unsigned int ifindex, char *ifname)
280 #if !defined SIOCGIFINDEX
281 __set_errno (ENOSYS);
282 return NULL;
283 #else
284 # ifdef SIOCGIFNAME
285 /* Use ioctl to avoid searching the list. */
286 struct ifreq ifr;
287 int fd;
289 fd = __opensock ();
291 if (fd < 0)
292 return NULL;
294 ifr.ifr_ifindex = ifindex;
295 if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
297 int serrno = errno;
298 close_not_cancel_no_status (fd);
299 if (serrno == ENODEV)
300 /* POSIX requires ENXIO. */
301 serrno = ENXIO;
302 __set_errno (serrno);
303 return NULL;
305 close_not_cancel_no_status (fd);
307 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
308 # else
309 struct if_nameindex *idx;
310 struct if_nameindex *p;
311 char *result = NULL;
313 idx = if_nameindex();
315 if (idx != NULL)
317 for (p = idx; p->if_index || p->if_name; ++p)
318 if (p->if_index == ifindex)
320 result = strncpy (ifname, p->if_name, IFNAMSIZ);
321 break;
324 if_freenameindex (idx);
326 if (result == NULL)
327 __set_errno (ENXIO);
329 return result;
330 # endif
331 #endif