?? nr3.c
字號:
/* net/rom level 3 low level processing
*/
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "pktdrvr.h"
#include "netuser.h"
#include "arp.h"
#include "slip.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "lapb.h"
#include "socket.h"
#include "trace.h"
#include "ip.h"
#include "commands.h"
static int accept_bc(uint8 *addr,unsigned ifnum);
static struct nr_bind *find_best(struct nr_bind *list,unsigned obso);
static struct nr_bind *find_binding(struct nr_bind *list,struct nrnbr_tab *neighbor);
static struct nrnbr_tab *find_nrnbr(uint8 *, unsigned);
static struct nrnf_tab *find_nrnf(uint8 *, unsigned);
static struct nr_bind *find_worst(struct nr_bind *list);
static int ismycall(uint8 *addr);
#ifdef notdef
static uint8 *nr_getroute(uint8 *);
#endif
static struct raw_nr *Raw_nr;
/* Nodes message broadcast address: "NODES" in shifted ASCII */
uint8 Nr_nodebc[AXALEN] = {
'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 short Nr_ttl = 64;
static unsigned Obso_init = 6;
static unsigned Obso_minbc = 5;
static unsigned Nr_maxroutes = 5;
static unsigned Nr_autofloor = 1;
int Nr_verbose = 0;
struct iface *Nr_iface;
/* send a NET/ROM layer 3 datagram */
void
nr3output(
uint8 *dest,
struct mbuf **data
){
struct nr3hdr n3hdr;
struct mbuf *n3b;
memcpy(n3hdr.dest,dest,AXALEN); /* copy destination field */
n3hdr.ttl = Nr_ttl; /* time to live from initializer parm */
if((n3b = htonnr3(&n3hdr)) == NULL){
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,NULL);
}
/* send IP datagrams across a net/rom network connection */
int
nr_send(
struct mbuf **bpp,
struct iface *iface,
int32 gateway,
uint8 tos
){
struct arp_tab *arp;
dump(iface,IF_TRACE_OUT,*bpp);
iface->rawsndcnt++;
iface->lastsent = secclock();
if((arp = arp_lookup(ARP_NETROM,gateway)) == NULL){
free_p(bpp); /* drop the packet if no route */
return -1;
}
nr_sendraw(arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bpp);
return 0;
}
/* Send arbitrary protocol data on top of a NET/ROM connection */
void
nr_sendraw(
uint8 *dest,
unsigned family,
unsigned proto,
struct mbuf **data
){
struct mbuf *pbp;
struct nr4hdr n4hdr;
/* Create a "network extension" transport header */
n4hdr.opcode = NR4OPPID;
n4hdr.u.pid.family = family;
n4hdr.u.pid.proto = proto;
if((pbp = htonnr4(&n4hdr)) == NULL){
free_p(data);
return;
}
append(&pbp,data); /* Append the data to that */
nr3output(dest, &pbp); /* and pass off to level 3 code */
}
/* Arrange for receipt of raw NET/ROM datagrams */
struct raw_nr *
raw_nr(protocol)
uint8 protocol;
{
register struct raw_nr *rp;
rp = (struct raw_nr *)callocw(1,sizeof(struct raw_nr));
rp->protocol = protocol;
rp->next = Raw_nr;
if(rp->next != NULL)
rp->next->prev = rp;
Raw_nr = rp;
return rp;
}
/* Free a raw NET/ROM descriptor */
void
del_rnr(rpp)
struct raw_nr *rpp;
{
register struct raw_nr *rp;
/* Do sanity check on arg */
for(rp = Raw_nr;rp != NULL;rp = rp->next)
if(rp == rpp)
break;
if(rp == NULL)
return; /* Doesn't exist */
/* Unlink */
if(rp->prev != NULL)
rp->prev->next = rp->next;
else
Raw_nr = rp->next;
if(rp->next != NULL)
rp->next->prev = rp->prev;
/* Free resources */
free_q(&rp->rcvq);
free(rp);
}
/* Figure out if a call is assigned to one of my net/rom
* interfaces.
*/
static int
ismycall(addr)
uint8 *addr;
{
register int i;
int found = 0;
for(i = 0; i < Nr_numiface; i++)
if(addreq(Nrifaces[i].iface->hwaddr,addr)){
found = 1;
break;
}
return found;
}
/* Route net/rom network layer packets.
*/
void
nr_route(bpp, iaxp)
struct mbuf **bpp; /* network packet */
struct ax25_cb *iaxp; /* incoming ax25 control block */
{
struct nr3hdr n3hdr;
struct nr4hdr n4hdr;
struct ax25_cb *axp;
struct mbuf *hbp, *pbp;
struct raw_nr *rnr;
register struct nrnbr_tab *np;
register struct nrroute_tab *rp;
register struct nr_bind *bindp;
struct iface *iface;
unsigned ifnum;
if(ntohnr3(&n3hdr,bpp) == -1){
free_p(bpp);
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 != NULL && ax_lookup(iaxp->remote) != NULL){
/* find the interface number */
for(ifnum = 0; ifnum < Nr_numiface; ifnum++)
if(iaxp->iface == Nrifaces[ifnum].iface)
break;
if(ifnum == Nr_numiface){ /* Not a net/rom interface! */
free_p(bpp);
return;
}
/* 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. */
(void) nr_routeadd(" ",n3hdr.source,ifnum,0,iaxp->remote,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)){
/* Toss if from me, or if we can't read the header */
if(iaxp == NULL || ntohnr4(&n4hdr,bpp) == -1){
free_p(bpp);
} else if((n4hdr.opcode & NR4OPCODE) == NR4OPPID){
for(rnr = Raw_nr;rnr!=NULL;rnr = rnr->next){
if(rnr->protocol!=n4hdr.u.pid.family ||
rnr->protocol != n4hdr.u.pid.proto)
continue;
/* Duplicate the data portion, and put the
* level 3 header back on
*/
dup_p(&pbp,*bpp,0,len_p(*bpp));
if(pbp != NULL &&
(hbp = htonnr3(&n3hdr)) != NULL){
append(&hbp,&pbp);
enqueue(&rnr->rcvq,&hbp);
} else {
free_p(&pbp);
free_p(&hbp);
}
}
/* IP does not use a NET/ROM level 3 socket */
if(n4hdr.u.pid.family == NRPROTO_IP
&& n4hdr.u.pid.proto == NRPROTO_IP)
ip_route(iaxp->iface,bpp,0);
else /* we don't do this proto */
free_p(bpp);
} else {
/* Must be net/rom transport: */
nr4input(&n4hdr,bpp);
}
return;
}
if((rp = find_nrroute(n3hdr.dest)) == NULL){
/* no route, drop the packet */
free_p(bpp);
return;
}
if((bindp = find_best(rp->routes,1)) == NULL){
/* This shouldn't happen yet, but might if we add */
/* dead route detection */
free_p(bpp);
return;
}
np = bindp->via;
iface = Nrifaces[np->iface].iface;
/* 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 == NULL)
memcpy(n3hdr.source,iface->hwaddr,AXALEN);
/* Make sure there is a connection to the neighbor */
if((axp = find_ax25(np->call)) == NULL ||
(axp->state != LAPB_CONNECTED && axp->state != LAPB_RECOVERY)){
/* Open a new connection or reinitialize old one */
/* hwaddr has been advanced to point to neighbor + digis */
axp = open_ax25(iface,iface->hwaddr,np->call, AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall,-1);
if(axp == NULL){
free_p(bpp);
return;
}
}
if(--n3hdr.ttl == 0){ /* the packet's time to live is over! */
free_p(bpp);
return;
}
/* now format network header */
if((pbp = htonnr3(&n3hdr)) == NULL){
free_p(bpp);
return;
}
append(&pbp,bpp); /* append data to header */
/* put AX.25 PID on front */
pushdown(&pbp,NULL,1);
pbp->data[0] = PID_NETROM;
if((pbp = segmenter(&pbp,axp->paclen)) == NULL){
free_p(&pbp);
return;
}
send_ax25(axp,&pbp,-1); /* pass it off to ax25 code */
}
/* Perform a nodes broadcast on interface # ifno in the net/rom
* interface table.
*/
void
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 uint8 *cp;
struct iface *axif = Nrifaces[ifno].iface;
/* prepare the header */
if((hbp = alloc_mbuf(NR3NODEHL)) == NULL)
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, Nr_nodebc, axif->hwaddr,
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 != NULL; rp = rp->next){
/* look for best, non-obsolescent route */
if((bp = find_best(rp->routes,0)) == NULL)
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,np->call,AXALEN);
/* insert destination from route table */
memcpy(nrdest.dest,rp->call,AXALEN);
/* 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)) == NULL){
free_p(&hbp); /* drop the whole idea ... */
free_p(&savehdr);
return;
}
/* we now have a partially filled packet */
didsend = 0;
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 */
/* indicate that we did broadcast */
didsend = 1;
/* reset the destination counter */
numdest = 0;
(*axif->output)(axif, Nr_nodebc, axif->hwaddr,
PID_NETROM,&hbp); /* send it */
/* new header */
hbp = copy_p(savehdr,NR3NODEHL);
}
}
}
/* 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].iface->hwaddr;
if(!addreq((uint8 *)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)) == NULL){
free_p(&hbp); /* drop the whole idea ... */
free_p(&savehdr);
return;
}
/* we now have a partially filled packet */
didsend = 0;
/* append to header and others */
append(&hbp,&dbp);
if(++numdest == NRDESTPERPACK){ /* filled it up */
/* indicate that we did broadcast */
didsend = 1;
/* reset the destination counter */
numdest = 0;
(*axif->output)(axif, Nr_nodebc, axif->hwaddr,
PID_NETROM,&hbp); /* send it */
/* new header */
hbp = copy_p(savehdr,NR3NODEHL);
}
}
}
/* 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, Nr_nodebc, axif->hwaddr,PID_NETROM, &hbp);
/* free the header copies */
if(numdest == 0)
free_p(&hbp);
free_p(&savehdr);
}
/* attach the net/rom interface. no parms for now. */
int
nr_attach(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(Nr_iface != (struct iface *)0){
printf("netrom interface already attached\n");
return -1;
}
Nr_iface = (struct iface *)callocw(1,sizeof(struct iface));
Nr_iface->addr = Ip_addr;
/* The strdup is needed to keep the detach routine happy (it'll
* free the allocated memory)
*/
Nr_iface->name = strdup("netrom");
if(Nr_iface->hwaddr == NULL){
Nr_iface->hwaddr = mallocw(AXALEN);
memcpy(Nr_iface->hwaddr,Mycall,AXALEN);
}
Nr_iface->mtu = NR4MAXINFO;
setencap(Nr_iface,"NETROM");
Nr_iface->next = Ifaces;
Ifaces = Nr_iface;
memcpy(Nr4user,Mycall,AXALEN);
Nr_iface->txproc = newproc("nr tx",512,if_tx,0,Nr_iface,NULL,0);
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.
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -