Annotation of embedaddon/quagga/zebra/if_ioctl.c, revision 1.1.1.2
1.1 misho 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 "log.h"
1.1.1.2 ! misho 32: #include "vrf.h"
1.1 misho 33:
34: #include "zebra/interface.h"
1.1.1.2 ! misho 35: #include "zebra/rib.h"
1.1 misho 36:
37: /* Interface looking up using infamous SIOCGIFCONF. */
38: static int
39: interface_list_ioctl (void)
40: {
41: int ret;
42: int sock;
43: #define IFNUM_BASE 32
44: int ifnum;
45: struct ifreq *ifreq;
46: struct ifconf ifconf;
47: struct interface *ifp;
48: int n;
49: int lastlen;
50:
51: /* Normally SIOCGIFCONF works with AF_INET socket. */
52: sock = socket (AF_INET, SOCK_DGRAM, 0);
53: if (sock < 0)
54: {
55: zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
56: return -1;
57: }
58:
59: /* Set initial ifreq count. This will be double when SIOCGIFCONF
60: fail. Solaris has SIOCGIFNUM. */
61: #ifdef SIOCGIFNUM
62: ret = ioctl (sock, SIOCGIFNUM, &ifnum);
63: if (ret < 0)
64: ifnum = IFNUM_BASE;
65: else
66: ifnum++;
67: #else
68: ifnum = IFNUM_BASE;
69: #endif /* SIOCGIFNUM */
70:
71: ifconf.ifc_buf = NULL;
72:
73: lastlen = 0;
74: /* Loop until SIOCGIFCONF success. */
75: for (;;)
76: {
77: ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
78: ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
79:
80: ret = ioctl(sock, SIOCGIFCONF, &ifconf);
81:
82: if (ret < 0)
83: {
84: zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
85: goto end;
86: }
87: /* Repeatedly get info til buffer fails to grow. */
88: if (ifconf.ifc_len > lastlen)
89: {
90: lastlen = ifconf.ifc_len;
91: ifnum += 10;
92: continue;
93: }
94: /* Success. */
95: break;
96: }
97:
98: /* Allocate interface. */
99: ifreq = ifconf.ifc_req;
100:
101: #ifdef OPEN_BSD
102: for (n = 0; n < ifconf.ifc_len; )
103: {
104: int size;
105:
106: ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
107: ifp = if_get_by_name_len(ifreq->ifr_name,
108: strnlen(ifreq->ifr_name,
109: sizeof(ifreq->ifr_name)));
110: if_add_update (ifp);
111: size = ifreq->ifr_addr.sa_len;
112: if (size < sizeof (ifreq->ifr_addr))
113: size = sizeof (ifreq->ifr_addr);
114: size += sizeof (ifreq->ifr_name);
115: n += size;
116: }
117: #else
118: for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
119: {
120: ifp = if_get_by_name_len(ifreq->ifr_name,
121: strnlen(ifreq->ifr_name,
122: sizeof(ifreq->ifr_name)));
123: if_add_update (ifp);
124: ifreq++;
125: }
126: #endif /* OPEN_BSD */
127:
128: end:
129: close (sock);
130: XFREE (MTYPE_TMP, ifconf.ifc_buf);
131:
132: return ret;
133: }
134:
135: /* Get interface's index by ioctl. */
136: static int
137: if_get_index (struct interface *ifp)
138: {
139: #if defined(HAVE_IF_NAMETOINDEX)
140: /* Modern systems should have if_nametoindex(3). */
141: ifp->ifindex = if_nametoindex(ifp->name);
142: #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
143: /* Fall-back for older linuxes. */
144: int ret;
145: struct ifreq ifreq;
146: static int if_fake_index;
147:
148: ifreq_set_name (&ifreq, ifp);
149:
150: ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
151: if (ret < 0)
152: {
153: /* Linux 2.0.X does not have interface index. */
154: ifp->ifindex = if_fake_index++;
155: return ifp->ifindex;
156: }
157:
158: /* OK we got interface index. */
159: #ifdef ifr_ifindex
160: ifp->ifindex = ifreq.ifr_ifindex;
161: #else
162: ifp->ifindex = ifreq.ifr_index;
163: #endif
164:
165: #else
166: /* Linux 2.2.X does not provide individual interface index
167: for aliases and we know it. For others issue a warning. */
168: #if !defined(HAVE_BROKEN_ALIASES)
169: #warning "Using if_fake_index. You may want to add appropriate"
170: #warning "mapping from ifname to ifindex for your system..."
171: #endif
172: /* This branch probably won't provide usable results, but anyway... */
173: static int if_fake_index = 1;
174: ifp->ifindex = if_fake_index++;
175: #endif
176:
177: return ifp->ifindex;
178: }
179:
180: #ifdef SIOCGIFHWADDR
181: static int
182: if_get_hwaddr (struct interface *ifp)
183: {
184: int ret;
185: struct ifreq ifreq;
186: int i;
187:
188: strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
189: ifreq.ifr_addr.sa_family = AF_INET;
190:
191: /* Fetch Hardware address if available. */
192: ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
193: if (ret < 0)
194: ifp->hw_addr_len = 0;
195: else
196: {
197: memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
198:
199: for (i = 0; i < 6; i++)
200: if (ifp->hw_addr[i] != 0)
201: break;
202:
203: if (i == 6)
204: ifp->hw_addr_len = 0;
205: else
206: ifp->hw_addr_len = 6;
207: }
208: return 0;
209: }
210: #endif /* SIOCGIFHWADDR */
211:
212: #ifdef HAVE_GETIFADDRS
213: #include <ifaddrs.h>
214:
215: static int
216: if_getaddrs (void)
217: {
218: int ret;
219: struct ifaddrs *ifap;
220: struct ifaddrs *ifapfree;
221: struct interface *ifp;
222: int prefixlen;
223:
224: ret = getifaddrs (&ifap);
225: if (ret != 0)
226: {
227: zlog_err ("getifaddrs(): %s", safe_strerror (errno));
228: return -1;
229: }
230:
231: for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
232: {
233: if (ifap->ifa_addr == NULL)
234: {
235: zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
236: __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
237: continue;
238: }
239:
240: ifp = if_lookup_by_name (ifap->ifa_name);
241: if (ifp == NULL)
242: {
243: zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
244: ifap->ifa_name);
245: continue;
246: }
247:
248: if (ifap->ifa_addr->sa_family == AF_INET)
249: {
250: struct sockaddr_in *addr;
251: struct sockaddr_in *mask;
252: struct sockaddr_in *dest;
253: struct in_addr *dest_pnt;
254: int flags = 0;
255:
256: addr = (struct sockaddr_in *) ifap->ifa_addr;
257: mask = (struct sockaddr_in *) ifap->ifa_netmask;
258: prefixlen = ip_masklen (mask->sin_addr);
259:
260: dest_pnt = NULL;
261:
262: if (ifap->ifa_dstaddr &&
263: !IPV4_ADDR_SAME(&addr->sin_addr,
264: &((struct sockaddr_in *)
265: ifap->ifa_dstaddr)->sin_addr))
266: {
267: dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
268: dest_pnt = &dest->sin_addr;
269: flags = ZEBRA_IFA_PEER;
270: }
271: else if (ifap->ifa_broadaddr &&
272: !IPV4_ADDR_SAME(&addr->sin_addr,
273: &((struct sockaddr_in *)
274: ifap->ifa_broadaddr)->sin_addr))
275: {
276: dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
277: dest_pnt = &dest->sin_addr;
278: }
279:
280: connected_add_ipv4 (ifp, flags, &addr->sin_addr,
281: prefixlen, dest_pnt, NULL);
282: }
283: #ifdef HAVE_IPV6
284: if (ifap->ifa_addr->sa_family == AF_INET6)
285: {
286: struct sockaddr_in6 *addr;
287: struct sockaddr_in6 *mask;
288: struct sockaddr_in6 *dest;
289: struct in6_addr *dest_pnt;
290: int flags = 0;
291:
292: addr = (struct sockaddr_in6 *) ifap->ifa_addr;
293: mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
294: prefixlen = ip6_masklen (mask->sin6_addr);
295:
296: dest_pnt = NULL;
297:
298: if (ifap->ifa_dstaddr &&
299: !IPV6_ADDR_SAME(&addr->sin6_addr,
300: &((struct sockaddr_in6 *)
301: ifap->ifa_dstaddr)->sin6_addr))
302: {
303: dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
304: dest_pnt = &dest->sin6_addr;
305: flags = ZEBRA_IFA_PEER;
306: }
307: else if (ifap->ifa_broadaddr &&
308: !IPV6_ADDR_SAME(&addr->sin6_addr,
309: &((struct sockaddr_in6 *)
310: ifap->ifa_broadaddr)->sin6_addr))
311: {
312: dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
313: dest_pnt = &dest->sin6_addr;
314: }
315:
316: #if defined(KAME)
317: if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
318: {
319: addr->sin6_scope_id =
320: ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
321: addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
322: }
323: #endif
324:
325: connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
326: dest_pnt, NULL);
327: }
328: #endif /* HAVE_IPV6 */
329: }
330:
331: freeifaddrs (ifapfree);
332:
333: return 0;
334: }
335: #else /* HAVE_GETIFADDRS */
336: /* Interface address lookup by ioctl. This function only looks up
337: IPv4 address. */
338: int
339: if_get_addr (struct interface *ifp)
340: {
341: int ret;
342: struct ifreq ifreq;
343: struct sockaddr_in addr;
344: struct sockaddr_in mask;
345: struct sockaddr_in dest;
346: struct in_addr *dest_pnt;
347: u_char prefixlen;
348: int flags = 0;
349:
350: /* Interface's name and address family. */
351: strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
352: ifreq.ifr_addr.sa_family = AF_INET;
353:
354: /* Interface's address. */
355: ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
356: if (ret < 0)
357: {
358: if (errno != EADDRNOTAVAIL)
359: {
360: zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
361: return ret;
362: }
363: return 0;
364: }
365: memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
366:
367: /* Interface's network mask. */
368: ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
369: if (ret < 0)
370: {
371: if (errno != EADDRNOTAVAIL)
372: {
373: zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
374: return ret;
375: }
376: return 0;
377: }
378: #ifdef ifr_netmask
379: memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
380: #else
381: memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
382: #endif /* ifr_netmask */
383: prefixlen = ip_masklen (mask.sin_addr);
384:
385: /* Point to point or borad cast address pointer init. */
386: dest_pnt = NULL;
387:
388: ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
389: if (ret < 0)
390: {
391: if (errno != EADDRNOTAVAIL)
392: zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
393: }
394: else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
395: {
396: memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
397: dest_pnt = &dest.sin_addr;
398: flags = ZEBRA_IFA_PEER;
399: }
400: if (!dest_pnt)
401: {
402: ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
403: if (ret < 0)
404: {
405: if (errno != EADDRNOTAVAIL)
406: zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
407: }
408: else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
409: {
410: memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
411: dest_pnt = &dest.sin_addr;
412: }
413: }
414:
415:
416: /* Set address to the interface. */
417: connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
418:
419: return 0;
420: }
421: #endif /* HAVE_GETIFADDRS */
422:
423: /* Fetch interface information via ioctl(). */
424: static void
425: interface_info_ioctl ()
426: {
427: struct listnode *node, *nnode;
428: struct interface *ifp;
429:
430: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
431: {
432: if_get_index (ifp);
433: #ifdef SIOCGIFHWADDR
434: if_get_hwaddr (ifp);
435: #endif /* SIOCGIFHWADDR */
436: if_get_flags (ifp);
437: #ifndef HAVE_GETIFADDRS
438: if_get_addr (ifp);
439: #endif /* ! HAVE_GETIFADDRS */
440: if_get_mtu (ifp);
441: if_get_metric (ifp);
442: }
443: }
444:
445: /* Lookup all interface information. */
446: void
1.1.1.2 ! misho 447: interface_list (struct zebra_vrf *zvrf)
1.1 misho 448: {
1.1.1.2 ! misho 449: if (zvrf->vrf_id != VRF_DEFAULT)
! 450: {
! 451: zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
! 452: return;
! 453: }
1.1 misho 454: /* Linux can do both proc & ioctl, ioctl is the only way to get
455: interface aliases in 2.2 series kernels. */
456: #ifdef HAVE_PROC_NET_DEV
457: interface_list_proc ();
458: #endif /* HAVE_PROC_NET_DEV */
459: interface_list_ioctl ();
460:
461: /* After listing is done, get index, address, flags and other
462: interface's information. */
463: interface_info_ioctl ();
464:
465: #ifdef HAVE_GETIFADDRS
466: if_getaddrs ();
467: #endif /* HAVE_GETIFADDRS */
468:
469: #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
470: /* Linux provides interface's IPv6 address via
471: /proc/net/if_inet6. */
472: ifaddr_proc_ipv6 ();
473: #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
474: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>