ospfd: Tighten up the connected check for redistribution
[jleu-quagga.git] / zebra / if_ioctl.c
blobf357e15447c363ad3be6922654fb77952690542d
1 /*
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
10 * later version.
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
20 * 02111-1307, USA.
23 #include <zebra.h>
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 "log.h"
33 #include "zebra/interface.h"
35 /* Interface looking up using infamous SIOCGIFCONF. */
36 static int
37 interface_list_ioctl (void)
39 int ret;
40 int sock;
41 #define IFNUM_BASE 32
42 int ifnum;
43 struct ifreq *ifreq;
44 struct ifconf ifconf;
45 struct interface *ifp;
46 int n;
47 int lastlen;
49 /* Normally SIOCGIFCONF works with AF_INET socket. */
50 sock = socket (AF_INET, SOCK_DGRAM, 0);
51 if (sock < 0)
53 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
54 return -1;
57 /* Set initial ifreq count. This will be double when SIOCGIFCONF
58 fail. Solaris has SIOCGIFNUM. */
59 #ifdef SIOCGIFNUM
60 ret = ioctl (sock, SIOCGIFNUM, &ifnum);
61 if (ret < 0)
62 ifnum = IFNUM_BASE;
63 else
64 ifnum++;
65 #else
66 ifnum = IFNUM_BASE;
67 #endif /* SIOCGIFNUM */
69 ifconf.ifc_buf = NULL;
71 lastlen = 0;
72 /* Loop until SIOCGIFCONF success. */
73 for (;;)
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);
80 if (ret < 0)
82 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
83 goto end;
85 /* Repeatedly get info til buffer fails to grow. */
86 if (ifconf.ifc_len > lastlen)
88 lastlen = ifconf.ifc_len;
89 ifnum += 10;
90 continue;
92 /* Success. */
93 break;
96 /* Allocate interface. */
97 ifreq = ifconf.ifc_req;
99 #ifdef OPEN_BSD
100 for (n = 0; n < ifconf.ifc_len; )
102 int size;
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)));
108 if_add_update (ifp);
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);
113 n += size;
115 #else
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)));
121 if_add_update (ifp);
122 ifreq++;
124 #endif /* OPEN_BSD */
126 end:
127 close (sock);
128 XFREE (MTYPE_TMP, ifconf.ifc_buf);
130 return ret;
133 /* Get interface's index by ioctl. */
134 static int
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. */
142 int ret;
143 struct ifreq ifreq;
144 static int if_fake_index;
146 ifreq_set_name (&ifreq, ifp);
148 ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
149 if (ret < 0)
151 /* Linux 2.0.X does not have interface index. */
152 ifp->ifindex = if_fake_index++;
153 return ifp->ifindex;
156 /* OK we got interface index. */
157 #ifdef ifr_ifindex
158 ifp->ifindex = ifreq.ifr_ifindex;
159 #else
160 ifp->ifindex = ifreq.ifr_index;
161 #endif
163 #else
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..."
169 #endif
170 /* This branch probably won't provide usable results, but anyway... */
171 static int if_fake_index = 1;
172 ifp->ifindex = if_fake_index++;
173 #endif
175 return ifp->ifindex;
178 #ifdef SIOCGIFHWADDR
179 static int
180 if_get_hwaddr (struct interface *ifp)
182 int ret;
183 struct ifreq ifreq;
184 int i;
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);
191 if (ret < 0)
192 ifp->hw_addr_len = 0;
193 else
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)
199 break;
201 if (i == 6)
202 ifp->hw_addr_len = 0;
203 else
204 ifp->hw_addr_len = 6;
206 return 0;
208 #endif /* SIOCGIFHWADDR */
210 #ifdef HAVE_GETIFADDRS
211 #include <ifaddrs.h>
213 static int
214 if_getaddrs (void)
216 int ret;
217 struct ifaddrs *ifap;
218 struct ifaddrs *ifapfree;
219 struct interface *ifp;
220 int prefixlen;
222 ret = getifaddrs (&ifap);
223 if (ret != 0)
225 zlog_err ("getifaddrs(): %s", safe_strerror (errno));
226 return -1;
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)"));
235 continue;
238 ifp = if_lookup_by_name (ifap->ifa_name);
239 if (ifp == NULL)
241 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
242 ifap->ifa_name);
243 continue;
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;
252 int flags = 0;
254 addr = (struct sockaddr_in *) ifap->ifa_addr;
255 mask = (struct sockaddr_in *) ifap->ifa_netmask;
256 prefixlen = ip_masklen (mask->sin_addr);
258 dest_pnt = NULL;
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);
281 #ifdef HAVE_IPV6
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;
288 int flags = 0;
290 addr = (struct sockaddr_in6 *) ifap->ifa_addr;
291 mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
292 prefixlen = ip6_masklen (mask->sin6_addr);
294 dest_pnt = NULL;
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;
314 #if defined(KAME)
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;
321 #endif
323 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
324 dest_pnt, NULL);
326 #endif /* HAVE_IPV6 */
329 freeifaddrs (ifapfree);
331 return 0;
333 #else /* HAVE_GETIFADDRS */
334 /* Interface address lookup by ioctl. This function only looks up
335 IPv4 address. */
337 if_get_addr (struct interface *ifp)
339 int ret;
340 struct ifreq ifreq;
341 struct sockaddr_in addr;
342 struct sockaddr_in mask;
343 struct sockaddr_in dest;
344 struct in_addr *dest_pnt;
345 u_char prefixlen;
346 int flags = 0;
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);
354 if (ret < 0)
356 if (errno != EADDRNOTAVAIL)
358 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
359 return ret;
361 return 0;
363 memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
365 /* Interface's network mask. */
366 ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
367 if (ret < 0)
369 if (errno != EADDRNOTAVAIL)
371 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
372 return ret;
374 return 0;
376 #ifdef ifr_netmask
377 memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
378 #else
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. */
384 dest_pnt = NULL;
386 ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
387 if (ret < 0)
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;
398 if (!dest_pnt)
400 ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
401 if (ret < 0)
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);
417 return 0;
419 #endif /* HAVE_GETIFADDRS */
421 /* Fetch interface information via ioctl(). */
422 static void
423 interface_info_ioctl ()
425 struct listnode *node, *nnode;
426 struct interface *ifp;
428 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
430 if_get_index (ifp);
431 #ifdef SIOCGIFHWADDR
432 if_get_hwaddr (ifp);
433 #endif /* SIOCGIFHWADDR */
434 if_get_flags (ifp);
435 #ifndef HAVE_GETIFADDRS
436 if_get_addr (ifp);
437 #endif /* ! HAVE_GETIFADDRS */
438 if_get_mtu (ifp);
439 if_get_metric (ifp);
443 /* Lookup all interface information. */
444 void
445 interface_list ()
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
459 if_getaddrs ();
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. */
465 ifaddr_proc_ipv6 ();
466 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */