]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/if_index.c
Update.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / if_index.c
1 /* Copyright (C) 1997 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 <net/if.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <bits/libc-lock.h>
27
28 /* Try to get a socket to talk to the kernel. */
29 #if defined SIOGIFINDEX || defined SIOGIFNAME
30 static int
31 internal_function
32 opensock (void)
33 {
34 /* Cache the last AF that worked, to avoid many redundant calls to
35 socket(). */
36 static int sock_af = -1;
37 int fd = -1;
38 __libc_lock_define_initialized (static, lock);
39
40 if (sock_af != -1)
41 {
42 fd = socket (sock_af, SOCK_DGRAM, 0);
43 if (fd != -1)
44 return fd;
45 }
46
47 __libc_lock_lock (lock);
48
49 if (sock_af != -1)
50 fd = socket (sock_af, SOCK_DGRAM, 0);
51
52 if (fd == -1)
53 {
54 fd = socket (sock_af = AF_INET6, SOCK_DGRAM, 0);
55 if (fd < 0)
56 fd = socket (sock_af = AF_INET, SOCK_DGRAM, 0);
57 if (fd < 0)
58 fd = socket (sock_af = AF_IPX, SOCK_DGRAM, 0);
59 if (fd < 0)
60 fd = socket (sock_af = AF_AX25, SOCK_DGRAM, 0);
61 if (fd < 0)
62 fd = socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0);
63 }
64
65 __libc_lock_unlock (lock);
66 return fd;
67 }
68 #endif
69
70 unsigned int
71 if_nametoindex (const char *ifname)
72 {
73 #ifndef SIOGIFINDEX
74 __set_errno (ENOSYS);
75 return 0;
76 #else
77 struct ifreq ifr;
78 int fd = opensock ();
79
80 if (fd < 0)
81 return 0;
82
83 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
84 if (ioctl (fd, SIOGIFINDEX, &ifr) < 0)
85 {
86 int saved_errno = errno;
87 close (fd);
88 if (saved_errno == EINVAL)
89 __set_errno (ENOSYS);
90 return 0;
91 }
92 close (fd);
93 return ifr.ifr_ifindex;
94 #endif
95 }
96
97 void
98 if_freenameindex (struct if_nameindex *ifn)
99 {
100 struct if_nameindex *ptr = ifn;
101 while (ptr->if_name || ptr->if_index)
102 {
103 if (ptr->if_name)
104 free (ptr->if_name);
105 ++ptr;
106 }
107 free (ifn);
108 }
109
110 struct if_nameindex *
111 if_nameindex (void)
112 {
113 #ifndef SIOGIFINDEX
114 __set_errno (ENOSYS);
115 return NULL;
116 #else
117 int fd = opensock ();
118 struct ifconf ifc;
119 unsigned int rq_ifs = 4, nifs, i;
120 int rq_len;
121 struct if_nameindex *idx = NULL;
122 #ifdef SIOCGIFCOUNT
123 static int siocgifcount_works = 1;
124 #endif
125
126 if (fd < 0)
127 return NULL;
128
129 #ifdef SIOCGIFCOUNT
130 /* We may be able to find out how many interfaces really exist, rather
131 than guessing. This ioctl is not present in kernels before version
132 2.1.50. */
133 if (siocgifcount_works)
134 {
135 int serrno = errno;
136
137 if (ioctl (fd, SIOCGIFCOUNT, &nifs) < 0)
138 {
139 if (errno == EINVAL)
140 {
141 siocgifcount_works = 0;
142 __set_errno (serrno);
143 }
144 }
145 else
146 rq_ifs = nifs + 1;
147 }
148 #endif
149
150 ifc.ifc_buf = NULL;
151
152 /* Read all the interfaces out of the kernel. */
153 do
154 {
155 rq_len = ifc.ifc_len = rq_ifs * sizeof (struct ifreq);
156 ifc.ifc_buf = alloca (ifc.ifc_len);
157 if ((ifc.ifc_buf == NULL) || (ioctl (fd, SIOCGIFCONF, &ifc) < 0))
158 {
159 close (fd);
160 return NULL;
161 }
162 rq_ifs *= 2;
163 }
164 while (ifc.ifc_len == rq_len);
165
166 nifs = ifc.ifc_len / sizeof (struct ifreq);
167
168 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
169 if (idx == NULL)
170 {
171 close (fd);
172 return NULL;
173 }
174
175 for (i = 0; i < nifs; ++i)
176 {
177 struct ifreq *ifr = &ifc.ifc_req[i];
178 idx[i].if_name = __strdup (ifr->ifr_name);
179 if (idx[i].if_name == NULL
180 || ioctl (fd, SIOGIFINDEX, ifr) < 0)
181 {
182 int saved_errno = errno;
183 unsigned int j;
184
185 for (j = 0; j < i; ++j)
186 free (idx[j].if_name);
187 free (idx);
188 close (fd);
189 if (saved_errno == EINVAL)
190 __set_errno (ENOSYS);
191 return NULL;
192 }
193 idx[i].if_index = ifr->ifr_ifindex;
194 }
195
196 idx[i].if_index = 0;
197 idx[i].if_name = NULL;
198
199 close (fd);
200 return idx;
201 #endif
202 }
203
204 char *
205 if_indextoname (unsigned int ifindex, char *ifname)
206 {
207 #ifndef SIOGIFINDEX
208 __set_errno (ENOSYS);
209 return NULL;
210 #else
211 struct if_nameindex *idx;
212 struct if_nameindex *p;
213 char *result = NULL;
214
215 #ifdef SIOGIFNAME
216 /* We may be able to do the conversion directly, rather than searching a
217 list. This ioctl is not present in kernels before version 2.1.50. */
218 struct ifreq ifr;
219 int fd;
220 static int siogifname_works = 1;
221
222 if (siogifname_works)
223 {
224 int serrno = errno;
225
226 fd = opensock ();
227
228 if (fd < 0)
229 return NULL;
230
231 ifr.ifr_ifindex = ifindex;
232 if (ioctl (fd, SIOGIFNAME, &ifr) < 0)
233 {
234 if (errno == EINVAL)
235 siogifname_works = 0; /* Don't make the same mistake twice. */
236 }
237 else
238 {
239 close (fd);
240 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
241 }
242
243 close (fd);
244
245 __set_errno (serrno);
246 }
247 #endif
248
249 idx = if_nameindex ();
250
251 if (idx != NULL)
252 {
253 for (p = idx; p->if_index || p->if_name; ++p)
254 if (p->if_index == ifindex)
255 {
256 result = strncpy (ifname, p->if_name, IFNAMSIZ);
257 break;
258 }
259
260 if_freenameindex (idx);
261 }
262 return result;
263 #endif
264 }