Annotation of embedaddon/quagga/zebra/if_ioctl_solaris.c, revision 1.1.1.2

1.1       misho       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"
1.1.1.2 ! misho      33: #include "vrf.h"
1.1       misho      34: 
                     35: #include "zebra/interface.h"
1.1.1.2 ! misho      36: #include "zebra/ioctl_solaris.h"
        !            37: #include "zebra/rib.h"
1.1       misho      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: 
1.1.1.2 ! misho      43: static int
1.1       misho      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. */
1.1.1.2 ! misho     212: static int
1.1       misho     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
1.1.1.2 ! misho     353: interface_list (struct zebra_vrf *zvrf)
1.1       misho     354: {
1.1.1.2 ! misho     355:   if (zvrf->vrf_id != VRF_DEFAULT)
        !           356:     {
        !           357:       zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
        !           358:       return;
        !           359:     }
1.1       misho     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>