Category : Network Files
Archive   : KA9Q.ZIP
Filename : NR3.C

 
Output of file : NR3.C contained in archive : KA9Q.ZIP
/* net/rom level 3 low level processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/

#include
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "lapb.h"
#include

/* Nodes message broadcast address: "NODES" in shifted ASCII */
struct ax25_addr nr_nodebc = {
'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
('0'<<1) | E
} ;

struct nriface nrifaces[NRNUMIFACE] ;
unsigned nr_numiface ;
struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
unsigned nr_nfmode = NRNF_NOFILTER ;
unsigned nr_ttl = 64 ;
unsigned obso_init = 6 ;
unsigned obso_minbc = 5 ;
unsigned nr_maxroutes = 5 ;
unsigned nr_autofloor = 1 ;
unsigned nr_verbose = 0 ;
struct interface *nr_interface ;

/* send a NET/ROM layer 3 datagram */
void nr3output(dest, data)
struct ax25_addr *dest ;
struct mbuf *data ;
{
struct nr3hdr n3hdr ;
struct mbuf *n3b ;

n3hdr.dest = *dest ; /* copy destination field */
n3hdr.ttl = nr_ttl ; /* time to live from initializer parm */

if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
free_p(data) ;
return ;
}

append(&n3b, data) ;

/* The null interface indicates that the packet needs to have */
/* an appropriate source address inserted by nr_route */

nr_route(n3b,NULLAX25) ;
}


/* send IP datagrams across a net/rom network connection */
int
nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp ;
struct interface *interface ;
int32 gateway ;
char precedence ;
char delay ;
char throughput ;
char reliability ;
{
struct ax25_addr dest ;
struct mbuf *pbp ;
struct nr4hdr n4hdr ;
char *hwaddr ;
struct arp_tab *arp ;

if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
free_p(bp) ; /* drop the packet if no route */
return ;
}
hwaddr = arp->hw_addr ; /* points to destination */
memcpy(dest.call, hwaddr, ALEN) ;
dest.ssid = hwaddr[ALEN] ;

/* Create a "network extension" transport header */
n4hdr.opcode = NR4OPPID ;
n4hdr.u.pid.family = PID_IP ;
n4hdr.u.pid.proto = PID_IP ;

if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
free_p(bp) ;
return ;
}

append(&pbp,bp) ; /* Append the data to that */
nr3output(&dest, pbp) ; /* and pass off to level 3 code */

}

/* Figure out if a call is assigned to one of my net/rom
* interfaces.
*/
static int
ismycall(addr)
struct ax25_addr *addr ;
{
register int i ;
int found = 0 ;

for (i = 0 ; i < nr_numiface ; i++)
if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
addr)) {
found = 1 ;
break ;
}

return found ;
}


/* Route net/rom network layer packets.
*/
nr_route(bp, iaxp)
struct mbuf *bp ; /* network packet */
struct ax25_cb *iaxp ; /* incoming ax25 control block */
{
struct nr3hdr n3hdr ;
struct nr4hdr n4hdr ;
struct ax25_cb *axp, *find_ax25(), *open_ax25() ;
struct ax25 naxhdr ;
struct ax25_addr neighbor, from ;
struct mbuf *hbp, *pbp ;
extern int16 axwindow ;
void ax_incom() ;
register struct nrnbr_tab *np ;
register struct nrroute_tab *rp ;
register struct nr_bind *bindp ;
struct nr_bind *find_best() ;
struct interface *interface ;
unsigned ifnum ;

if (ntohnr3(&n3hdr,&bp) == -1) {
free_p(bp) ;
return ;
}

/* If this isn't an internally generated network packet,
* give the router a chance to record a route back to the
* sender, in case they aren't in the local node's routing
* table yet.
*/

if (iaxp != NULLAX25) {
/* find the interface number */
for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
if (iaxp->interface == nrifaces[ifnum].interface)
break ;

if (ifnum == nr_numiface) { /* shouldn't happen! */
free_p(bp) ;
return ;
}

from = iaxp->addr.dest ;
from.ssid |= E ;

/* Add (possibly) a zero-quality recorded route via */
/* the neighbor from which this packet was received */
/* Note that this doesn't work with digipeated neighbors, */
/* at this point. */

(void) nr_routeadd(" ",&n3hdr.source,ifnum,0,
(char *)&from,0,1) ;
}

/* A packet from me, to me, can only be one thing: */
/* a horrible routing loop. This will probably result */
/* from a bad manual ARP entry, but we should fix these */
/* obscure errors as we find them. */

if (ismycall(&n3hdr.dest)) {
if (iaxp == NULLAX25) { /* From me? */
free_p(bp) ;
return ;
} else { /* It's from somewhere else! */
if (ntohnr4(&n4hdr,&bp) == -1) {
free_p(bp) ;
return ;
}
if ((n4hdr.opcode & NR4OPCODE) == 0) {
if (n4hdr.u.pid.family == PID_IP
&& n4hdr.u.pid.proto == PID_IP)
ip_route(bp,0) ;
else /* we don't do this proto */
free_p(bp) ;

return ;
}

/* Must be net/rom transport: */

nr4input(&n4hdr,bp) ;

}
return ;
}

if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
/* no route, drop the packet */
free_p(bp) ;
return ;
}

