File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / if_ioctl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>