]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/inet/if_index.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / inet / if_index.c
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.
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; see the file COPYING.LIB.  If
17    not, see <http://www.gnu.org/licenses/>.
18
19    Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
20  */
21
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>
32
33 #include "netlinkaccess.h"
34
35 extern int __opensock(void) attribute_hidden;
36
37 unsigned int
38 if_nametoindex(const char* ifname)
39 {
40 #ifndef SIOCGIFINDEX
41   __set_errno (ENOSYS);
42   return 0;
43 #else
44   struct ifreq ifr;
45   int fd = __opensock();
46
47   if (fd < 0)
48     return 0;
49
50   strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
51   if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
52     {
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;
59     }
60
61   close_not_cancel_no_status(fd);
62   return ifr.ifr_ifindex;
63 #endif
64 }
65 libc_hidden_def(if_nametoindex)
66
67 void
68 if_freenameindex (struct if_nameindex *ifn)
69 {
70   struct if_nameindex *ptr = ifn;
71   while (ptr->if_name || ptr->if_index)
72     {
73       free (ptr->if_name);
74       ++ptr;
75     }
76   free (ifn);
77 }
78 libc_hidden_def(if_freenameindex)
79
80 #if !__ASSUME_NETLINK_SUPPORT
81 struct if_nameindex *
82 if_nameindex (void)
83 {
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
94
95   if (fd < 0)
96     return NULL;
97
98   ifc.ifc_buf = NULL;
99
100   /* Guess on the correct buffer size... */
101   rq_len = RQ_IFS * sizeof (struct ifreq);
102
103   /* Read all the interfaces out of the kernel.  */
104   /* Note: alloca's in this loop are diff from glibc because it's smaller */
105   do
106     {
107       ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
108       ifc.ifc_len = rq_len;
109
110       if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
111         {
112           close_not_cancel_no_status (fd);
113           return NULL;
114         }
115     }
116   while (ifc.ifc_len == rq_len);
117
118   nifs = ifc.ifc_len / sizeof(struct ifreq);
119
120   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
121   if (idx == NULL)
122     {
123       close_not_cancel_no_status (fd);
124       __set_errno(ENOBUFS);
125       return NULL;
126     }
127
128   for (i = 0; i < nifs; ++i)
129     {
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)
134         {
135           int saved_errno = errno;
136           unsigned int j;
137
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;
148         }
149       idx[i].if_index = ifr->ifr_ifindex;
150     }
151
152   idx[i].if_index = 0;
153   idx[i].if_name = NULL;
154
155   close_not_cancel_no_status (fd);
156   return idx;
157 #endif
158 }
159 #else
160 struct if_nameindex *
161 if_nameindex (void)
162 {
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;
167
168   if (__netlink_open (&nh) < 0)
169     return NULL;
170
171
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;
176
177   /* Count the interfaces.  */
178   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
179     {
180       struct nlmsghdr *nlh;
181       size_t size = nlp->size;
182
183       if (nlp->nlh == NULL)
184         continue;
185
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))
189         {
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;
193
194           if (nlh->nlmsg_type == NLMSG_DONE)
195             break;              /* ok */
196
197           if (nlh->nlmsg_type == RTM_NEWLINK)
198             ++nifs;
199         }
200     }
201
202   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
203   if (idx == NULL)
204     {
205     nomem:
206       __set_errno (ENOBUFS);
207       goto exit_free;
208     }
209
210   /* Add the interfaces.  */
211   nifs = 0;
212   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
213     {
214       struct nlmsghdr *nlh;
215       size_t size = nlp->size;
216
217       if (nlp->nlh == NULL)
218         continue;
219
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))
223         {
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;
227
228           if (nlh->nlmsg_type == NLMSG_DONE)
229             break;              /* ok */
230
231           if (nlh->nlmsg_type == RTM_NEWLINK)
232             {
233               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
234               struct rtattr *rta = IFLA_RTA (ifim);
235               size_t rtasize = IFLA_PAYLOAD (nlh);
236
237               idx[nifs].if_index = ifim->ifi_index;
238
239               while (RTA_OK (rta, rtasize))
240                 {
241                   char *rta_data = RTA_DATA (rta);
242                   size_t rta_payload = RTA_PAYLOAD (rta);
243
244                   if (rta->rta_type == IFLA_IFNAME)
245                     {
246                       idx[nifs].if_name = strndup (rta_data, rta_payload);
247                       if (idx[nifs].if_name == NULL)
248                         {
249                           idx[nifs].if_index = 0;
250                           if_freenameindex (idx);
251                           idx = NULL;
252                           goto nomem;
253                         }
254                       break;
255                     }
256
257                   rta = RTA_NEXT (rta, rtasize);
258                 }
259
260               ++nifs;
261             }
262         }
263     }
264
265   idx[nifs].if_index = 0;
266   idx[nifs].if_name = NULL;
267
268  exit_free:
269   __netlink_free_handle (&nh);
270   __netlink_close (&nh);
271
272   return idx;
273 }
274 #endif
275 libc_hidden_def(if_nameindex)
276
277 char *
278 if_indextoname (unsigned int ifindex, char *ifname)
279 {
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;
288
289   fd = __opensock ();
290
291   if (fd < 0)
292     return NULL;
293
294   ifr.ifr_ifindex = ifindex;
295   if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
296     {
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;
304   }
305   close_not_cancel_no_status (fd);
306
307   return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
308 # else
309   struct if_nameindex *idx;
310   struct if_nameindex *p;
311   char *result = NULL;
312
313   idx = if_nameindex();
314
315   if (idx != NULL)
316     {
317       for (p = idx; p->if_index || p->if_name; ++p)
318         if (p->if_index == ifindex)
319           {
320             result = strncpy (ifname, p->if_name, IFNAMSIZ);
321             break;
322           }
323
324       if_freenameindex (idx);
325
326       if (result == NULL)
327         __set_errno (ENXIO);
328     }
329   return result;
330 # endif
331 #endif
332 }
333