OSDN Git Service

- adds several config-options to allow for turning off certain features
[uclinux-h8/uClibc.git] / 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; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.
19
20    Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
21  */
22
23 #define __FORCE_GLIBC
24 #include <features.h>
25 #include <string.h>
26 #include <alloca.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <net/if.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <libc-internal.h>
35
36 #include "netlinkaccess.h"
37
38 /* Experimentally off - libc_hidden_proto(strncpy) */
39 /* Experimentally off - libc_hidden_proto(strdup) */
40 libc_hidden_proto(ioctl)
41 libc_hidden_proto(close)
42 #if __ASSUME_NETLINK_SUPPORT
43 /* Experimentally off - libc_hidden_proto(strndup) */
44 #endif
45
46 extern int __opensock(void) attribute_hidden;
47
48 libc_hidden_proto(if_nametoindex)
49 unsigned int
50 if_nametoindex(const char* ifname) 
51 {
52 #ifndef SIOCGIFINDEX
53   __set_errno (ENOSYS);
54   return 0;
55 #else
56   struct ifreq ifr;
57   int fd = __opensock();
58
59   if (fd < 0)
60     return 0;
61
62   strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
63   if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
64     {
65       int saved_errno = errno;
66       close(fd);
67       if (saved_errno == EINVAL)
68         __set_errno(ENOSYS);
69       return 0;
70     }
71
72   close(fd);
73   return ifr.ifr_ifindex;
74 #endif
75 }
76 libc_hidden_def(if_nametoindex)
77
78 libc_hidden_proto(if_freenameindex)
79 void
80 if_freenameindex (struct if_nameindex *ifn)
81 {
82   struct if_nameindex *ptr = ifn;
83   while (ptr->if_name || ptr->if_index)
84     {
85       free (ptr->if_name);
86       ++ptr;
87     }
88   free (ifn);
89 }
90 libc_hidden_def(if_freenameindex)
91
92 libc_hidden_proto(if_nameindex)
93 #if !__ASSUME_NETLINK_SUPPORT
94 struct if_nameindex *
95 if_nameindex (void)
96 {
97 #ifndef SIOCGIFINDEX
98   __set_errno (ENOSYS);
99   return NULL;
100 #else
101   int fd = __opensock ();
102   struct ifconf ifc;
103   unsigned int nifs, i;
104   int rq_len;
105   struct if_nameindex *idx = NULL;
106 # define RQ_IFS 4
107
108   if (fd < 0)
109     return NULL;
110
111   ifc.ifc_buf = NULL;
112
113   /* Guess on the correct buffer size... */
114   rq_len = RQ_IFS * sizeof (struct ifreq);
115
116   /* Read all the interfaces out of the kernel.  */
117   /* Note: alloca's in this loop are diff from glibc because it's smaller */
118   do
119     {
120       ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
121       ifc.ifc_len = rq_len;
122
123       if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
124         {
125           close (fd);
126           return NULL;
127         }
128     }
129   while (ifc.ifc_len == rq_len);
130
131   nifs = ifc.ifc_len / sizeof(struct ifreq);
132
133   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
134   if (idx == NULL)
135     {
136       close(fd);
137       __set_errno(ENOBUFS);
138       return NULL;
139     }
140
141   for (i = 0; i < nifs; ++i)
142     {
143       struct ifreq *ifr = &ifc.ifc_req[i];
144       idx[i].if_name = strdup (ifr->ifr_name);
145       if (idx[i].if_name == NULL
146           || ioctl (fd, SIOCGIFINDEX, ifr) < 0)
147         {
148           int saved_errno = errno;
149           unsigned int j;
150
151           for (j =  0; j < i; ++j)
152             free (idx[j].if_name);
153           free(idx);
154           close(fd);
155           if (saved_errno == EINVAL)
156             saved_errno = ENOSYS;
157           else if (saved_errno == ENOMEM)
158             saved_errno = ENOBUFS;
159           __set_errno (saved_errno);
160           return NULL;
161         }
162       idx[i].if_index = ifr->ifr_ifindex;
163     }
164
165   idx[i].if_index = 0;
166   idx[i].if_name = NULL;
167
168   close(fd);
169   return idx;
170 #endif
171 }
172 #else
173 struct if_nameindex *
174 if_nameindex (void)
175 {
176   unsigned int nifs = 0;
177   struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
178   struct if_nameindex *idx = NULL;
179   struct netlink_res *nlp;
180
181   if (__netlink_open (&nh) < 0)
182     return NULL;
183
184
185   /* Tell the kernel that we wish to get a list of all
186      active interfaces.  Collect all data for every interface.  */
187   if (__netlink_request (&nh, RTM_GETLINK) < 0)
188     goto exit_free;
189
190   /* Count the interfaces.  */
191   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
192     {
193       struct nlmsghdr *nlh;
194       size_t size = nlp->size;
195
196       if (nlp->nlh == NULL)
197         continue;
198
199       /* Walk through all entries we got from the kernel and look, which
200          message type they contain.  */
201       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
202         {
203           /* Check if the message is what we want.  */
204           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
205             continue;
206
207           if (nlh->nlmsg_type == NLMSG_DONE)
208             break;              /* ok */
209
210           if (nlh->nlmsg_type == RTM_NEWLINK)
211             ++nifs;
212         }
213     }
214
215   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
216   if (idx == NULL)
217     {
218     nomem:
219       __set_errno (ENOBUFS);
220       goto exit_free;
221     }
222
223   /* Add the interfaces.  */
224   nifs = 0;
225   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
226     {
227       struct nlmsghdr *nlh;
228       size_t size = nlp->size;
229
230       if (nlp->nlh == NULL)
231         continue;
232
233       /* Walk through all entries we got from the kernel and look, which
234          message type they contain.  */
235       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
236         {
237           /* Check if the message is what we want.  */
238           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
239             continue;
240
241           if (nlh->nlmsg_type == NLMSG_DONE)
242             break;              /* ok */
243
244           if (nlh->nlmsg_type == RTM_NEWLINK)
245             {
246               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
247               struct rtattr *rta = IFLA_RTA (ifim);
248               size_t rtasize = IFLA_PAYLOAD (nlh);
249
250               idx[nifs].if_index = ifim->ifi_index;
251
252               while (RTA_OK (rta, rtasize))
253                 {
254                   char *rta_data = RTA_DATA (rta);
255                   size_t rta_payload = RTA_PAYLOAD (rta);
256
257                   if (rta->rta_type == IFLA_IFNAME)
258                     {
259                       idx[nifs].if_name = strndup (rta_data, rta_payload);
260                       if (idx[nifs].if_name == NULL)
261                         {
262                           idx[nifs].if_index = 0;
263                           if_freenameindex (idx);
264                           idx = NULL;
265                           goto nomem;
266                         }
267                       break;
268                     }
269
270                   rta = RTA_NEXT (rta, rtasize);
271                 }
272
273               ++nifs;
274             }
275         }
276     }
277
278   idx[nifs].if_index = 0;
279   idx[nifs].if_name = NULL;
280
281  exit_free:
282   __netlink_free_handle (&nh);
283   __netlink_close (&nh);
284
285   return idx;
286 }
287 #endif
288 libc_hidden_def(if_nameindex)
289
290 char *
291 if_indextoname (unsigned int ifindex, char *ifname)
292 {
293 #if !defined SIOCGIFINDEX
294   __set_errno (ENOSYS);
295   return NULL;
296 #else
297 # ifdef SIOCGIFNAME
298   /* Use ioctl to avoid searching the list. */
299   struct ifreq ifr;
300   int fd;
301
302   fd = __opensock ();
303
304   if (fd < 0)
305     return NULL;
306
307   ifr.ifr_ifindex = ifindex;
308   if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
309     {
310       int serrno = errno;
311       close (fd);
312       if (serrno == ENODEV)
313         /* POSIX requires ENXIO.  */
314         serrno = ENXIO;
315       __set_errno (serrno);
316       return NULL;
317   }
318   close (fd);
319
320   return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
321 # else
322   struct if_nameindex *idx;
323   struct if_nameindex *p;
324   char *result = NULL;
325
326   idx = if_nameindex();
327
328   if (idx != NULL)
329     {
330       for (p = idx; p->if_index || p->if_name; ++p)
331         if (p->if_index == ifindex)
332           {
333             result = strncpy (ifname, p->if_name, IFNAMSIZ);
334             break;
335           }
336
337       if_freenameindex (idx);
338
339       if (result == NULL)
340         __set_errno (ENXIO);
341     }
342   return result;
343 # endif
344 #endif
345 }
346