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

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

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