irdp_main.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:8k
源码类别:

网络

开发平台:

Unix_Linux

  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.  * This work includes work with the following copywrite:
  25.  *
  26.  * Copyright (C) 1997, 2000 Kunihiro Ishiguro
  27.  *
  28.  */
  29. /* 
  30.  * Thanks to Jens L邋s at Swedish University of Agricultural Sciences
  31.  * for reviewing and tests.
  32.  */
  33. #include <zebra.h>
  34. #ifdef HAVE_IRDP
  35. #include "if.h"
  36. #include "vty.h"
  37. #include "sockunion.h"
  38. #include "prefix.h"
  39. #include "command.h"
  40. #include "memory.h"
  41. #include "stream.h"
  42. #include "ioctl.h"
  43. #include "connected.h"
  44. #include "log.h"
  45. #include "zclient.h"
  46. #include "thread.h"
  47. #include "zebra/interface.h"
  48. #include "zebra/rtadv.h"
  49. #include "zebra/rib.h"
  50. #include "zebra/zserv.h"
  51. #include "zebra/redistribute.h"
  52. #include "zebra/irdp.h"
  53. #include <netinet/ip_icmp.h>
  54. #include "if.h"
  55. #include "sockunion.h"
  56. #include "log.h"
  57. /* GLOBAL VARS */
  58. /* Master of threads. */
  59. extern struct thread_master *master;
  60. struct thread *t_irdp_raw;
  61. /* Timer interval of irdp. */
  62. int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
  63. int irdp_read_raw(struct thread *r);
  64. int in_cksum (void *ptr, int nbytes);
  65. extern int irdp_sock;
  66. void send_packet(struct interface *ifp, 
  67.  struct stream *s,
  68.  u_int32_t dst,
  69.  struct prefix *p,
  70.  u_int32_t ttl);
  71. void irdp_if_init ();
  72. char *
  73. inet_2a(u_int32_t a, char *b)
  74. {
  75.   sprintf(b, "%u.%u.%u.%u", 
  76.           (a    ) & 0xFF,
  77.           (a>> 8) & 0xFF, 
  78.           (a>>16) & 0xFF, 
  79.           (a>>24) & 0xFF);
  80.   return  b;
  81. }
  82. int
  83. irdp_sock_init (void)
  84. {
  85.   int ret, i;
  86.   irdp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
  87.   if (irdp_sock < 0) {
  88.     zlog_warn ("IRDP: can't create irdp socket %s", strerror(errno));
  89.     return irdp_sock;
  90.   };
  91.   
  92.   i = 1;
  93.   ret = setsockopt (irdp_sock, IPPROTO_IP, IP_TTL, 
  94.                         (void *) &i, sizeof (i));
  95.   if (ret < 0) {
  96.     zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
  97.     return ret;
  98.   };
  99.   
  100.   i = 1;
  101.   ret = setsockopt (irdp_sock, IPPROTO_IP, IP_PKTINFO, 
  102.                         (void *) &i, sizeof (i));
  103.   if (ret < 0) {
  104.     zlog_warn ("IRDP: can't do irdp sockopt %s", strerror(errno));
  105.     return ret;
  106.   };
  107.   t_irdp_raw = thread_add_read (master, irdp_read_raw, NULL, irdp_sock); 
  108.   return irdp_sock;
  109. }
  110. int get_pref(struct irdp_interface *irdp, struct prefix *p)
  111. {
  112.   listnode node;
  113.   struct Adv *adv;
  114.   /* Use default preference or use the override pref */
  115.   
  116.   if( irdp->AdvPrefList == NULL ) return irdp->Preference;
  117.   
  118.   for (node = listhead (irdp->AdvPrefList); node; nextnode (node)) {
  119.     adv = getdata (node);
  120.     if( p->u.prefix4.s_addr == adv->ip.s_addr )
  121.       return adv->pref;
  122.   }
  123.   return irdp->Preference;
  124. }
  125. /* Make ICMP Router Advertisement Message. */
  126. int make_advertisement_packet (struct interface *ifp, 
  127.        struct prefix *p,
  128.        struct stream *s)
  129. {
  130.   struct zebra_if *zi=ifp->info;
  131.   struct irdp_interface *irdp=&zi->irdp;
  132.   int size;
  133.   int pref;
  134.   u_int16_t checksum;
  135.   pref =  get_pref(irdp, p);
  136.   stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
  137.   stream_putc (s, 0); /* Code. */
  138.   stream_putw (s, 0); /* Checksum. */
  139.   stream_putc (s, 1); /* Num address. */
  140.   stream_putc (s, 2); /* Address Entry Size. */
  141.   if(irdp->flags & IF_SHUTDOWN)  
  142.     stream_putw (s, 0);
  143.   else 
  144.     stream_putw (s, irdp->Lifetime);
  145.   stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
  146.   stream_putl (s, pref);
  147.   /* in_cksum return network byte order value */
  148.   size = 16;
  149.   checksum = in_cksum (s->data, size);
  150.   stream_putw_at (s, 2, htons(checksum));
  151.   return size;
  152. }
  153. void irdp_send(struct interface *ifp, 
  154.        struct prefix *p, 
  155.        struct stream *s)
  156. {
  157.   struct zebra_if *zi=ifp->info;
  158.   struct irdp_interface *irdp=&zi->irdp;
  159.   u_int32_t dst;
  160.   u_int32_t ttl=1;
  161.   if (! (ifp->flags & IFF_UP)) return; 
  162.   if (irdp->flags & IF_BROADCAST) 
  163.     dst =INADDR_BROADCAST ;
  164.   else 
  165.     dst = htonl(INADDR_ALLHOSTS_GROUP);
  166.   if(irdp->flags & IF_DEBUG_MESSAGES) 
  167.     zlog_warn("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", 
  168.       ifp->name,
  169.       inet_ntoa(p->u.prefix4), 
  170.       p->prefixlen,
  171.       irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
  172.       get_pref(irdp, p));
  173.   send_packet (ifp, s, dst, p, ttl);
  174. }
  175. void irdp_advertisement (struct interface *ifp, 
  176.    struct prefix *p)
  177. {
  178.   struct stream *s;
  179.   s = stream_new (128);
  180.   make_advertisement_packet (ifp, p, s);
  181.   irdp_send(ifp, p, s); 
  182. }
  183. int irdp_send_thread(struct thread *t_advert)
  184. {
  185.   u_int32_t timer, tmp;
  186.   struct interface *ifp = THREAD_ARG (t_advert);
  187.   struct zebra_if *zi=ifp->info;
  188.   struct irdp_interface *irdp=&zi->irdp;
  189.   struct prefix *p;
  190.   listnode node;
  191.   struct connected *ifc;
  192.   irdp->flags &= ~IF_SOLICIT;
  193.   if(ifp->connected) 
  194.     for (node = listhead (ifp->connected); node; nextnode (node)) {
  195.       ifc = getdata (node);
  196.       p = ifc->address;
  197.       irdp_advertisement(ifp, p);
  198.       irdp->irdp_sent++;
  199.     }
  200.   tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
  201.   timer =  (random () % tmp ) + 1;
  202.   timer = irdp->MinAdvertInterval + timer;
  203.   if(irdp->irdp_sent <  MAX_INITIAL_ADVERTISEMENTS &&
  204.      timer > MAX_INITIAL_ADVERT_INTERVAL ) 
  205.   timer= MAX_INITIAL_ADVERT_INTERVAL;
  206.   if(irdp->flags & IF_DEBUG_MISC)
  207.     zlog_warn("IRDP: New timer for %s set to %un", ifp->name, timer);
  208.   irdp->t_advertise = thread_add_timer(master, irdp_send_thread, ifp, timer);
  209.   return 0;
  210. }
  211. void irdp_advert_off(struct interface *ifp)
  212. {
  213.   struct zebra_if *zi=ifp->info;
  214.   struct irdp_interface *irdp=&zi->irdp;
  215.   listnode node;
  216.   int i;
  217.   struct connected *ifc;
  218.   struct prefix *p;
  219.   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
  220.   irdp->t_advertise = NULL;
  221.   
  222.   if(ifp->connected) 
  223.     for (node = listhead (ifp->connected); node; nextnode (node)) {
  224.       ifc = getdata (node);
  225.       p = ifc->address;
  226.       /* Output some packets with Lifetime 0 
  227.  we should add a wait...
  228.       */
  229.       for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) {
  230. irdp->irdp_sent++;
  231. irdp_advertisement(ifp, p);
  232.       }
  233.     }
  234. }
  235. void process_solicit (struct interface *ifp)
  236. {
  237.   struct zebra_if *zi=ifp->info;
  238.   struct irdp_interface *irdp=&zi->irdp;
  239.   u_int32_t timer;
  240.   /* When SOLICIT is active we reject further incoming solicits 
  241.      this keeps down the answering rate so we don't have think
  242.      about DoS attacks here. */
  243.   if( irdp->flags & IF_SOLICIT) return;
  244.   irdp->flags |= IF_SOLICIT;
  245.   if(irdp->t_advertise)  thread_cancel(irdp->t_advertise);
  246.   irdp->t_advertise = NULL;
  247.   timer =  (random () % MAX_RESPONSE_DELAY) + 1;
  248.   irdp->t_advertise = thread_add_timer(master, 
  249.        irdp_send_thread, 
  250.        ifp, 
  251.        timer);
  252. }
  253. void irdp_finish()
  254. {
  255.   listnode node;
  256.   struct interface *ifp;
  257.   struct zebra_if *zi;
  258.   struct irdp_interface *irdp;
  259.   zlog_warn("IRDP: Received shutdown notification.");
  260.   
  261.   for (node = listhead (iflist); node; node = nextnode (node))
  262.     {
  263.       ifp = getdata(node);
  264.       zi= ifp->info;
  265.       if(! zi) continue;
  266.       irdp = &zi->irdp;
  267.       if(!irdp) continue;
  268.       if(irdp->flags & IF_ACTIVE ) {
  269. irdp->flags |= IF_SHUTDOWN;
  270. irdp_advert_off(ifp);
  271.       }
  272.     }
  273. }
  274. void irdp_init()
  275. {
  276.   irdp_sock_init();
  277.   irdp_if_init ();
  278. }
  279. #endif /* HAVE_IRDP */