]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
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 ()
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 (ifreq
->ifr_name
);
107 size
= ifreq
->ifr_addr
.sa_len
;
108 if (size
< sizeof (ifreq
->ifr_addr
))
109 size
= sizeof (ifreq
->ifr_addr
);
110 size
+= sizeof (ifreq
->ifr_name
);
114 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
))
116 ifp
= if_get_by_name (ifreq
->ifr_name
);
120 #endif /* OPEN_BSD */
124 XFREE (MTYPE_TMP
, ifconf
.ifc_buf
);
129 /* Get interface's index by ioctl. */
131 if_get_index (struct interface
*ifp
)
133 #if defined(HAVE_IF_NAMETOINDEX)
134 /* Modern systems should have if_nametoindex(3). */
135 ifp
->ifindex
= if_nametoindex(ifp
->name
);
136 #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
137 /* Fall-back for older linuxes. */
140 static int if_fake_index
;
142 ifreq_set_name (&ifreq
, ifp
);
144 ret
= if_ioctl (SIOCGIFINDEX
, (caddr_t
) &ifreq
);
147 /* Linux 2.0.X does not have interface index. */
148 ifp
->ifindex
= if_fake_index
++;
152 /* OK we got interface index. */
154 ifp
->ifindex
= ifreq
.ifr_ifindex
;
156 ifp
->ifindex
= ifreq
.ifr_index
;
160 /* Linux 2.2.X does not provide individual interface index
161 for aliases and we know it. For others issue a warning. */
162 #if !defined(HAVE_BROKEN_ALIASES)
163 #warning "Using if_fake_index. You may want to add appropriate"
164 #warning "mapping from ifname to ifindex for your system..."
166 /* This branch probably won't provide usable results, but anyway... */
167 static int if_fake_index
= 1;
168 ifp
->ifindex
= if_fake_index
++;
176 if_get_hwaddr (struct interface
*ifp
)
182 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
183 ifreq
.ifr_addr
.sa_family
= AF_INET
;
185 /* Fetch Hardware address if available. */
186 ret
= if_ioctl (SIOCGIFHWADDR
, (caddr_t
) &ifreq
);
188 ifp
->hw_addr_len
= 0;
191 memcpy (ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
193 for (i
= 0; i
< 6; i
++)
194 if (ifp
->hw_addr
[i
] != 0)
198 ifp
->hw_addr_len
= 0;
200 ifp
->hw_addr_len
= 6;
204 #endif /* SIOCGIFHWADDR */
206 #ifdef HAVE_GETIFADDRS
213 struct ifaddrs
*ifap
;
214 struct ifaddrs
*ifapfree
;
215 struct interface
*ifp
;
218 ret
= getifaddrs (&ifap
);
221 zlog_err ("getifaddrs(): %s", safe_strerror (errno
));
225 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
)
227 ifp
= if_lookup_by_name (ifap
->ifa_name
);
230 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
235 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
237 struct sockaddr_in
*addr
;
238 struct sockaddr_in
*mask
;
239 struct sockaddr_in
*dest
;
240 struct in_addr
*dest_pnt
;
242 addr
= (struct sockaddr_in
*) ifap
->ifa_addr
;
243 mask
= (struct sockaddr_in
*) ifap
->ifa_netmask
;
244 prefixlen
= ip_masklen (mask
->sin_addr
);
248 if (ifap
->ifa_flags
& IFF_POINTOPOINT
)
250 dest
= (struct sockaddr_in
*) ifap
->ifa_dstaddr
;
251 dest_pnt
= &dest
->sin_addr
;
254 if (ifap
->ifa_flags
& IFF_BROADCAST
)
256 dest
= (struct sockaddr_in
*) ifap
->ifa_broadaddr
;
257 dest_pnt
= &dest
->sin_addr
;
260 connected_add_ipv4 (ifp
, 0, &addr
->sin_addr
,
261 prefixlen
, dest_pnt
, NULL
);
264 if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
266 struct sockaddr_in6
*addr
;
267 struct sockaddr_in6
*mask
;
268 struct sockaddr_in6
*dest
;
269 struct in6_addr
*dest_pnt
;
271 addr
= (struct sockaddr_in6
*) ifap
->ifa_addr
;
272 mask
= (struct sockaddr_in6
*) ifap
->ifa_netmask
;
273 prefixlen
= ip6_masklen (mask
->sin6_addr
);
277 if (ifap
->ifa_flags
& IFF_POINTOPOINT
)
279 if (ifap
->ifa_dstaddr
)
281 dest
= (struct sockaddr_in6
*) ifap
->ifa_dstaddr
;
282 dest_pnt
= &dest
->sin6_addr
;
286 if (ifap
->ifa_flags
& IFF_BROADCAST
)
288 if (ifap
->ifa_broadaddr
)
290 dest
= (struct sockaddr_in6
*) ifap
->ifa_broadaddr
;
291 dest_pnt
= &dest
->sin6_addr
;
296 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
298 addr
->sin6_scope_id
=
299 ntohs(*(u_int16_t
*)&addr
->sin6_addr
.s6_addr
[2]);
300 addr
->sin6_addr
.s6_addr
[2] = addr
->sin6_addr
.s6_addr
[3] = 0;
304 connected_add_ipv6 (ifp
, &addr
->sin6_addr
, prefixlen
, dest_pnt
);
306 #endif /* HAVE_IPV6 */
309 freeifaddrs (ifapfree
);
313 #else /* HAVE_GETIFADDRS */
314 /* Interface address lookup by ioctl. This function only looks up
317 if_get_addr (struct interface
*ifp
)
321 struct sockaddr_in addr
;
322 struct sockaddr_in mask
;
323 struct sockaddr_in dest
;
324 struct in_addr
*dest_pnt
;
327 /* Interface's name and address family. */
328 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
329 ifreq
.ifr_addr
.sa_family
= AF_INET
;
331 /* Interface's address. */
332 ret
= if_ioctl (SIOCGIFADDR
, (caddr_t
) &ifreq
);
335 if (errno
!= EADDRNOTAVAIL
)
337 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno
));
342 memcpy (&addr
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
344 /* Interface's network mask. */
345 ret
= if_ioctl (SIOCGIFNETMASK
, (caddr_t
) &ifreq
);
348 if (errno
!= EADDRNOTAVAIL
)
350 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno
));
356 memcpy (&mask
, &ifreq
.ifr_netmask
, sizeof (struct sockaddr_in
));
358 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
359 #endif /* ifr_netmask */
360 prefixlen
= ip_masklen (mask
.sin_addr
);
362 /* Point to point or borad cast address pointer init. */
365 if (ifp
->flags
& IFF_POINTOPOINT
)
367 ret
= if_ioctl (SIOCGIFDSTADDR
, (caddr_t
) &ifreq
);
370 if (errno
!= EADDRNOTAVAIL
)
372 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno
));
377 memcpy (&dest
, &ifreq
.ifr_dstaddr
, sizeof (struct sockaddr_in
));
378 dest_pnt
= &dest
.sin_addr
;
380 if (ifp
->flags
& IFF_BROADCAST
)
382 ret
= if_ioctl (SIOCGIFBRDADDR
, (caddr_t
) &ifreq
);
385 if (errno
!= EADDRNOTAVAIL
)
387 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno
));
392 memcpy (&dest
, &ifreq
.ifr_broadaddr
, sizeof (struct sockaddr_in
));
393 dest_pnt
= &dest
.sin_addr
;
397 /* Set address to the interface. */
398 connected_add_ipv4 (ifp
, 0, &addr
.sin_addr
, prefixlen
, dest_pnt
, NULL
);
402 #endif /* HAVE_GETIFADDRS */
404 /* Fetch interface information via ioctl(). */
406 interface_info_ioctl ()
408 struct listnode
*node
;
409 struct interface
*ifp
;
411 LIST_LOOP (iflist
, ifp
, node
)
413 ifp
= getdata (node
);
418 #endif /* SIOCGIFHWADDR */
420 #ifndef HAVE_GETIFADDRS
422 #endif /* ! HAVE_GETIFADDRS */
428 /* Lookup all interface information. */
432 /* Linux can do both proc & ioctl, ioctl is the only way to get
433 interface aliases in 2.2 series kernels. */
434 #ifdef HAVE_PROC_NET_DEV
435 interface_list_proc ();
436 #endif /* HAVE_PROC_NET_DEV */
437 interface_list_ioctl ();
439 /* After listing is done, get index, address, flags and other
440 interface's information. */
441 interface_info_ioctl ();
443 #ifdef HAVE_GETIFADDRS
445 #endif /* HAVE_GETIFADDRS */
447 #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
448 /* Linux provides interface's IPv6 address via
449 /proc/net/if_inet6. */
451 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */