Annotation of embedaddon/quagga/zebra/if_ioctl.c, revision 1.1.1.1
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"
32:
33: #include "zebra/interface.h"
34:
35: /* Interface looking up using infamous SIOCGIFCONF. */
36: static int
37: interface_list_ioctl (void)
38: {
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;
48:
49: /* Normally SIOCGIFCONF works with AF_INET socket. */
50: sock = socket (AF_INET, SOCK_DGRAM, 0);
51: if (sock < 0)
52: {
53: zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
54: return -1;
55: }
56:
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 */
68:
69: ifconf.ifc_buf = NULL;
70:
71: lastlen = 0;
72: /* Loop until SIOCGIFCONF success. */
73: for (;;)
74: {
75: ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
76: ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
77:
78: ret = ioctl(sock, SIOCGIFCONF, &ifconf);
79:
80: if (ret < 0)
81: {
82: zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
83: goto end;
84: }
85: /* Repeatedly get info til buffer fails to grow. */
86: if (ifconf.ifc_len > lastlen)
87: {
88: lastlen = ifconf.ifc_len;
89: ifnum += 10;
90: continue;
91: }
92: /* Success. */
93: break;
94: }
95:
96: /* Allocate interface. */
97: ifreq = ifconf.ifc_req;
98:
99: #ifdef OPEN_BSD
100: for (n = 0; n < ifconf.ifc_len; )
101: {
102: int size;
103:
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;
114: }
115: #else
116: for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
117: {
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++;
123: }
124: #endif /* OPEN_BSD */
125:
126: end:
127: close (sock);
128: XFREE (MTYPE_TMP, ifconf.ifc_buf);
129:
130: return ret;
131: }
132:
133: /* Get interface's index by ioctl. */
134: static int
135: if_get_index (struct interface *ifp)
136: {
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;
145:
146: ifreq_set_name (&ifreq, ifp);
147:
148: ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
149: if (ret < 0)
150: {
151: /* Linux 2.0.X does not have interface index. */
152: ifp->ifindex = if_fake_index++;
153: return ifp->ifindex;
154: }
155:
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
162:
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
174:
175: return ifp->ifindex;
176: }
177:
178: #ifdef SIOCGIFHWADDR
179: static int
180: if_get_hwaddr (struct interface *ifp)
181: {
182: int ret;
183: struct ifreq ifreq;
184: int i;
185:
186: strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
187: ifreq.ifr_addr.sa_family = AF_INET;
188:
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
194: {
195: memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
196:
197: for (i = 0; i < 6; i++)
198: if (ifp->hw_addr[i] != 0)
199: break;
200:
201: if (i == 6)
202: ifp->hw_addr_len = 0;
203: else
204: ifp->hw_addr_len = 6;
205: }
206: return 0;
207: }
208: #endif /* SIOCGIFHWADDR */
209:
210: #ifdef HAVE_GETIFADDRS
211: #include <ifaddrs.h>
212:
213: static int
214: if_getaddrs (void)
215: {
216: int ret;
217: struct ifaddrs *ifap;
218: struct ifaddrs *ifapfree;
219: struct interface *ifp;
220: int prefixlen;
221:
222: ret = getifaddrs (&ifap);
223: if (ret != 0)
224: {
225: zlog_err ("getifaddrs(): %s", safe_strerror (errno));
226: return -1;
227: }
228:
229: for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
230: {
231: if (ifap->ifa_addr == NULL)
232: {
233: zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
234: __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
235: continue;
236: }
237:
238: ifp = if_lookup_by_name (ifap->ifa_name);
239: if (ifp == NULL)
240: {
241: zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
242: ifap->ifa_name);
243: continue;
244: }
245:
246: if (ifap->ifa_addr->sa_family == AF_INET)
247: {
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;
253:
254: addr = (struct sockaddr_in *) ifap->ifa_addr;
255: mask = (struct sockaddr_in *) ifap->ifa_netmask;
256: prefixlen = ip_masklen (mask->sin_addr);
257:
258: dest_pnt = NULL;
259:
260: if (ifap->ifa_dstaddr &&
261: !IPV4_ADDR_SAME(&addr->sin_addr,
262: &((struct sockaddr_in *)
263: ifap->ifa_dstaddr)->sin_addr))
264: {
265: dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
266: dest_pnt = &dest->sin_addr;
267: flags = ZEBRA_IFA_PEER;
268: }
269: else if (ifap->ifa_broadaddr &&
270: !IPV4_ADDR_SAME(&addr->sin_addr,
271: &((struct sockaddr_in *)
272: ifap->ifa_broadaddr)->sin_addr))
273: {
274: dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
275: dest_pnt = &dest->sin_addr;
276: }
277:
278: connected_add_ipv4 (ifp, flags, &addr->sin_addr,
279: prefixlen, dest_pnt, NULL);
280: }
281: #ifdef HAVE_IPV6
282: if (ifap->ifa_addr->sa_family == AF_INET6)
283: {
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;
289:
290: addr = (struct sockaddr_in6 *) ifap->ifa_addr;
291: mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
292: prefixlen = ip6_masklen (mask->sin6_addr);
293:
294: dest_pnt = NULL;
295:
296: if (ifap->ifa_dstaddr &&
297: !IPV6_ADDR_SAME(&addr->sin6_addr,
298: &((struct sockaddr_in6 *)
299: ifap->ifa_dstaddr)->sin6_addr))
300: {
301: dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
302: dest_pnt = &dest->sin6_addr;
303: flags = ZEBRA_IFA_PEER;
304: }
305: else if (ifap->ifa_broadaddr &&
306: !IPV6_ADDR_SAME(&addr->sin6_addr,
307: &((struct sockaddr_in6 *)
308: ifap->ifa_broadaddr)->sin6_addr))
309: {
310: dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
311: dest_pnt = &dest->sin6_addr;
312: }
313:
314: #if defined(KAME)
315: if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
316: {
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;
320: }
321: #endif
322:
323: connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
324: dest_pnt, NULL);
325: }
326: #endif /* HAVE_IPV6 */
327: }
328:
329: freeifaddrs (ifapfree);
330:
331: return 0;
332: }
333: #else /* HAVE_GETIFADDRS */
334: /* Interface address lookup by ioctl. This function only looks up
335: IPv4 address. */
336: int
337: if_get_addr (struct interface *ifp)
338: {
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;
347:
348: /* Interface's name and address family. */
349: strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
350: ifreq.ifr_addr.sa_family = AF_INET;
351:
352: /* Interface's address. */
353: ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
354: if (ret < 0)
355: {
356: if (errno != EADDRNOTAVAIL)
357: {
358: zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
359: return ret;
360: }
361: return 0;
362: }
363: memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
364:
365: /* Interface's network mask. */
366: ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
367: if (ret < 0)
368: {
369: if (errno != EADDRNOTAVAIL)
370: {
371: zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
372: return ret;
373: }
374: return 0;
375: }
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);
382:
383: /* Point to point or borad cast address pointer init. */
384: dest_pnt = NULL;
385:
386: ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
387: if (ret < 0)
388: {
389: if (errno != EADDRNOTAVAIL)
390: zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
391: }
392: else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
393: {
394: memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
395: dest_pnt = &dest.sin_addr;
396: flags = ZEBRA_IFA_PEER;
397: }
398: if (!dest_pnt)
399: {
400: ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
401: if (ret < 0)
402: {
403: if (errno != EADDRNOTAVAIL)
404: zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
405: }
406: else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
407: {
408: memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
409: dest_pnt = &dest.sin_addr;
410: }
411: }
412:
413:
414: /* Set address to the interface. */
415: connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
416:
417: return 0;
418: }
419: #endif /* HAVE_GETIFADDRS */
420:
421: /* Fetch interface information via ioctl(). */
422: static void
423: interface_info_ioctl ()
424: {
425: struct listnode *node, *nnode;
426: struct interface *ifp;
427:
428: for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
429: {
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);
440: }
441: }
442:
443: /* Lookup all interface information. */
444: void
445: interface_list ()
446: {
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 ();
453:
454: /* After listing is done, get index, address, flags and other
455: interface's information. */
456: interface_info_ioctl ();
457:
458: #ifdef HAVE_GETIFADDRS
459: if_getaddrs ();
460: #endif /* HAVE_GETIFADDRS */
461:
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 */
467: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>