File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / if_ioctl.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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: #include "vrf.h"
   33: 
   34: #include "zebra/interface.h"
   35: #include "zebra/rib.h"
   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
  447: interface_list (struct zebra_vrf *zvrf)
  448: {
  449:   if (zvrf->vrf_id != VRF_DEFAULT)
  450:     {
  451:       zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
  452:       return;
  453:     }
  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>