if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
/* This shouldn't happen yet, but might if we add */
/* dead route detection */
free_p(bp) ;
return ;
}

np = bindp->via ;
memcpy(neighbor.call,np->call,ALEN) ;
neighbor.ssid = np->call[ALEN] ;
interface = nrifaces[np->interface].interface ;

/* Now check to see if iaxp is null. That is */
/* a signal that the packet originates here, */
/* so we need to insert the callsign of the appropriate */
/* interface */
if (iaxp == NULLAX25)
memcpy(&n3hdr.source,interface->hwaddr,AXALEN) ;

/* Make sure there is a connection to the neighbor */
if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
(axp->state != CONNECTED && axp->state != RECOVERY)) {
/* Open a new connection or reinitialize old one */
/* hwaddr has been advanced to point to neighbor + digis */
atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
axp = open_ax25(&naxhdr, axwindow, ax_incom, NULLVFP, NULLVFP,
interface,(char *)0) ;
if (axp == NULLAX25) {
free_p(bp) ;
return ;
}
}

if (--n3hdr.ttl == 0) { /* the packet's time to live is over! */
free_p(bp) ;
return ;
}

/* allocate and fill PID mbuf */
if ((pbp = alloc_mbuf(1)) == NULLBUF) {
free_p(bp) ;
return ;
}
pbp->cnt = 1 ;
*pbp->data = (PID_FIRST | PID_LAST | PID_NETROM) ;

/* now format network header */
if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
free_p(pbp) ;
free_p(bp) ;
return ;
}

append(&pbp,hbp) ; /* append header to pid */
append(&pbp,bp) ; /* append data to header */
send_ax25(axp,pbp) ; /* pass it off to ax25 code */
}


/* Perform a nodes broadcast on interface # ifno in the net/rom
* interface table.
*/

nr_bcnodes(ifno)
unsigned ifno ;
{
struct mbuf *hbp, *dbp, *savehdr ;
struct nrroute_tab *rp ;
struct nrnbr_tab *np ;
struct nr_bind * bp ;
struct nr3dest nrdest ;
int i, didsend = 0, numdest = 0 ;
register char *cp ;
struct interface *axif = nrifaces[ifno].interface ;
struct nr_bind *find_best() ;

/* prepare the header */
if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
return ;

hbp->cnt = NR3NODEHL ;

*hbp->data = NR3NODESIG ;
memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;

/* Some people don't want to advertise any routes; they
* just want to be a terminal node. In that case we just
* want to send our call and alias and be done with it.
*/

if (!nr_verbose) {
(*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
(PID_FIRST | PID_LAST | PID_NETROM),
hbp) ; /* send it */
return ;
}

/* make a copy of the header in case we need to send more than */
/* one packet */
savehdr = copy_p(hbp,NR3NODEHL) ;

/* now scan through the routing table, finding the best routes */
/* and their neighbors. create destination subpackets and append */
/* them to the header */
for (i = 0 ; i < NRNUMCHAINS ; i++) {
for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
/* look for best, non-obsolescent route */
if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
continue ; /* no non-obsolescent routes found */
if (bp->quality == 0) /* this is a loopback route */
continue ; /* we never broadcast these */
np = bp->via ;
/* insert best neighbor */
memcpy(nrdest.neighbor.call,np->call,ALEN) ;
nrdest.neighbor.ssid = np->call[ALEN] ;
/* insert destination from route table */
nrdest.dest = rp->call ;
/* insert alias from route table */
strcpy(nrdest.alias,rp->alias) ;
/* insert quality from binding */
nrdest.quality = bp->quality ;
/* create a network format destination subpacket */
if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
free_p(hbp) ; /* drop the whole idea ... */
free_p(savehdr) ;
return ;
}
append(&hbp,dbp) ; /* append to header and others */
/* see if we have appended as many destinations */
/* as we can fit into a single broadcast. If we */
/* have, go ahead and send them out. */
if (++numdest == NRDESTPERPACK) { /* filled it up */
didsend = 1 ; /* indicate that we did broadcast */
numdest = 0 ; /* reset the destination counter */
(*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
(PID_FIRST | PID_LAST | PID_NETROM),
hbp) ; /* send it */
hbp = copy_p(savehdr,NR3NODEHL) ; /* new header */
}
}
}

