home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / RIP.C < prev    next >
C/C++ Source or Header  |  1992-05-01  |  17KB  |  689 lines

  1. /* This file contains code to implement the Routing Information Protocol (RIP)
  2.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  3.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  4.  * credited. (Well, here's some credit :-). AGB 4-28-88
  5.  
  6.  * Further documentation on the RIP protocol is now available in Charles
  7.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  8.  *
  9.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  10.  *
  11.  * Code gutted and substantially rewritten. KA9Q 9/89
  12.  */
  13. #include "global.h"
  14. #include "mbuf.h"
  15. #include "netuser.h"
  16. #include "udp.h"
  17. #include "timer.h"
  18. #include "iface.h"
  19. #include "ip.h"
  20. #include "internet.h"
  21. #include "rip.h"
  22. #include "arp.h"
  23.  
  24. struct rip_stat Rip_stat;
  25. int16 Rip_trace;
  26. int Rip_merge;
  27. struct rip_list *Rip_list;
  28. struct udp_cb *Rip_cb;
  29.  
  30. struct rip_refuse *Rip_refuse;
  31.  
  32. static void rip_rx __ARGS((struct iface *iface,struct udp_cb *sock,int cnt));
  33. static void proc_rip __ARGS((struct iface *iface,int32 gateway,
  34.     struct rip_route *ep,int32 ttl));
  35. static char *putheader __ARGS((char *cp,char command,char version));
  36. static char *putentry __ARGS((char *cp,int16 fam,int32 target,int32 metric));
  37. static void rip_shout __ARGS((void *p));
  38. static void send_routes __ARGS((int32 dest,int16 port,int split,int trig,
  39.     int us));
  40.  
  41. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  42. static void
  43. rip_shout(p)
  44. void *p;
  45. {
  46.     register struct rip_list *rl;
  47.  
  48.     rl = (struct rip_list *)p;
  49.     stop_timer(&rl->rip_time);
  50.     send_routes(rl->dest,RIP_PORT,rl->flags&RIP_SPLIT,0,rl->flags&RIP_US);
  51.     set_timer(&rl->rip_time,rl->interval*1000L);
  52.     start_timer(&rl->rip_time);
  53. }
  54.  
  55. /* Send the routing table. */
  56. static void
  57. send_routes(dest,port,split,trig,us)
  58. int32 dest;        /* IP destination address to send to */
  59. int16 port;
  60. int split;        /* Do split horizon? */
  61. int trig;        /* Send only triggered updates? */
  62. int us;            /* Include our address in update */
  63. {
  64.     char *cp;
  65.     int i,bits,numroutes,maxroutes;
  66.     int16 pktsize;
  67.     struct mbuf *bp;
  68.     struct route *rp;
  69.     struct socket lsock,fsock;
  70.     struct iface *iface;
  71.  
  72.     if((rp = rt_lookup(dest)) == NULLROUTE)
  73.         return;    /* No route exists, can't do it */
  74.     iface = rp->iface;
  75.  
  76.     /* Compute maximum packet size and number of routes we can send */
  77.     pktsize = ip_mtu(dest) - IPLEN;
  78.     pktsize = min(pktsize,MAXRIPPACKET);
  79.     maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
  80.  
  81.     lsock.address = INADDR_ANY;
  82.     lsock.port = RIP_PORT;
  83.     fsock.address = dest;
  84.     fsock.port = port;
  85.  
  86.     /* Allocate space for a full size RIP packet and generate header */
  87.     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  88.         return; 
  89.     numroutes = 0;
  90.     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  91.  
  92.     /* Emit route to ourselves, if requested */
  93.     if(us){
  94.         cp = putentry(cp,RIP_IPFAM,iface->addr,0);
  95.         numroutes++;
  96.     }
  97.     /* Emit default route, if appropriate */
  98.     if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)
  99.      && (!trig || (R_default.flags & RTTRIG))){
  100.         if(!split || iface != R_default.iface){
  101.              cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
  102.             numroutes++;
  103.         } else if(trig){
  104.             cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
  105.             numroutes++;
  106.         }
  107.     }
  108.     for(bits=0;bits<32;bits++){
  109.         for(i=0;i<HASHMOD;i++){
  110.             for(rp = Routes[bits][i];rp != NULLROUTE;rp=rp->next){
  111.                 if((rp->flags & RTPRIVATE)
  112.                  || (trig && !(rp->flags & RTTRIG))) 
  113.                     continue;
  114.  
  115.                 if(numroutes >= maxroutes){
  116.                     /* Packet full, flush and make another */
  117.                     bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  118.                     send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  119.                     Rip_stat.output++;
  120.                     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  121.                         return; 
  122.                     numroutes = 0;
  123.                     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  124.                 }
  125.                 if(!split || iface != rp->iface){
  126.                      cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric);
  127.                     numroutes++;
  128.                 } else if(trig){
  129.                      cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
  130.                     numroutes++;
  131.                 }
  132.             }
  133.         }
  134.     }
  135.     if(numroutes != 0){
  136.         bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  137.         send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  138.         Rip_stat.output++;
  139.     } else {
  140.         free_p(bp);
  141.     }
  142. }
  143. /* Add an entry to the rip broadcast list */
  144. int
  145. rip_add(dest,interval,flags)
  146. int32 dest;
  147. int32 interval;
  148. char flags;
  149. {
  150.     register struct rip_list *rl;
  151.     struct route *rp;
  152.  
  153.     if((rp = rt_lookup(dest)) == NULLROUTE){
  154.         printf("%s is unreachable\n",inet_ntoa(dest));
  155.         return 1;
  156.     }
  157.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  158.         if(rl->dest == dest)
  159.             break;
  160.  
  161.     if(rl == NULLRL){
  162.         /* get a chunk of memory for the rip interface descriptor */
  163.         rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  164.  
  165.         /* tack this record on as the first in the list */
  166.         rl->next = Rip_list;
  167.         if(rl->next != NULLRL)
  168.             rl->next->prev = rl;
  169.         Rip_list = rl;
  170.         rl->dest = dest;
  171.     }
  172.     /* and the interface ptr, tick interval and flags */
  173.     rl->iface = rp->iface;
  174.     rl->interval = interval;
  175.     rl->flags = flags;
  176.  
  177.     /* set up the timer stuff */
  178.     rl->rip_time.func = rip_shout;
  179.     rl->rip_time.arg = rl;
  180.     /* This will initialize the timer and do an immediate broadcast */
  181.     rip_shout(rl);
  182.     return 0;
  183. }
  184.  
  185. /* add a gateway to the rip_refuse list which allows us to ignore their
  186.  * advertisements
  187. */
  188. int
  189. riprefadd(gateway)
  190. int32 gateway;
  191. {
  192.     register struct rip_refuse *rl;
  193.  
  194.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  195.         if(rl->target == gateway)
  196.             return 0;    /* Already in table */
  197.   
  198.  
  199.     /* get a chunk of memory for the rip interface descriptor */
  200.     rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  201.  
  202.     /* tack this record on as the first in the list */
  203.     rl->next = Rip_refuse;
  204.     if(rl->next != NULLREF)
  205.         rl->next->prev = rl;
  206.     Rip_refuse = rl;
  207.  
  208.     /* fill in the gateway to ignore */
  209.     rl->target = gateway;
  210.     return 0;
  211. }
  212.  
  213. /* drop a RIP target */
  214. int
  215. rip_drop(dest)
  216. int32    dest;
  217. {
  218.     register struct rip_list *rl;
  219.  
  220.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  221.         if(rl->dest == dest)
  222.             break;
  223.  
  224.     /* leave if we didn't find it */
  225.     if(rl == NULLRL)
  226.         return 0;
  227.  
  228.     /* stop the timer */
  229.     stop_timer(&rl->rip_time);
  230.  
  231.     /* Unlink from list */
  232.     if(rl->next != NULLRL)
  233.         rl->next->prev = rl->prev;
  234.     if(rl->prev != NULLRL)
  235.         rl->prev->next = rl->next;
  236.     else
  237.         Rip_list = rl->next;
  238.  
  239.     /* and deallocate the descriptor memory */
  240.     free((char *)rl);
  241.     return 0;
  242. }
  243.  
  244. /* drop a RIP-refuse target from the rip_refuse list */
  245. int
  246. riprefdrop(gateway)
  247. int32 gateway;
  248. {
  249.     register struct rip_refuse *rl;
  250.     
  251.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  252.         if(rl->target == gateway)
  253.             break;
  254.   
  255.     /* leave if we didn't find it */
  256.     if(rl == NULLREF)
  257.         return 0;
  258.  
  259.     /* Unlink from list */
  260.     if(rl->next != NULLREF)
  261.         rl->next->prev = rl->prev;
  262.     if(rl->prev != NULLREF)
  263.         rl->prev->next = rl->next;
  264.     else
  265.         Rip_refuse = rl->next;
  266.  
  267.     /* and deallocate the structure memory */
  268.     free((char *)rl);
  269.     return 0;
  270. }
  271.  
  272. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  273. void
  274. rip_trigger()
  275. {
  276.     register struct rip_list *rl;
  277.     int bits,i;
  278.     struct route *rp;
  279.  
  280.     for(rl=Rip_list;rl != NULLRL;rl = rl->next){
  281.         send_routes(rl->dest,RIP_PORT,(rl->flags & RIP_SPLIT),1,0);
  282.     }
  283.     /* Clear the trigger list */
  284.     R_default.flags &= ~RTTRIG;
  285.     for(bits=0;bits<32;bits++){
  286.         for(i=0;i<HASHMOD;i++){
  287.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  288.                 rp->flags &= ~RTTRIG;
  289.             }
  290.         }
  291.     }
  292. }
  293.  
  294. /* Start RIP agent listening at local RIP UDP port */
  295. int
  296. rip_init()
  297. {
  298.     struct socket lsock;
  299.  
  300.     lsock.address = INADDR_ANY;
  301.     lsock.port = RIP_PORT;
  302.  
  303.     if(Rip_cb == NULLUDP)
  304.         Rip_cb = open_udp(&lsock,rip_rx);
  305.  
  306.     return 0;
  307. }
  308.  
  309. /* Process RIP input received from 'interface'. */
  310. static void
  311. rip_rx(iface,sock,cnt)
  312. struct iface *iface;
  313. struct udp_cb *sock;
  314. int cnt;
  315. {
  316.     struct mbuf *bp;
  317.     struct socket fsock;
  318.     int cmd;
  319.     register struct rip_refuse *rfl;
  320.     struct rip_route entry;
  321.     struct route *rp;
  322.     struct rip_list *rl;
  323.     int32 ttl;
  324.  
  325.     /* receive the RIP packet */
  326.     recv_udp(sock,&fsock,&bp);
  327.  
  328.     /* increment the rcvd cnt */
  329.     Rip_stat.rcvd++;
  330.  
  331.     /* check the gateway of this packet against the rip_refuse list and
  332.      * discard it if a match is found
  333.      */
  334.     for(rfl=Rip_refuse;rfl != NULLREF;rfl = rfl->next){
  335.         if(fsock.address == rfl->target){
  336.             Rip_stat.refusals++;
  337.             if(Rip_trace > 1)
  338.                 printf("RIP refused from %s\n",
  339.                  inet_ntoa(fsock.address));
  340.             free_p(bp);
  341.             return;
  342.          }
  343.     }
  344.     cmd = PULLCHAR(&bp);
  345.     /* Check the version of the frame */
  346.     if(PULLCHAR(&bp) != RIPVERSION){
  347.         free_p(bp);
  348.         Rip_stat.version++;
  349.         return;
  350.     }
  351.     switch(cmd){
  352.     case RIPCMD_RESPONSE:
  353.         if(Rip_trace > 1)
  354.             printf("RIPCMD_RESPONSE from %s \n",inet_ntoa(fsock.address));
  355.  
  356.         Rip_stat.response++;
  357.         /* See if this interface is on our broadcast list; if so,
  358.          * use its interval to calculate entry lifetimes. Otherwise,
  359.          * use default
  360.          */
  361.         ttl = RIP_TTL;
  362.         for(rl=Rip_list; rl != NULLRL; rl = rl->next){
  363.             if(rl->iface == iface){
  364.                 ttl = rl->interval * 4;
  365.                 break;
  366.             }
  367.         }
  368.         (void)pull16(&bp);    /* remove one word of padding */
  369.         while(len_p(bp) >= RIPROUTE){
  370.             pullentry(&entry,&bp);
  371.             proc_rip(iface,fsock.address,&entry,ttl);
  372.         }
  373.         /* If we can't reach the sender of this update, or if
  374.          * our existing route is not through the interface we
  375.          * got this update on, add him as a host specific entry
  376.          */
  377.         if((rp = rt_blookup(fsock.address,32)) != NULLROUTE){
  378.             /* Host-specific route already exists, refresh it */
  379.             start_timer(&rp->timer);
  380.         } else if((rp = rt_lookup(fsock.address)) == NULLROUTE
  381.          || rp->iface != iface){
  382.             entry.addr_fam = RIP_IPFAM;
  383.             entry.target = fsock.address;
  384.             entry.metric = 0; /* will get incremented to 1 */
  385.             proc_rip(iface,fsock.address,&entry,ttl);
  386.         }
  387.         if(Rip_merge)
  388.             rt_merge(Rip_trace);
  389.         rip_trigger();
  390.         break;
  391.     case RIPCMD_REQUEST:
  392.         if(Rip_trace > 1)
  393.             printf("RIPCMD_REQUEST\n");
  394.  
  395.         Rip_stat.request++;
  396.         /* For now, just send the whole table with split horizon
  397.          * enabled when the source port is RIP_PORT, and send
  398.          * the whole table with split horizon disable when another
  399.          * source port is used. This should be replaced with a more
  400.          * complete implementation that checks for non-global requests
  401.          */
  402.         if(fsock.port == RIP_PORT)
  403.             send_routes(fsock.address,fsock.port,1,0,1);
  404.         else
  405.             send_routes(fsock.address,fsock.port,0,0,1);
  406.         break;
  407.     default:
  408.         if(Rip_trace > 1)
  409.             printf("RIPCMD: Unknown Type\n");
  410.  
  411.         Rip_stat.unknown++;
  412.         break;
  413.     } /* switch */
  414.     free_p(bp);
  415. }
  416. /* Apply a set of heuristics for determining the number of significant bits
  417.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  418.  * include the address mask for each entry.
  419.  */
  420. int
  421. nbits(target)
  422. int32 target;
  423. {
  424.     int bits;
  425.  
  426.     if(target == 0)
  427.         return 0;    /* Special case: 0.0.0.0 is the default route */
  428.  
  429.     /* Check the host-part bytes of
  430.      * the address to check for byte-wide zeros
  431.      * which we'll consider to be subnet routes.
  432.      * e.g.    44.80.0.0 will be considered to be equal to 44.80/16
  433.      * whereas 44.80.1.0 will be considered to be 44.80.1/24
  434.      */
  435.     switch (hibyte(hiword(target)) >> 6) {
  436.     case 3:    /* Class C address */
  437.         /*is it a host address ? i.e. are there any 1's in the
  438.          * host part ?
  439.          */
  440.         if(target & 0xff)
  441.             bits = 32;
  442.         else
  443.             bits = 24;
  444.         break;
  445.     case 2:  /* Class B address */
  446.         if(target & 0xff)
  447.             bits = 32;
  448.         else if(target & 0xff00)
  449.             bits = 24;
  450.         else
  451.             bits = 16;
  452.         break;
  453.         case 0:      /* Class A address */
  454.         case 1:
  455.         if(target & 0xff)
  456.             bits = 32;
  457.         else if(target & 0xff00)
  458.             bits = 24;
  459.         else if(target & 0xff0000)
  460.             bits = 16;
  461.         else
  462.             bits = 8;
  463.     }
  464.  
  465.     return bits;
  466. }
  467. /* Remove and process a RIP response entry from a packet */
  468. static void
  469. proc_rip(iface,gateway,ep,ttl)
  470. struct iface *iface;
  471. int32 gateway;
  472. register struct rip_route *ep;
  473. int32 ttl;
  474. {
  475.     unsigned int bits;
  476.     register struct route *rp;
  477.     int add = 0;    /* action flags */
  478.     int drop = 0;
  479.     int trigger = 0;
  480.  
  481.     if(ep->addr_fam != RIP_IPFAM) {
  482.         /* Skip non-IP addresses */
  483.         if(Rip_trace > 1)
  484.             printf("RIP_rx: Not an IP RIP packet !\n");
  485.         Rip_stat.addr_family++;
  486.         return;
  487.     }
  488.     /* Guess at the mask, since it's not explicit */
  489.     bits = nbits(ep->target);
  490.  
  491.     /* Don't ever add a route to myself through somebody! */
  492.     if(bits == 32 && ismyaddr(ep->target) != NULLIF){
  493.         if(Rip_trace > 1){
  494.             printf("route to self: %s %ld\n",
  495.              inet_ntoa(ep->target),ep->metric);
  496.         }
  497.         return;
  498.     }
  499.     /* Update metric to reflect link cost */
  500.     ep->metric++;
  501.     ep->metric = min(ep->metric,RIP_INFINITY);
  502.  
  503.     /* Find existing entry, if any */
  504.     rp = rt_blookup(ep->target,bits);
  505.  
  506.     /* Don't touch private routes */
  507.     if(rp != NULLROUTE && (rp->flags & RTPRIVATE))
  508.         return;
  509.  
  510.     if(rp == NULLROUTE){
  511.         if(ep->metric < RIP_INFINITY){
  512.             /* New route; add it and trigger an update */
  513.             add++;
  514.             trigger++;
  515.         }
  516.     } else if(rp->metric == RIP_INFINITY){
  517.         /* Route is in hold-down; ignore this guy */
  518.         if(Rip_trace > 0){
  519.             printf("ignored (hold-down): %s %lu\n",
  520.              inet_ntoa(ep->target),ep->metric);
  521.         }
  522.     } else if(rp->gateway == gateway && rp->iface == iface){
  523.         /* This is the gateway for the entry we already have;
  524.          * restart the timer
  525.          */
  526.         set_timer(&rp->timer,ttl*1000L);
  527.         start_timer(&rp->timer);
  528.         if(rp->metric != ep->metric){
  529.             /* Metric has changed. Update it and trigger an
  530.              * update. If route has become unavailable, start
  531.              * the hold-down timeout.
  532.              */
  533.             if(Rip_trace){
  534.                 printf("metric change: %s %lu -> %lu\n",
  535.                  inet_ntoa(ep->target),rp->metric,ep->metric);
  536.             }
  537.             if(ep->metric == RIP_INFINITY)
  538.                 rt_timeout(rp);    /* Enter hold-down timeout */
  539.             else
  540.                 rp->metric = ep->metric;
  541.             trigger++;
  542.         }
  543.     } else {
  544.         /* Entry is from a different gateway than the current route */
  545.         if(ep->metric < rp->metric){
  546.             /* Switch to a new gateway */
  547.             if(Rip_trace > 0){
  548.                 printf("metric better: %s %lu\n",
  549.                  inet_ntoa(ep->target),ep->metric);
  550.             }
  551.             drop++;
  552.             add++;
  553.             trigger++;
  554.         } else {
  555.             /* Metric is no better, stay with current route */
  556.             if(Rip_trace > 1){
  557.                 printf("metric not better: %s %lu\n",
  558.                  inet_ntoa(ep->target),ep->metric);
  559.             }
  560.         }
  561.     }
  562.     if(drop){
  563.         /* Switching to a better gateway; delete old entry */
  564.         if(Rip_trace){
  565.             printf("route drop [%s]/%u",
  566.              inet_ntoa(ep->target),bits);
  567.             if(rp != NULLROUTE)
  568.                 printf(" %s %s %lu",rp->iface->name,
  569.                  inet_ntoa(rp->gateway),rp->metric);
  570.             printf("\n");
  571.         }
  572.         rt_drop(ep->target,bits);
  573.     }
  574.     if(add){
  575.         /* Add a new entry */
  576.         if(Rip_trace > 0){
  577.             printf("route add [%s]/%u %s",inet_ntoa(ep->target),
  578.              bits,iface->name);
  579.             printf(" [%s] %u\n",inet_ntoa(gateway),
  580.              (int)ep->metric);
  581.         }
  582.         rp = rt_add(ep->target,(unsigned) bits,gateway,iface,
  583.          (int) ep->metric,ttl,0);
  584.     }
  585.     /* If the route changed, mark it for a triggered update */
  586.     if(trigger){
  587.         rp->flags |= RTTRIG;
  588.     }
  589. }
  590. /* Send a RIP request packet to the specified destination */
  591. int
  592. ripreq(dest,replyport)
  593. int32 dest;
  594. int16 replyport;
  595. {
  596.     struct mbuf *bp;
  597.     struct socket lsock,fsock;
  598.     char *cp;
  599.  
  600.     lsock.address = INADDR_ANY;
  601.     lsock.port = replyport;
  602.  
  603.     /* if we were given a valid dest addr, ask it (the routers on that net)
  604.      * for a default gateway
  605.      */
  606.     if(dest == 0)
  607.         return 0;
  608.  
  609.     fsock.address = dest;
  610.     fsock.port = RIP_PORT;
  611.  
  612.     /* Send out one RIP Request packet as a broadcast to 'dest'  */
  613.     if((bp = alloc_mbuf(RIPHEADER + RIPROUTE)) == NULLBUF)
  614.         return -1;
  615.  
  616.     cp = putheader(bp->data,RIPCMD_REQUEST,RIPVERSION);
  617.     cp = putentry(cp,0,0L,RIP_INFINITY);
  618.     bp->cnt = RIPHEADER + RIPROUTE;
  619.     send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  620.     Rip_stat.output++;
  621.     return 0;
  622. }
  623. void
  624. pullentry(ep,bpp)
  625. register struct rip_route *ep;
  626. struct mbuf **bpp;
  627. {
  628.     ep->addr_fam = pull16(bpp);
  629.     (void)pull16(bpp);
  630.     ep->target = pull32(bpp);
  631.     (void)pull32(bpp);
  632.     (void)pull32(bpp);
  633.     ep->metric = pull32(bpp);
  634. }
  635.  
  636. /* Write the header of a RIP packet */
  637. static char *
  638. putheader(cp,command,version)
  639. register char *cp;
  640. char command;
  641. char version;
  642. {
  643.     *cp++ = command;
  644.     *cp++ = version;
  645.     return put16(cp,0);
  646. }
  647.  
  648. /* Write a single entry into a rip packet */
  649. static char *
  650. putentry(cp,fam,target,metric)
  651. register char *cp;
  652. int16 fam;
  653. int32 target;
  654. int32 metric;
  655. {
  656.     cp = put16(cp,fam);
  657.     cp = put16(cp,0);
  658.     cp = put32(cp,target);
  659.     cp = put32(cp,0L);
  660.     cp = put32(cp,0L);
  661.     return put32(cp,metric);
  662. }
  663. /* Route timeout handler. If route has already been marked for deletion
  664.  * then delete it. Otherwise mark for deletion and restart timer.
  665.  */
  666. void
  667. rt_timeout(s)
  668. void *s;
  669. {
  670.     register struct route *rp = (struct route *)s;
  671.  
  672.     stop_timer(&rp->timer);
  673.     if(rp->metric < RIP_INFINITY){
  674.         rp->metric = RIP_INFINITY;
  675.         if(dur_timer(&rp->timer) == 0)
  676.             set_timer(&rp->timer,RIP_TTL*1000L);
  677.         /* wait 2/3 of timeout before garbage collect */
  678.         set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  679.         rp->timer.func = (void *)rt_timeout;
  680.         rp->timer.arg = (void *)rp;
  681.         start_timer(&rp->timer);
  682.         /* Route changed; mark it for triggered update */
  683.         rp->flags |= RTTRIG;
  684.         rip_trigger();
  685.     } else {
  686.         rt_drop(rp->target,rp->bits);
  687.     }
  688. }
  689.