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