Annotation of embedaddon/quagga/zebra/if_ioctl.c, revision 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>