File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / irdp_main.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:  *
    3:  * Copyright (C) 2000  Robert Olsson.
    4:  * Swedish University of Agricultural Sciences
    5:  *
    6:  * This file is part of GNU Zebra.
    7:  *
    8:  * GNU Zebra is free software; you can redistribute it and/or modify it
    9:  * under the terms of the GNU General Public License as published by the
   10:  * Free Software Foundation; either version 2, or (at your option) any
   11:  * later version.
   12:  *
   13:  * GNU Zebra is distributed in the hope that it will be useful, but
   14:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16:  * General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License
   19:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
   20:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   21:  * 02111-1307, USA.  
   22:  */
   23: 
   24: /* 
   25:  * This work includes work with the following copywrite:
   26:  *
   27:  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
   28:  *
   29:  */
   30: 
   31: /* 
   32:  * Thanks to Jens Låås at Swedish University of Agricultural Sciences
   33:  * for reviewing and tests.
   34:  */
   35: 
   36: 
   37: #include <zebra.h>
   38: 
   39: #ifdef HAVE_IRDP
   40: 
   41: #include "if.h"
   42: #include "vty.h"
   43: #include "sockunion.h"
   44: #include "sockopt.h"
   45: #include "prefix.h"
   46: #include "command.h"
   47: #include "memory.h"
   48: #include "stream.h"
   49: #include "ioctl.h"
   50: #include "connected.h"
   51: #include "log.h"
   52: #include "zclient.h"
   53: #include "thread.h"
   54: #include "privs.h"
   55: #include "zebra/interface.h"
   56: #include "zebra/rtadv.h"
   57: #include "zebra/rib.h"
   58: #include "zebra/zserv.h"
   59: #include "zebra/redistribute.h"
   60: #include "zebra/irdp.h"
   61: #include <netinet/ip_icmp.h>
   62: 
   63: #include "checksum.h"
   64: #include "if.h"
   65: #include "sockunion.h"
   66: #include "log.h"
   67: 
   68: /* GLOBAL VARS */
   69: 
   70: extern struct zebra_privs_t zserv_privs;
   71: 
   72: /* Master of threads. */
   73: extern struct zebra_t zebrad;
   74: struct thread *t_irdp_raw;
   75: 
   76: /* Timer interval of irdp. */
   77: int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
   78: 
   79: int
   80: irdp_sock_init (void)
   81: {
   82:   int ret, i;
   83:   int save_errno;
   84:   int sock;
   85: 
   86:   if ( zserv_privs.change (ZPRIVS_RAISE) )
   87:        zlog_err ("irdp_sock_init: could not raise privs, %s",
   88:                   safe_strerror (errno) );
   89: 
   90:   sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
   91:   save_errno = errno;
   92: 
   93:   if ( zserv_privs.change (ZPRIVS_LOWER) )
   94:        zlog_err ("irdp_sock_init: could not lower privs, %s",
   95:              safe_strerror (errno) );
   96: 
   97:   if (sock < 0) {
   98:     zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
   99:     return sock;
  100:   };
  101:   
  102:   i = 1;
  103:   ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 
  104:                         (void *) &i, sizeof (i));
  105:   if (ret < 0) {
  106:     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
  107:     close(sock);
  108:     return ret;
  109:   };
  110:   
  111:   ret = setsockopt_ifindex (AF_INET, sock, 1);
  112:   if (ret < 0) {
  113:     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
  114:     close(sock);
  115:     return ret;
  116:   };
  117: 
  118:   t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock); 
  119: 
  120:   return sock;
  121: }
  122: 
  123: 
  124: static int
  125: get_pref(struct irdp_interface *irdp, struct prefix *p)
  126: {
  127:   struct listnode *node;
  128:   struct Adv *adv;
  129: 
  130:   /* Use default preference or use the override pref */
  131:   
  132:   if( irdp->AdvPrefList == NULL )
  133:     return irdp->Preference;
  134:   
  135:   for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
  136:     if( p->u.prefix4.s_addr == adv->ip.s_addr )
  137:       return adv->pref;
  138: 
  139:   return irdp->Preference;
  140: }
  141: 
  142: /* Make ICMP Router Advertisement Message. */
  143: static int
  144: make_advertisement_packet (struct interface *ifp, 
  145: 			   struct prefix *p,
  146: 			   struct stream *s)
  147: {
  148:   struct zebra_if *zi=ifp->info;
  149:   struct irdp_interface *irdp=&zi->irdp;
  150:   int size;
  151:   int pref;
  152:   u_int16_t checksum;
  153: 
  154:   pref =  get_pref(irdp, p);
  155: 
  156:   stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
  157:   stream_putc (s, 0);		/* Code. */
  158:   stream_putw (s, 0);		/* Checksum. */
  159:   stream_putc (s, 1);		/* Num address. */
  160:   stream_putc (s, 2);		/* Address Entry Size. */
  161: 
  162:   if(irdp->flags & IF_SHUTDOWN)  
  163:     stream_putw (s, 0);
  164:   else 
  165:     stream_putw (s, irdp->Lifetime);
  166: 
  167:   stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
  168:   stream_putl (s, pref);
  169: 
  170:   /* in_cksum return network byte order value */
  171:   size = 16;
  172:   checksum = in_cksum (s->data, size);
  173:   stream_putw_at (s, 2, htons(checksum));
  174: 
  175:   return size;
  176: }
  177: 
  178: static void
  179: irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
  180: {
  181:   struct zebra_if *zi=ifp->info;
  182:   struct irdp_interface *irdp=&zi->irdp;
  183:   u_int32_t dst;
  184:   u_int32_t ttl=1;
  185: 
  186:   if (! (ifp->flags & IFF_UP)) return; 
  187: 
  188:   if (irdp->flags & IF_BROADCAST) 
  189:     dst =INADDR_BROADCAST ;
  190:   else 
  191:     dst = htonl(INADDR_ALLHOSTS_GROUP);
  192: 
  193:   if(irdp->flags & IF_DEBUG_MESSAGES) 
  194:     zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", 
  195: 	      ifp->name,
  196: 	      inet_ntoa(p->u.prefix4), 
  197: 	      p->prefixlen,
  198: 	      irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
  199: 	      get_pref(irdp, p));
  200: 
  201:   send_packet (ifp, s, dst, p, ttl);
  202: }
  203: 
  204: static void irdp_advertisement (struct interface *ifp, struct prefix *p)
  205: {
  206:   struct stream *s;
  207:   s = stream_new (128);
  208:   make_advertisement_packet (ifp, p, s);
  209:   irdp_send(ifp, p, s);
  210:   stream_free (s);
  211: }
  212: 
  213: int irdp_send_thread(struct thread *t_advert)
  214: {
  215:   u_int32_t timer, tmp;
  216:   struct interface *ifp = THREAD_ARG (t_advert);
  217:   struct zebra_if *zi=ifp->info;
  218:   struct irdp_interface *irdp=&zi->irdp;
  219:   struct prefix *p;
  220:   struct listnode *node, *nnode;
  221:   struct connected *ifc;
  222: 
  223:   irdp->flags &= ~IF_SOLICIT;
  224: 
  225:   if(ifp->connected) 
  226:     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
  227:       {
  228:         p = ifc->address;
  229:         
  230:         if (p->family != AF_INET)
  231:           continue;
  232:         
  233:         irdp_advertisement(ifp, p);
  234:         irdp->irdp_sent++;
  235:       }
  236: 
  237:   tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
  238:   timer =  (random () % tmp ) + 1;
  239:   timer = irdp->MinAdvertInterval + timer;
  240: 
  241:   if(irdp->irdp_sent <  MAX_INITIAL_ADVERTISEMENTS &&
  242:      timer > MAX_INITIAL_ADVERT_INTERVAL ) 
  243: 	  timer= MAX_INITIAL_ADVERT_INTERVAL;
  244: 
  245:   if(irdp->flags & IF_DEBUG_MISC)
  246:     zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
  247: 
  248:   irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
  249:   return 0;
  250: }
  251: 
  252: void irdp_advert_off(struct interface *ifp)
  253: {
  254:   struct zebra_if *zi=ifp->info;
  255:   struct irdp_interface *irdp=&zi->irdp;
  256:   struct listnode *node, *nnode;
  257:   int i;
  258:   struct connected *ifc;
  259:   struct prefix *p;
  260: 
  261:   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
  262:   irdp->t_advertise = NULL;
  263:   
  264:   if(ifp->connected) 
  265:     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
  266:       {
  267:         p = ifc->address;
  268: 
  269:         /* Output some packets with Lifetime 0 
  270:            we should add a wait...
  271:         */
  272: 
  273:         for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) 
  274:           {
  275:             irdp->irdp_sent++;
  276:             irdp_advertisement(ifp, p);
  277:           }
  278:       }
  279: }
  280: 
  281: 
  282: void process_solicit (struct interface *ifp)
  283: {
  284:   struct zebra_if *zi=ifp->info;
  285:   struct irdp_interface *irdp=&zi->irdp;
  286:   u_int32_t timer;
  287: 
  288:   /* When SOLICIT is active we reject further incoming solicits 
  289:      this keeps down the answering rate so we don't have think
  290:      about DoS attacks here. */
  291: 
  292:   if( irdp->flags & IF_SOLICIT) return;
  293: 
  294:   irdp->flags |= IF_SOLICIT;
  295:   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
  296:   irdp->t_advertise = NULL;
  297: 
  298:   timer =  (random () % MAX_RESPONSE_DELAY) + 1;
  299: 
  300:   irdp->t_advertise = thread_add_timer(zebrad.master, 
  301: 				       irdp_send_thread, 
  302: 				       ifp, 
  303: 				       timer);
  304: }
  305: 
  306: void irdp_finish()
  307: {
  308: 
  309:   struct listnode *node, *nnode;
  310:   struct interface *ifp;
  311:   struct zebra_if *zi;
  312:   struct irdp_interface *irdp;
  313: 
  314:   zlog_info("IRDP: Received shutdown notification.");
  315:   
  316:   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
  317:     {
  318:       zi = ifp->info;
  319:       
  320:       if (!zi) 
  321:         continue;
  322:       irdp = &zi->irdp;
  323:       if (!irdp) 
  324:         continue;
  325: 
  326:       if (irdp->flags & IF_ACTIVE ) 
  327:         {
  328: 	  irdp->flags |= IF_SHUTDOWN;
  329: 	  irdp_advert_off(ifp);
  330:         }
  331:     }
  332: }
  333: 
  334: #endif /* HAVE_IRDP */

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