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