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

1.1       misho       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>