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

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