Tomato 1.28
[tomato.git] / release / src / router / bridge / libbridge / if_index.c
blob54ced95c5d4647b2b01c69c1f1a3cdb0858dc7b6
1 /* Copyright (C) 1997, 1998, 1999 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 Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 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 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
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 #if __GLIBC_MINOR__ < 1
28 #include <libc-lock.h>
29 #else
30 #include "bits/libc-lock.h"
31 #endif
33 /* Try to get a socket to talk to the kernel. */
34 #if defined SIOCGIFINDEX || defined SIOCGIFNAME
35 static int
36 internal_function
37 opensock (void)
39 /* Cache the last AF that worked, to avoid many redundant calls to
40 socket(). */
41 static int sock_af = -1;
42 int fd = -1;
43 __libc_lock_define_initialized (static, lock);
45 if (sock_af != -1)
47 fd = __socket (sock_af, SOCK_DGRAM, 0);
48 if (fd != -1)
49 return fd;
52 __libc_lock_lock (lock);
54 if (sock_af != -1)
55 fd = __socket (sock_af, SOCK_DGRAM, 0);
57 if (fd == -1)
59 fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
60 if (fd < 0)
61 fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0);
62 if (fd < 0)
63 fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
64 if (fd < 0)
65 fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
66 if (fd < 0)
67 fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
70 __libc_lock_unlock (lock);
71 return fd;
73 #endif
75 unsigned int
76 if_nametoindex (const char *ifname)
78 #ifndef SIOCGIFINDEX
79 __set_errno (ENOSYS);
80 return 0;
81 #else
82 struct ifreq ifr;
83 int fd = opensock ();
85 if (fd < 0)
86 return 0;
88 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
89 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
91 int saved_errno = errno;
92 close (fd);
93 if (saved_errno == EINVAL)
94 __set_errno (ENOSYS);
95 return 0;
97 close (fd);
98 return ifr.ifr_ifindex;
99 #endif
102 void
103 if_freenameindex (struct if_nameindex *ifn)
105 struct if_nameindex *ptr = ifn;
106 while (ptr->if_name || ptr->if_index)
108 if (ptr->if_name)
109 free (ptr->if_name);
110 ++ptr;
112 free (ifn);
115 struct if_nameindex *
116 if_nameindex (void)
118 #ifndef SIOCGIFINDEX
119 __set_errno (ENOSYS);
120 return NULL;
121 #else
122 int fd = opensock ();
123 struct ifconf ifc;
124 unsigned int nifs, i;
125 int rq_len;
126 struct if_nameindex *idx = NULL;
127 static int old_siocgifconf;
128 #define RQ_IFS 4
130 if (fd < 0)
131 return NULL;
133 ifc.ifc_buf = NULL;
135 /* We may be able to get the needed buffer size directly, rather than
136 guessing. */
137 if (! old_siocgifconf)
139 ifc.ifc_buf = NULL;
140 ifc.ifc_len = 0;
141 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
143 old_siocgifconf = 1;
144 rq_len = RQ_IFS * sizeof (struct ifreq);
146 else
147 rq_len = ifc.ifc_len;
149 else
150 rq_len = RQ_IFS * sizeof (struct ifreq);
152 /* Read all the interfaces out of the kernel. */
155 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
156 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
158 close (fd);
159 return NULL;
161 rq_len *= 2;
163 while (ifc.ifc_len == rq_len && old_siocgifconf);
165 nifs = ifc.ifc_len / sizeof (struct ifreq);
167 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
168 if (idx == NULL)
170 close (fd);
171 return NULL;
174 for (i = 0; i < nifs; ++i)
176 struct ifreq *ifr = &ifc.ifc_req[i];
177 idx[i].if_name = strdup (ifr->ifr_name);
178 if (idx[i].if_name == NULL
179 || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
181 int saved_errno = errno;
182 unsigned int j;
184 for (j = 0; j < i; ++j)
185 free (idx[j].if_name);
186 free (idx);
187 close (fd);
188 if (saved_errno == EINVAL)
189 __set_errno (ENOSYS);
190 return NULL;
192 idx[i].if_index = ifr->ifr_ifindex;
195 idx[i].if_index = 0;
196 idx[i].if_name = NULL;
198 close (fd);
199 return idx;
200 #endif
203 char *
204 if_indextoname (unsigned int ifindex, char *ifname)
206 #ifndef SIOCGIFINDEX
207 __set_errno (ENOSYS);
208 return NULL;
209 #else
210 struct if_nameindex *idx;
211 struct if_nameindex *p;
212 char *result = NULL;
214 #ifdef SIOCGIFNAME
215 /* We may be able to do the conversion directly, rather than searching a
216 list. This ioctl is not present in kernels before version 2.1.50. */
217 struct ifreq ifr;
218 int fd;
219 static int siocgifname_works_not;
221 if (!siocgifname_works_not)
223 int serrno = errno;
225 fd = opensock ();
227 if (fd < 0)
228 return NULL;
230 ifr.ifr_ifindex = ifindex;
231 if (__ioctl (fd, SIOCGIFNAME, &ifr) < 0)
233 if (errno == EINVAL)
234 siocgifname_works_not = 1; /* Don't make the same mistake twice. */
236 else
238 close (fd);
239 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
242 close (fd);
244 __set_errno (serrno);
246 #endif
248 idx = if_nameindex ();
250 if (idx != NULL)
252 for (p = idx; p->if_index || p->if_name; ++p)
253 if (p->if_index == ifindex)
255 result = strncpy (ifname, p->if_name, IFNAMSIZ);
256 break;
259 if_freenameindex (idx);
261 return result;
262 #endif