1 /* Copyright (C) 1997, 1998, 1999 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. */
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #if __GLIBC_MINOR__ < 1
28 #include <libc-lock.h>
30 #include "bits/libc-lock.h"
33 /* Try to get a socket to talk to the kernel. */
34 #if defined SIOCGIFINDEX || defined SIOCGIFNAME
39 /* Cache the last AF that worked, to avoid many redundant calls to
41 static int sock_af
= -1;
43 __libc_lock_define_initialized (static, lock
);
47 fd
= __socket (sock_af
, SOCK_DGRAM
, 0);
52 __libc_lock_lock (lock
);
55 fd
= __socket (sock_af
, SOCK_DGRAM
, 0);
59 fd
= __socket (sock_af
= AF_INET6
, SOCK_DGRAM
, 0);
61 fd
= __socket (sock_af
= AF_INET
, SOCK_DGRAM
, 0);
63 fd
= __socket (sock_af
= AF_IPX
, SOCK_DGRAM
, 0);
65 fd
= __socket (sock_af
= AF_AX25
, SOCK_DGRAM
, 0);
67 fd
= __socket (sock_af
= AF_APPLETALK
, SOCK_DGRAM
, 0);
70 __libc_lock_unlock (lock
);
76 if_nametoindex (const char *ifname
)
88 strncpy (ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
89 if (__ioctl (fd
, SIOCGIFINDEX
, &ifr
) < 0)
91 int saved_errno
= errno
;
93 if (saved_errno
== EINVAL
)
98 return ifr
.ifr_ifindex
;
103 if_freenameindex (struct if_nameindex
*ifn
)
105 struct if_nameindex
*ptr
= ifn
;
106 while (ptr
->if_name
|| ptr
->if_index
)
115 struct if_nameindex
*
119 __set_errno (ENOSYS
);
122 int fd
= opensock ();
124 unsigned int nifs
, i
;
126 struct if_nameindex
*idx
= NULL
;
127 static int old_siocgifconf
;
135 /* We may be able to get the needed buffer size directly, rather than
137 if (! old_siocgifconf
)
141 if (__ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0 || ifc
.ifc_len
== 0)
144 rq_len
= RQ_IFS
* sizeof (struct ifreq
);
147 rq_len
= ifc
.ifc_len
;
150 rq_len
= RQ_IFS
* sizeof (struct ifreq
);
152 /* Read all the interfaces out of the kernel. */
155 ifc
.ifc_buf
= alloca (ifc
.ifc_len
= rq_len
);
156 if (ifc
.ifc_buf
== NULL
|| __ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0)
163 while (ifc
.ifc_len
== rq_len
&& old_siocgifconf
);
165 nifs
= ifc
.ifc_len
/ sizeof (struct ifreq
);
167 idx
= malloc ((nifs
+ 1) * sizeof (struct if_nameindex
));
174 for (i
= 0; i
< nifs
; ++i
)
176 struct ifreq
*ifr
= &ifc
.ifc_req
[i
];
177 idx
[i
].if_name
= strdup (ifr
->ifr_name
);
178 if (idx
[i
].if_name
== NULL
179 || __ioctl (fd
, SIOCGIFINDEX
, ifr
) < 0)
181 int saved_errno
= errno
;
184 for (j
= 0; j
< i
; ++j
)
185 free (idx
[j
].if_name
);
188 if (saved_errno
== EINVAL
)
189 __set_errno (ENOSYS
);
192 idx
[i
].if_index
= ifr
->ifr_ifindex
;
196 idx
[i
].if_name
= NULL
;
204 if_indextoname (unsigned int ifindex
, char *ifname
)
207 __set_errno (ENOSYS
);
210 struct if_nameindex
*idx
;
211 struct if_nameindex
*p
;
215 /* We may be able to do the conversion directly, rather than searching a
216 list. This ioctl is not present in kernels before version 2.1.50. */
219 static int siocgifname_works_not
;
221 if (!siocgifname_works_not
)
230 ifr
.ifr_ifindex
= ifindex
;
231 if (__ioctl (fd
, SIOCGIFNAME
, &ifr
) < 0)
234 siocgifname_works_not
= 1; /* Don't make the same mistake twice. */
239 return strncpy (ifname
, ifr
.ifr_name
, IFNAMSIZ
);
244 __set_errno (serrno
);
248 idx
= if_nameindex ();
252 for (p
= idx
; p
->if_index
|| p
->if_name
; ++p
)
253 if (p
->if_index
== ifindex
)
255 result
= strncpy (ifname
, p
->if_name
, IFNAMSIZ
);
259 if_freenameindex (idx
);