46f8b1ec1121d6465b8362e143f8511aa5fa8308
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / if_index.c
1 /* Copyright (C) 1997,98,99,2000,02 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
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
29 #include "kernel-features.h"
30
31 /* Variable to signal whether SIOCGIFCONF is not available.  */
32 #if __ASSUME_SIOCGIFNAME == 0
33 static int old_siocgifconf;
34 #else
35 # define old_siocgifconf 0
36 #endif
37
38
39 unsigned int
40 if_nametoindex (const char *ifname)
41 {
42 #ifndef SIOCGIFINDEX
43   __set_errno (ENOSYS);
44   return 0;
45 #else
46   struct ifreq ifr;
47   int fd = __opensock ();
48
49   if (fd < 0)
50     return 0;
51
52   strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
53   if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
54     {
55       int saved_errno = errno;
56       __close (fd);
57       if (saved_errno == EINVAL)
58         __set_errno (ENOSYS);
59       return 0;
60     }
61   __close (fd);
62   return ifr.ifr_ifindex;
63 #endif
64 }
65 libc_hidden_def (if_nametoindex)
66
67
68 void
69 if_freenameindex (struct if_nameindex *ifn)
70 {
71   struct if_nameindex *ptr = ifn;
72   while (ptr->if_name || ptr->if_index)
73     {
74       if (ptr->if_name)
75         free (ptr->if_name);
76       ++ptr;
77     }
78   free (ifn);
79 }
80
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   /* We may be able to get the needed buffer size directly, rather than
101      guessing.  */
102   if (! old_siocgifconf)
103     {
104       ifc.ifc_buf = NULL;
105       ifc.ifc_len = 0;
106       if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
107         {
108 # if __ASSUME_SIOCGIFNAME == 0
109           old_siocgifconf = 1;
110 # endif
111           rq_len = RQ_IFS * sizeof (struct ifreq);
112         }
113       else
114         rq_len = ifc.ifc_len;
115     }
116   else
117     rq_len = RQ_IFS * sizeof (struct ifreq);
118
119   /* Read all the interfaces out of the kernel.  */
120   do
121     {
122       ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
123       if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
124         {
125           __close (fd);
126           return NULL;
127         }
128       rq_len *= 2;
129     }
130   while (ifc.ifc_len == rq_len && old_siocgifconf);
131
132   nifs = ifc.ifc_len / sizeof (struct ifreq);
133
134   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
135   if (idx == NULL)
136     {
137       __close (fd);
138       __set_errno (ENOBUFS);
139       return NULL;
140     }
141
142   for (i = 0; i < nifs; ++i)
143     {
144       struct ifreq *ifr = &ifc.ifc_req[i];
145       idx[i].if_name = __strdup (ifr->ifr_name);
146       if (idx[i].if_name == NULL
147           || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
148         {
149           int saved_errno = errno;
150           unsigned int j;
151
152           for (j =  0; j < i; ++j)
153             free (idx[j].if_name);
154           free (idx);
155           __close (fd);
156           if (saved_errno == EINVAL)
157             saved_errno = ENOSYS;
158           else if (saved_errno == ENOMEM)
159             saved_errno = ENOBUFS;
160           __set_errno (saved_errno);
161           return NULL;
162         }
163       idx[i].if_index = ifr->ifr_ifindex;
164     }
165
166   idx[i].if_index = 0;
167   idx[i].if_name = NULL;
168
169   __close (fd);
170   return idx;
171 #endif
172 }
173
174 char *
175 if_indextoname (unsigned int ifindex, char *ifname)
176 {
177 #if !defined SIOCGIFINDEX && __ASSUME_SIOCGIFNAME == 0
178   __set_errno (ENOSYS);
179   return NULL;
180 #else
181 # if __ASSUME_SIOCGIFNAME == 0
182   struct if_nameindex *idx;
183   struct if_nameindex *p;
184   char *result = NULL;
185 # endif
186
187 # if defined SIOCGIFNAME || __ASSUME_SIOCGIFNAME > 0
188   /* We may be able to do the conversion directly, rather than searching a
189      list.  This ioctl is not present in kernels before version 2.1.50.  */
190   struct ifreq ifr;
191   int fd;
192 #  if __ASSUME_SIOCGIFNAME == 0
193   static int siocgifname_works_not;
194
195   if (!siocgifname_works_not)
196 #  endif
197     {
198 #  if __ASSUME_SIOCGIFNAME == 0
199       int serrno = errno;
200 #  endif
201       int status;
202
203       fd = __opensock ();
204
205       if (fd < 0)
206         return NULL;
207
208       ifr.ifr_ifindex = ifindex;
209       status = __ioctl (fd, SIOCGIFNAME, &ifr);
210
211       __close (fd);
212
213 #  if __ASSUME_SIOCGIFNAME == 0
214       if (status  < 0)
215         {
216           if (errno == EINVAL)
217             siocgifname_works_not = 1; /* Don't make the same mistake twice. */
218         }
219       else
220         return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
221
222       __set_errno (serrno);
223 #  else
224       return status < 0 ? NULL : strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
225 #  endif
226     }
227 # endif
228
229 # if __ASSUME_SIOCGIFNAME == 0
230   idx = if_nameindex ();
231
232   if (idx != NULL)
233     {
234       for (p = idx; p->if_index || p->if_name; ++p)
235         if (p->if_index == ifindex)
236           {
237             result = strncpy (ifname, p->if_name, IFNAMSIZ);
238             break;
239           }
240
241       if_freenameindex (idx);
242     }
243   return result;
244 # endif
245 #endif
246 }
247 libc_hidden_def (if_indextoname)
248
249 #if 0
250 void
251 internal_function
252 __protocol_available (int *have_inet, int *have_inet6)
253 {
254   int fd = __opensock ();
255   unsigned int nifs;
256   int rq_len;
257   struct ifconf ifc;
258 # define RQ_IFS 4
259
260   /* Wirst case assumption.  */
261   *have_inet = 0;
262   *have_inet6 = 0;
263
264   if (fd < 0)
265     /* We cannot open the socket.  No networking at all?  */
266     return;
267
268   /* We may be able to get the needed buffer size directly, rather than
269      guessing.  */
270   if (! old_siocgifconf)
271     {
272       ifc.ifc_buf = NULL;
273       ifc.ifc_len = 0;
274       if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
275         {
276 # if __ASSUME_SIOCGIFNAME == 0
277           old_siocgifconf = 1;
278 # endif
279           rq_len = RQ_IFS * sizeof (struct ifreq);
280         }
281       else
282         rq_len = ifc.ifc_len;
283     }
284   else
285     rq_len = RQ_IFS * sizeof (struct ifreq);
286
287   /* Read all the interfaces out of the kernel.  */
288   do
289     {
290       ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
291       if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
292         {
293           __close (fd);
294           return;
295         }
296       rq_len *= 2;
297     }
298   while (ifc.ifc_len == rq_len && old_siocgifconf);
299
300   nifs = ifc.ifc_len / sizeof (struct ifreq);
301
302   /* Go through all the interfaces and get the address.  */
303   while (nifs-- > 0)
304     if (__ioctl (fd, SIOCGIFADDR, &ifc.ifc_req[nifs]) >= 0)
305       {
306         /* We successfully got information about this interface.  Now
307            test whether it is an IPv4 or IPv6 address.  */
308         if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET)
309           *have_inet = 1;
310         else if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET6)
311           *have_inet6 = 1;
312
313         /* Note, this is & not &&.  It works since the values are always
314            0 or 1.  */
315         if (*have_inet & *have_inet6)
316           /* We can stop early.  */
317           break;
318       }
319
320   __close (fd);
321 }
322 #endif