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

1.1       misho       1: /*
                      2:  * Interface looking up by ioctl ().
                      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"
1.1.1.2 ! misho      32: #include "vrf.h"
1.1       misho      33: 
                     34: #include "zebra/interface.h"
1.1.1.2 ! misho      35: #include "zebra/rib.h"
1.1       misho      36: 
                     37: /* Interface looking up using infamous SIOCGIFCONF. */
                     38: static int
                     39: interface_list_ioctl (void)
                     40: {
                     41:   int ret;
                     42:   int sock;
                     43: #define IFNUM_BASE 32
                     44:   int ifnum;
                     45:   struct ifreq *ifreq;
                     46:   struct ifconf ifconf;
                     47:   struct interface *ifp;
                     48:   int n;
                     49:   int lastlen;
                     50: 
                     51:   /* Normally SIOCGIFCONF works with AF_INET socket. */
                     52:   sock = socket (AF_INET, SOCK_DGRAM, 0);
                     53:   if (sock < 0) 
                     54:     {
                     55:       zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
                     56:       return -1;
                     57:     }
                     58: 
                     59:   /* Set initial ifreq count.  This will be double when SIOCGIFCONF
                     60:      fail.  Solaris has SIOCGIFNUM. */
                     61: #ifdef SIOCGIFNUM
                     62:   ret = ioctl (sock, SIOCGIFNUM, &ifnum);
                     63:   if (ret < 0)
                     64:     ifnum = IFNUM_BASE;
                     65:   else
                     66:     ifnum++;
                     67: #else
                     68:   ifnum = IFNUM_BASE;
                     69: #endif /* SIOCGIFNUM */
                     70: 
                     71:   ifconf.ifc_buf = NULL;
                     72: 
                     73:   lastlen = 0;
                     74:   /* Loop until SIOCGIFCONF success. */
                     75:   for (;;) 
                     76:     {
                     77:       ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
                     78:       ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
                     79: 
                     80:       ret = ioctl(sock, SIOCGIFCONF, &ifconf);
                     81: 
                     82:       if (ret < 0) 
                     83:        {
                     84:          zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
                     85:          goto end;
                     86:        }
                     87:       /* Repeatedly get info til buffer fails to grow. */
                     88:       if (ifconf.ifc_len > lastlen)
                     89:        {
                     90:           lastlen = ifconf.ifc_len;
                     91:          ifnum += 10;
                     92:          continue;
                     93:        }
                     94:       /* Success. */
                     95:       break;
                     96:     }
                     97: 
                     98:   /* Allocate interface. */
                     99:   ifreq = ifconf.ifc_req;
                    100: 
                    101: #ifdef OPEN_BSD
                    102:   for (n = 0; n < ifconf.ifc_len; )
                    103:     {
                    104:       int size;
                    105: 
                    106:       ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
                    107:       ifp = if_get_by_name_len(ifreq->ifr_name,
                    108:                               strnlen(ifreq->ifr_name,
                    109:                                       sizeof(ifreq->ifr_name)));
                    110:       if_add_update (ifp);
                    111:       size = ifreq->ifr_addr.sa_len;
                    112:       if (size < sizeof (ifreq->ifr_addr))
                    113:        size = sizeof (ifreq->ifr_addr);
                    114:       size += sizeof (ifreq->ifr_name);
                    115:       n += size;
                    116:     }
                    117: #else
                    118:   for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
                    119:     {
                    120:       ifp = if_get_by_name_len(ifreq->ifr_name,
                    121:                               strnlen(ifreq->ifr_name,
                    122:                                       sizeof(ifreq->ifr_name)));
                    123:       if_add_update (ifp);
                    124:       ifreq++;
                    125:     }
                    126: #endif /* OPEN_BSD */
                    127: 
                    128:  end:
                    129:   close (sock);
                    130:   XFREE (MTYPE_TMP, ifconf.ifc_buf);
                    131: 
                    132:   return ret;
                    133: }
                    134: 
                    135: /* Get interface's index by ioctl. */
                    136: static int
                    137: if_get_index (struct interface *ifp)
                    138: {
                    139: #if defined(HAVE_IF_NAMETOINDEX)
                    140:   /* Modern systems should have if_nametoindex(3). */
                    141:   ifp->ifindex = if_nametoindex(ifp->name);
                    142: #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
                    143:   /* Fall-back for older linuxes. */
                    144:   int ret;
                    145:   struct ifreq ifreq;
                    146:   static int if_fake_index;
                    147: 
                    148:   ifreq_set_name (&ifreq, ifp);
                    149: 
                    150:   ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
                    151:   if (ret < 0)
                    152:     {
                    153:       /* Linux 2.0.X does not have interface index. */
                    154:       ifp->ifindex = if_fake_index++;
                    155:       return ifp->ifindex;
                    156:     }
                    157: 
                    158:   /* OK we got interface index. */
                    159: #ifdef ifr_ifindex
                    160:   ifp->ifindex = ifreq.ifr_ifindex;
                    161: #else
                    162:   ifp->ifindex = ifreq.ifr_index;
                    163: #endif
                    164: 
                    165: #else
                    166: /* Linux 2.2.X does not provide individual interface index 
                    167:    for aliases and we know it. For others issue a warning. */
                    168: #if !defined(HAVE_BROKEN_ALIASES)
                    169: #warning "Using if_fake_index. You may want to add appropriate"
                    170: #warning "mapping from ifname to ifindex for your system..."
                    171: #endif
                    172:   /* This branch probably won't provide usable results, but anyway... */
                    173:   static int if_fake_index = 1;
                    174:   ifp->ifindex = if_fake_index++;
                    175: #endif
                    176: 
                    177:   return ifp->ifindex;
                    178: }
                    179: 
                    180: #ifdef SIOCGIFHWADDR
                    181: static int
                    182: if_get_hwaddr (struct interface *ifp)
                    183: {
                    184:   int ret;
                    185:   struct ifreq ifreq;
                    186:   int i;
                    187: 
                    188:   strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
                    189:   ifreq.ifr_addr.sa_family = AF_INET;
                    190: 
                    191:   /* Fetch Hardware address if available. */
                    192:   ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
                    193:   if (ret < 0)
                    194:     ifp->hw_addr_len = 0;
                    195:   else
                    196:     {
                    197:       memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
                    198: 
                    199:       for (i = 0; i < 6; i++)
                    200:        if (ifp->hw_addr[i] != 0)
                    201:          break;
                    202: 
                    203:       if (i == 6)
                    204:        ifp->hw_addr_len = 0;
                    205:       else
                    206:        ifp->hw_addr_len = 6;
                    207:     }
                    208:   return 0;
                    209: }
                    210: #endif /* SIOCGIFHWADDR */
                    211: 
                    212: #ifdef HAVE_GETIFADDRS
                    213: #include <ifaddrs.h>
                    214: 
                    215: static int
                    216: if_getaddrs (void)
                    217: {
                    218:   int ret;
                    219:   struct ifaddrs *ifap;
                    220:   struct ifaddrs *ifapfree;
                    221:   struct interface *ifp;
                    222:   int prefixlen;
                    223: 
                    224:   ret = getifaddrs (&ifap); 
                    225:   if (ret != 0)
                    226:     {
                    227:       zlog_err ("getifaddrs(): %s", safe_strerror (errno));
                    228:       return -1;
                    229:     }
                    230: 
                    231:   for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
                    232:     {
                    233:       if (ifap->ifa_addr == NULL)
                    234:         {
                    235:           zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
                    236:                     __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
                    237:           continue;
                    238:         }
                    239:        
                    240:       ifp = if_lookup_by_name (ifap->ifa_name);
                    241:       if (ifp == NULL)
                    242:        {
                    243:          zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
                    244:                    ifap->ifa_name);
                    245:          continue;
                    246:        }
                    247: 
                    248:       if (ifap->ifa_addr->sa_family == AF_INET)
                    249:        {
                    250:          struct sockaddr_in *addr;
                    251:          struct sockaddr_in *mask;
                    252:          struct sockaddr_in *dest;
                    253:          struct in_addr *dest_pnt;
                    254:          int flags = 0;
                    255: 
                    256:          addr = (struct sockaddr_in *) ifap->ifa_addr;
                    257:          mask = (struct sockaddr_in *) ifap->ifa_netmask;
                    258:          prefixlen = ip_masklen (mask->sin_addr);
                    259: 
                    260:          dest_pnt = NULL;
                    261: 
                    262:          if (ifap->ifa_dstaddr &&
                    263:              !IPV4_ADDR_SAME(&addr->sin_addr,
                    264:                              &((struct sockaddr_in *)
                    265:                                ifap->ifa_dstaddr)->sin_addr))
                    266:            {
                    267:              dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
                    268:              dest_pnt = &dest->sin_addr;
                    269:              flags = ZEBRA_IFA_PEER;
                    270:            }
                    271:          else if (ifap->ifa_broadaddr &&
                    272:                   !IPV4_ADDR_SAME(&addr->sin_addr,
                    273:                                   &((struct sockaddr_in *)
                    274:                                     ifap->ifa_broadaddr)->sin_addr))
                    275:            {
                    276:              dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
                    277:              dest_pnt = &dest->sin_addr;
                    278:            }
                    279: 
                    280:          connected_add_ipv4 (ifp, flags, &addr->sin_addr,
                    281:                              prefixlen, dest_pnt, NULL);
                    282:        }
                    283: #ifdef HAVE_IPV6
                    284:       if (ifap->ifa_addr->sa_family == AF_INET6)
                    285:        {
                    286:          struct sockaddr_in6 *addr;
                    287:          struct sockaddr_in6 *mask;
                    288:          struct sockaddr_in6 *dest;
                    289:          struct in6_addr *dest_pnt;
                    290:          int flags = 0;
                    291: 
                    292:          addr = (struct sockaddr_in6 *) ifap->ifa_addr;
                    293:          mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
                    294:          prefixlen = ip6_masklen (mask->sin6_addr);
                    295: 
                    296:          dest_pnt = NULL;
                    297: 
                    298:          if (ifap->ifa_dstaddr &&
                    299:              !IPV6_ADDR_SAME(&addr->sin6_addr,
                    300:                              &((struct sockaddr_in6 *)
                    301:                                ifap->ifa_dstaddr)->sin6_addr))
                    302:            {
                    303:              dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
                    304:              dest_pnt = &dest->sin6_addr;
                    305:              flags = ZEBRA_IFA_PEER;
                    306:            }
                    307:          else if (ifap->ifa_broadaddr &&
                    308:                   !IPV6_ADDR_SAME(&addr->sin6_addr,
                    309:                                   &((struct sockaddr_in6 *)
                    310:                                     ifap->ifa_broadaddr)->sin6_addr))
                    311:            {
                    312:              dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
                    313:              dest_pnt = &dest->sin6_addr;
                    314:            }
                    315: 
                    316: #if defined(KAME)
                    317:          if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) 
                    318:            {
                    319:              addr->sin6_scope_id =
                    320:                        ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
                    321:              addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
                    322:            }   
                    323: #endif          
                    324: 
                    325:          connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, 
                    326:                              dest_pnt, NULL);
                    327:        }
                    328: #endif /* HAVE_IPV6 */
                    329:     }
                    330: 
                    331:   freeifaddrs (ifapfree);
                    332: 
                    333:   return 0; 
                    334: }
                    335: #else /* HAVE_GETIFADDRS */
                    336: /* Interface address lookup by ioctl.  This function only looks up
                    337:    IPv4 address. */
                    338: int
                    339: if_get_addr (struct interface *ifp)
                    340: {
                    341:   int ret;
                    342:   struct ifreq ifreq;
                    343:   struct sockaddr_in addr;
                    344:   struct sockaddr_in mask;
                    345:   struct sockaddr_in dest;
                    346:   struct in_addr *dest_pnt;
                    347:   u_char prefixlen;
                    348:   int flags = 0;
                    349: 
                    350:   /* Interface's name and address family. */
                    351:   strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
                    352:   ifreq.ifr_addr.sa_family = AF_INET;
                    353: 
                    354:   /* Interface's address. */
                    355:   ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
                    356:   if (ret < 0) 
                    357:     {
                    358:       if (errno != EADDRNOTAVAIL)
                    359:        {
                    360:          zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
                    361:          return ret;
                    362:        }
                    363:       return 0;
                    364:     }
                    365:   memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
                    366: 
                    367:   /* Interface's network mask. */
                    368:   ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
                    369:   if (ret < 0) 
                    370:     {
                    371:       if (errno != EADDRNOTAVAIL) 
                    372:        {
                    373:          zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
                    374:          return ret;
                    375:        }
                    376:       return 0;
                    377:     }
                    378: #ifdef ifr_netmask
                    379:   memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
                    380: #else
                    381:   memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
                    382: #endif /* ifr_netmask */
                    383:   prefixlen = ip_masklen (mask.sin_addr);
                    384: 
                    385:   /* Point to point or borad cast address pointer init. */
                    386:   dest_pnt = NULL;
                    387: 
                    388:   ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
                    389:   if (ret < 0) 
                    390:     {
                    391:       if (errno != EADDRNOTAVAIL) 
                    392:        zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
                    393:     }
                    394:   else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
                    395:     {
                    396:       memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
                    397:       dest_pnt = &dest.sin_addr;
                    398:       flags = ZEBRA_IFA_PEER;
                    399:     }
                    400:   if (!dest_pnt)
                    401:     {
                    402:       ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
                    403:       if (ret < 0) 
                    404:        {
                    405:          if (errno != EADDRNOTAVAIL) 
                    406:            zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
                    407:        }
                    408:       else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
                    409:         {
                    410:          memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
                    411:          dest_pnt = &dest.sin_addr;
                    412:         }
                    413:     }
                    414: 
                    415: 
                    416:   /* Set address to the interface. */
                    417:   connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
                    418: 
                    419:   return 0;
                    420: }
                    421: #endif /* HAVE_GETIFADDRS */
                    422: 
                    423: /* Fetch interface information via ioctl(). */
                    424: static void
                    425: interface_info_ioctl ()
                    426: {
                    427:   struct listnode *node, *nnode;
                    428:   struct interface *ifp;
                    429:   
                    430:   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
                    431:     {
                    432:       if_get_index (ifp);
                    433: #ifdef SIOCGIFHWADDR
                    434:       if_get_hwaddr (ifp);
                    435: #endif /* SIOCGIFHWADDR */
                    436:       if_get_flags (ifp);
                    437: #ifndef HAVE_GETIFADDRS
                    438:       if_get_addr (ifp);
                    439: #endif /* ! HAVE_GETIFADDRS */
                    440:       if_get_mtu (ifp);
                    441:       if_get_metric (ifp);
                    442:     }
                    443: }
                    444: 
                    445: /* Lookup all interface information. */
                    446: void
1.1.1.2 ! misho     447: interface_list (struct zebra_vrf *zvrf)
1.1       misho     448: {
1.1.1.2 ! misho     449:   if (zvrf->vrf_id != VRF_DEFAULT)
        !           450:     {
        !           451:       zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
        !           452:       return;
        !           453:     }
1.1       misho     454:   /* Linux can do both proc & ioctl, ioctl is the only way to get
                    455:      interface aliases in 2.2 series kernels. */
                    456: #ifdef HAVE_PROC_NET_DEV
                    457:   interface_list_proc ();
                    458: #endif /* HAVE_PROC_NET_DEV */
                    459:   interface_list_ioctl ();
                    460: 
                    461:   /* After listing is done, get index, address, flags and other
                    462:      interface's information. */
                    463:   interface_info_ioctl ();
                    464: 
                    465: #ifdef HAVE_GETIFADDRS
                    466:   if_getaddrs ();
                    467: #endif /* HAVE_GETIFADDRS */
                    468: 
                    469: #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
                    470:   /* Linux provides interface's IPv6 address via
                    471:      /proc/net/if_inet6. */
                    472:   ifaddr_proc_ipv6 ();
                    473: #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
                    474: }

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