home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / nhclb120 / nr3.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  26KB  |  983 lines

  1. /* net/rom level 3 low level processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "iface.h"
  10. #include "timer.h"
  11. #include "arp.h"
  12. #include "slip.h"
  13. #include "ax25.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "lapb.h"
  17. #include <ctype.h>
  18. #ifdef    UNIX
  19. #include <string.h>
  20. #include <memory.h>
  21. #endif
  22.  
  23. static struct nr_bind *find_best();
  24.  
  25. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  26. struct ax25_addr nr_nodebc = {
  27.     'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  28.     ('0'<<1) | E
  29. } ;
  30.  
  31. struct nriface nrifaces[NRNUMIFACE] ;
  32. unsigned nr_numiface ;
  33. struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
  34. struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
  35. struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
  36. unsigned nr_nfmode = NRNF_NOFILTER ;
  37. unsigned nr_ttl = 64 ;
  38. unsigned obso_init = 6 ;
  39. unsigned obso_minbc = 5 ;
  40. unsigned nr_maxroutes = 5 ;
  41. unsigned nr_autofloor = 1 ;
  42. unsigned nr_verbose = 0 ;
  43. struct interface *nr_interface ;
  44.  
  45. /* send a NET/ROM layer 3 datagram */
  46. void nr3output(dest, data)
  47. struct ax25_addr *dest ;
  48. struct mbuf *data ;
  49. {
  50.     struct nr3hdr n3hdr ;
  51.     struct mbuf *n3b ;
  52.  
  53.     n3hdr.dest = *dest ;    /* copy destination field */
  54.     n3hdr.ttl = nr_ttl ;    /* time to live from initializer parm */
  55.  
  56.     if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
  57.         free_p(data) ;
  58.         return ;
  59.     }
  60.  
  61.     append(&n3b, data) ;
  62.  
  63.     /* The null interface indicates that the packet needs to have */
  64.     /* an appropriate source address inserted by nr_route */
  65.     
  66.     nr_route(n3b,NULLAX25) ;
  67. }
  68.  
  69.  
  70. /* send IP datagrams across a net/rom network connection */
  71. /*ARGSUSED*/
  72. int
  73. nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  74. struct mbuf *bp ;
  75. struct interface *interface ;
  76. int32 gateway ;
  77. char precedence ;
  78. char delay ;
  79. char throughput ;
  80. char reliability ;
  81. {
  82.     struct ax25_addr dest ;
  83.     struct mbuf *pbp ;
  84.     struct nr4hdr n4hdr ;
  85.     char *hwaddr ;
  86.     struct arp_tab *arp ;
  87.  
  88.     if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  89.         free_p(bp) ;    /* drop the packet if no route */
  90.         return ;
  91.     }
  92.     hwaddr = arp->hw_addr ;                /* points to destination */
  93.     memcpy(dest.call, hwaddr, ALEN) ;
  94.     dest.ssid = hwaddr[ALEN] ;
  95.         
  96.     /* Create a "network extension" transport header */
  97.     n4hdr.opcode = NR4OPPID ;
  98.     n4hdr.u.pid.family = PID_IP ;
  99.     n4hdr.u.pid.proto = PID_IP ;
  100.  
  101.     if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
  102.         free_p(bp) ;
  103.         return ;
  104.     }
  105.  
  106.     append(&pbp,bp) ;        /* Append the data to that */
  107.     nr3output(&dest, pbp) ; /* and pass off to level 3 code */
  108.  
  109. }
  110.  
  111. /* Figure out if a call is assigned to one of my net/rom
  112.  * interfaces.
  113.  */
  114. static int
  115. ismycall(addr)
  116. struct ax25_addr *addr ;
  117. {
  118.     register int i ;
  119.     int found = 0 ;
  120.     
  121.     for (i = 0 ; i < nr_numiface ; i++)
  122.         if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
  123.             addr)) {
  124.             found = 1 ;
  125.             break ;
  126.         }
  127.  
  128.     return found ;
  129. }
  130.  
  131.  
  132. /* Route net/rom network layer packets.
  133.  */
  134. nr_route(bp, iaxp)
  135. struct mbuf *bp ;            /* network packet */
  136. struct ax25_cb *iaxp ;        /* incoming ax25 control block */
  137. {
  138.     struct nr3hdr n3hdr ;
  139.     struct nr4hdr n4hdr ;
  140.     struct ax25_cb *axp, *find_ax25(), *open_ax25() ;
  141.     struct ax25 naxhdr ;
  142.     struct ax25_addr neighbor, from ;
  143.     struct mbuf *hbp, *pbp ;
  144.     extern int16 axwindow ;
  145.     void ax_incom(), nr4input() ;
  146.     register struct nrnbr_tab *np ;
  147.     register struct nrroute_tab *rp ;
  148.     register struct nr_bind *bindp ;
  149.     struct nr_bind *find_best() ;
  150.     struct interface *interface ;
  151.     unsigned ifnum ;
  152.     
  153.     if (ntohnr3(&n3hdr,&bp) == -1) {
  154.         free_p(bp) ;
  155.         return ;
  156.     }
  157.  
  158.     /* If this isn't an internally generated network packet,
  159.      * give the router a chance to record a route back to the
  160.      * sender, in case they aren't in the local node's routing
  161.      * table yet.
  162.      */
  163.  
  164.     if (iaxp != NULLAX25) {
  165.         /* find the interface number */
  166.         for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  167.             if (iaxp->interface == nrifaces[ifnum].interface)
  168.                 break ;
  169.  
  170.         if (ifnum == nr_numiface) {    /* shouldn't happen! */
  171.             free_p(bp) ;
  172.             return ;
  173.         }
  174.  
  175.         from = iaxp->addr.dest ;
  176.         from.ssid |= E ;
  177.  
  178.         /* Add (possibly) a zero-quality recorded route via */
  179.         /* the neighbor from which this packet was received */
  180.         /* Note that this doesn't work with digipeated neighbors, */
  181.         /* at this point. */
  182.         
  183.         (void) nr_routeadd("      ",&n3hdr.source,ifnum,0,
  184.                                     (char *)&from,0,1) ;
  185.     }
  186.  
  187.     /* A packet from me, to me, can only be one thing: */
  188.     /* a horrible routing loop.  This will probably result */
  189.     /* from a bad manual ARP entry, but we should fix these */
  190.     /* obscure errors as we find them. */
  191.     
  192.     if (ismycall(&n3hdr.dest)) {
  193.         if (iaxp == NULLAX25) {        /* From me? */
  194.             free_p(bp) ;
  195.             return ;
  196.         } else {                    /* It's from somewhere else! */
  197.             if (ntohnr4(&n4hdr,&bp) == -1) {
  198.                 free_p(bp) ;
  199.                 return ;
  200.             }
  201.             if ((n4hdr.opcode & NR4OPCODE) == 0) {
  202.                 if (n4hdr.u.pid.family == PID_IP
  203.                     && n4hdr.u.pid.proto == PID_IP)
  204.                     ip_route(bp,0) ;
  205.                 else                     /* we don't do this proto */
  206.                     free_p(bp) ;
  207.  
  208.                 return ;
  209.             }
  210.             
  211.             /* Must be net/rom transport: */
  212.  
  213.             nr4input(&n4hdr,bp) ;
  214.  
  215.         }
  216.         return ;
  217.     }
  218.  
  219.     if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  220.         /* no route, drop the packet */
  221.         free_p(bp) ;
  222.         return ;
  223.     }
  224.  
  225.     if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  226.         /* This shouldn't happen yet, but might if we add */
  227.         /* dead route detection */
  228.         free_p(bp) ;
  229.         return ;
  230.     }
  231.  
  232.     np = bindp->via ;
  233.     memcpy(neighbor.call,np->call,ALEN) ;
  234.     neighbor.ssid = np->call[ALEN] ;
  235.     interface = nrifaces[np->interface].interface ;
  236.  
  237.     /* Now check to see if iaxp is null.  That is */
  238.     /* a signal that the packet originates here, */
  239.     /* so we need to insert the callsign of the appropriate  */
  240.     /* interface */
  241.     if (iaxp == NULLAX25)
  242.         memcpy((char *)&n3hdr.source,interface->hwaddr,AXALEN) ;
  243.     
  244.     /* Make sure there is a connection to the neighbor */
  245.     if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
  246.         (axp->state != CONNECTED && axp->state != RECOVERY)) {
  247.         /* Open a new connection or reinitialize old one */
  248.         /* hwaddr has been advanced to point to neighbor + digis */
  249.         atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
  250.         axp = open_ax25(&naxhdr, axwindow, ax_incom, NULLVFP, NULLVFP,
  251.                         interface,(char *)0) ;
  252.         if (axp == NULLAX25) {
  253.             free_p(bp) ;
  254.             return ;
  255.         }
  256.     }
  257.         
  258.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  259.         free_p(bp) ;
  260.         return ;
  261.     }
  262.  
  263.     /* allocate and fill PID mbuf */
  264.     if ((pbp = alloc_mbuf(1)) == NULLBUF) {
  265.         free_p(bp) ;
  266.         return ;
  267.     }
  268.     pbp->cnt = 1 ;
  269.     *pbp->data = (PID_FIRST | PID_LAST | PID_NETROM) ;
  270.  
  271.     /* now format network header */
  272.     if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
  273.         free_p(pbp) ;
  274.         free_p(bp) ;
  275.         return ;
  276.     }
  277.  
  278.     append(&pbp,hbp) ;        /* append header to pid */
  279.     append(&pbp,bp) ;        /* append data to header */
  280.     send_ax25(axp,pbp) ;    /* pass it off to ax25 code */
  281. }
  282.     
  283.  
  284. /* Perform a nodes broadcast on interface # ifno in the net/rom
  285.  * interface table.
  286.  */
  287.  
  288. nr_bcnodes(ifno)
  289. unsigned ifno ;
  290. {
  291.     struct mbuf *hbp, *dbp, *savehdr ;
  292.     struct nrroute_tab *rp ;
  293.     struct nrnbr_tab *np ;
  294.     struct nr_bind * bp ;
  295.     struct nr3dest nrdest ;
  296.     int i, didsend = 0, numdest = 0 ;
  297.     register char *cp ;
  298.     struct interface *axif = nrifaces[ifno].interface ;
  299.     struct nr_bind *find_best() ;
  300.     
  301.     /* prepare the header */
  302.     if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  303.         return ;
  304.         
  305.     hbp->cnt = NR3NODEHL ;    
  306.     
  307.     *hbp->data = NR3NODESIG ;
  308.     memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;
  309.  
  310.     /* Some people don't want to advertise any routes; they
  311.      * just want to be a terminal node.  In that case we just
  312.      * want to send our call and alias and be done with it.
  313.      */
  314.  
  315.     if (!nr_verbose) {
  316.         (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  317.                          (PID_FIRST | PID_LAST | PID_NETROM),
  318.                          hbp) ;    /* send it */
  319.         return ;
  320.     }
  321.     
  322.     /* make a copy of the header in case we need to send more than */
  323.     /* one packet */
  324.     savehdr = copy_p(hbp,NR3NODEHL) ;
  325.  
  326.     /* now scan through the routing table, finding the best routes */
  327.     /* and their neighbors.  create destination subpackets and append */
  328.     /* them to the header */
  329.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  330.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  331.             /* look for best, non-obsolescent route */
  332.             if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  333.                 continue ;    /* no non-obsolescent routes found */
  334.             if (bp->quality == 0)    /* this is a loopback route */
  335.                 continue ;            /* we never broadcast these */
  336.             np = bp->via ;
  337.             /* insert best neighbor */
  338.             memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  339.             nrdest.neighbor.ssid = np->call[ALEN] ;
  340.             /* insert destination from route table */
  341.             nrdest.dest = rp->call ;
  342.             /* insert alias from route table */
  343.             strcpy(nrdest.alias,rp->alias) ;
  344.             /* insert quality from binding */
  345.             nrdest.quality = bp->quality ;
  346.             /* create a network format destination subpacket */
  347.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  348.                 free_p(hbp) ;    /* drop the whole idea ... */
  349.                 free_p(savehdr) ;
  350.                 return ;
  351.             }
  352.             append(&hbp,dbp) ;    /* append to header and others */
  353.             /* see if we have appended as many destinations */
  354.             /* as we can fit into a single broadcast.  If we */
  355.             /* have, go ahead and send them out. */
  356.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  357.                 didsend = 1 ;    /* indicate that we did broadcast */
  358.                 numdest = 0 ;    /* reset the destination counter */
  359.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  360.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  361.                                  hbp) ;    /* send it */
  362.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  363.             }
  364.         }
  365.     }
  366.  
  367.     /* Now, here is something totally weird.  If our interfaces */
  368.     /* have different callsigns than this one, advertise a very */
  369.     /* high quality route to them.  Is this a good idea?  I don't */
  370.     /* know.  However, it allows us to simulate a bunch of net/roms */
  371.     /* hooked together with a diode matrix coupler. */
  372.     for (i = 0 ; i < nr_numiface ; i++) {
  373.         if (i == ifno)
  374.             continue ;        /* don't bother with ours */
  375.         cp = nrifaces[i].interface->hwaddr ;
  376.         if (!addreq((struct ax25_addr *)axif->hwaddr,(struct ax25_addr *)cp)) {
  377.             /* both destination and neighbor address */
  378.             memcpy((char *)&nrdest.dest,cp,AXALEN) ;
  379.             memcpy((char *)&nrdest.neighbor,cp,AXALEN) ;
  380.             /* alias of the interface */
  381.             strcpy(nrdest.alias,nrifaces[i].alias) ;
  382.             /* and the very highest quality */
  383.             nrdest.quality = 255 ;
  384.             /* create a network format destination subpacket */
  385.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  386.                 free_p(hbp) ;    /* drop the whole idea ... */
  387.                 free_p(savehdr) ;
  388.                 return ;
  389.             }
  390.             append(&hbp,dbp) ;    /* append to header and others */
  391.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  392.                 didsend = 1 ;    /* indicate that we did broadcast */
  393.                 numdest = 0 ;    /* reset the destination counter */
  394.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  395.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  396.                                  hbp) ;    /* send it */
  397.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  398.             }
  399.         }
  400.     }
  401.             
  402.     /* If we have a partly filled packet left over, or we never */
  403.     /* sent one at all, we broadcast: */
  404.     if (!didsend || numdest > 0)
  405.         (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  406.                         (PID_FIRST | PID_LAST | PID_NETROM), hbp) ;
  407.  
  408.     free_p(savehdr) ;    /* free the header copy */
  409. }
  410.  
  411.  
  412. /* initialize fake arp entry for netrom */
  413. nr3arp()
  414. {
  415.     int psax25(), setpath() ;
  416.  
  417.     arp_init(ARP_NETROM,AXALEN,0,0,NULLCHAR,psax25,setpath) ;
  418. }
  419.  
  420. /* attach the net/rom interface.  no parms for now. */
  421. /*ARGSUSED*/
  422. nr_attach(argc,argv)
  423. int argc ;
  424. char *argv[] ;
  425. {
  426.     if (nr_interface != (struct interface *)0) {
  427.         printf("netrom interface already attached\n") ;
  428.         return -1 ;
  429.     }
  430.  
  431.     nr3arp() ;
  432.     
  433.     nr_interface = (struct interface *)calloc(1,sizeof(struct interface)) ;
  434.     nr_interface->name = "netrom" ;
  435.     nr_interface->mtu = NR4MAXINFO ;
  436.     nr_interface->send = nr_send ;
  437.     nr_interface->next = ifaces ;
  438.     ifaces = nr_interface ;
  439.     return 0 ;
  440. }
  441.  
  442. /* This function checks an ax.25 address and interface number against
  443.  * the filter table and mode, and returns 1 if the address is to be
  444.  * accepted, and 0 if it is to be filtered out.
  445.  */
  446. static int
  447. accept_bc(addr,ifnum)
  448. struct ax25_addr *addr ;
  449. unsigned ifnum ;
  450. {
  451.     struct nrnf_tab *fp ;
  452.  
  453.     if (nr_nfmode == NRNF_NOFILTER)        /* no filtering in effect */
  454.         return 1 ;
  455.  
  456.     fp = find_nrnf(addr,ifnum) ;        /* look it up */
  457.     
  458.     if ((fp != NULLNRNFTAB && nr_nfmode == NRNF_ACCEPT)
  459.         || (fp == NULLNRNFTAB && nr_nfmode == NRNF_REJECT))
  460.         return 1 ;
  461.     else
  462.         return 0 ;
  463. }
  464.  
  465.  
  466. /* receive and process node broadcasts. */
  467. nr_nodercv(interface,source,bp)
  468. struct interface *interface ;
  469. struct ax25_addr *source ;
  470. struct mbuf *bp ;
  471. {
  472.     register int ifnum ;
  473.     char bcalias[7] ;
  474.     struct nr3dest ds ;
  475.     char sbuf[AXALEN*3] ;
  476.     
  477.     /* First, see if this is even a net/rom interface: */
  478.     for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  479.         if (interface == nrifaces[ifnum].interface)
  480.             break ;
  481.             
  482.     if (ifnum == nr_numiface) {    /* not in the interface table */
  483.         free_p(bp) ;
  484.         return ;
  485.     }
  486.  
  487.     if (!accept_bc(source,(unsigned)ifnum)) {    /* check against filter */
  488.         free_p(bp) ;
  489.         return ;
  490.     }
  491.     
  492.     /* See if it has a routing broadcast signature: */
  493.     if (uchar(pullchar(&bp)) != NR3NODESIG) {
  494.         free_p(bp) ;
  495.         return ;
  496.     }
  497.  
  498.     /* now try to get the alias */
  499.     if (pullup(&bp,bcalias,ALEN) < ALEN) {
  500.         free_p(bp) ;
  501.         return ;
  502.     }
  503.  
  504.     bcalias[ALEN] = '\0' ;        /* null terminate */
  505.  
  506.     /* copy source address and convert to arp format */
  507.     memcpy(sbuf,source->call,ALEN) ;
  508.     sbuf[ALEN] = (source->ssid | E) ;    /* terminate */
  509.     
  510.     /* enter the neighbor into our routing table */
  511.     if (nr_routeadd(bcalias,source,(unsigned)ifnum,nrifaces[ifnum].quality,
  512.                     sbuf, 0, 0) == -1) {
  513.         free_p(bp) ;
  514.         return ;
  515.     }
  516.     
  517.     /* we've digested the header; now digest the actual */
  518.     /* routing information */
  519.     while (ntohnrdest(&ds,&bp) != -1) {
  520.         /* ignore routes to me! */
  521.         if (ismycall(&ds.dest))
  522.             continue ;
  523.         /* ignore routes below the minimum quality threshhold */
  524.         if (ds.quality < nr_autofloor)
  525.             continue ;
  526.         /* set loopback paths to 0 quality */
  527.         if (ismycall(&ds.neighbor))
  528.             ds.quality = 0 ;
  529.         else
  530.             ds.quality = ((ds.quality * nrifaces[ifnum].quality + 128)
  531.                           / 256) & 0xff ;
  532.         if (nr_routeadd(ds.alias,&ds.dest,(unsigned)ifnum,ds.quality,sbuf,0,0)
  533.             == -1)
  534.             break ;
  535.     }
  536.             
  537.     free_p(bp) ;    /* This will free the mbuf if anything fails above */
  538. }
  539.  
  540.  
  541. /* The following are utilities for manipulating the routing table */
  542.  
  543. /* hash function for callsigns.  Look familiar? */
  544. int16
  545. nrhash(s)
  546. struct ax25_addr *s ;
  547. {
  548.     register char x ;
  549.     register int i ;
  550.     register char *cp ;
  551.  
  552.     x = 0 ;
  553.     cp = s->call ;
  554.     for (i = ALEN ; i !=0 ; i--)
  555.         x ^= *cp++ & 0xfe ;
  556.     x ^= s->ssid & SSID ;
  557.     return uchar(x) % NRNUMCHAINS ;
  558. }
  559.  
  560. /* Find a neighbor table entry.  Neighbors are determined by
  561.  * their callsign and the interface number.  This takes care
  562.  * of the case where the same switch or hosts uses the same
  563.  * callsign on two different channels.  This isn't done by
  564.  * net/rom, but it might be done by stations running *our*
  565.  * software.
  566.  */
  567. struct nrnbr_tab *
  568. find_nrnbr(addr,ifnum)
  569. register struct ax25_addr *addr ;
  570. unsigned ifnum ;
  571. {
  572.     int16 hashval ;
  573.     register struct nrnbr_tab *np ;
  574.     char i_state ;
  575.     struct ax25_addr ncall ;
  576.  
  577.     /* Find appropriate hash chain */
  578.     hashval = nrhash(addr) ;
  579.  
  580.     /* search hash chain */
  581.     i_state = disable() ;
  582.     for (np = nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  583.         memcpy(ncall.call,np->call,ALEN) ;    /* convert first in */
  584.         ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  585.         if (addreq(&ncall,addr) && np->interface == ifnum) {
  586.             restore(i_state) ;
  587.             return np ;
  588.         }
  589.     }
  590.     restore(i_state) ;
  591.     return NULLNTAB ;
  592. }
  593.  
  594.  
  595. /* Find a route table entry */
  596. struct nrroute_tab *
  597. find_nrroute(addr)
  598. register struct ax25_addr *addr ;
  599. {
  600.     int16 hashval ;
  601.     register struct nrroute_tab *rp ;
  602.     char i_state ;
  603.  
  604.     /* Find appropriate hash chain */
  605.     hashval = nrhash(addr) ;
  606.  
  607.     /* search hash chain */
  608.     i_state = disable() ;
  609.     for (rp = nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  610.         if (addreq(&rp->call,addr)) {
  611.             restore(i_state) ;
  612.             return rp ;
  613.         }
  614.     }
  615.     restore(i_state) ;
  616.     return NULLNRRTAB ;
  617. }
  618.  
  619. /* Try to find the AX.25 address of a node with the given alias.  Return */
  620. /* a pointer to the AX.25 address if found, otherwise NULLAXADDR.  The alias */
  621. /* should be a six character, blank-padded, upper-case string. */
  622.  
  623. struct ax25_addr *
  624. find_nralias(alias)
  625. char *alias ;
  626. {
  627.     int i ;
  628.     register struct nrroute_tab *rp ;
  629.  
  630.     /* Since the route entries are hashed by ax.25 address, we'll */
  631.     /* have to search all the chains */
  632.     
  633.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  634.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
  635.             if (strncmp(alias, rp->alias, 6) == 0)
  636.                 return &rp->call ;
  637.  
  638.     /* If we get to here, we're out of luck */
  639.  
  640.     return NULLAXADDR ;
  641. }
  642.  
  643.     
  644. /* Find a binding in a list by its neighbor structure's address */
  645. struct nr_bind *
  646. find_binding(list,neighbor)
  647. struct nr_bind *list ;
  648. register struct nrnbr_tab *neighbor ;
  649. {
  650.     register struct nr_bind *bp ;
  651.  
  652.     for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  653.         if (bp->via == neighbor)
  654.             return bp ;
  655.  
  656.     return NULLNRBIND ;
  657. }
  658.  
  659. /* Find the worst quality non-permanent binding in a list */
  660. static
  661. struct nr_bind *
  662. find_worst(list)
  663. struct nr_bind *list ;
  664. {
  665.     register struct nr_bind *bp ;
  666.     struct nr_bind *worst = NULLNRBIND ;
  667.     unsigned minqual = 1000 ;     /* infinity */
  668.  
  669.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  670.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  671.             worst = bp ;
  672.             minqual = bp->quality ;
  673.         }
  674.  
  675.     return worst ;
  676. }
  677.  
  678. /* Find the best binding of any sort in a list.  If obso is 1,
  679.  * include entries below the obsolescence threshhold in the
  680.  * search (used when this is called for routing broadcasts).
  681.  * If it is 0, routes below the threshhold are treated as
  682.  * though they don't exist.
  683.  */
  684. static
  685. struct nr_bind *
  686. find_best(list,obso)
  687. struct nr_bind *list ;
  688. unsigned obso ;
  689. {
  690.     register struct nr_bind *bp ;
  691.     struct nr_bind *best = NULLNRBIND ;
  692.     int maxqual = -1 ;    /* negative infinity */
  693.  
  694.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  695.         if ((int)bp->quality > maxqual)
  696.             if (obso || bp->obsocnt >= obso_minbc) {
  697.                 best = bp ;
  698.                 maxqual = bp->quality ;
  699.             }
  700.  
  701.     return best ;
  702. }
  703.  
  704. /* Add a route to the net/rom routing table */
  705. nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
  706. char *alias ;                /* net/rom node alias, blank-padded and */
  707.                             /* null-terminated */
  708. struct ax25_addr *dest ;    /* destination node callsign */
  709. unsigned ifnum ;            /* net/rom interface number */
  710. unsigned quality ;            /* route quality */
  711. char *neighbor ;            /* neighbor node + 2 digis (max) in arp format */
  712. unsigned permanent ;        /* 1 if route is permanent (hand-entered) */
  713. unsigned record ;            /* 1 if route is a "record route" */
  714. {
  715.     struct nrroute_tab *rp ;
  716.     struct nr_bind *bp ;
  717.     struct nrnbr_tab *np ;
  718.     int16 rhash, nhash ;
  719.     struct ax25_addr ncall ;
  720.  
  721.     /* See if a routing table entry exists for this destination */
  722.     if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  723.         if ((rp =
  724.              (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  725.             == NULLNRRTAB)
  726.             return -1 ;
  727.         else {            /* create a new route table entry */
  728.             strncpy(rp->alias,alias,6) ;
  729.             rp->call = *dest ;
  730.             rhash = nrhash(dest) ;
  731.             rp->next = nrroute_tab[rhash] ;
  732.             if (rp->next != NULLNRRTAB)
  733.                 rp->next->prev = rp ;
  734.             nrroute_tab[rhash] = rp ;    /* link at head of hash chain */
  735.         }
  736.     } else if (!record) {
  737.         strncpy(rp->alias,alias,6) ;    /* update the alias */
  738.     }
  739.  
  740.     /* See if an entry exists for this neighbor */
  741.     memcpy(ncall.call,neighbor,ALEN) ;    /* no digis included */
  742.     ncall.ssid = neighbor[ALEN] ;
  743.     if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  744.         if ((np =
  745.              (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  746.              == NULLNTAB) {
  747.             if (rp->num_routes == 0) {    /* we just added to table */
  748.                 nrroute_tab[rhash] = rp->next ;
  749.                 free((char *)rp) ;                /* so get rid of it */
  750.             }
  751.             return -1 ;
  752.         }
  753.         else {        /* create a new neighbor entry */
  754.             memcpy(np->call,neighbor,3 * AXALEN) ;
  755.             np->interface = ifnum ;
  756.             nhash = nrhash(&ncall) ;
  757.             np->next = nrnbr_tab[nhash] ;
  758.             if (np->next != NULLNTAB)
  759.                 np->next->prev = np ;
  760.             nrnbr_tab[nhash] = np ;
  761.         }
  762.     }
  763.     else if (permanent) {        /* force this path to the neighbor */
  764.         memcpy(np->call,neighbor,3 * AXALEN) ;
  765.     }
  766.         
  767.     /* See if there is a binding between the dest and neighbor */
  768.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  769.         if ((bp =
  770.              (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  771.             == NULLNRBIND) {
  772.             if (rp->num_routes == 0) {    /* we just added to table */
  773.                 nrroute_tab[rhash] = rp->next ;
  774.                 free((char *)rp) ;                /* so get rid of it */
  775.             }
  776.             if (np->refcnt == 0) {        /* we just added it */
  777.                 nrnbr_tab[nhash] = np->next ;
  778.                 free((char *)np) ;
  779.             }
  780.             return -1 ;
  781.         }
  782.         else {        /* create a new binding and link it in */
  783.             bp->via = np ;    /* goes via this neighbor */
  784.             bp->next = rp->routes ;    /* link into binding chain */
  785.             if (bp->next != NULLNRBIND)
  786.                 bp->next->prev = bp ;
  787.             rp->routes = bp ;
  788.             rp->num_routes++ ;    /* bump route count */
  789.             np->refcnt++ ;        /* bump neighbor ref count */
  790.             bp->quality = quality ;
  791.             bp->obsocnt = obso_init ;    /* use initial value */
  792.             if (permanent)
  793.                 bp->flags |= NRB_PERMANENT ;
  794.             else if (record)    /* notice permanent overrides record! */
  795.                 bp->flags |= NRB_RECORDED ;
  796.         }
  797.     } else {
  798.         if (permanent) {    /* permanent request trumps all */
  799.             bp->quality = quality ;
  800.             bp->obsocnt = obso_init ;
  801.             bp->flags |= NRB_PERMANENT ;
  802.             bp->flags &= ~NRB_RECORDED ;    /* perm is not recorded */
  803.         } else if (!(bp->flags & NRB_PERMANENT)) {    /* not permanent */
  804.             if (record) {    /* came from nr_route */
  805.                 if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
  806.                     bp->quality = quality ;
  807.                     bp->obsocnt = obso_init ; /* freshen recorded routes */
  808.                 }
  809.             } else {        /* came from a routing broadcast */
  810.                 bp->quality = quality ;
  811.                 bp->obsocnt = obso_init ;
  812.                 bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
  813.             }
  814.         }
  815.     }
  816.         
  817.     /* Now, check to see if we have too many bindings, and drop */
  818.     /* the worst if we do */
  819.     if (rp->num_routes > nr_maxroutes) {
  820.         /* since find_worst never returns permanent entries, the */
  821.         /* limitation on number of routes is circumvented for    */
  822.         /* permanent routes */
  823.         if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  824.             memcpy(ncall.call,bp->via->call,ALEN) ;
  825.             ncall.ssid = bp->via->call[ALEN] ;
  826.             nr_routedrop(dest,&ncall,bp->via->interface) ;
  827.         }
  828.     }
  829.  
  830.     return 0 ;
  831. }
  832.  
  833.  
  834. /* Drop a route to dest via neighbor */
  835. nr_routedrop(dest,neighbor,ifnum)
  836. struct ax25_addr *dest, *neighbor ;
  837. unsigned ifnum ;
  838. {
  839.     register struct nrroute_tab *rp ;
  840.     register struct nrnbr_tab *np ;
  841.     register struct nr_bind *bp ;
  842.  
  843.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  844.         return -1 ;
  845.  
  846.     if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  847.         return -1 ;
  848.  
  849.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  850.         return -1 ;
  851.  
  852.     /* drop the binding first */
  853.     if (bp->next != NULLNRBIND)
  854.         bp->next->prev = bp->prev ;
  855.     if (bp->prev != NULLNRBIND)
  856.         bp->prev->next = bp->next ;
  857.     else
  858.         rp->routes = bp->next ;
  859.  
  860.     free((char *)bp) ;
  861.     rp->num_routes-- ;        /* decrement the number of bindings */
  862.     np->refcnt-- ;            /* and the number of neighbor references */
  863.     
  864.     /* now see if we should drop the route table entry */
  865.     if (rp->num_routes == 0) {
  866.         if (rp->next != NULLNRRTAB)
  867.             rp->next->prev = rp->prev ;
  868.         if (rp->prev != NULLNRRTAB)
  869.             rp->prev->next = rp->next ;
  870.         else
  871.             nrroute_tab[nrhash(dest)] = rp->next ;
  872.  
  873.         free((char *)rp) ;
  874.     }
  875.  
  876.     /* and check to see if this neighbor can be dropped */
  877.     if (np->refcnt == 0) {
  878.         if (np->next != NULLNTAB)
  879.             np->next->prev = np->prev ;
  880.         if (np->prev != NULLNTAB)
  881.             np->prev->next = np->next ;
  882.         else
  883.             nrnbr_tab[nrhash(neighbor)] = np->next ;
  884.  
  885.         free((char *)np) ;
  886.     }
  887.     
  888.     return 0 ;
  889. }
  890.  
  891. /* Find the best neighbor for destination dest, in arp format */
  892. char *
  893. nr_getroute(dest)
  894. struct ax25_addr *dest ;
  895. {
  896.     register struct nrroute_tab *rp ;
  897.     register struct nr_bind *bp ;
  898.  
  899.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  900.         return NULLCHAR ;
  901.  
  902.     if ((bp = find_best(rp->routes,0)) == NULLNRBIND)    /* shouldn't happen! */
  903.         return NULLCHAR ;
  904.  
  905.     return bp->via->call ;
  906. }
  907.  
  908. /* Find an entry in the filter table */
  909. struct nrnf_tab *
  910. find_nrnf(addr,ifnum)
  911. register struct ax25_addr *addr ;
  912. unsigned ifnum ;
  913. {
  914.     int16 hashval ;
  915.     register struct nrnf_tab *fp ;
  916.  
  917.     /* Find appropriate hash chain */
  918.     hashval = nrhash(addr) ;
  919.  
  920.     /* search hash chain */
  921.     for (fp = nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  922.         if (addreq(&fp->neighbor,addr) && fp->interface == ifnum) {
  923.             return fp ;
  924.         }
  925.     }
  926.  
  927.     return NULLNRNFTAB ;
  928. }
  929.  
  930. /* Add an entry to the filter table.  Return 0 on success,
  931.  * -1 on failure
  932.  */
  933. int
  934. nr_nfadd(addr,ifnum)
  935. struct ax25_addr *addr ;
  936. unsigned ifnum ;
  937. {
  938.     struct nrnf_tab *fp ;
  939.     int16 hashval ;
  940.     
  941.     if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  942.         return 0 ;    /* already there; it's a no-op */
  943.  
  944.     if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  945.         == NULLNRNFTAB)
  946.         return -1 ;    /* no storage */
  947.  
  948.     hashval = nrhash(addr) ;
  949.     fp->neighbor = *addr ;
  950.     fp->interface = ifnum ;
  951.     fp->next = nrnf_tab[hashval] ;
  952.     if (fp->next != NULLNRNFTAB)
  953.         fp->next->prev = fp ;
  954.     nrnf_tab[hashval] = fp ;
  955.  
  956.     return 0 ;
  957. }
  958.  
  959. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  960.  * on failure.
  961.  */
  962. int
  963. nr_nfdrop(addr,ifnum)
  964. struct ax25_addr *addr ;
  965. unsigned ifnum ;
  966. {
  967.     struct nrnf_tab *fp ;
  968.  
  969.     if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  970.         return -1 ;    /* not in the table */
  971.  
  972.     if (fp->next != NULLNRNFTAB)
  973.         fp->next->prev = fp->prev ;
  974.     if (fp->prev != NULLNRNFTAB)
  975.         fp->prev->next = fp->next ;
  976.     else
  977.         nrnf_tab[nrhash(addr)] = fp->next ;
  978.  
  979.     free((char *)fp) ;
  980.  
  981.     return 0 ;
  982. }
  983.