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