Update.
[glibc.git] / sysdeps / unix / sysv / linux / if_index.c
blobaa89a38e69dfee8093c13d80058faba6e3799aed
1 /* Copyright (C) 1997, 1998 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 #include <bits/libc-lock.h>
29 /* Try to get a socket to talk to the kernel. */
30 #if defined SIOGIFINDEX || defined SIOGIFNAME
31 static int
32 internal_function
33 opensock (void)
35 /* Cache the last AF that worked, to avoid many redundant calls to
36 socket(). */
37 static int sock_af = -1;
38 int fd = -1;
39 __libc_lock_define_initialized (static, lock);
41 if (sock_af != -1)
43 fd = __socket (sock_af, SOCK_DGRAM, 0);
44 if (fd != -1)
45 return fd;
48 __libc_lock_lock (lock);
50 if (sock_af != -1)
51 fd = __socket (sock_af, SOCK_DGRAM, 0);
53 if (fd == -1)
55 fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
56 if (fd < 0)
57 fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0);
58 if (fd < 0)
59 fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
60 if (fd < 0)
61 fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
62 if (fd < 0)
63 fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
66 __libc_lock_unlock (lock);
67 return fd;
69 #endif
71 unsigned int
72 if_nametoindex (const char *ifname)
74 #ifndef SIOGIFINDEX
75 __set_errno (ENOSYS);
76 return 0;
77 #else
78 struct ifreq ifr;
79 int fd = opensock ();
81 if (fd < 0)
82 return 0;
84 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
85 if (__ioctl (fd, SIOGIFINDEX, &ifr) < 0)
87 int saved_errno = errno;
88 __close (fd);
89 if (saved_errno == EINVAL)
90 __set_errno (ENOSYS);
91 return 0;
93 __close (fd);
94 return ifr.ifr_ifindex;
95 #endif
98 void
99 if_freenameindex (struct if_nameindex *ifn)
101 struct if_nameindex *ptr = ifn;
102 while (ptr->if_name || ptr->if_index)
104 if (ptr->if_name)
105 free (ptr->if_name);
106 ++ptr;
108 free (ifn);
111 struct if_nameindex *
112 if_nameindex (void)
114 #ifndef SIOGIFINDEX
115 __set_errno (ENOSYS);
116 return NULL;
117 #else
118 int fd = opensock ();
119 struct ifconf ifc;
120 unsigned int nifs, i;
121 int rq_len;
122 struct if_nameindex *idx = NULL;
123 static int new_siocgifconf = 1;
124 #define RQ_IFS 4
126 if (fd < 0)
127 return NULL;
129 ifc.ifc_buf = NULL;
131 /* We may be able to get the needed buffer size directly, rather than
132 guessing. */
133 if (new_siocgifconf)
135 ifc.ifc_buf = NULL;
136 ifc.ifc_len = 0;
137 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
139 new_siocgifconf = 0;
140 rq_len = RQ_IFS * sizeof (struct ifreq);
142 else
143 rq_len = ifc.ifc_len;
145 else
146 rq_len = RQ_IFS * sizeof (struct ifreq);
148 /* Read all the interfaces out of the kernel. */
151 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
152 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
154 __close (fd);
155 return NULL;
157 rq_len *= 2;
159 while (ifc.ifc_len == rq_len && new_siocgifconf == 0);
161 nifs = ifc.ifc_len / sizeof (struct ifreq);
163 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
164 if (idx == NULL)
166 __close (fd);
167 return NULL;
170 for (i = 0; i < nifs; ++i)
172 struct ifreq *ifr = &ifc.ifc_req[i];
173 idx[i].if_name = __strdup (ifr->ifr_name);
174 if (idx[i].if_name == NULL
175 || __ioctl (fd, SIOGIFINDEX, ifr) < 0)
177 int saved_errno = errno;
178 unsigned int j;
180 for (j = 0; j < i; ++j)
181 free (idx[j].if_name);
182 free (idx);
183 __close (fd);
184 if (saved_errno == EINVAL)
185 __set_errno (ENOSYS);
186 return NULL;
188 idx[i].if_index = ifr->ifr_ifindex;
191 idx[i].if_index = 0;
192 idx[i].if_name = NULL;
194 __close (fd);
195 return idx;
196 #endif
199 char *
200 if_indextoname (unsigned int ifindex, char *ifname)
202 #ifndef SIOGIFINDEX
203 __set_errno (ENOSYS);
204 return NULL;
205 #else
206 struct if_nameindex *idx;
207 struct if_nameindex *p;
208 char *result = NULL;
210 #ifdef SIOGIFNAME
211 /* We may be able to do the conversion directly, rather than searching a
212 list. This ioctl is not present in kernels before version 2.1.50. */
213 struct ifreq ifr;
214 int fd;
215 static int siogifname_works = 1;
217 if (siogifname_works)
219 int serrno = errno;
221 fd = opensock ();
223 if (fd < 0)
224 return NULL;
226 ifr.ifr_ifindex = ifindex;
227 if (__ioctl (fd, SIOGIFNAME, &ifr) < 0)
229 if (errno == EINVAL)
230 siogifname_works = 0; /* Don't make the same mistake twice. */
232 else
234 __close (fd);
235 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
238 __close (fd);
240 __set_errno (serrno);
242 #endif
244 idx = if_nameindex ();
246 if (idx != NULL)
248 for (p = idx; p->if_index || p->if_name; ++p)
249 if (p->if_index == ifindex)
251 result = strncpy (ifname, p->if_name, IFNAMSIZ);
252 break;
255 if_freenameindex (idx);
257 return result;
258 #endif