1 /* Copyright (C) 1997,98,99,2000,02 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 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.
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 Lesser General Public License for more details.
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
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <bits/libc-lock.h>
29 #include "kernel-features.h"
31 /* Variable to signal whether SIOCGIFCONF is not available. */
32 #if __ASSUME_SIOCGIFNAME == 0
33 static int old_siocgifconf;
35 # define old_siocgifconf 0
40 if_nametoindex (const char *ifname)
47 int fd = __opensock ();
52 strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
53 if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
55 int saved_errno = errno;
57 if (saved_errno == EINVAL)
62 return ifr.ifr_ifindex;
65 libc_hidden_def (if_nametoindex)
69 if_freenameindex (struct if_nameindex *ifn)
71 struct if_nameindex *ptr = ifn;
72 while (ptr->if_name || ptr->if_index)
88 int fd = __opensock ();
92 struct if_nameindex *idx = NULL;
100 /* We may be able to get the needed buffer size directly, rather than
102 if (! old_siocgifconf)
106 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
108 # if __ASSUME_SIOCGIFNAME == 0
111 rq_len = RQ_IFS * sizeof (struct ifreq);
114 rq_len = ifc.ifc_len;
117 rq_len = RQ_IFS * sizeof (struct ifreq);
119 /* Read all the interfaces out of the kernel. */
122 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
123 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
130 while (ifc.ifc_len == rq_len && old_siocgifconf);
132 nifs = ifc.ifc_len / sizeof (struct ifreq);
134 idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
138 __set_errno (ENOBUFS);
142 for (i = 0; i < nifs; ++i)
144 struct ifreq *ifr = &ifc.ifc_req[i];
145 idx[i].if_name = __strdup (ifr->ifr_name);
146 if (idx[i].if_name == NULL
147 || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
149 int saved_errno = errno;
152 for (j = 0; j < i; ++j)
153 free (idx[j].if_name);
156 if (saved_errno == EINVAL)
157 saved_errno = ENOSYS;
158 else if (saved_errno == ENOMEM)
159 saved_errno = ENOBUFS;
160 __set_errno (saved_errno);
163 idx[i].if_index = ifr->ifr_ifindex;
167 idx[i].if_name = NULL;
175 if_indextoname (unsigned int ifindex, char *ifname)
177 #if !defined SIOCGIFINDEX && __ASSUME_SIOCGIFNAME == 0
178 __set_errno (ENOSYS);
181 # if __ASSUME_SIOCGIFNAME == 0
182 struct if_nameindex *idx;
183 struct if_nameindex *p;
187 # if defined SIOCGIFNAME || __ASSUME_SIOCGIFNAME > 0
188 /* We may be able to do the conversion directly, rather than searching a
189 list. This ioctl is not present in kernels before version 2.1.50. */
192 # if __ASSUME_SIOCGIFNAME == 0
193 static int siocgifname_works_not;
195 if (!siocgifname_works_not)
198 # if __ASSUME_SIOCGIFNAME == 0
208 ifr.ifr_ifindex = ifindex;
209 status = __ioctl (fd, SIOCGIFNAME, &ifr);
213 # if __ASSUME_SIOCGIFNAME == 0
217 siocgifname_works_not = 1; /* Don't make the same mistake twice. */
220 return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
222 __set_errno (serrno);
224 return status < 0 ? NULL : strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
229 # if __ASSUME_SIOCGIFNAME == 0
230 idx = if_nameindex ();
234 for (p = idx; p->if_index || p->if_name; ++p)
235 if (p->if_index == ifindex)
237 result = strncpy (ifname, p->if_name, IFNAMSIZ);
241 if_freenameindex (idx);
247 libc_hidden_def (if_indextoname)
252 __protocol_available (int *have_inet, int *have_inet6)
254 int fd = __opensock ();
260 /* Wirst case assumption. */
265 /* We cannot open the socket. No networking at all? */
268 /* We may be able to get the needed buffer size directly, rather than
270 if (! old_siocgifconf)
274 if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)
276 # if __ASSUME_SIOCGIFNAME == 0
279 rq_len = RQ_IFS * sizeof (struct ifreq);
282 rq_len = ifc.ifc_len;
285 rq_len = RQ_IFS * sizeof (struct ifreq);
287 /* Read all the interfaces out of the kernel. */
290 ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);
291 if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0)
298 while (ifc.ifc_len == rq_len && old_siocgifconf);
300 nifs = ifc.ifc_len / sizeof (struct ifreq);
302 /* Go through all the interfaces and get the address. */
304 if (__ioctl (fd, SIOCGIFADDR, &ifc.ifc_req[nifs]) >= 0)
306 /* We successfully got information about this interface. Now
307 test whether it is an IPv4 or IPv6 address. */
308 if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET)
310 else if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET6)
313 /* Note, this is & not &&. It works since the values are always
315 if (*have_inet & *have_inet6)
316 /* We can stop early. */