]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
build: massively remove needless checks
[mirror_frr.git] / zebra / if_ioctl.c
1 /*
2 * Interface looking up by ioctl ().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
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
10 * later version.
11 *
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.
16 *
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
20 * 02111-1307, USA.
21 */
22
23 #include <zebra.h>
24
25 #include "if.h"
26 #include "sockunion.h"
27 #include "prefix.h"
28 #include "ioctl.h"
29 #include "connected.h"
30 #include "memory.h"
31 #include "zebra_memory.h"
32 #include "log.h"
33 #include "vrf.h"
34 #include "vty.h"
35
36 #include "zebra/interface.h"
37 #include "zebra/rib.h"
38
39 #include <ifaddrs.h>
40
41 /* Interface looking up using infamous SIOCGIFCONF. */
42 static int
43 interface_list_ioctl (void)
44 {
45 int ret;
46 int sock;
47 #define IFNUM_BASE 32
48 int ifnum;
49 struct ifreq *ifreq;
50 struct ifconf ifconf;
51 struct interface *ifp;
52 int n;
53 int lastlen;
54
55 /* Normally SIOCGIFCONF works with AF_INET socket. */
56 sock = socket (AF_INET, SOCK_DGRAM, 0);
57 if (sock < 0)
58 {
59 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
60 return -1;
61 }
62
63 /* Set initial ifreq count. This will be double when SIOCGIFCONF
64 fail. Solaris has SIOCGIFNUM. */
65 #ifdef SIOCGIFNUM
66 ret = ioctl (sock, SIOCGIFNUM, &ifnum);
67 if (ret < 0)
68 ifnum = IFNUM_BASE;
69 else
70 ifnum++;
71 #else
72 ifnum = IFNUM_BASE;
73 #endif /* SIOCGIFNUM */
74
75 ifconf.ifc_buf = NULL;
76
77 lastlen = 0;
78 /* Loop until SIOCGIFCONF success. */
79 for (;;)
80 {
81 ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
82 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
83
84 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
85
86 if (ret < 0)
87 {
88 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
89 goto end;
90 }
91 /* Repeatedly get info til buffer fails to grow. */
92 if (ifconf.ifc_len > lastlen)
93 {
94 lastlen = ifconf.ifc_len;
95 ifnum += 10;
96 continue;
97 }
98 /* Success. */
99 break;
100 }
101
102 /* Allocate interface. */
103 ifreq = ifconf.ifc_req;
104
105 #ifdef OPEN_BSD
106 for (n = 0; n < ifconf.ifc_len; )
107 {
108 int size;
109
110 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
111 ifp = if_get_by_name_len(ifreq->ifr_name,
112 strnlen(ifreq->ifr_name,
113 sizeof(ifreq->ifr_name)));
114 if_add_update (ifp);
115 size = ifreq->ifr_addr.sa_len;
116 if (size < sizeof (ifreq->ifr_addr))
117 size = sizeof (ifreq->ifr_addr);
118 size += sizeof (ifreq->ifr_name);
119 n += size;
120 }
121 #else
122 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
123 {
124 ifp = if_get_by_name_len(ifreq->ifr_name,
125 strnlen(ifreq->ifr_name,
126 sizeof(ifreq->ifr_name)));
127 if_add_update (ifp);
128 ifreq++;
129 }
130 #endif /* OPEN_BSD */
131
132 end:
133 close (sock);
134 XFREE (MTYPE_TMP, ifconf.ifc_buf);
135
136 return ret;
137 }
138
139 /* Get interface's index by ioctl. */
140 static int
141 if_get_index (struct interface *ifp)
142 {
143 ifp->ifindex = if_nametoindex(ifp->name);
144 return ifp->ifindex;
145 }
146
147 #ifdef SIOCGIFHWADDR
148 static int
149 if_get_hwaddr (struct interface *ifp)
150 {
151 int ret;
152 struct ifreq ifreq;
153 int i;
154
155 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
156 ifreq.ifr_addr.sa_family = AF_INET;
157
158 /* Fetch Hardware address if available. */
159 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
160 if (ret < 0)
161 ifp->hw_addr_len = 0;
162 else
163 {
164 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
165
166 for (i = 0; i < 6; i++)
167 if (ifp->hw_addr[i] != 0)
168 break;
169
170 if (i == 6)
171 ifp->hw_addr_len = 0;
172 else
173 ifp->hw_addr_len = 6;
174 }
175 return 0;
176 }
177 #endif /* SIOCGIFHWADDR */
178
179 static int
180 if_getaddrs (void)
181 {
182 int ret;
183 struct ifaddrs *ifap;
184 struct ifaddrs *ifapfree;
185 struct interface *ifp;
186 int prefixlen;
187
188 ret = getifaddrs (&ifap);
189 if (ret != 0)
190 {
191 zlog_err ("getifaddrs(): %s", safe_strerror (errno));
192 return -1;
193 }
194
195 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
196 {
197 if (ifap->ifa_addr == NULL)
198 {
199 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
200 __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
201 continue;
202 }
203
204 ifp = if_lookup_by_name (ifap->ifa_name);
205 if (ifp == NULL)
206 {
207 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
208 ifap->ifa_name);
209 continue;
210 }
211
212 if (ifap->ifa_addr->sa_family == AF_INET)
213 {
214 struct sockaddr_in *addr;
215 struct sockaddr_in *mask;
216 struct sockaddr_in *dest;
217 struct in_addr *dest_pnt;
218 int flags = 0;
219
220 addr = (struct sockaddr_in *) ifap->ifa_addr;
221 mask = (struct sockaddr_in *) ifap->ifa_netmask;
222 prefixlen = ip_masklen (mask->sin_addr);
223
224 dest_pnt = NULL;
225
226 if (ifap->ifa_dstaddr &&
227 !IPV4_ADDR_SAME(&addr->sin_addr,
228 &((struct sockaddr_in *)
229 ifap->ifa_dstaddr)->sin_addr))
230 {
231 dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
232 dest_pnt = &dest->sin_addr;
233 flags = ZEBRA_IFA_PEER;
234 }
235 else if (ifap->ifa_broadaddr &&
236 !IPV4_ADDR_SAME(&addr->sin_addr,
237 &((struct sockaddr_in *)
238 ifap->ifa_broadaddr)->sin_addr))
239 {
240 dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
241 dest_pnt = &dest->sin_addr;
242 }
243
244 connected_add_ipv4 (ifp, flags, &addr->sin_addr,
245 prefixlen, dest_pnt, NULL);
246 }
247 #ifdef HAVE_IPV6
248 if (ifap->ifa_addr->sa_family == AF_INET6)
249 {
250 struct sockaddr_in6 *addr;
251 struct sockaddr_in6 *mask;
252 struct sockaddr_in6 *dest;
253 struct in6_addr *dest_pnt;
254 int flags = 0;
255
256 addr = (struct sockaddr_in6 *) ifap->ifa_addr;
257 mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
258 prefixlen = ip6_masklen (mask->sin6_addr);
259
260 dest_pnt = NULL;
261
262 if (ifap->ifa_dstaddr &&
263 !IPV6_ADDR_SAME(&addr->sin6_addr,
264 &((struct sockaddr_in6 *)
265 ifap->ifa_dstaddr)->sin6_addr))
266 {
267 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
268 dest_pnt = &dest->sin6_addr;
269 flags = ZEBRA_IFA_PEER;
270 }
271 else if (ifap->ifa_broadaddr &&
272 !IPV6_ADDR_SAME(&addr->sin6_addr,
273 &((struct sockaddr_in6 *)
274 ifap->ifa_broadaddr)->sin6_addr))
275 {
276 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
277 dest_pnt = &dest->sin6_addr;
278 }
279
280 #if defined(KAME)
281 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
282 {
283 addr->sin6_scope_id =
284 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
285 addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
286 }
287 #endif
288
289 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
290 dest_pnt, NULL);
291 }
292 #endif /* HAVE_IPV6 */
293 }
294
295 freeifaddrs (ifapfree);
296
297 return 0;
298 }
299
300 /* Fetch interface information via ioctl(). */
301 static void
302 interface_info_ioctl ()
303 {
304 struct listnode *node, *nnode;
305 struct interface *ifp;
306
307 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), node, nnode, ifp))
308 {
309 if_get_index (ifp);
310 #ifdef SIOCGIFHWADDR
311 if_get_hwaddr (ifp);
312 #endif /* SIOCGIFHWADDR */
313 if_get_flags (ifp);
314 if_get_mtu (ifp);
315 if_get_metric (ifp);
316 }
317 }
318
319 /* Lookup all interface information. */
320 void
321 interface_list (struct zebra_ns *zns)
322 {
323
324 zlog_info ("interface_list: NS %u", zns->ns_id);
325
326 /* Linux can do both proc & ioctl, ioctl is the only way to get
327 interface aliases in 2.2 series kernels. */
328 #ifdef HAVE_PROC_NET_DEV
329 interface_list_proc ();
330 #endif /* HAVE_PROC_NET_DEV */
331 interface_list_ioctl ();
332
333 /* After listing is done, get index, address, flags and other
334 interface's information. */
335 interface_info_ioctl ();
336
337 if_getaddrs ();
338
339 #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
340 /* Linux provides interface's IPv6 address via
341 /proc/net/if_inet6. */
342 ifaddr_proc_ipv6 ();
343 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
344 }