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

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"
                     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>