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. */