/* Now, here is something totally weird. If our interfaces */
/* have different callsigns than this one, advertise a very */
/* high quality route to them. Is this a good idea? I don't */
/* know. However, it allows us to simulate a bunch of net/roms */
/* hooked together with a diode matrix coupler. */
for (i = 0 ; i < nr_numiface ; i++) {
if (i == ifno)
continue ; /* don't bother with ours */
cp = nrifaces[i].interface->hwaddr ;
if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
/* both destination and neighbor address */
memcpy(&nrdest.dest,cp,AXALEN) ;
memcpy(&nrdest.neighbor,cp,AXALEN) ;
/* alias of the interface */
strcpy(nrdest.alias,nrifaces[i].alias) ;
/* and the very highest quality */
nrdest.quality = 255 ;
/* create a network format destination subpacket */
if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
free_p(hbp) ; /* drop the whole idea ... */
free_p(savehdr) ;
return ;
}
append(&hbp,dbp) ; /* append to header and others */
if (++numdest == NRDESTPERPACK) { /* filled it up */
didsend = 1 ; /* indicate that we did broadcast */
numdest = 0 ; /* reset the destination counter */
(*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
(PID_FIRST | PID_LAST | PID_NETROM),
hbp) ; /* send it */
hbp = copy_p(savehdr,NR3NODEHL) ; /* new header */
}
}
}

/* If we have a partly filled packet left over, or we never */
/* sent one at all, we broadcast: */
if (!didsend || numdest > 0)
(*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
(PID_FIRST | PID_LAST | PID_NETROM), hbp) ;

free_p(savehdr) ; /* free the header copy */
}


/* initialize fake arp entry for netrom */
nr3arp()
{
int psax25(), setpath() ;

arp_init(ARP_NETROM,AXALEN,0,0,NULLCHAR,psax25,setpath) ;
}

/* attach the net/rom interface. no parms for now. */
nr_attach(argc,argv)
int argc ;
char *argv[] ;
{
if (nr_interface != (struct interface *)0) {
printf("netrom interface already attached\n") ;
return -1 ;
}

nr3arp() ;

nr_interface = (struct interface *)calloc(1,sizeof(struct interface)) ;
nr_interface->name = "netrom" ;
nr_interface->mtu = NR4MAXINFO ;
nr_interface->send = nr_send ;
nr_interface->next = ifaces ;
ifaces = nr_interface ;
return 0 ;
}

/* This function checks an ax.25 address and interface number against
* the filter table and mode, and returns 1 if the address is to be
* accepted, and 0 if it is to be filtered out.
*/
static int
accept_bc(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;

if (nr_nfmode == NRNF_NOFILTER) /* no filtering in effect */
return 1 ;

fp = find_nrnf(addr,ifnum) ; /* look it up */

if ((fp != NULLNRNFTAB && nr_nfmode == NRNF_ACCEPT)
|| (fp == NULLNRNFTAB && nr_nfmode == NRNF_REJECT))
return 1 ;
else
return 0 ;
}


