File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / if_ioctl_solaris.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 () on Solaris.
    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 "privs.h"
   33: #include "vrf.h"
   34: 
   35: #include "zebra/interface.h"
   36: #include "zebra/ioctl_solaris.h"
   37: #include "zebra/rib.h"
   38: 
   39: static int if_get_addr (struct interface *, struct sockaddr *, const char *);
   40: static void interface_info_ioctl (struct interface *);
   41: extern struct zebra_privs_t zserv_privs;
   42: 
   43: static int
   44: interface_list_ioctl (int af)
   45: {
   46:   int ret;
   47:   int sock;
   48: #define IFNUM_BASE 32
   49:   struct lifnum lifn;
   50:   int ifnum;
   51:   struct lifreq *lifreq;
   52:   struct lifconf lifconf;
   53:   struct interface *ifp;
   54:   int n;
   55:   int save_errno;
   56:   size_t needed, lastneeded = 0;
   57:   char *buf = NULL;
   58: 
   59:   if (zserv_privs.change(ZPRIVS_RAISE))
   60:     zlog (NULL, LOG_ERR, "Can't raise privileges");
   61:   
   62:   sock = socket (af, SOCK_DGRAM, 0);
   63:   if (sock < 0)
   64:     {
   65:       zlog_warn ("Can't make %s socket stream: %s",
   66:                  (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
   67:                  
   68:       if (zserv_privs.change(ZPRIVS_LOWER))
   69:         zlog (NULL, LOG_ERR, "Can't lower privileges");
   70:         
   71:       return -1;
   72:     }
   73: 
   74: calculate_lifc_len:     /* must hold privileges to enter here */
   75:   lifn.lifn_family = af;
   76:   lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
   77:   ret = ioctl (sock, SIOCGLIFNUM, &lifn);
   78:   save_errno = errno;
   79:   
   80:   if (zserv_privs.change(ZPRIVS_LOWER))
   81:     zlog (NULL, LOG_ERR, "Can't lower privileges");
   82:  
   83:   if (ret < 0)
   84:     {
   85:       zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
   86:                  safe_strerror (save_errno));
   87:       close (sock);
   88:       return -1;
   89:     }
   90:   ifnum = lifn.lifn_count;
   91: 
   92:   /*
   93:    * When calculating the buffer size needed, add a small number
   94:    * of interfaces to those we counted.  We do this to capture
   95:    * the interface status of potential interfaces which may have
   96:    * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
   97:    */
   98:   needed = (ifnum + 4) * sizeof (struct lifreq);
   99:   if (needed > lastneeded || needed < lastneeded / 2)
  100:     {
  101:       if (buf != NULL)
  102:         XFREE (MTYPE_TMP, buf);
  103:       if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
  104:         {
  105:           zlog_warn ("interface_list_ioctl: malloc failed");
  106:           close (sock);
  107:           return -1;
  108:         }
  109:     }
  110:   lastneeded = needed;
  111: 
  112:   lifconf.lifc_family = af;
  113:   lifconf.lifc_flags = LIFC_NOXMIT;
  114:   lifconf.lifc_len = needed;
  115:   lifconf.lifc_buf = buf;
  116: 
  117:   if (zserv_privs.change(ZPRIVS_RAISE))
  118:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  119:     
  120:   ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
  121: 
  122:   if (ret < 0)
  123:     {
  124:       if (errno == EINVAL)
  125:         goto calculate_lifc_len; /* deliberately hold privileges */
  126: 
  127:       zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
  128: 
  129:       if (zserv_privs.change(ZPRIVS_LOWER))
  130:         zlog (NULL, LOG_ERR, "Can't lower privileges");
  131: 
  132:       goto end;
  133:     }
  134: 
  135:   if (zserv_privs.change(ZPRIVS_LOWER))
  136:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  137:     
  138:   /* Allocate interface. */
  139:   lifreq = lifconf.lifc_req;
  140: 
  141:   for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
  142:     {
  143:       /* we treat Solaris logical interfaces as addresses, because that is
  144:        * how PF_ROUTE on Solaris treats them. Hence we can not directly use
  145:        * the lifreq_name to get the ifp.  We need to normalise the name
  146:        * before attempting get.
  147:        *
  148:        * Solaris logical interface names are in the form of:
  149:        * <interface name>:<logical interface id>
  150:        */
  151:       unsigned int normallen = 0;
  152:       uint64_t lifflags;
  153:       
  154:       /* We should exclude ~IFF_UP interfaces, as we'll find out about them
  155:        * coming up later through RTM_NEWADDR message on the route socket.
  156:        */
  157:       if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
  158:                            lifreq->lifr_addr.ss_family)
  159:           || !CHECK_FLAG (lifflags, IFF_UP))
  160:         {
  161:           lifreq++;
  162:           continue;
  163:         }
  164:       
  165:       /* Find the normalised name */
  166:       while ( (normallen < sizeof(lifreq->lifr_name))
  167:              && ( *(lifreq->lifr_name + normallen) != '\0')
  168:              && ( *(lifreq->lifr_name + normallen) != ':') )
  169:         normallen++;
  170:       
  171:       ifp = if_get_by_name_len(lifreq->lifr_name, normallen);
  172: 
  173:       if (lifreq->lifr_addr.ss_family == AF_INET)
  174:         ifp->flags |= IFF_IPV4;
  175: 
  176:       if (lifreq->lifr_addr.ss_family == AF_INET6)
  177:         {
  178: #ifdef HAVE_IPV6
  179:           ifp->flags |= IFF_IPV6;
  180: #else
  181:           lifreq++;
  182:           continue;
  183: #endif /* HAVE_IPV6 */
  184:         }
  185:         
  186:       if_add_update (ifp);
  187: 
  188:       interface_info_ioctl (ifp);
  189:       
  190:       /* If a logical interface pass the full name so it can be
  191:        * as a label on the address
  192:        */
  193:       if ( *(lifreq->lifr_name + normallen) != '\0')
  194:         if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
  195:                      lifreq->lifr_name);
  196:       else
  197:         if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
  198:         
  199:       /* Poke the interface flags. Lets IFF_UP mangling kick in */
  200:       if_flags_update (ifp, ifp->flags);
  201:       
  202:       lifreq++;
  203:     }
  204: 
  205: end:
  206:   close (sock);
  207:   XFREE (MTYPE_TMP, lifconf.lifc_buf);
  208:   return ret;
  209: }
  210: 
  211: /* Get interface's index by ioctl. */
  212: static int
  213: if_get_index (struct interface *ifp)
  214: {
  215:   int ret;
  216:   struct lifreq lifreq;
  217: 
  218:   lifreq_set_name (&lifreq, ifp->name);
  219: 
  220:   if (ifp->flags & IFF_IPV4)
  221:     ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
  222:   else if (ifp->flags & IFF_IPV6)
  223:     ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
  224:   else
  225:     ret = -1;
  226: 
  227:   if (ret < 0)
  228:     {
  229:       zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
  230:       return ret;
  231:     }
  232: 
  233:   /* OK we got interface index. */
  234: #ifdef ifr_ifindex
  235:   ifp->ifindex = lifreq.lifr_ifindex;
  236: #else
  237:   ifp->ifindex = lifreq.lifr_index;
  238: #endif
  239:   return ifp->ifindex;
  240: 
  241: }
  242: 
  243: 
  244: /* Interface address lookup by ioctl.  This function only looks up
  245:    IPv4 address. */
  246: #define ADDRLEN(sa) (((sa)->sa_family == AF_INET ?  \
  247:                 sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
  248: 
  249: #define SIN(s) ((struct sockaddr_in *)(s))
  250: #define SIN6(s) ((struct sockaddr_in6 *)(s))
  251: 
  252: /* Retrieve address information for the given ifp */
  253: static int
  254: if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
  255: {
  256:   int ret;
  257:   struct lifreq lifreq;
  258:   struct sockaddr_storage mask, dest;
  259:   char *dest_pnt = NULL;
  260:   u_char prefixlen = 0;
  261:   afi_t af;
  262:   int flags = 0;
  263: 
  264:   /* Interface's name and address family.
  265:    * We need to use the logical interface name / label, if we've been
  266:    * given one, in order to get the right address
  267:    */
  268:   strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
  269: 
  270:   /* Interface's address. */
  271:   memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
  272:   af = addr->sa_family;
  273: 
  274:   /* Point to point or broad cast address pointer init. */
  275:   dest_pnt = NULL;
  276: 
  277:   if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
  278:     {
  279:       memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
  280:       if (af == AF_INET)
  281:         dest_pnt = (char *) &(SIN (&dest)->sin_addr);
  282:       else
  283:         dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
  284:       flags = ZEBRA_IFA_PEER;
  285:     }
  286: 
  287:   if (af == AF_INET)
  288:     {
  289:       ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
  290:       
  291:       if (ret < 0)
  292:         {
  293:           if (errno != EADDRNOTAVAIL)
  294:             {
  295:               zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
  296:                          safe_strerror (errno));
  297:               return ret;
  298:             }
  299:           return 0;
  300:         }
  301:       memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
  302: 
  303:       prefixlen = ip_masklen (SIN (&mask)->sin_addr);
  304:       if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
  305: 	{
  306:           memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
  307:           dest_pnt = (char *) &SIN (&dest)->sin_addr;
  308:         }
  309:     }
  310: #ifdef HAVE_IPV6
  311:   else if (af == AF_INET6)
  312:     {
  313:       if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0)
  314: 	{
  315: 	  if (ifp->flags & IFF_POINTOPOINT)
  316: 	    prefixlen = IPV6_MAX_BITLEN;
  317: 	  else
  318: 	    zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
  319: 		       ifp->name, safe_strerror (errno));
  320: 	}
  321:       else
  322: 	{
  323: 	  prefixlen = lifreq.lifr_addrlen;
  324: 	}
  325:     }
  326: #endif /* HAVE_IPV6 */
  327: 
  328:   /* Set address to the interface. */
  329:   if (af == AF_INET)
  330:     connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
  331:                         (struct in_addr *) dest_pnt, label);
  332: #ifdef HAVE_IPV6
  333:   else if (af == AF_INET6)
  334:     connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
  335:                         (struct in6_addr *) dest_pnt, label);
  336: #endif /* HAVE_IPV6 */
  337: 
  338:   return 0;
  339: }
  340: 
  341: /* Fetch interface information via ioctl(). */
  342: static void
  343: interface_info_ioctl (struct interface *ifp)
  344: {
  345:   if_get_index (ifp);
  346:   if_get_flags (ifp);
  347:   if_get_mtu (ifp);
  348:   if_get_metric (ifp);
  349: }
  350: 
  351: /* Lookup all interface information. */
  352: void
  353: interface_list (struct zebra_vrf *zvrf)
  354: {
  355:   if (zvrf->vrf_id != VRF_DEFAULT)
  356:     {
  357:       zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
  358:       return;
  359:     }
  360:   interface_list_ioctl (AF_INET);
  361:   interface_list_ioctl (AF_INET6);
  362:   interface_list_ioctl (AF_UNSPEC);
  363: }
  364: 
  365: struct connected *
  366: if_lookup_linklocal (struct interface *ifp)
  367: {
  368: #ifdef HAVE_IPV6
  369:   struct listnode *node;
  370:   struct connected *ifc;
  371: 
  372:   if (ifp == NULL)
  373:     return NULL;
  374: 
  375:   for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
  376:     {
  377:       if ((ifc->address->family == AF_INET6) &&
  378:           (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
  379:         return ifc;
  380:     }
  381: #endif /* HAVE_IPV6 */
  382: 
  383:   return NULL;
  384: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>