]>
Commit | Line | Data |
---|---|---|
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 | |
33 | static int old_siocgifconf; | |
34 | #else | |
35 | # define old_siocgifconf 0 | |
36 | #endif | |
37 | ||
1f205a47 | 38 | |
8f2ece69 UD |
39 | unsigned int |
40 | if_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 |
66 | void |
67 | if_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 |
79 | struct if_nameindex * |
80 | if_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 | ||
172 | char * | |
173 | if_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 |
247 | void |
248 | internal_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 |