2 * Interface looking up by ioctl ().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 #include "sockunion.h"
29 #include "connected.h"
33 #include "zebra/interface.h"
35 /* Interface looking up using infamous SIOCGIFCONF. */
37 interface_list_ioctl (void)
45 struct interface
*ifp
;
49 /* Normally SIOCGIFCONF works with AF_INET socket. */
50 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
53 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno
));
57 /* Set initial ifreq count. This will be double when SIOCGIFCONF
58 fail. Solaris has SIOCGIFNUM. */
60 ret
= ioctl (sock
, SIOCGIFNUM
, &ifnum
);
67 #endif /* SIOCGIFNUM */
69 ifconf
.ifc_buf
= NULL
;
72 /* Loop until SIOCGIFCONF success. */
75 ifconf
.ifc_len
= sizeof (struct ifreq
) * ifnum
;
76 ifconf
.ifc_buf
= XREALLOC(MTYPE_TMP
, ifconf
.ifc_buf
, ifconf
.ifc_len
);
78 ret
= ioctl(sock
, SIOCGIFCONF
, &ifconf
);
82 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno
));
85 /* Repeatedly get info til buffer fails to grow. */
86 if (ifconf
.ifc_len
> lastlen
)
88 lastlen
= ifconf
.ifc_len
;
96 /* Allocate interface. */
97 ifreq
= ifconf
.ifc_req
;
100 for (n
= 0; n
< ifconf
.ifc_len
; )
104 ifreq
= (struct ifreq
*)((caddr_t
) ifconf
.ifc_req
+ n
);
105 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
106 strnlen(ifreq
->ifr_name
,
107 sizeof(ifreq
->ifr_name
)));
109 size
= ifreq
->ifr_addr
.sa_len
;
110 if (size
< sizeof (ifreq
->ifr_addr
))
111 size
= sizeof (ifreq
->ifr_addr
);
112 size
+= sizeof (ifreq
->ifr_name
);
116 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
))
118 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
119 strnlen(ifreq
->ifr_name
,
120 sizeof(ifreq
->ifr_name
)));
124 #endif /* OPEN_BSD */
128 XFREE (MTYPE_TMP
, ifconf
.ifc_buf
);
133 /* Get interface's index by ioctl. */
135 if_get_index (struct interface
*ifp
)
137 #if defined(HAVE_IF_NAMETOINDEX)
138 /* Modern systems should have if_nametoindex(3). */
139 ifp
->ifindex
= if_nametoindex(ifp
->name
);
140 #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
141 /* Fall-back for older linuxes. */
144 static int if_fake_index
;
146 ifreq_set_name (&ifreq
, ifp
);
148 ret
= if_ioctl (SIOCGIFINDEX
, (caddr_t
) &ifreq
);
151 /* Linux 2.0.X does not have interface index. */
152 ifp
->ifindex
= if_fake_index
++;
156 /* OK we got interface index. */
158 ifp
->ifindex
= ifreq
.ifr_ifindex
;
160 ifp
->ifindex
= ifreq
.ifr_index
;
164 /* Linux 2.2.X does not provide individual interface index
165 for aliases and we know it. For others issue a warning. */
166 #if !defined(HAVE_BROKEN_ALIASES)
167 #warning "Using if_fake_index. You may want to add appropriate"
168 #warning "mapping from ifname to ifindex for your system..."
170 /* This branch probably won't provide usable results, but anyway... */
171 static int if_fake_index
= 1;
172 ifp
->ifindex
= if_fake_index
++;
180 if_get_hwaddr (struct interface
*ifp
)
186 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
187 ifreq
.ifr_addr
.sa_family
= AF_INET
;
189 /* Fetch Hardware address if available. */
190 ret
= if_ioctl (SIOCGIFHWADDR
, (caddr_t
) &ifreq
);
192 ifp
->hw_addr_len
= 0;
195 memcpy (ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
197 for (i
= 0; i
< 6; i
++)
198 if (ifp
->hw_addr
[i
] != 0)
202 ifp
->hw_addr_len
= 0;
204 ifp
->hw_addr_len
= 6;
208 #endif /* SIOCGIFHWADDR */
210 #ifdef HAVE_GETIFADDRS
217 struct ifaddrs
*ifap
;
218 struct ifaddrs
*ifapfree
;
219 struct interface
*ifp
;
222 ret
= getifaddrs (&ifap
);
225 zlog_err ("getifaddrs(): %s", safe_strerror (errno
));
229 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
)
231 if (ifap
->ifa_addr
== NULL
)
233 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
234 __func__
, (ifap
->ifa_name
? ifap
->ifa_name
: "(null)"));
238 ifp
= if_lookup_by_name (ifap
->ifa_name
);
241 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
246 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
248 struct sockaddr_in
*addr
;
249 struct sockaddr_in
*mask
;
250 struct sockaddr_in
*dest
;
251 struct in_addr
*dest_pnt
;
254 addr
= (struct sockaddr_in
*) ifap
->ifa_addr
;
255 mask
= (struct sockaddr_in
*) ifap
->ifa_netmask
;
256 prefixlen
= ip_masklen (mask
->sin_addr
);
260 if (ifap
->ifa_dstaddr
&&
261 !IPV4_ADDR_SAME(&addr
->sin_addr
,
262 &((struct sockaddr_in
*)
263 ifap
->ifa_dstaddr
)->sin_addr
))
265 dest
= (struct sockaddr_in
*) ifap
->ifa_dstaddr
;
266 dest_pnt
= &dest
->sin_addr
;
267 flags
= ZEBRA_IFA_PEER
;
269 else if (ifap
->ifa_broadaddr
&&
270 !IPV4_ADDR_SAME(&addr
->sin_addr
,
271 &((struct sockaddr_in
*)
272 ifap
->ifa_broadaddr
)->sin_addr
))
274 dest
= (struct sockaddr_in
*) ifap
->ifa_broadaddr
;
275 dest_pnt
= &dest
->sin_addr
;
278 connected_add_ipv4 (ifp
, flags
, &addr
->sin_addr
,
279 prefixlen
, dest_pnt
, NULL
);
282 if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
284 struct sockaddr_in6
*addr
;
285 struct sockaddr_in6
*mask
;
286 struct sockaddr_in6
*dest
;
287 struct in6_addr
*dest_pnt
;
290 addr
= (struct sockaddr_in6
*) ifap
->ifa_addr
;
291 mask
= (struct sockaddr_in6
*) ifap
->ifa_netmask
;
292 prefixlen
= ip6_masklen (mask
->sin6_addr
);
296 if (ifap
->ifa_dstaddr
&&
297 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
298 &((struct sockaddr_in6
*)
299 ifap
->ifa_dstaddr
)->sin6_addr
))
301 dest
= (struct sockaddr_in6
*) ifap
->ifa_dstaddr
;
302 dest_pnt
= &dest
->sin6_addr
;
303 flags
= ZEBRA_IFA_PEER
;
305 else if (ifap
->ifa_broadaddr
&&
306 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
307 &((struct sockaddr_in6
*)
308 ifap
->ifa_broadaddr
)->sin6_addr
))
310 dest
= (struct sockaddr_in6
*) ifap
->ifa_broadaddr
;
311 dest_pnt
= &dest
->sin6_addr
;
315 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
317 addr
->sin6_scope_id
=
318 ntohs(*(u_int16_t
*)&addr
->sin6_addr
.s6_addr
[2]);
319 addr
->sin6_addr
.s6_addr
[2] = addr
->sin6_addr
.s6_addr
[3] = 0;
323 connected_add_ipv6 (ifp
, flags
, &addr
->sin6_addr
, prefixlen
,
326 #endif /* HAVE_IPV6 */
329 freeifaddrs (ifapfree
);
333 #else /* HAVE_GETIFADDRS */
334 /* Interface address lookup by ioctl. This function only looks up
337 if_get_addr (struct interface
*ifp
)
341 struct sockaddr_in addr
;
342 struct sockaddr_in mask
;
343 struct sockaddr_in dest
;
344 struct in_addr
*dest_pnt
;
348 /* Interface's name and address family. */
349 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
350 ifreq
.ifr_addr
.sa_family
= AF_INET
;
352 /* Interface's address. */
353 ret
= if_ioctl (SIOCGIFADDR
, (caddr_t
) &ifreq
);
356 if (errno
!= EADDRNOTAVAIL
)
358 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno
));
363 memcpy (&addr
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
365 /* Interface's network mask. */
366 ret
= if_ioctl (SIOCGIFNETMASK
, (caddr_t
) &ifreq
);
369 if (errno
!= EADDRNOTAVAIL
)
371 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno
));
377 memcpy (&mask
, &ifreq
.ifr_netmask
, sizeof (struct sockaddr_in
));
379 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
380 #endif /* ifr_netmask */
381 prefixlen
= ip_masklen (mask
.sin_addr
);
383 /* Point to point or borad cast address pointer init. */
386 ret
= if_ioctl (SIOCGIFDSTADDR
, (caddr_t
) &ifreq
);
389 if (errno
!= EADDRNOTAVAIL
)
390 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno
));
392 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_dstaddr
.sin_addr
))
394 memcpy (&dest
, &ifreq
.ifr_dstaddr
, sizeof (struct sockaddr_in
));
395 dest_pnt
= &dest
.sin_addr
;
396 flags
= ZEBRA_IFA_PEER
;
400 ret
= if_ioctl (SIOCGIFBRDADDR
, (caddr_t
) &ifreq
);
403 if (errno
!= EADDRNOTAVAIL
)
404 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno
));
406 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_broadaddr
.sin_addr
))
408 memcpy (&dest
, &ifreq
.ifr_broadaddr
, sizeof (struct sockaddr_in
));
409 dest_pnt
= &dest
.sin_addr
;
414 /* Set address to the interface. */
415 connected_add_ipv4 (ifp
, flags
, &addr
.sin_addr
, prefixlen
, dest_pnt
, NULL
);
419 #endif /* HAVE_GETIFADDRS */
421 /* Fetch interface information via ioctl(). */
423 interface_info_ioctl ()
425 struct listnode
*node
, *nnode
;
426 struct interface
*ifp
;
428 for (ALL_LIST_ELEMENTS (iflist
, node
, nnode
, ifp
))
433 #endif /* SIOCGIFHWADDR */
435 #ifndef HAVE_GETIFADDRS
437 #endif /* ! HAVE_GETIFADDRS */
443 /* Lookup all interface information. */
447 /* Linux can do both proc & ioctl, ioctl is the only way to get
448 interface aliases in 2.2 series kernels. */
449 #ifdef HAVE_PROC_NET_DEV
450 interface_list_proc ();
451 #endif /* HAVE_PROC_NET_DEV */
452 interface_list_ioctl ();
454 /* After listing is done, get index, address, flags and other
455 interface's information. */
456 interface_info_ioctl ();
458 #ifdef HAVE_GETIFADDRS
460 #endif /* HAVE_GETIFADDRS */
462 #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
463 /* Linux provides interface's IPv6 address via
464 /proc/net/if_inet6. */
466 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */