]>
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 along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "sockunion.h"
30 #include "connected.h"
32 #include "zebra_memory.h"
36 #include "lib_errors.h"
38 #include "zebra/interface.h"
39 #include "zebra/rib.h"
41 #include "zebra/zebra_errors.h"
45 /* Interface looking up using infamous SIOCGIFCONF. */
46 static int interface_list_ioctl(void)
54 struct interface
*ifp
;
57 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
59 /* Normally SIOCGIFCONF works with AF_INET socket. */
60 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
62 flog_err_sys(EC_LIB_SOCKET
,
63 "Can't make AF_INET socket stream: %s",
64 safe_strerror(errno
));
68 /* Set initial ifreq count. This will be double when SIOCGIFCONF
69 fail. Solaris has SIOCGIFNUM. */
71 ret
= ioctl(sock
, SIOCGIFNUM
, &ifnum
);
78 #endif /* SIOCGIFNUM */
80 ifconf
.ifc_buf
= NULL
;
83 /* Loop until SIOCGIFCONF success. */
85 ifconf
.ifc_len
= sizeof(struct ifreq
) * ifnum
;
87 XREALLOC(MTYPE_TMP
, ifconf
.ifc_buf
, ifconf
.ifc_len
);
89 ret
= ioctl(sock
, SIOCGIFCONF
, &ifconf
);
92 flog_err_sys(EC_LIB_SYSTEM_CALL
, "SIOCGIFCONF: %s",
93 safe_strerror(errno
));
96 /* Repeatedly get info til buffer fails to grow. */
97 if (ifconf
.ifc_len
> lastlen
) {
98 lastlen
= ifconf
.ifc_len
;
106 /* Allocate interface. */
107 ifreq
= ifconf
.ifc_req
;
110 for (n
= 0; n
< ifconf
.ifc_len
;) {
113 ifreq
= (struct ifreq
*)((caddr_t
)ifconf
.ifc_req
+ n
);
114 ifp
= if_get_by_name(ifreq
->ifr_name
, vrf
);
116 size
= ifreq
->ifr_addr
.sa_len
;
117 if (size
< sizeof(ifreq
->ifr_addr
))
118 size
= sizeof(ifreq
->ifr_addr
);
119 size
+= sizeof(ifreq
->ifr_name
);
123 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
)) {
124 ifp
= if_get_by_name(ifreq
->ifr_name
, vrf
);
128 #endif /* OPEN_BSD */
132 XFREE(MTYPE_TMP
, ifconf
.ifc_buf
);
137 /* Get interface's index by ioctl. */
138 static int if_get_index(struct interface
*ifp
)
140 if_set_index(ifp
, if_nametoindex(ifp
->name
));
145 static int if_get_hwaddr(struct interface
*ifp
)
151 strlcpy(ifreq
.ifr_name
, ifp
->name
, sizeof(ifreq
.ifr_name
));
152 ifreq
.ifr_addr
.sa_family
= AF_INET
;
154 /* Fetch Hardware address if available. */
155 ret
= vrf_if_ioctl(SIOCGIFHWADDR
, (caddr_t
)&ifreq
, ifp
->vrf_id
);
157 ifp
->hw_addr_len
= 0;
159 memcpy(ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
161 for (i
= 0; i
< 6; i
++)
162 if (ifp
->hw_addr
[i
] != 0)
166 ifp
->hw_addr_len
= 0;
168 ifp
->hw_addr_len
= 6;
172 #endif /* SIOCGIFHWADDR */
174 static int if_getaddrs(void)
177 struct ifaddrs
*ifap
;
178 struct ifaddrs
*ifapfree
;
179 struct interface
*ifp
;
182 ret
= getifaddrs(&ifap
);
184 flog_err_sys(EC_LIB_SYSTEM_CALL
, "getifaddrs(): %s",
185 safe_strerror(errno
));
189 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
) {
190 if (ifap
->ifa_addr
== NULL
) {
193 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
195 (ifap
->ifa_name
? ifap
->ifa_name
: "(null)"));
199 ifp
= if_lookup_by_name(ifap
->ifa_name
,
200 vrf_lookup_by_id(VRF_DEFAULT
));
202 flog_err(EC_LIB_INTERFACE
,
203 "if_getaddrs(): Can't lookup interface %s\n",
208 if (ifap
->ifa_addr
->sa_family
== AF_INET
) {
209 struct sockaddr_in
*addr
;
210 struct sockaddr_in
*mask
;
211 struct sockaddr_in
*dest
;
212 struct in_addr
*dest_pnt
;
215 addr
= (struct sockaddr_in
*)ifap
->ifa_addr
;
216 mask
= (struct sockaddr_in
*)ifap
->ifa_netmask
;
217 prefixlen
= ip_masklen(mask
->sin_addr
);
221 if (if_is_pointopoint(ifp
) && ifap
->ifa_dstaddr
222 && !IPV4_ADDR_SAME(&addr
->sin_addr
,
223 &((struct sockaddr_in
*)
226 dest
= (struct sockaddr_in
*)ifap
->ifa_dstaddr
;
227 dest_pnt
= &dest
->sin_addr
;
228 flags
= ZEBRA_IFA_PEER
;
229 } else if (ifap
->ifa_broadaddr
232 &((struct sockaddr_in
*)
235 dest
= (struct sockaddr_in
*)
237 dest_pnt
= &dest
->sin_addr
;
240 connected_add_ipv4(ifp
, flags
, &addr
->sin_addr
,
241 prefixlen
, dest_pnt
, NULL
,
244 if (ifap
->ifa_addr
->sa_family
== AF_INET6
) {
245 struct sockaddr_in6
*addr
;
246 struct sockaddr_in6
*mask
;
249 addr
= (struct sockaddr_in6
*)ifap
->ifa_addr
;
250 mask
= (struct sockaddr_in6
*)ifap
->ifa_netmask
;
251 prefixlen
= ip6_masklen(mask
->sin6_addr
);
254 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
)) {
255 addr
->sin6_scope_id
=
256 ntohs(*(uint16_t *)&addr
->sin6_addr
258 addr
->sin6_addr
.s6_addr
[2] =
259 addr
->sin6_addr
.s6_addr
[3] = 0;
263 connected_add_ipv6(ifp
, flags
, &addr
->sin6_addr
, NULL
,
264 prefixlen
, NULL
, METRIC_MAX
);
268 freeifaddrs(ifapfree
);
273 /* Fetch interface information via ioctl(). */
274 static void interface_info_ioctl()
276 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
277 struct interface
*ifp
;
279 FOR_ALL_INTERFACES (vrf
, ifp
) {
283 #endif /* SIOCGIFHWADDR */
290 /* Lookup all interface information. */
291 void interface_list(struct zebra_ns
*zns
)
294 zlog_info("interface_list: NS %u", zns
->ns_id
);
296 /* Linux can do both proc & ioctl, ioctl is the only way to get
297 interface aliases in 2.2 series kernels. */
298 #ifdef HAVE_PROC_NET_DEV
299 interface_list_proc();
300 #endif /* HAVE_PROC_NET_DEV */
301 interface_list_ioctl();
303 /* After listing is done, get index, address, flags and other
304 interface's information. */
305 interface_info_ioctl();
309 #if defined(HAVE_PROC_NET_IF_INET6)
310 /* Linux provides interface's IPv6 address via
311 /proc/net/if_inet6. */
313 #endif /* HAVE_PROC_NET_IF_INET6 */
316 #endif /* OPEN_BSD */