]> sourceware.org Git - glibc.git/blob - sysdeps/unix/sysv/linux/if_index.c
Update.
[glibc.git] / sysdeps / unix / sysv / linux / if_index.c
1 /* Copyright (C) 1997, 1998, 1999 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 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.
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 Library General Public License for more details.
13
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. */
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 /* Try to get a socket to talk to the kernel. */
39 #if defined SIOCGIFINDEX || defined SIOCGIFNAME
40 static int
41 internal_function
42 opensock (void)
43 {
44 /* Cache the last AF that worked, to avoid many redundant calls to
45 socket(). */
46 static int sock_af = -1;
47 int fd = -1;
48 __libc_lock_define_initialized (static, lock);
49
50 if (sock_af != -1)
51 {
52 fd = __socket (sock_af, SOCK_DGRAM, 0);
53 if (fd != -1)
54 return fd;
55 }
56
57 __libc_lock_lock (lock);
58
59 if (sock_af != -1)
60 fd = __socket (sock_af, SOCK_DGRAM, 0);
61
62 if (fd == -1)
63 {
64 fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0);
65 if (fd < 0)
66 fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
67 if (fd < 0)
68 fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
69 if (fd < 0)
70 fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
71 if (fd < 0)
72 fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
73 }
74
75 __libc_lock_unlock (lock);
76 return fd;
77 }
78 #endif
79
80 unsigned int
81 if_nametoindex (const char *ifname)
82 {
83 #ifndef SIOCGIFINDEX
84 __set_errno (ENOSYS);
85 return 0;
86 #else
87 struct ifreq ifr;
88 int fd = opensock ();
89
90 if (fd < 0)
91 return 0;
92
93 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
94 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
95 {
96 int saved_errno = errno;
97 __close (fd);
98 if (saved_errno == EINVAL)
99 __set_errno (ENOSYS);
100 return 0;
101 }
102 __close (fd);
103 return ifr.ifr_ifindex;
104 #endif
105 }
106
107 void
108 if_freenameindex (struct if_nameindex *ifn)
109 {
110 struct if_nameindex *ptr = ifn;
111 while (ptr->if_name || ptr->if_index)
112 {
113 if (ptr->if_name)
114 free (ptr->if_name);
115 ++ptr;
116 }
117 free (ifn);
118 }
119
120 struct if_nameindex *
121 if_nameindex (void)
122 {
123 #ifndef SIOCGIFINDEX
124 __set_errno (ENOSYS);
125 return NULL;
126 #else
127 int fd = opensock ();
128 struct ifconf ifc;
129 unsigned int nifs, i;
130 int rq_len;
131 struct if_nameindex *idx = NULL;
132 # define RQ_IFS 4
133
134 if (fd < 0)
135 return NULL;
136
137 ifc.ifc_buf = NULL;
138
139 /* We may be able to get the needed buffer size directly, rather than
140 guessing. */
141 if (! old_siocgifconf)
142 {
143 ifc.ifc_buf = NULL;
144 ifc.ifc_len = 0;
145 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
146 {
147 # if __ASSUME_SIOCGIFNAME == 0
148 old_siocgifconf = 1;
149 # endif
150 rq_len = RQ_IFS * sizeof (struct ifreq);
151 }
152 else
153 rq_len = ifc.ifc_len;
154 }
155 else
156 rq_len = RQ_IFS * sizeof (struct ifreq);
157
158 /* Read all the interfaces out of the kernel. */
159 do
160 {
161 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
162 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
163 {
164 __close (fd);
165 return NULL;
166 }
167 rq_len *= 2;
168 }
169 while (ifc.ifc_len == rq_len && old_siocgifconf);
170
171 nifs = ifc.ifc_len / sizeof (struct ifreq);
172
173 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
174 if (idx == NULL)
175 {
176 __close (fd);
177 return NULL;
178 }
179
180 for (i = 0; i < nifs; ++i)
181 {
182 struct ifreq *ifr = &ifc.ifc_req[i];
183 idx[i].if_name = __strdup (ifr->ifr_name);
184 if (idx[i].if_name == NULL
185 || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
186 {
187 int saved_errno = errno;
188 unsigned int j;
189
190 for (j = 0; j < i; ++j)
191 free (idx[j].if_name);
192 free (idx);
193 __close (fd);
194 if (saved_errno == EINVAL)
195 __set_errno (ENOSYS);
196 return NULL;
197 }
198 idx[i].if_index = ifr->ifr_ifindex;
199 }
200
201 idx[i].if_index = 0;
202 idx[i].if_name = NULL;
203
204 __close (fd);
205 return idx;
206 #endif
207 }
208
209 char *
210 if_indextoname (unsigned int ifindex, char *ifname)
211 {
212 #if !defined SIOCGIFINDEX && __ASSUME_SIOCGIFNAME == 0
213 __set_errno (ENOSYS);
214 return NULL;
215 #else
216 # if __ASSUME_SIOCGIFNAME == 0
217 struct if_nameindex *idx;
218 struct if_nameindex *p;
219 char *result = NULL;
220 # endif
221
222 # if defined SIOCGIFNAME || __ASSUME_SIOCGIFNAME > 0
223 /* We may be able to do the conversion directly, rather than searching a
224 list. This ioctl is not present in kernels before version 2.1.50. */
225 struct ifreq ifr;
226 int fd;
227 # if __ASSUME_SIOCGIFNAME == 0
228 static int siocgifname_works_not;
229
230 if (!siocgifname_works_not)
231 # endif
232 {
233 # if __ASSUME_SIOCGIFNAME == 0
234 int serrno = errno;
235 # endif
236 int status;
237
238 fd = opensock ();
239
240 if (fd < 0)
241 return NULL;
242
243 ifr.ifr_ifindex = ifindex;
244 status = __ioctl (fd, SIOCGIFNAME, &ifr);
245
246 __close (fd);
247
248 # if __ASSUME_SIOCGIFNAME == 0
249 if (status < 0)
250 {
251 if (errno == EINVAL)
252 siocgifname_works_not = 1; /* Don't make the same mistake twice. */
253 }
254 else
255 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
256
257 __set_errno (serrno);
258 # else
259 return status < 0 ? NULL : strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
260 # endif
261 }
262 # endif
263
264 # if __ASSUME_SIOCGIFNAME == 0
265 idx = if_nameindex ();
266
267 if (idx != NULL)
268 {
269 for (p = idx; p->if_index || p->if_name; ++p)
270 if (p->if_index == ifindex)
271 {
272 result = strncpy (ifname, p->if_name, IFNAMSIZ);
273 break;
274 }
275
276 if_freenameindex (idx);
277 }
278 return result;
279 # endif
280 #endif
281 }
282
283
284 void
285 internal_function
286 __protocol_available (int *have_inet, int *have_inet6)
287 {
288 int fd = opensock ();
289 unsigned int nifs;
290 int rq_len;
291 struct ifconf ifc;
292 # define RQ_IFS 4
293
294 /* Wirst case assumption. */
295 *have_inet = 0;
296 *have_inet6 = 0;
297
298 if (fd < 0)
299 /* We cannot open the socket. No networking at all? */
300 return;
301
302 /* We may be able to get the needed buffer size directly, rather than
303 guessing. */
304 if (! old_siocgifconf)
305 {
306 ifc.ifc_buf = NULL;
307 ifc.ifc_len = 0;
308 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
309 {
310 # if __ASSUME_SIOCGIFNAME == 0
311 old_siocgifconf = 1;
312 # endif
313 rq_len = RQ_IFS * sizeof (struct ifreq);
314 }
315 else
316 rq_len = ifc.ifc_len;
317 }
318 else
319 rq_len = RQ_IFS * sizeof (struct ifreq);
320
321 /* Read all the interfaces out of the kernel. */
322 do
323 {
324 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
325 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
326 {
327 __close (fd);
328 return;
329 }
330 rq_len *= 2;
331 }
332 while (ifc.ifc_len == rq_len && old_siocgifconf);
333
334 nifs = ifc.ifc_len / sizeof (struct ifreq);
335
336 /* Go through all the interfaces and get the address. */
337 while (nifs-- > 0)
338 if (__ioctl (fd, SIOCGIFADDR, &ifc.ifc_req[nifs]) >= 0)
339 {
340 /* We successfully got information about this interface. Now
341 test whether it is an IPv4 or IPv6 address. */
342 if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET)
343 *have_inet = 1;
344 else if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET6)
345 *have_inet6 = 1;
346
347 /* Note, this is & not &&. It works since the values are always
348 0 or 1. */
349 if (*have_inet & *have_inet6)
350 /* We can stop early. */
351 break;
352 }
353
354 __close (fd);
355 }
This page took 0.053019 seconds and 5 git commands to generate.