LCOV - code coverage report
Current view: top level - zebra - irdp_main.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 9 125 7.2 %
Date: 2015-11-19 Functions: 1 9 11.1 %

          Line data    Source code
       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           0 : irdp_sock_init (void)
      81             : {
      82             :   int ret, i;
      83             :   int save_errno;
      84             :   int sock;
      85             : 
      86           0 :   if ( zserv_privs.change (ZPRIVS_RAISE) )
      87           0 :        zlog_err ("irdp_sock_init: could not raise privs, %s",
      88           0 :                   safe_strerror (errno) );
      89             : 
      90           0 :   sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
      91           0 :   save_errno = errno;
      92             : 
      93           0 :   if ( zserv_privs.change (ZPRIVS_LOWER) )
      94           0 :        zlog_err ("irdp_sock_init: could not lower privs, %s",
      95           0 :              safe_strerror (errno) );
      96             : 
      97           0 :   if (sock < 0) {
      98           0 :     zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
      99           0 :     return sock;
     100             :   };
     101             :   
     102           0 :   i = 1;
     103           0 :   ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 
     104             :                         (void *) &i, sizeof (i));
     105           0 :   if (ret < 0) {
     106           0 :     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
     107           0 :     close(sock);
     108           0 :     return ret;
     109             :   };
     110             :   
     111           0 :   ret = setsockopt_ifindex (AF_INET, sock, 1);
     112           0 :   if (ret < 0) {
     113           0 :     zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
     114           0 :     close(sock);
     115           0 :     return ret;
     116             :   };
     117             : 
     118           0 :   t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock); 
     119             : 
     120           0 :   return sock;
     121             : }
     122             : 
     123             : 
     124             : static int
     125           0 : 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           0 :   if( irdp->AdvPrefList == NULL )
     133           0 :     return irdp->Preference;
     134             :   
     135           0 :   for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
     136           0 :     if( p->u.prefix4.s_addr == adv->ip.s_addr )
     137           0 :       return adv->pref;
     138             : 
     139           0 :   return irdp->Preference;
     140             : }
     141             : 
     142             : /* Make ICMP Router Advertisement Message. */
     143             : static int
     144           0 : make_advertisement_packet (struct interface *ifp, 
     145             :                            struct prefix *p,
     146             :                            struct stream *s)
     147             : {
     148           0 :   struct zebra_if *zi=ifp->info;
     149           0 :   struct irdp_interface *irdp=&zi->irdp;
     150             :   int size;
     151             :   int pref;
     152             :   u_int16_t checksum;
     153             : 
     154           0 :   pref =  get_pref(irdp, p);
     155             : 
     156           0 :   stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
     157           0 :   stream_putc (s, 0);           /* Code. */
     158           0 :   stream_putw (s, 0);           /* Checksum. */
     159           0 :   stream_putc (s, 1);           /* Num address. */
     160           0 :   stream_putc (s, 2);           /* Address Entry Size. */
     161             : 
     162           0 :   if(irdp->flags & IF_SHUTDOWN)  
     163           0 :     stream_putw (s, 0);
     164             :   else 
     165           0 :     stream_putw (s, irdp->Lifetime);
     166             : 
     167           0 :   stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
     168           0 :   stream_putl (s, pref);
     169             : 
     170             :   /* in_cksum return network byte order value */
     171           0 :   size = 16;
     172           0 :   checksum = in_cksum (s->data, size);
     173           0 :   stream_putw_at (s, 2, htons(checksum));
     174             : 
     175           0 :   return size;
     176             : }
     177             : 
     178             : static void
     179           0 : irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
     180             : {
     181           0 :   struct zebra_if *zi=ifp->info;
     182           0 :   struct irdp_interface *irdp=&zi->irdp;
     183             :   u_int32_t dst;
     184           0 :   u_int32_t ttl=1;
     185             : 
     186           0 :   if (! (ifp->flags & IFF_UP)) return; 
     187             : 
     188           0 :   if (irdp->flags & IF_BROADCAST) 
     189           0 :     dst =INADDR_BROADCAST ;
     190             :   else 
     191           0 :     dst = htonl(INADDR_ALLHOSTS_GROUP);
     192             : 
     193           0 :   if(irdp->flags & IF_DEBUG_MESSAGES) 
     194           0 :     zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", 
     195           0 :               ifp->name,
     196             :               inet_ntoa(p->u.prefix4), 
     197           0 :               p->prefixlen,
     198           0 :               irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
     199             :               get_pref(irdp, p));
     200             : 
     201           0 :   send_packet (ifp, s, dst, p, ttl);
     202             : }
     203             : 
     204           0 : static void irdp_advertisement (struct interface *ifp, struct prefix *p)
     205             : {
     206             :   struct stream *s;
     207           0 :   s = stream_new (128);
     208           0 :   make_advertisement_packet (ifp, p, s);
     209           0 :   irdp_send(ifp, p, s);
     210           0 :   stream_free (s);
     211           0 : }
     212             : 
     213           0 : int irdp_send_thread(struct thread *t_advert)
     214             : {
     215             :   u_int32_t timer, tmp;
     216           0 :   struct interface *ifp = THREAD_ARG (t_advert);
     217           0 :   struct zebra_if *zi=ifp->info;
     218           0 :   struct irdp_interface *irdp=&zi->irdp;
     219             :   struct prefix *p;
     220             :   struct listnode *node, *nnode;
     221             :   struct connected *ifc;
     222             : 
     223           0 :   irdp->flags &= ~IF_SOLICIT;
     224             : 
     225           0 :   if(ifp->connected) 
     226           0 :     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
     227             :       {
     228           0 :         p = ifc->address;
     229             :         
     230           0 :         if (p->family != AF_INET)
     231           0 :           continue;
     232             :         
     233           0 :         irdp_advertisement(ifp, p);
     234           0 :         irdp->irdp_sent++;
     235             :       }
     236             : 
     237           0 :   tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
     238           0 :   timer =  (random () % tmp ) + 1;
     239           0 :   timer = irdp->MinAdvertInterval + timer;
     240             : 
     241           0 :   if(irdp->irdp_sent <  MAX_INITIAL_ADVERTISEMENTS &&
     242             :      timer > MAX_INITIAL_ADVERT_INTERVAL ) 
     243           0 :           timer= MAX_INITIAL_ADVERT_INTERVAL;
     244             : 
     245           0 :   if(irdp->flags & IF_DEBUG_MISC)
     246           0 :     zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
     247             : 
     248           0 :   irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
     249           0 :   return 0;
     250             : }
     251             : 
     252           0 : void irdp_advert_off(struct interface *ifp)
     253             : {
     254           0 :   struct zebra_if *zi=ifp->info;
     255           0 :   struct irdp_interface *irdp=&zi->irdp;
     256             :   struct listnode *node, *nnode;
     257             :   int i;
     258             :   struct connected *ifc;
     259             :   struct prefix *p;
     260             : 
     261           0 :   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
     262           0 :   irdp->t_advertise = NULL;
     263             :   
     264           0 :   if(ifp->connected) 
     265           0 :     for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
     266             :       {
     267           0 :         p = ifc->address;
     268             : 
     269             :         /* Output some packets with Lifetime 0 
     270             :            we should add a wait...
     271             :         */
     272             : 
     273           0 :         for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) 
     274             :           {
     275           0 :             irdp->irdp_sent++;
     276           0 :             irdp_advertisement(ifp, p);
     277             :           }
     278             :       }
     279           0 : }
     280             : 
     281             : 
     282           0 : void process_solicit (struct interface *ifp)
     283             : {
     284           0 :   struct zebra_if *zi=ifp->info;
     285           0 :   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           0 :   if( irdp->flags & IF_SOLICIT) return;
     293             : 
     294           0 :   irdp->flags |= IF_SOLICIT;
     295           0 :   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
     296           0 :   irdp->t_advertise = NULL;
     297             : 
     298           0 :   timer =  (random () % MAX_RESPONSE_DELAY) + 1;
     299             : 
     300           0 :   irdp->t_advertise = thread_add_timer(zebrad.master, 
     301             :                                        irdp_send_thread, 
     302             :                                        ifp, 
     303             :                                        timer);
     304             : }
     305             : 
     306          45 : 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          45 :   zlog_info("IRDP: Received shutdown notification.");
     315             :   
     316         179 :   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
     317             :     {
     318         134 :       zi = ifp->info;
     319             :       
     320         134 :       if (!zi) 
     321           0 :         continue;
     322         134 :       irdp = &zi->irdp;
     323         134 :       if (!irdp) 
     324           0 :         continue;
     325             : 
     326         134 :       if (irdp->flags & IF_ACTIVE ) 
     327             :         {
     328           0 :           irdp->flags |= IF_SHUTDOWN;
     329           0 :           irdp_advert_off(ifp);
     330             :         }
     331             :     }
     332          45 : }
     333             : 
     334             : #endif /* HAVE_IRDP */

Generated by: LCOV version 1.10