home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / NR3.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  38KB  |  1,266 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. /* Mods by PA0GRI and WG7J */
  6.   
  7. #include <ctype.h>
  8. #include "global.h"
  9. #ifdef NETROM
  10. #include "mbuf.h"
  11. #include "pktdrvr.h"
  12. #include "iface.h"
  13. #include "netuser.h"
  14. #include "timer.h"
  15. #include "arp.h"
  16. #include "slip.h"
  17. #include "ax25.h"
  18. #include "netrom.h"
  19. #include "nr4.h"
  20. #include "lapb.h"
  21. #include "socket.h"
  22. #include "trace.h"
  23. #include "ip.h"
  24. #include "commands.h"
  25.   
  26. /* IF the following is defined,
  27.  * when we receive a nodes broadcast of a new neighbour,
  28.  * we will immediately respond with a nodes broadcast on that interface
  29.  * This speeds up route discovery at bootup etc..
  30.  * 920422 - WG7J
  31.  */
  32. #define NR_BC_RESPOND 1
  33.   
  34. static int accept_bc __ARGS((char *addr,struct iface *ifp));
  35. struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
  36. static struct nr_bind *find_binding __ARGS((struct nr_bind *list,struct nrnbr_tab *neighbor));
  37. void nrresetlinks __ARGS((struct nrroute_tab *rp)); /* s/b in a header file */
  38. static struct nrnf_tab *find_nrnf __ARGS((char *, struct iface *));
  39. static struct nr_bind *find_worst __ARGS((struct nr_bind *list));
  40. #ifdef  notdef
  41. static char *nr_getroute __ARGS((char *));
  42. #endif
  43. #ifdef NRRAW
  44. static struct raw_nr *Raw_nr;
  45. #endif
  46. static int nr_aliasck __ARGS(( char *alias));
  47.   
  48. struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS];
  49. struct nrroute_tab *Nrroute_tab[NRNUMCHAINS];
  50. struct nrnf_tab *Nrnf_tab[NRNUMCHAINS];
  51. unsigned Nr_nfmode = NRNF_NOFILTER;
  52. unsigned short Nr_ttl = 10;
  53. static unsigned Obso_init = 6;
  54. static unsigned Obso_minbc = 5;
  55. static unsigned Nr_maxroutes = 5;
  56. unsigned Nr_autofloor = 10;
  57. int Nr_derate = 1;          /* Allow automatic derating of routes */
  58. int Nr_promisc = 0;         /* behave promisuously with nr bcasts or not? */
  59. struct iface *Nr_iface;
  60.   
  61. extern char Nralias[ALEN+1];
  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.   
  100.     if((arp = arp_lookup(ARP_NETROM,gateway,iface)) == NULLARP){
  101.         free_p(bp); /* drop the packet if no route */
  102.         return -1;
  103.     }
  104.   
  105.     /*
  106.        these are already taken care of when the packet reaches
  107.        nr_route() to be routed - WG7J
  108.   
  109.     iface->rawsndcnt++;
  110.     iface->lastsent = Nr_iface->lastsent = secclock();
  111.     */
  112.   
  113.     Nr_iface->ipsndcnt++;
  114.     nr_sendraw(arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bp);
  115.     return 0;
  116. }
  117.   
  118. /* Send arbitrary protocol data on top of a NET/ROM connection */
  119. void
  120. nr_sendraw(dest,family,proto,data)
  121. char *dest;
  122. unsigned family;
  123. unsigned proto;
  124. struct mbuf *data;
  125. {
  126.     struct mbuf *pbp;
  127.     struct nr4hdr n4hdr;
  128.   
  129.     /* Create a "network extension" transport header */
  130.     n4hdr.opcode = NR4OPPID;
  131.     n4hdr.u.pid.family = family;
  132.     n4hdr.u.pid.proto = proto;
  133.   
  134.     if((pbp = htonnr4(&n4hdr)) == NULLBUF){
  135.         free_p(data);
  136.         return;
  137.     }
  138.     append(&pbp,data);      /* Append the data to that */
  139.     nr3output(dest, pbp); /* and pass off to level 3 code */
  140. }
  141.   
  142. #ifdef NRRAW
  143. /* Arrange for receipt of raw NET/ROM datagrams */
  144. struct raw_nr *
  145. raw_nr(protocol)
  146. char protocol;
  147. {
  148.     register struct raw_nr *rp;
  149.   
  150.     rp = (struct raw_nr *)callocw(1,sizeof(struct raw_nr));
  151.     rp->protocol = protocol;
  152.     rp->next = Raw_nr;
  153.     if(rp->next != NULLRNR)
  154.         rp->next->prev = rp;
  155.     Raw_nr = rp;
  156.     return rp;
  157. }
  158.   
  159. /* Free a raw NET/ROM descriptor */
  160. void
  161. del_rnr(rpp)
  162. struct raw_nr *rpp;
  163. {
  164.     register struct raw_nr *rp;
  165.   
  166.     /* Do sanity check on arg */
  167.     for(rp = Raw_nr;rp != NULLRNR;rp = rp->next)
  168.         if(rp == rpp)
  169.             break;
  170.     if(rp == NULLRNR)
  171.         return; /* Doesn't exist */
  172.   
  173.     /* Unlink */
  174.     if(rp->prev != NULLRNR)
  175.         rp->prev->next = rp->next;
  176.     else
  177.         Raw_nr = rp->next;
  178.     if(rp->next != NULLRNR)
  179.         rp->next->prev = rp->prev;
  180.     /* Free resources */
  181.     free_q(&rp->rcvq);
  182.     free((char *)rp);
  183. }
  184. #endif /* NRRAW */
  185.   
  186. /* Route net/rom network layer packets.
  187.  */
  188. void
  189. nr_route(bp, iaxp)
  190. struct mbuf *bp;            /* network packet */
  191. struct ax25_cb *iaxp;           /* incoming ax25 control block */
  192. {
  193.     struct nr3hdr n3hdr;
  194.     struct nr4hdr n4hdr;
  195.     struct ax25_cb *axp;
  196.     struct mbuf *hbp, *pbp;
  197. #ifdef NRRAW
  198.     struct raw_nr *rnr;
  199. #endif
  200.     struct nrnbr_tab *np;
  201.     struct nrroute_tab *rp;
  202.     struct nr_bind *bindp;
  203.     struct iface *iface;
  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.     /* Add some statictics gathering - WG7J */
  215.     if(iaxp != NULLAX25){
  216.         /* incoming packet, find the interface number */
  217.         if(!(iaxp->iface->flags & IS_NR_IFACE)){   /* Not a net/rom interface! */
  218.             free_p(bp);
  219.             return;
  220.         }
  221.   
  222.         /* Add (possibly) a zero-quality recorded route via */
  223.         /* the neighbor from which this packet was received */
  224.         /* Note that this doesn't work with digipeated neighbors. */
  225.         (void) nr_routeadd("##temp",n3hdr.source,iaxp->iface,0,iaxp->remote,0,1);
  226.   
  227.         Nr_iface->rawrecvcnt++;
  228.         Nr_iface->lastrecv = secclock();
  229.   
  230.     } else {
  231.         Nr_iface->rawsndcnt++;
  232.         Nr_iface->lastsent = secclock();
  233.     }
  234.   
  235.     /* A packet from me, to me, can only be one thing:
  236.      * a horrible routing loop.  This will probably result
  237.      * from a bad manual ARP entry, but we should fix these
  238.      * obscure errors as we find them.
  239.      */
  240.     if(addreq(Nr_iface->hwaddr,n3hdr.dest)){
  241.         /* Toss if from me */
  242.         if(iaxp == NULLAX25 || ntohnr4(&n4hdr,&bp) == -1){
  243.             free_p(bp);
  244.             return;
  245.         }
  246. #ifdef G8BPQ
  247.         /* Add the G8BPQ stuff to our route info - WG7J */
  248.         if(n4hdr.flags & NR4_G8BPQMASK)
  249.             if((rp = find_nrroute(n3hdr.source)) != NULLNRRTAB)
  250.                 if(n4hdr.flags & NR4_G8BPQTTL) {
  251.                     rp->hops = n4hdr.u.conack.ttl - n3hdr.ttl + 1;
  252.                     rp->flags |= G8BPQ_NODETTL;
  253.                 } else {
  254.                     rp->irtt = n4hdr.u.conreq.t4init;
  255.                     rp->flags |= G8BPQ_NODERTT;
  256.                 }
  257. #endif
  258.   
  259.         if((n4hdr.opcode & NR4OPCODE) == NR4OPPID){
  260. #ifdef NRRAW
  261.             for(rnr = Raw_nr;rnr!=NULLRNR;rnr = rnr->next){
  262.                 if(rnr->protocol!=n4hdr.u.pid.family ||
  263.                     rnr->protocol != n4hdr.u.pid.proto)
  264.                     continue;
  265.                 /* Duplicate the data portion, and put the
  266.                  * level 3 header back on
  267.                  */
  268.                 dup_p(&pbp,bp,0,len_p(bp));
  269.                 if(pbp != NULLBUF &&
  270.                 (hbp = htonnr3(&n3hdr)) != NULLBUF){
  271.                     append(&hbp,pbp);
  272.                     enqueue(&rnr->rcvq,hbp);
  273.                 } else {
  274.                     free_p(pbp);
  275.                     free_p(hbp);
  276.                 }
  277.             }
  278. #endif
  279.             /* IP does not use a NET/ROM level 3 socket */
  280.             if(n4hdr.u.pid.family == NRPROTO_IP
  281.             && n4hdr.u.pid.proto == NRPROTO_IP) {
  282.                 if(Nr_iface->flags & LOG_IPHEARD) {
  283.                     struct mbuf *nbp;
  284.                     int pid;
  285.                     struct ip ip;
  286.                     int len;
  287.   
  288.                     len = len_p(bp);
  289.                     if(dup_p(&nbp, bp, 0, len) == len) {
  290.                         ntohip(&ip,&nbp);
  291.                         if(ip.version == IPVERSION)
  292.                             log_ipheard(ip.source,Nr_iface);
  293.                     }
  294.                     free_p(nbp);
  295.                 }
  296.                 Nr_iface->iprecvcnt++;
  297.                 ip_route(iaxp->iface,bp,0);
  298.             } else        /* we don't do this proto */
  299.                 free_p(bp);
  300.         } else {
  301.             /* Must be net/rom transport: */
  302.             nr4input(&n4hdr,bp);
  303.         }
  304.         return;
  305.     }
  306.   
  307. #ifdef G8BPQ
  308.     {
  309.         struct mbuf *nbp;
  310.   
  311.     /* If this is not a locally generated packet,
  312.      * Add the G8BPQ stuff to our route info - WG7J
  313.      */
  314.         if(iaxp != NULLAX25) {
  315.             dup_p(&nbp,bp,0,len_p(bp));
  316.             if(ntohnr4(&n4hdr,&nbp) != -1)
  317.                 if(n4hdr.flags & NR4_G8BPQMASK)
  318.                     if((rp = find_nrroute(n3hdr.source)) != NULLNRRTAB) {
  319.                         if(n4hdr.flags & NR4_G8BPQTTL) {
  320.                             rp->hops = n4hdr.u.conack.ttl - n3hdr.ttl + 1;
  321.                             rp->flags |= G8BPQ_NODETTL;
  322.                         } else {
  323.                             rp->irtt = n4hdr.u.conreq.t4init;
  324.                             rp->flags |= G8BPQ_NODERTT;
  325.                         }
  326.                     }
  327.             free_p(nbp);
  328.         }
  329.     }
  330. #endif
  331.   
  332.     /* Now finally go route it */
  333.     if((rp = find_nrroute(n3hdr.dest)) == NULLNRRTAB) {
  334.         /* no route, drop the packet */
  335.         free_p(bp);
  336.         return;
  337.     }
  338.   
  339.     if((bindp = find_best(rp->routes,1)) == NULLNRBIND){
  340.         /* This shouldn't happen yet, but might if we add */
  341.         /* dead route detection */
  342.         free_p(bp);
  343.         return;
  344.     }
  345.   
  346.     np = bindp->via;
  347.     iface = np->iface;
  348.   
  349.     /* Now check to see if iaxp is null.  That is */
  350.     /* a signal that the packet originates here, */
  351.     /* so we need to insert the callsign of the appropriate  */
  352.     /* interface */
  353.     if(iaxp == NULLAX25)
  354.         memcpy(n3hdr.source,Nr_iface->hwaddr,AXALEN);
  355.   
  356.     /* Make sure there is a connection to the neighbor */
  357.     /* Make sure we use the netrom-interface call for this connection!
  358.      * 11/20/91 WG7J/PA3DIS
  359.      */
  360.     if((axp = find_ax25(Nr_iface->hwaddr,np->call,iface)) == NULLAX25 ||
  361.     (axp->state != LAPB_CONNECTED && axp->state != LAPB_RECOVERY)){
  362.         /* Open a new connection or reinitialize old one */
  363.         /* hwaddr has been advanced to point to neighbor + digis */
  364.         axp = open_ax25(iface,Nr_iface->hwaddr,np->call,AX_ACTIVE,
  365.         0,s_arcall,s_atcall, s_ascall,-1);
  366.         if(axp == NULLAX25){
  367.             free_p(bp);
  368.             return;
  369.         }
  370.     }
  371.   
  372.     if(--n3hdr.ttl == 0){   /* the packet's time to live is over! */
  373.         free_p(bp);
  374.         return;
  375.     }
  376.     /* now format network header */
  377.     if((pbp = htonnr3(&n3hdr)) == NULLBUF){
  378.         free_p(bp);
  379.         return;
  380.     }
  381.     append(&pbp,bp);        /* append data to header */
  382.   
  383.     /* put AX.25 PID on front */
  384.     if((bp = pushdown(pbp,1)) == NULLBUF){
  385.         free_p(pbp);
  386.         return;
  387.     }
  388.     bp->data[0] = PID_NETROM;
  389.   
  390.     if((pbp = segmenter(bp,axp->paclen)) == NULLBUF){
  391.         free_p(bp);
  392.         return;
  393.     }
  394.     /*Update the last-used timestamp - WG7J */
  395.     np->lastsent = secclock();
  396.   
  397.     /* Add one to the route usage count */
  398.     bindp->usage++;
  399.   
  400.     /* Add one to the number of tries for this neighbour */
  401.     np->tries++;
  402.   
  403.     send_ax25(axp,pbp,-1);  /* pass it off to ax25 code */
  404. }
  405.   
  406.   
  407. /* Perform a nodes broadcast on interface # ifno in the net/rom
  408.  * interface table.
  409.  */
  410. /* This uses Nralias as the alias instead of Nriface.alias as before - WG7J */
  411. void
  412. nr_bcnodes(ifp)
  413. struct iface *ifp;
  414. {
  415.     struct mbuf *hbp, *dbp, *savehdr;
  416.     struct nrroute_tab *rp;
  417.     struct nrnbr_tab *np;
  418.     struct nr_bind * bp;
  419.     struct nr3dest nrdest;
  420.     int i, didsend = 0, numdest = 0;
  421.   
  422.     /* prepare the header */
  423.     if((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  424.         return;
  425.   
  426.     hbp->cnt = NR3NODEHL;
  427.   
  428.     *hbp->data = NR3NODESIG;
  429.     memcpy(hbp->data+1,Nralias,ALEN);
  430.   
  431.     /* Some people don't want to advertise any routes; they
  432.      * just want to be a terminal node.  In that case we just
  433.      * want to send our call and alias and be done with it.
  434.      */
  435.   
  436.     if(ifp->nr_autofloor == 0) {
  437.         /*changed to use the Netrom interface call on all broadcasts,
  438.          *INDEPENDENT from the actual interface call!
  439.          *11/20/91 WG7J/PA3DIS
  440.          */
  441.         (*ifp->output)(ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr,
  442.         PID_NETROM, hbp);   /* send it */
  443.         return;
  444.     }
  445.   
  446.     /* make a copy of the header in case we need to send more than */
  447.     /* one packet */
  448.     savehdr = copy_p(hbp,NR3NODEHL);
  449.   
  450.     /* now scan through the routing table, finding the best routes */
  451.     /* and their neighbors.  create destination subpackets and append */
  452.     /* them to the header */
  453.     for(i = 0; i < NRNUMCHAINS; i++){
  454.         for(rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next){
  455.             /* look for best, non-obsolescent route */
  456.             if((bp = find_best(rp->routes,0)) == NULLNRBIND)
  457.                 continue;   /* no non-obsolescent routes found */
  458.   
  459.             if(bp->quality == 0)    /* this is a loopback route */
  460.                 continue;           /* we never broadcast these */
  461.   
  462.             if (bp->quality < ifp->nr_autofloor) /* below threshhold route */
  463.                 continue ;      /* so don't broadcast it */
  464.   
  465.             if (nr_aliasck(rp->alias))  /* corrupted alias entry? */
  466.                 continue ;      /* don't rebroadcast it */
  467.                             /* safety measure! */
  468.             np = bp->via;
  469.             /* insert best neighbor */
  470.             memcpy(nrdest.neighbor,np->call,AXALEN);
  471.             /* insert destination from route table */
  472.             memcpy(nrdest.dest,rp->call,AXALEN);
  473.             /* insert alias from route table */
  474.             strcpy(nrdest.alias,rp->alias);
  475.             /* insert quality from binding */
  476.             nrdest.quality = bp->quality;
  477.             /* create a network format destination subpacket */
  478.             if((dbp = htonnrdest(&nrdest)) == NULLBUF){
  479.                 free_p(hbp);    /* drop the whole idea ... */
  480.                 free_p(savehdr);
  481.                 return;
  482.             }
  483.             /* we now have a partially filled packet */
  484.             didsend = 0;
  485.             append(&hbp,dbp);   /* append to header and others */
  486.             /* see if we have appended as many destinations
  487.              * as we can fit into a single broadcast.  If we
  488.              * have, go ahead and send them out.
  489.              */
  490.             if(++numdest == NRDESTPERPACK){ /* filled it up */
  491.                 /* indicate that we did broadcast */
  492.                 didsend = 1;
  493.                 /* reset the destination counter */
  494.                 numdest = 0;
  495.                 (*ifp->output)(ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr,
  496.                 PID_NETROM,hbp);   /* send it */
  497.                 /* new header */
  498.                 hbp = copy_p(savehdr,NR3NODEHL);
  499.             }
  500.         }
  501.     }
  502.   
  503.     /* If we have a partly filled packet left over, or we never */
  504.     /* sent one at all, we broadcast: */
  505.   
  506.     if(!didsend || numdest > 0) {
  507.         (*ifp->output)(ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr,PID_NETROM, hbp);
  508.     } else {
  509.         if(numdest == 0)    /* free the header copies */
  510.             free_p(hbp);
  511.     }
  512.   
  513.     free_p(savehdr);
  514. }
  515.   
  516. /* Perform a nodes broadcast poll on interface ifp
  517.  * in the net/rom interface table. - WG7J
  518.  */
  519. void
  520. nr_bcpoll(ifp)
  521. struct iface *ifp;
  522. {
  523.     struct mbuf *hbp;
  524.   
  525.     /* prepare the header */
  526.     if((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  527.         return;
  528.     hbp->cnt = NR3NODEHL;
  529.     *hbp->data = NR3POLLSIG;
  530.     memcpy(hbp->data+1,Nralias,ALEN);
  531.   
  532.     /* send it out */
  533.     (*ifp->output)(ifp, Ax25multi[1],Nr_iface->hwaddr,PID_NETROM, hbp);
  534.     return;
  535. }
  536.   
  537. extern struct timer Nodetimer,Obsotimer;
  538. extern void donodetick __ARGS((void)),doobsotick __ARGS((void));
  539. int nr_stop(struct iface *);
  540.   
  541. int nr_stop(struct iface *iftmp) {
  542.   
  543.     /*make sure that the netrom interface is properly detached
  544.      *fixed 11/15/91, Johan. K. Reinalda, WG7J/PA3DIS
  545.      */
  546.     for(iftmp=Ifaces;iftmp;iftmp=iftmp->next)
  547.         iftmp->flags &= ~IS_NR_IFACE; /* this 'resets' active interfaces */
  548.     Nr_iface = NULLIF;
  549.     return 0;
  550. }
  551.   
  552. /* attach the net/rom interface.  no parms for now. */
  553. int
  554. nr_attach(argc,argv,p)
  555. int argc;
  556. char *argv[];
  557. void *p;
  558. {
  559.     if(Nr_iface != (struct iface *)0){
  560.         tputs("netrom interface already attached\n");
  561.         return -1;
  562.     }
  563.   
  564.     Nr_iface = (struct iface *)callocw(1,sizeof(struct iface));
  565.     Nr_iface->addr = Ip_addr;
  566.   
  567.     /* The strdup is needed to keep the detach routine happy (it'll
  568.      * free the allocated memory)
  569.      */
  570.     Nr_iface->name = strdup("netrom");
  571.     if(Nr_iface->hwaddr == NULLCHAR){
  572.         Nr_iface->hwaddr = mallocw(AXALEN);
  573.         memcpy(Nr_iface->hwaddr,Mycall,AXALEN);
  574.     }
  575.     Nr_iface->stop = nr_stop;
  576.     Nr_iface->mtu = NR4MAXINFO;
  577.     setencap(Nr_iface,"NETROM");
  578.     Nr_iface->next = Ifaces;
  579.     Ifaces = Nr_iface;
  580.     memcpy(Nr4user,Mycall,AXALEN);
  581.   
  582.     /*Added some default settings for node-broadcast interval and
  583.      *obsolescence timers.
  584.      *11/21/91 WG7J/PA3DIS
  585.      */
  586.     stop_timer(&Nodetimer);
  587.     Nodetimer.func = (void (*)__ARGS((void*)))donodetick;/* what to call on timeout */
  588.     Nodetimer.arg = NULLCHAR;       /* dummy value */
  589.     set_timer(&Nodetimer,1800000L);  /* 'standard netrom' 30 minutes*/
  590.     start_timer(&Nodetimer);        /* and fire it up */
  591.   
  592.     stop_timer(&Obsotimer);
  593.     Obsotimer.func = (void (*)__ARGS((void*)))doobsotick;/* what to call on timeout */
  594.     Obsotimer.arg = NULLCHAR;       /* dummy value */
  595.     set_timer(&Obsotimer,2100000L);  /* 35 minutes */
  596.     start_timer(&Obsotimer);        /* and fire it up */
  597.   
  598.     return 0;
  599. }
  600.   
  601. /* This function checks an ax.25 address and interface number against
  602.  * the filter table and mode, and returns -1 if the address is to be accepted
  603.  * verbatim, the quality if filtered in or 0 if it is to be filtered out.
  604.  */
  605. static int
  606. accept_bc(addr,ifp)
  607. char *addr;
  608. struct iface *ifp;
  609. {
  610.     struct nrnf_tab *fp;
  611.   
  612.     if(Nr_nfmode == NRNF_NOFILTER)      /* no filtering in effect */
  613.         return -1;
  614.   
  615.     fp = find_nrnf(addr,ifp);     /* look it up */
  616.   
  617.     if (fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
  618.         return fp->quality ;
  619.   
  620.     if (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT)
  621.         return -1;
  622.   
  623.     if (Nr_promisc)
  624.         return -1;      /* Come up and see me sometime..... */
  625.     else
  626.         return 0 ;      /* My mummy said not to listen to strangers! */
  627. }
  628.   
  629. struct targ {
  630.     struct iface *iface;
  631.     struct timer *t;
  632. };
  633.   
  634. void nr_poll_resp(struct targ *targ) {
  635.   
  636.     nr_bcnodes(targ->iface);
  637.     free(targ->t);
  638.     free(targ);
  639. }
  640.   
  641. void nr_poll_respond(struct iface *iface) {
  642.   
  643.     struct timer *t;
  644.     struct targ *targ;
  645.   
  646.     /* Set the random delay timer */
  647.     t = mallocw(sizeof(struct timer));
  648.     targ = mallocw(sizeof(struct targ));
  649.   
  650.     /* Set the arguments */
  651.     targ->iface = iface;
  652.     targ->t = t;
  653.     t->func = (void (*)())nr_poll_resp;
  654.     t->arg = targ;
  655.   
  656.     set_timer(t,random(30000) + 1);
  657.     start_timer(t);
  658.   
  659. }
  660.   
  661. /* receive and process node broadcasts. */
  662. void
  663. nr_nodercv(iface,source,bp)
  664. struct iface *iface;
  665. char *source;
  666. struct mbuf *bp;
  667. {
  668.     char bcalias[AXALEN];
  669.     struct nr3dest ds;
  670.     int qual,poll;
  671.     unsigned char c;
  672.     struct timer t;
  673.   
  674.     /* First, see if this is even a net/rom interface: */
  675.     if(!(iface->flags & IS_NR_IFACE)){
  676.         free_p(bp);
  677.         return;
  678.     }
  679.   
  680.     if ((qual = accept_bc(source,iface)) == 0) {    /* check against filter */
  681.         free_p(bp) ;                /* and get quality */
  682.         return ;
  683.     }
  684.   
  685.     c = PULLCHAR(&bp);
  686.     /* is this a route update poll from a neigbour ? - WG7J */
  687.     poll = 0;
  688.     if(c == NR3POLLSIG) {
  689.         poll = 1;
  690.         nr_poll_respond(iface);
  691.     } else if(c != NR3NODESIG) {
  692.         free_p(bp);
  693.         return;
  694.     }
  695.   
  696.     /* now try to get the alias */
  697.     if(pullup(&bp,bcalias,ALEN) < ALEN){
  698.         free_p(bp);
  699.         return;
  700.     }
  701.   
  702.     /* now check that the alias field is not corrupted - saftey measure! */
  703.     if (nr_aliasck(bcalias)) {
  704.         free_p(bp);
  705.         return;
  706.     }
  707.   
  708.     bcalias[ALEN] = '\0';       /* null terminate */
  709.   
  710. #ifdef NR_BC_RESPOND
  711.     /* If we were polled, we've already sent the routes list - WG7J */
  712.     if(!poll && (find_nrnbr(source,iface) == NULLNTAB)) /* a new node ! */
  713.         nr_poll_respond(iface);
  714. #endif
  715.   
  716.     /* enter the neighbor into our routing table */
  717.     if(qual == -1)
  718.         qual = iface->quality; /* use default quality */
  719.   
  720.     if(nr_routeadd(bcalias, source, iface, qual, source, 0, 0) == -1){
  721.         free_p(bp);
  722.         return;
  723.     }
  724.   
  725.     /* we've digested the header; now digest the actual */
  726.     /* routing information */
  727.     while(ntohnrdest(&ds,&bp) != -1){
  728.   
  729.         /* ignore routes to me! */
  730.         if(addreq(Nr_iface->hwaddr,ds.dest))
  731.             continue;
  732.   
  733.         /* ignore routes with corrupted aliases - safety measure */
  734.         if (nr_aliasck (ds.alias))
  735.             continue;
  736.   
  737.         /* ignore loopback paths to ourselves */
  738.         if(addreq(Nr_iface->hwaddr,ds.neighbor))
  739.             continue;
  740.         else
  741.             ds.quality = ((ds.quality * qual + 128) / 256) & 0xff;
  742.   
  743.         /* ignore routes below the minimum quality threshhold */
  744.         if(ds.quality < Nr_autofloor)
  745.             continue;
  746.   
  747.         if(nr_routeadd(ds.alias,ds.dest,iface,ds.quality,source,0,0)
  748.             == -1)
  749.             break;
  750.     }
  751.     free_p(bp); /* This will free the mbuf if anything fails above */
  752. }
  753.   
  754.   
  755. /* The following are utilities for manipulating the routing table */
  756.   
  757. /* hash function for callsigns.  Look familiar? */
  758. int16
  759. nrhash(s)
  760. char *s;
  761. {
  762.     register char x;
  763.     register int i;
  764.   
  765.     x = 0;
  766.     for(i = ALEN; i !=0; i--)
  767.         x ^= *s++ & 0xfe;
  768.     x ^= *s & SSID;
  769.     return (int16)(uchar(x) % NRNUMCHAINS);
  770. }
  771.   
  772. /* Find a neighbor table entry.  Neighbors are determined by
  773.  * their callsign and the interface number.  This takes care
  774.  * of the case where the same switch or hosts uses the same
  775.  * callsign on two different channels.  This isn't done by
  776.  * net/rom, but it might be done by stations running *our*
  777.  * software.
  778.  */
  779. struct nrnbr_tab *
  780. find_nrnbr(addr,ifp)
  781. register char *addr;
  782. struct iface *ifp;
  783. {
  784.     int16 hashval;
  785.     register struct nrnbr_tab *np;
  786.   
  787.     /* Find appropriate hash chain */
  788.     hashval = nrhash(addr);
  789.   
  790.     /* search hash chain */
  791.     for(np = Nrnbr_tab[hashval]; np != NULLNTAB; np = np->next){
  792.         /* convert first in  list to ax25 address format */
  793.         if(addreq(np->call,addr) && np->iface == ifp){
  794.             return np;
  795.         }
  796.     }
  797.     return NULLNTAB;
  798. }
  799.   
  800. /* Try to find the AX.25 address of a node with the given call or alias.
  801.  * Return a pointer to the route if found, otherwize NULLNRRTAB.
  802.  * alias should be a six character, blank-padded, upper-case string.
  803.  * call should be a upper-case string.
  804.  * 12-21-91, WG7J
  805.  */
  806.   
  807. struct nrroute_tab *
  808. find_nrboth(alias,call)
  809. char *alias;
  810. char *call;
  811. {
  812.     int i;
  813.     register struct nrroute_tab *rp;
  814.     char tmp[AXBUF];
  815.   
  816.     /* Since the route entries are hashed by ax.25 address, we'll */
  817.     /* have to search all the chains */
  818.   
  819.     for(i = 0; i < NRNUMCHAINS; i++)
  820.         for(rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  821.             if( (strncmp(alias, rp->alias, 6) == 0) ||
  822.                 (strcmp(call,pax25(tmp,rp->call)) == 0) )
  823.                 return rp;
  824.   
  825.     /* If we get to here, we're out of luck */
  826.     return NULLNRRTAB;
  827. }
  828.   
  829. /* Find a route table entry */
  830. struct nrroute_tab *
  831. find_nrroute(addr)
  832. register char *addr;
  833. {
  834.     int16 hashval;
  835.     register struct nrroute_tab *rp;
  836.   
  837.     /* Find appropriate hash chain */
  838.     hashval = nrhash(addr);
  839.   
  840.     /* search hash chain */
  841.     for(rp = Nrroute_tab[hashval]; rp != NULLNRRTAB; rp = rp->next){
  842.         if(addreq(rp->call,addr)){
  843.             return rp;
  844.         }
  845.     }
  846.     return NULLNRRTAB;
  847. }
  848.   
  849. /* Try to find the AX.25 address of a node with the given alias.  Return */
  850. /* a pointer to the AX.25 address if found, otherwise NULLCHAR.  The alias */
  851. /* should be a six character, blank-padded, upper-case string. */
  852.   
  853. char *
  854. find_nralias(alias)
  855. char *alias;
  856. {
  857.     int i;
  858.     register struct nrroute_tab *rp;
  859.   
  860.     /* Since the route entries are hashed by ax.25 address, we'll */
  861.     /* have to search all the chains */
  862.   
  863.     for(i = 0; i < NRNUMCHAINS; i++)
  864.         for(rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  865.             if(strncmp(alias, rp->alias, 6) == 0)
  866.                 return rp->call;
  867.   
  868.     /* If we get to here, we're out of luck */
  869.   
  870.     return NULLCHAR;
  871. }
  872.   
  873.   
  874. /* Find a binding in a list by its neighbor structure's address */
  875. static struct nr_bind *
  876. find_binding(list,neighbor)
  877. struct nr_bind *list;
  878. register struct nrnbr_tab *neighbor;
  879. {
  880.     register struct nr_bind *bp;
  881.   
  882.     for(bp = list; bp != NULLNRBIND; bp = bp->next)
  883.         if(bp->via == neighbor)
  884.             return bp;
  885.   
  886.     return NULLNRBIND;
  887. }
  888.   
  889. /* Find the worst quality non-permanent binding in a list */
  890. static
  891. struct nr_bind *
  892. find_worst(list)
  893. struct nr_bind *list;
  894. {
  895.     register struct nr_bind *bp;
  896.     struct nr_bind *worst = NULLNRBIND;
  897.     unsigned minqual = 1000;    /* infinity */
  898.   
  899.     for(bp = list; bp != NULLNRBIND; bp = bp->next)
  900.         if(!(bp->flags & NRB_PERMANENT) && bp->quality < minqual){
  901.             worst = bp;
  902.             minqual = bp->quality;
  903.         }
  904.   
  905.     return worst;
  906. }
  907.   
  908. /* Find the binding for a given neighbour in a list of routes */
  909. struct nr_bind *
  910. find_bind(list,np)
  911. struct nr_bind *list;
  912. struct nrnbr_tab *np;
  913. {
  914.     struct nr_bind *bp;
  915.   
  916.     for(bp = list; bp != NULLNRBIND; bp = bp->next)
  917.         if(bp->via == np)
  918.             break;
  919.     return bp;
  920. }
  921.   
  922. /* Find the best binding of any sort in a list.  If obso is 1,
  923.  * include entries below the obsolescence threshhold in the
  924.  * search (used when this is called for routing broadcasts).
  925.  * If it is 0, routes below the threshhold are treated as
  926.  * though they don't exist.
  927.  */
  928. struct nr_bind *
  929. find_best(list,obso)
  930. struct nr_bind *list;
  931. unsigned obso;
  932. {
  933.     register struct nr_bind *bp;
  934.     struct nr_bind *best = NULLNRBIND;
  935.     int maxqual = -1;   /* negative infinity */
  936.   
  937.     for(bp = list; bp != NULLNRBIND; bp = bp->next)
  938.         if((int)bp->quality > maxqual)
  939.             if(obso || bp->obsocnt >= Obso_minbc){
  940.                 best = bp;
  941.                 maxqual = bp->quality;
  942.             }
  943.   
  944.     return best;
  945. }
  946.   
  947. /* Add a route to the net/rom routing table */
  948. int
  949. nr_routeadd(alias,dest,ifp,quality,neighbor,permanent,record)
  950. char *alias;        /* net/rom node alias, blank-padded and */
  951.             /* null-terminated */
  952. char *dest;     /* destination node callsign */
  953. struct iface *ifp;
  954. unsigned quality;   /* route quality */
  955. char *neighbor; /* neighbor node + 2 digis (max) in arp format */
  956. unsigned permanent; /* 1 if route is permanent (hand-entered) */
  957. unsigned record;    /* 1 if route is a "record route" */
  958. {
  959.     struct nrroute_tab *rp;
  960.     struct nr_bind *bp;
  961.     struct nrnbr_tab *np;
  962.     int16 rhash, nhash;
  963.   
  964.     /* See if a routing table entry exists for this destination */
  965.     if((rp = find_nrroute(dest)) == NULLNRRTAB){
  966.         rp = (struct nrroute_tab *)callocw(1,sizeof(struct nrroute_tab));
  967.         /* create a new route table entry */
  968.         strncpy(rp->alias,alias,6);
  969.         memcpy(rp->call,dest,AXALEN);
  970.         rhash = nrhash(dest);
  971.         rp->next = Nrroute_tab[rhash];
  972.         if(rp->next != NULLNRRTAB)
  973.             rp->next->prev = rp;
  974.         Nrroute_tab[rhash] = rp;    /* link at head of hash chain */
  975.     } else if(permanent || !strncmp(rp->alias,"##temp",6)) {
  976.         strncpy(rp->alias,alias,6); /* update the alias */
  977.     }
  978.   
  979.     /* See if an entry exists for this neighbor */
  980.     if((np = find_nrnbr(neighbor,ifp)) == NULLNTAB){
  981.         np = (struct nrnbr_tab *)callocw(1,sizeof(struct nrnbr_tab));
  982.         /* create a new neighbor entry */
  983.         memcpy(np->call,neighbor,AXALEN);
  984.         np->iface = ifp;
  985.         nhash = nrhash(neighbor);
  986.         np->next = Nrnbr_tab[nhash];
  987.         if(np->next != NULLNTAB)
  988.             np->next->prev = np;
  989.         Nrnbr_tab[nhash] = np;
  990.     } else if(permanent){       /* force this path to the neighbor */
  991.         memcpy(np->call,neighbor,AXALEN);
  992.     }
  993.   
  994.     /* See if there is a binding between the dest and neighbor */
  995.     if((bp = find_binding(rp->routes,np)) == NULLNRBIND){
  996.         bp = (struct nr_bind *)callocw(1,sizeof(struct nr_bind));
  997.         /* create a new binding and link it in */
  998.         bp->via = np;   /* goes via this neighbor */
  999.         bp->next = rp->routes;  /* link into binding chain */
  1000.         if(bp->next != NULLNRBIND)
  1001.             bp->next->prev = bp;
  1002.         rp->routes = bp;
  1003.         rp->num_routes++;   /* bump route count */
  1004.         np->refcnt++;       /* bump neighbor ref count */
  1005.         bp->quality = quality;
  1006.         bp->obsocnt = Obso_init;    /* use initial value */
  1007.         if(permanent)
  1008.             bp->flags |= NRB_PERMANENT;
  1009.         else if(record) /* notice permanent overrides record! */
  1010.             bp->flags |= NRB_RECORDED;
  1011.     } else {
  1012.         if(permanent){  /* permanent request trumps all */
  1013.             bp->quality = quality;
  1014.             bp->obsocnt = Obso_init;
  1015.             bp->flags |= NRB_PERMANENT;
  1016.             bp->flags &= ~NRB_RECORDED; /* perm is not recorded */
  1017.         } else if(!(bp->flags & NRB_PERMANENT)){    /* not permanent */
  1018.             if(record){ /* came from nr_route */
  1019.                 if(bp->flags & NRB_RECORDED){ /* no mod non-rec bindings */
  1020.                     bp->quality = quality;
  1021.                     bp->obsocnt = Obso_init; /* freshen recorded routes */
  1022.                 }
  1023.             } else {        /* came from a routing broadcast */
  1024.                 bp->quality = quality;
  1025.                 bp->obsocnt = Obso_init;
  1026.                 bp->flags &= ~NRB_RECORDED; /* no longer a recorded route */
  1027.             }
  1028.         }
  1029.     }
  1030.   
  1031.     /* Now, check to see if we have too many bindings, and drop */
  1032.     /* the worst if we do */
  1033.     if(rp->num_routes > Nr_maxroutes){
  1034.         /* since find_worst never returns permanent entries, the */
  1035.         /* limitation on number of routes is circumvented for    */
  1036.         /* permanent routes */
  1037.         if((bp = find_worst(rp->routes)) != NULLNRBIND){
  1038.             nr_routedrop(dest,bp->via->call,bp->via->iface);
  1039.         }
  1040.     }
  1041.   
  1042.     return 0;
  1043. }
  1044.   
  1045. /* Reset the netrom links to this neighbour, since the
  1046.  * route to it just expired - WG7J
  1047.  */
  1048. void
  1049. nrresetlinks(struct nrroute_tab *rp) {
  1050.     int i ;
  1051.     struct nr4cb *cb ;
  1052.   
  1053.     for(i = 0 ; i < NR4MAXCIRC ; i++)
  1054.         if((cb = Nr4circuits[i].ccb) != NULLNR4CB)
  1055.             if(!memcmp(cb->remote.node,rp->call,AXALEN))
  1056.                 reset_nr4(cb);
  1057. }
  1058.   
  1059. /* Drop a route to dest via neighbor */
  1060. int
  1061. nr_routedrop(dest,neighbor,ifp)
  1062. char *dest, *neighbor;
  1063. struct iface *ifp;
  1064. {
  1065.     register struct nrroute_tab *rp;
  1066.     register struct nrnbr_tab *np;
  1067.     register struct nr_bind *bp;
  1068.   
  1069.     if((rp = find_nrroute(dest)) == NULLNRRTAB)
  1070.         return -1;
  1071.   
  1072.     if((np = find_nrnbr(neighbor,ifp)) == NULLNTAB)
  1073.         return -1;
  1074.   
  1075.     if((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  1076.         return -1;
  1077.   
  1078.     /* drop the binding first */
  1079.     if(bp->next != NULLNRBIND)
  1080.         bp->next->prev = bp->prev;
  1081.     if(bp->prev != NULLNRBIND)
  1082.         bp->prev->next = bp->next;
  1083.     else
  1084.         rp->routes = bp->next;
  1085.   
  1086.     free((char *)bp);
  1087.     rp->num_routes--;       /* decrement the number of bindings */
  1088.     np->refcnt--;           /* and the number of neighbor references */
  1089.   
  1090.     /* now see if we should drop the route table entry */
  1091.     if(rp->num_routes == 0){
  1092.         if(rp->next != NULLNRRTAB)
  1093.             rp->next->prev = rp->prev;
  1094.         if(rp->prev != NULLNRRTAB)
  1095.             rp->prev->next = rp->next;
  1096.         else
  1097.             Nrroute_tab[nrhash(dest)] = rp->next;
  1098.         /* No more routes left !
  1099.          * We should close/reset any netrom connections
  1100.          * still idling for this route ! - WG7J
  1101.          */
  1102.         nrresetlinks(rp);
  1103.   
  1104.         free((char *)rp);
  1105.     }
  1106.   
  1107.     /* and check to see if this neighbor can be dropped */
  1108.     if(np->refcnt == 0){
  1109.         if(np->next != NULLNTAB)
  1110.             np->next->prev = np->prev;
  1111.         if(np->prev != NULLNTAB)
  1112.             np->prev->next = np->next;
  1113.         else
  1114.             Nrnbr_tab[nrhash(neighbor)] = np->next;
  1115.   
  1116.         free((char *)np);
  1117.     }
  1118.   
  1119.     return 0;
  1120. }
  1121.   
  1122. /* Find an entry in the filter table */
  1123. static struct nrnf_tab *
  1124. find_nrnf(addr,ifp)
  1125. register char *addr;
  1126. struct iface *ifp;
  1127. {
  1128.     int16 hashval;
  1129.     register struct nrnf_tab *fp;
  1130.   
  1131.     /* Find appropriate hash chain */
  1132.     hashval = nrhash(addr);
  1133.   
  1134.     /* search hash chain */
  1135.     for(fp = Nrnf_tab[hashval]; fp != NULLNRNFTAB; fp = fp->next){
  1136.         if(addreq(fp->neighbor,addr) && (fp->iface == ifp)){
  1137.             return fp;
  1138.         }
  1139.     }
  1140.   
  1141.     return NULLNRNFTAB;
  1142. }
  1143.   
  1144. /* Add an entry to the filter table.  Return 0 on success,
  1145.  * -1 on failure
  1146.  */
  1147. int
  1148. nr_nfadd(addr,ifp,qual)
  1149. char *addr;
  1150. struct iface *ifp;
  1151. unsigned qual;
  1152. {
  1153.     struct nrnf_tab *fp;
  1154.     int16 hashval;
  1155.   
  1156.     if(find_nrnf(addr,ifp) != NULLNRNFTAB)
  1157.         return 0;   /* already there; it's a no-op */
  1158.   
  1159.     fp = (struct nrnf_tab *)callocw(1,sizeof(struct nrnf_tab));
  1160.   
  1161.     hashval = nrhash(addr);
  1162.     memcpy(fp->neighbor,addr,AXALEN);
  1163.     fp->iface = ifp;
  1164.     fp->next = Nrnf_tab[hashval];
  1165.     fp->quality = qual;
  1166.     if(fp->next != NULLNRNFTAB)
  1167.         fp->next->prev = fp;
  1168.     Nrnf_tab[hashval] = fp;
  1169.   
  1170.     return 0;
  1171. }
  1172.   
  1173. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  1174.  * on failure.
  1175.  */
  1176. int
  1177. nr_nfdrop(addr,ifp)
  1178. char *addr;
  1179. struct iface *ifp;
  1180. {
  1181.     struct nrnf_tab *fp;
  1182.   
  1183.     if((fp = find_nrnf(addr,ifp)) == NULLNRNFTAB)
  1184.         return -1;  /* not in the table */
  1185.   
  1186.     if(fp->next != NULLNRNFTAB)
  1187.         fp->next->prev = fp->prev;
  1188.     if(fp->prev != NULLNRNFTAB)
  1189.         fp->prev->next = fp->next;
  1190.     else
  1191.         Nrnf_tab[nrhash(addr)] = fp->next;
  1192.   
  1193.     free((char *)fp);
  1194.   
  1195.     return 0;
  1196. }
  1197.   
  1198. /*
  1199.  * Validate the alias field is good quality ascii to prevent network corruption
  1200.  */
  1201.   
  1202. static int
  1203. nr_aliasck(alias)
  1204. char *alias;
  1205. {
  1206.     int x = ALEN;
  1207.     int c;
  1208.     while (x--) {
  1209.         c = *alias++;
  1210.         if (!isprint( (int) c) )
  1211.             return 1;
  1212.     }
  1213.     return 0;
  1214. }
  1215.   
  1216. /* called from lapb whenever a link failure implies that a particular ax25
  1217.  * path may not be able to carry netrom traffic too well. Experimental!!!!
  1218.  */
  1219. void nr_derate(axp)
  1220. struct ax25_cb *axp;
  1221. {
  1222.     register struct nrnbr_tab *np ;
  1223.     register struct nrroute_tab *rp;
  1224.     register struct nr_bind *bp;
  1225.     struct mbuf *buf;
  1226.     int i;
  1227.     int nr_traffic = 0; /* assume no netrom traffic on connection */
  1228.   
  1229.     if(!Nr_derate)
  1230.         return;     /* derating function is disabled */
  1231.   
  1232.     /* is this an active netrom interface ? */
  1233.     if (!(axp->iface->flags & IS_NR_IFACE))
  1234.         return ;
  1235.   
  1236.     if (axp == NULLAX25)
  1237.         return;         /* abandon ship! */
  1238.   
  1239.     /* If it is valid for netrom traffic, lets see if there is */
  1240.     /* really netrom traffic on the connection to be derated.  */
  1241.     for (buf = axp->txq; buf != NULLBUF; buf = buf->anext)
  1242.         if ((buf->data[0] & 0xff) == PID_NETROM)
  1243.             nr_traffic = 1;     /* aha - netrom traffic! */
  1244.   
  1245.     if (!nr_traffic)
  1246.         return;     /* no sign of being used by netrom just now */
  1247.   
  1248.     /* we now have the appropriate interface entry */
  1249.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  1250.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  1251.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  1252.                 np = bp->via;
  1253.                 if(bp->quality >= 1 && np->iface == axp->iface &&
  1254.                     !(bp->flags & NRB_PERMANENT) &&
  1255.                     !memcmp(np->call,axp->remote,ALEN) &&
  1256.                 (np->call[6] & SSID) == (axp->remote[6] & SSID)) {
  1257.                     bp->quality = ((bp->quality * 2) / 3);
  1258.                 }
  1259.             }
  1260.         }
  1261.     }
  1262. }
  1263.   
  1264. #endif /* NETROM */
  1265.   
  1266.