home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / ka9q / ka9q_src.arc / NR3.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-07-28  |  21.3 KB  |  838 lines

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