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