Annotation of embedaddon/quagga/zebra/if_ioctl_solaris.c, revision 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>