/* receive and process node broadcasts. */
nr_nodercv(interface,source,bp)
struct interface *interface ;
struct ax25_addr *source ;
struct mbuf *bp ;
{
register int ifnum ;
char bcalias[7] ;
char buf[16] ;
struct nr3dest ds ;
char sbuf[AXALEN*3] ;

/* First, see if this is even a net/rom interface: */
for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
if (interface == nrifaces[ifnum].interface)
break ;

if (ifnum == nr_numiface) { /* not in the interface table */
free_p(bp) ;
return ;
}

if (!accept_bc(source,ifnum)) { /* check against filter */
free_p(bp) ;
return ;

}

/* See if it has a routing broadcast signature: */
if (uchar(pullchar(&bp)) != NR3NODESIG) {
free_p(bp) ;
return ;
}

/* now try to get the alias */
if (pullup(&bp,bcalias,ALEN) < ALEN) {
free_p(bp) ;
return ;
}

bcalias[ALEN] = '\0' ; /* null terminate */

/* copy source address and convert to arp format */
memcpy(sbuf,source->call,ALEN) ;
sbuf[ALEN] = (source->ssid | E) ; /* terminate */

/* enter the neighbor into our routing table */
if (nr_routeadd(bcalias,source,ifnum,nrifaces[ifnum].quality,
sbuf, 0, 0) == -1) {
free_p(bp) ;
return ;
}

/* we've digested the header; now digest the actual */
/* routing information */
while (ntohnrdest(&ds,&bp) != -1) {
/* ignore routes to me! */
if (ismycall(&ds.dest))
continue ;
/* ignore routes below the minimum quality threshhold */
if (ds.quality < nr_autofloor)
continue ;
/* set loopback paths to 0 quality */
if (ismycall(&ds.neighbor))
ds.quality = 0 ;
else
ds.quality = ((ds.quality * nrifaces[ifnum].quality + 128)
/ 256) & 0xff ;
if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
== -1)
break ;
}

free_p(bp) ; /* This will free the mbuf if anything fails above */
}


/* The following are utilities for manipulating the routing table */

/* hash function for callsigns. Look familiar? */
int16
nrhash(s)
struct ax25_addr *s ;
{
register char x ;
register int i ;
register char *cp ;

x = 0 ;
cp = s->call ;
for (i = ALEN ; i !=0 ; i--)
x ^= *cp++ & 0xfe ;
x ^= s->ssid & SSID ;
return uchar(x) % NRNUMCHAINS ;
}

/* Find a neighbor table entry. Neighbors are determined by
* their callsign and the interface number. This takes care
* of the case where the same switch or hosts uses the same
* callsign on two different channels. This isn't done by
* net/rom, but it might be done by stations running *our*
* software.
*/
struct nrnbr_tab *
find_nrnbr(addr,ifnum)
register struct ax25_addr *addr ;
unsigned ifnum ;
{
int16 hashval ;
register struct nrnbr_tab *np ;
char i_state ;
struct ax25_addr ncall ;

/* Find appropriate hash chain */
hashval = nrhash(addr) ;

/* search hash chain */
i_state = disable() ;
for (np = nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
memcpy(ncall.call,np->call,ALEN) ; /* convert first in */
ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
if (addreq(&ncall,addr) && np->interface == ifnum) {
restore(i_state) ;
return np ;
}
}
restore(i_state) ;
return NULLNTAB ;
}


/* Find a route table entry */
struct nrroute_tab *
find_nrroute(addr)
register struct ax25_addr *addr ;
{
int16 hashval ;
register struct nrroute_tab *rp ;
char i_state ;

/* Find appropriate hash chain */
hashval = nrhash(addr) ;

/* search hash chain */
i_state = disable() ;
for (rp = nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
if (addreq(&rp->call,addr)) {
restore(i_state) ;
return rp ;
}
}
restore(i_state) ;
return NULLNRRTAB ;
}

/* Try to find the AX.25 address of a node with the given alias. Return */
/* a pointer to the AX.25 address if found, otherwise NULLAXADDR. The alias */
/* should be a six character, blank-padded, upper-case string. */

struct ax25_addr *
find_nralias(alias)
char *alias ;
{
int i ;
register struct nrroute_tab *rp ;

/* Since the route entries are hashed by ax.25 address, we'll */
/* have to search all the chains */

for (i = 0 ; i < NRNUMCHAINS ; i++)
for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
if (strncmp(alias, rp->alias, 6) == 0)
return &rp->call ;

/* If we get to here, we're out of luck */

return NULLAXADDR ;
}


/* Find a binding in a list by its neighbor structure's address */
struct nr_bind *
find_binding(list,neighbor)
struct nr_bind *list ;
register struct nrnbr_tab *neighbor ;
{
register struct nr_bind *bp ;

for(bp = list ; bp != NULLNRBIND ; bp = bp->next)

if (bp->via == neighbor)
return bp ;

return NULLNRBIND ;
}

