File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / ioctl_solaris.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    1: /*
    2:  * Common ioctl functions for 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 "linklist.h"
   26: #include "if.h"
   27: #include "prefix.h"
   28: #include "ioctl.h"
   29: #include "log.h"
   30: #include "privs.h"
   31: 
   32: #include "zebra/rib.h"
   33: #include "zebra/rt.h"
   34: #include "zebra/interface.h"
   35: 
   36: extern struct zebra_privs_t zserv_privs;
   37: 
   38: /* clear and set interface name string */
   39: void
   40: lifreq_set_name (struct lifreq *lifreq, const char *ifname)
   41: {
   42:   strncpy (lifreq->lifr_name, ifname, IFNAMSIZ);
   43: }
   44: 
   45: /* call ioctl system call */
   46: int
   47: if_ioctl (u_long request, caddr_t buffer)
   48: {
   49:   int sock;
   50:   int ret;
   51:   int err;
   52: 
   53:   if (zserv_privs.change(ZPRIVS_RAISE))
   54:     zlog (NULL, LOG_ERR, "Can't raise privileges");
   55:     
   56:   sock = socket (AF_INET, SOCK_DGRAM, 0);
   57:   if (sock < 0)
   58:     {
   59:       int save_errno = errno;
   60:       if (zserv_privs.change(ZPRIVS_LOWER))
   61:         zlog (NULL, LOG_ERR, "Can't lower privileges");
   62:       zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno));
   63:       exit (1);
   64:     }
   65: 
   66:   if ((ret = ioctl (sock, request, buffer)) < 0)
   67:     err = errno;
   68:   
   69:   if (zserv_privs.change(ZPRIVS_LOWER))
   70:     zlog (NULL, LOG_ERR, "Can't lower privileges");
   71: 
   72:   close (sock);
   73: 
   74:   if (ret < 0)
   75:     {
   76:       errno = err;
   77:       return ret;
   78:     }
   79:   return 0;
   80: }
   81: 
   82: 
   83: int
   84: if_ioctl_ipv6 (u_long request, caddr_t buffer)
   85: {
   86: #ifdef HAVE_IPV6
   87:   int sock;
   88:   int ret;
   89:   int err;
   90: 
   91:   if (zserv_privs.change(ZPRIVS_RAISE))
   92:     zlog (NULL, LOG_ERR, "Can't raise privileges");
   93: 
   94:   sock = socket (AF_INET6, SOCK_DGRAM, 0);
   95:   if (sock < 0)
   96:     {
   97:       int save_errno = errno;
   98:       if (zserv_privs.change(ZPRIVS_LOWER))
   99:         zlog (NULL, LOG_ERR, "Can't lower privileges");
  100:       zlog_err("Cannot create IPv6 datagram socket: %s",
  101: 	       safe_strerror(save_errno));
  102:       exit (1);
  103:     }
  104: 
  105:   if ((ret = ioctl (sock, request, buffer)) < 0)
  106:     err = errno;
  107: 
  108:   if (zserv_privs.change(ZPRIVS_LOWER))
  109:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  110: 
  111:   close (sock);
  112: 
  113:   if (ret < 0)
  114:     {
  115:       errno = err;
  116:       return ret;
  117:     }
  118: #endif /* HAVE_IPV6 */
  119: 
  120:   return 0;
  121: }
  122: 
  123: /*
  124:  * get interface metric
  125:  *   -- if value is not avaliable set -1
  126:  */
  127: void
  128: if_get_metric (struct interface *ifp)
  129: {
  130:   struct lifreq lifreq;
  131:   int ret;
  132: 
  133:   lifreq_set_name (&lifreq, ifp->name);
  134: 
  135:   if (ifp->flags & IFF_IPV4)
  136:     ret = AF_IOCTL (AF_INET, SIOCGLIFMETRIC, (caddr_t) & lifreq);
  137: #ifdef SOLARIS_IPV6
  138:   else if (ifp->flags & IFF_IPV6)
  139:     ret = AF_IOCTL (AF_INET6, SIOCGLIFMETRIC, (caddr_t) & lifreq);
  140: #endif /* SOLARIS_IPV6 */
  141:   else
  142:     ret = -1;
  143:     
  144:   if (ret < 0)
  145:     return;
  146: 
  147:   ifp->metric = lifreq.lifr_metric;
  148: 
  149:   if (ifp->metric == 0)
  150:     ifp->metric = 1;
  151: }
  152: 
  153: /* get interface MTU */
  154: void
  155: if_get_mtu (struct interface *ifp)
  156: {
  157:   struct lifreq lifreq;
  158:   int ret;
  159:   u_char changed = 0;
  160:   
  161:   if (ifp->flags & IFF_IPV4)
  162:     {
  163:       lifreq_set_name (&lifreq, ifp->name);
  164:       ret = AF_IOCTL (AF_INET, SIOCGLIFMTU, (caddr_t) & lifreq);
  165:       if (ret < 0)
  166:         {
  167:           zlog_info ("Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
  168:                      ifp->name);
  169:           ifp->mtu = -1;
  170:         }
  171:       else
  172:         {
  173:           ifp->mtu = lifreq.lifr_metric;
  174:           changed = 1;
  175:         }
  176:     }
  177: 
  178: #ifdef HAVE_IPV6
  179:   if (ifp->flags & IFF_IPV6)
  180:   {
  181:     memset(&lifreq, 0, sizeof(lifreq));
  182:     lifreq_set_name (&lifreq, ifp->name);
  183: 
  184:     ret = AF_IOCTL (AF_INET6, SIOCGLIFMTU, (caddr_t) & lifreq);
  185:     if (ret < 0)
  186:     {
  187:       zlog_info ("Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)", ifp->name);
  188:       ifp->mtu6 = -1;
  189:     }
  190:     else
  191:     {
  192:       ifp->mtu6 = lifreq.lifr_metric;
  193:       changed = 1;
  194:     }
  195:   }
  196: #endif /* HAVE_IPV6 */
  197: 
  198:   if (changed)
  199:     zebra_interface_up_update(ifp);
  200: }
  201: 
  202: /* Set up interface's address, netmask (and broadcast? ).
  203:    Solaris uses ifname:number semantics to set IP address aliases. */
  204: int
  205: if_set_prefix (struct interface *ifp, struct connected *ifc)
  206: {
  207:   int ret;
  208:   struct ifreq ifreq;
  209:   struct sockaddr_in addr;
  210:   struct sockaddr_in broad;
  211:   struct sockaddr_in mask;
  212:   struct prefix_ipv4 ifaddr;
  213:   struct prefix_ipv4 *p;
  214: 
  215:   p = (struct prefix_ipv4 *) ifc->address;
  216: 
  217:   ifaddr = *p;
  218: 
  219:   strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  220: 
  221:   addr.sin_addr = p->prefix;
  222:   addr.sin_family = p->family;
  223:   memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
  224: 
  225:   ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq);
  226: 
  227:   if (ret < 0)
  228:     return ret;
  229: 
  230:   /* We need mask for make broadcast addr. */
  231:   masklen2ip (p->prefixlen, &mask.sin_addr);
  232: 
  233:   if (if_is_broadcast (ifp))
  234:     {
  235:       apply_mask_ipv4 (&ifaddr);
  236:       addr.sin_addr = ifaddr.prefix;
  237: 
  238:       broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
  239:       broad.sin_family = p->family;
  240: 
  241:       memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
  242:       ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) & ifreq);
  243:       if (ret < 0)
  244:         return ret;
  245:     }
  246: 
  247:   mask.sin_family = p->family;
  248: #ifdef SUNOS_5
  249:   memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
  250: #else
  251:   memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
  252: #endif /* SUNOS_5 */
  253:   ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) & ifreq);
  254: 
  255:   return ((ret < 0) ? ret : 0);
  256: }
  257: 
  258: /* Set up interface's address, netmask (and broadcast).
  259:    Solaris uses ifname:number semantics to set IP address aliases. */
  260: int
  261: if_unset_prefix (struct interface *ifp, struct connected *ifc)
  262: {
  263:   int ret;
  264:   struct ifreq ifreq;
  265:   struct sockaddr_in addr;
  266:   struct prefix_ipv4 *p;
  267: 
  268:   p = (struct prefix_ipv4 *) ifc->address;
  269: 
  270:   strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  271: 
  272:   memset (&addr, 0, sizeof (struct sockaddr_in));
  273:   addr.sin_family = p->family;
  274:   memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
  275: 
  276:   ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq);
  277:   
  278:   if (ret < 0)
  279:     return ret;
  280: 
  281:   return 0;
  282: }
  283: 
  284: /* Get just the flags for the given name.
  285:  * Used by the normal 'if_get_flags' function, as well
  286:  * as the bootup interface-list code, which has to peek at per-address
  287:  * flags in order to figure out which ones should be ignored..
  288:  */
  289: int
  290: if_get_flags_direct (const char *ifname, uint64_t *flags, unsigned int af)
  291: {
  292:   struct lifreq lifreq;
  293:   int ret;
  294:     
  295:   lifreq_set_name (&lifreq, ifname);
  296:   
  297:   ret = AF_IOCTL (af, SIOCGLIFFLAGS, (caddr_t) &lifreq);
  298:   
  299:   if (ret)
  300:     zlog_debug ("%s: ifname %s, error %s (%d)",
  301:                 __func__, ifname, safe_strerror (errno), errno);
  302:   
  303:   *flags = lifreq.lifr_flags;
  304:   
  305:   return ret;
  306: }
  307: 
  308: /* get interface flags */
  309: void
  310: if_get_flags (struct interface *ifp)
  311: {
  312:   int ret4, ret6;
  313:   uint64_t newflags = 0;
  314:   uint64_t tmpflags;
  315: 
  316:   if (ifp->flags & IFF_IPV4)
  317:     {
  318:       ret4 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET);
  319:       
  320:       if (!ret4)
  321:         newflags |= tmpflags;
  322:       else if (errno == ENXIO)
  323:         {
  324:           /* it's gone */
  325:           UNSET_FLAG (ifp->flags, IFF_UP);
  326:           if_flags_update (ifp, ifp->flags);
  327:         }
  328:     }
  329: 
  330:   if (ifp->flags & IFF_IPV6)
  331:     {
  332:       ret6 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET6);
  333:       
  334:       if (!ret6)
  335:         newflags |= tmpflags;
  336:       else if (errno == ENXIO)
  337:         {
  338:           /* it's gone */
  339:           UNSET_FLAG (ifp->flags, IFF_UP);
  340:           if_flags_update (ifp, ifp->flags);
  341:         }
  342:     }
  343:   
  344:   /* only update flags if one of above succeeded */
  345:   if ( !(ret4 && ret6) )
  346:     if_flags_update (ifp, newflags);
  347: }
  348: 
  349: /* Set interface flags */
  350: int
  351: if_set_flags (struct interface *ifp, uint64_t flags)
  352: {
  353:   int ret;
  354:   struct lifreq lifreq;
  355: 
  356:   lifreq_set_name (&lifreq, ifp->name);
  357: 
  358:   lifreq.lifr_flags = ifp->flags;
  359:   lifreq.lifr_flags |= flags;
  360: 
  361:   if (ifp->flags & IFF_IPV4)
  362:     ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq);
  363:   else if (ifp->flags & IFF_IPV6)
  364:     ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq);
  365:   else
  366:     ret = -1;
  367: 
  368:   if (ret < 0)
  369:     zlog_info ("can't set interface flags on %s: %s", ifp->name,
  370:                safe_strerror (errno));
  371:   else
  372:     ret = 0;
  373:     
  374:   return ret;
  375: }
  376: 
  377: /* Unset interface's flag. */
  378: int
  379: if_unset_flags (struct interface *ifp, uint64_t flags)
  380: {
  381:   int ret;
  382:   struct lifreq lifreq;
  383: 
  384:   lifreq_set_name (&lifreq, ifp->name);
  385: 
  386:   lifreq.lifr_flags = ifp->flags;
  387:   lifreq.lifr_flags &= ~flags;
  388: 
  389:   if (ifp->flags & IFF_IPV4)
  390:     ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq);
  391:   else if (ifp->flags & IFF_IPV6)
  392:     ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq);
  393:   else
  394:     ret = -1;
  395: 
  396:   if (ret < 0)
  397:     zlog_info ("can't unset interface flags");
  398:   else
  399:     ret = 0;
  400:   
  401:   return ret;
  402: }
  403: 
  404: #ifdef HAVE_IPV6
  405: 
  406: /* Interface's address add/delete functions. */
  407: int
  408: if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
  409: {
  410:   char addrbuf[INET_ADDRSTRLEN];
  411: 
  412:   inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix),
  413:              addrbuf, sizeof (addrbuf));
  414:   zlog_warn ("Can't set %s on interface %s", addrbuf, ifp->name);
  415: 
  416:   return 0;
  417: 
  418: }
  419: 
  420: int
  421: if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
  422: {
  423:   char addrbuf[INET_ADDRSTRLEN];
  424: 
  425:   inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix),
  426:              addrbuf, sizeof (addrbuf));
  427:   zlog_warn ("Can't delete %s on interface %s", addrbuf, ifp->name);
  428: 
  429:   return 0;
  430: 
  431: }
  432: 
  433: #endif /* HAVE_IPV6 */

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