/* Find the worst quality non-permanent binding in a list */
static
struct nr_bind *
find_worst(list)
struct nr_bind *list ;
{
register struct nr_bind *bp ;
struct nr_bind *worst = NULLNRBIND ;
unsigned minqual = 1000 ; /* infinity */

for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
worst = bp ;
minqual = bp->quality ;
}

return worst ;
}

/* Find the best binding of any sort in a list. If obso is 1,
* include entries below the obsolescence threshhold in the
* search (used when this is called for routing broadcasts).
* If it is 0, routes below the threshhold are treated as
* though they don't exist.
*/
static
struct nr_bind *
find_best(list,obso)
struct nr_bind *list ;
unsigned obso ;
{
register struct nr_bind *bp ;
struct nr_bind *best = NULLNRBIND ;
int maxqual = -1 ; /* negative infinity */

for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
if ((int)bp->quality > maxqual)
if (obso || bp->obsocnt >= obso_minbc) {
best = bp ;
maxqual = bp->quality ;
}

return best ;
}

/* Add a route to the net/rom routing table */
nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
char *alias ; /* net/rom node alias, blank-padded and */
/* null-terminated */
struct ax25_addr *dest ; /* destination node callsign */
unsigned ifnum ; /* net/rom interface number */
unsigned quality ; /* route quality */
char *neighbor ; /* neighbor node + 2 digis (max) in arp format */
unsigned permanent ; /* 1 if route is permanent (hand-entered) */
unsigned record ; /* 1 if route is a "record route" */
{
struct nrroute_tab *rp ;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
int16 rhash, nhash ;
struct ax25_addr ncall ;

/* See if a routing table entry exists for this destination */
if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
if ((rp =
(struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
== NULLNRRTAB)
return -1 ;
else { /* create a new route table entry */
strncpy(rp->alias,alias,6) ;
rp->call = *dest ;
rhash = nrhash(dest) ;
rp->next = nrroute_tab[rhash] ;
if (rp->next != NULLNRRTAB)
rp->next->prev = rp ;
nrroute_tab[rhash] = rp ; /* link at head of hash chain */
}
} else if (!record) {
strncpy(rp->alias,alias,6) ; /* update the alias */
}

/* See if an entry exists for this neighbor */
memcpy(ncall.call,neighbor,ALEN) ; /* no digis included */
ncall.ssid = neighbor[ALEN] ;
if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
if ((np =
(struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
== NULLNTAB) {
if (rp->num_routes == 0) { /* we just added to table */
nrroute_tab[rhash] = rp->next ;
free(rp) ; /* so get rid of it */
}
return -1 ;
}
else { /* create a new neighbor entry */
memcpy(np->call,neighbor,3 * AXALEN) ;
np->interface = ifnum ;
nhash = nrhash(&ncall) ;
np->next = nrnbr_tab[nhash] ;
if (np->next != NULLNTAB)
np->next->prev = np ;
nrnbr_tab[nhash] = np ;
}
}
else if (permanent) { /* force this path to the neighbor */
memcpy(np->call,neighbor,3 * AXALEN) ;
}

/* See if there is a binding between the dest and neighbor */
if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
if ((bp =
(struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
== NULLNRBIND) {
if (rp->num_routes == 0) { /* we just added to table */
nrroute_tab[rhash] = rp->next ;
free(rp) ; /* so get rid of it */
}
if (np->refcnt == 0) { /* we just added it */
nrnbr_tab[nhash] = np->next ;
free(np) ;
}
return -1 ;
}
else { /* create a new binding and link it in */
bp->via = np ; /* goes via this neighbor */
bp->next = rp->routes ; /* link into binding chain */
if (bp->next != NULLNRBIND)
bp->next->prev = bp ;
rp->routes = bp ;
rp->num_routes++ ; /* bump route count */
np->refcnt++ ; /* bump neighbor ref count */
bp->quality = quality ;
bp->obsocnt = obso_init ; /* use initial value */
if (permanent)
bp->flags |= NRB_PERMANENT ;
else if (record) /* notice permanent overrides record! */
bp->flags |= NRB_RECORDED ;
}
} else {
if (permanent) { /* permanent request trumps all */
bp->quality = quality ;
bp->obsocnt = obso_init ;
bp->flags |= NRB_PERMANENT ;
bp->flags &= ~NRB_RECORDED ; /* perm is not recorded */
} else if (!(bp->flags & NRB_PERMANENT)) { /* not permanent */
if (record) { /* came from nr_route */
if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
bp->quality = quality ;
bp->obsocnt = obso_init ; /* freshen recorded routes */
}
} else { /* came from a routing broadcast */
bp->quality = quality ;
bp->obsocnt = obso_init ;
bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
}
}
}

/* Now, check to see if we have too many bindings, and drop */
/* the worst if we do */
if (rp->num_routes > nr_maxroutes) {
/* since find_worst never returns permanent entries, the */
/* limitation on number of routes is circumvented for */
/* permanent routes */
if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
memcpy(ncall.call,bp->via->call,ALEN) ;
ncall.ssid = bp->via->call[ALEN] ;
nr_routedrop(dest,&ncall,bp->via->interface) ;
}
}

return 0 ;
}


/* Drop a route to dest via neighbor */
nr_routedrop(dest,neighbor,ifnum)
struct ax25_addr *dest, *neighbor ;
unsigned ifnum ;
{
register struct nrroute_tab *rp ;
register struct nrnbr_tab *np ;
register struct nr_bind *bp ;

if ((rp = find_nrroute(dest)) == NULLNRRTAB)
return -1 ;

if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
return -1 ;

if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
return -1 ;

/* drop the binding first */
if (bp->next != NULLNRBIND)
bp->next->prev = bp->prev ;
if (bp->prev != NULLNRBIND)
bp->prev->next = bp->next ;
else
rp->routes = bp->next ;

free(bp) ;
rp->num_routes-- ; /* decrement the number of bindings */
np->refcnt-- ; /* and the number of neighbor references */

/* now see if we should drop the route table entry */
if (rp->num_routes == 0) {
if (rp->next != NULLNRRTAB)
rp->next->prev = rp->prev ;
if (rp->prev != NULLNRRTAB)
rp->prev->next = rp->next ;
else
nrroute_tab[nrhash(dest)] = rp->next ;

free(rp) ;
}

/* and check to see if this neighbor can be dropped */
if (np->refcnt == 0) {
if (np->next != NULLNTAB)
np->next->prev = np->prev ;
if (np->prev != NULLNTAB)
np->prev->next = np->next ;
else
nrnbr_tab[nrhash(neighbor)] = np->next ;

free(np) ;
}

return 0 ;
}

/* Find the best neighbor for destination dest, in arp format */
char *
nr_getroute(dest)
struct ax25_addr *dest ;
{
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;

if ((rp = find_nrroute(dest)) == NULLNRRTAB)
return NULLCHAR ;

if ((bp = find_best(rp->routes)) == NULLNRBIND) /* shouldn't happen! */
return NULLCHAR ;

return bp->via->call ;
}

/* Find an entry in the filter table */
struct nrnf_tab *
find_nrnf(addr,ifnum)
register struct ax25_addr *addr ;
unsigned ifnum ;
{
int16 hashval ;
register struct nrnf_tab *fp ;

/* Find appropriate hash chain */
hashval = nrhash(addr) ;

/* search hash chain */
for (fp = nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
if (addreq(&fp->neighbor,addr) && fp->interface == ifnum) {
return fp ;
}
}

return NULLNRNFTAB ;
}

/* Add an entry to the filter table. Return 0 on success,
* -1 on failure
*/
int
nr_nfadd(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;
int16 hashval ;

if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
return 0 ; /* already there; it's a no-op */

if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
== NULLNRNFTAB)
return -1 ; /* no storage */

hashval = nrhash(addr) ;
fp->neighbor = *addr ;
fp->interface = ifnum ;
fp->next = nrnf_tab[hashval] ;
if (fp->next != NULLNRNFTAB)
fp->next->prev = fp ;
nrnf_tab[hashval] = fp ;

return 0 ;
}

/* Drop a neighbor from the filter table. Returns 0 on success, -1
* on failure.
*/
int
nr_nfdrop(addr,ifnum)
struct ax25_addr *addr ;
unsigned ifnum ;
{
struct nrnf_tab *fp ;

if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
return -1 ; /* not in the table */

if (fp->next != NULLNRNFTAB)
fp->next->prev = fp->prev ;
if (fp->prev != NULLNRNFTAB)
fp->prev->next = fp->next ;
else
nrnf_tab[nrhash(addr)] = fp->next ;

free(fp) ;

return 0 ;
}


  3 Responses to “Category : Network Files
Archive   : KA9Q.ZIP
Filename : NR3.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/