398 lines
8.0 KiB
C
398 lines
8.0 KiB
C
/*
|
|
* nr4subr.c: subroutines for net/rom transport layer.
|
|
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
|
|
* non-commercial distribution only.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "config.h" /* K5JB */
|
|
#ifdef NETROM /* K5JB */
|
|
#include "global.h"
|
|
#include "mbuf.h"
|
|
#include "timer.h"
|
|
#include "ax25.h"
|
|
#include "iface.h" /* K5JB */
|
|
#include "netrom.h"
|
|
#include "nr4.h"
|
|
#include "lapb.h"
|
|
#include <ctype.h>
|
|
|
|
/* Convert a net/rom transport header to host format structure.
|
|
* Return -1 if error, 0 if OK.
|
|
*/
|
|
|
|
int
|
|
ntohnr4(hdr,bpp)
|
|
register struct nr4hdr *hdr ;
|
|
struct mbuf **bpp ;
|
|
{
|
|
char *getaxaddr() ;
|
|
char axbuf[AXALEN] ;
|
|
unsigned char tbuf[NR4MINHDR] ;
|
|
|
|
if (pullup(bpp, tbuf, NR4MINHDR) < NR4MINHDR)
|
|
return -1 ;
|
|
|
|
hdr->opcode = tbuf[4] ;
|
|
|
|
switch (tbuf[4] & NR4OPCODE) {
|
|
|
|
case NR4OPPID: /* protocol ID extension */
|
|
hdr->u.pid.family = tbuf[0] ;
|
|
hdr->u.pid.proto = tbuf[1] ;
|
|
break ;
|
|
|
|
case NR4OPCONRQ: /* connect request */
|
|
hdr->u.conreq.myindex = tbuf[0] ;
|
|
hdr->u.conreq.myid = tbuf[1] ;
|
|
if (pullup(bpp,&(hdr->u.conreq.window), 1) < 1)
|
|
return -1 ;
|
|
if (pullup(bpp,axbuf,AXALEN) < AXALEN)
|
|
return -1 ;
|
|
(void)getaxaddr(&hdr->u.conreq.user,axbuf) ;
|
|
if (pullup(bpp,axbuf,AXALEN) < AXALEN)
|
|
return -1 ;
|
|
(void)getaxaddr(&hdr->u.conreq.node,axbuf) ;
|
|
break ;
|
|
|
|
case NR4OPCONAK: /* connect acknowledge */
|
|
hdr->yourindex = tbuf[0] ;
|
|
hdr->yourid = tbuf[1] ;
|
|
hdr->u.conack.myindex = tbuf[2] ;
|
|
hdr->u.conack.myid = tbuf[3] ;
|
|
if (pullup(bpp,&(hdr->u.conack.window), 1) < 1)
|
|
return -1 ;
|
|
break ;
|
|
|
|
case NR4OPDISRQ: /* disconnect request */
|
|
hdr->yourindex = tbuf[0] ;
|
|
hdr->yourid = tbuf[1] ;
|
|
break ;
|
|
|
|
case NR4OPDISAK: /* disconnect acknowledge */
|
|
hdr->yourindex = tbuf[0] ;
|
|
hdr->yourid = tbuf[1] ;
|
|
break ;
|
|
|
|
case NR4OPINFO: /* information frame */
|
|
hdr->yourindex = tbuf[0] ;
|
|
hdr->yourid = tbuf[1] ;
|
|
hdr->u.info.txseq = tbuf[2] ;
|
|
hdr->u.info.rxseq = tbuf[3] ;
|
|
break ;
|
|
|
|
case NR4OPACK: /* information acknowledge */
|
|
hdr->yourindex = tbuf[0] ;
|
|
hdr->yourid = tbuf[1] ;
|
|
hdr->u.ack.rxseq = tbuf[3] ;
|
|
break ;
|
|
|
|
default: /* what kind of frame is this? */
|
|
return -1 ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
struct mbuf *
|
|
htonnr4(hdr)
|
|
register struct nr4hdr *hdr ;
|
|
{
|
|
static unsigned char hlen[NR4NUMOPS] = {5,20,6,5,5,5,5} ;
|
|
struct mbuf *rbuf ;
|
|
register char *cp ;
|
|
char *putaxaddr() ;
|
|
unsigned char opcode ;
|
|
|
|
opcode = hdr->opcode & NR4OPCODE ;
|
|
|
|
if (opcode >= NR4NUMOPS)
|
|
return NULLBUF ;
|
|
|
|
if (hdr == (struct nr4hdr *)0) /* K5JB */
|
|
return NULLBUF ;
|
|
|
|
if ((rbuf = alloc_mbuf(hlen[opcode])) == NULLBUF)
|
|
return NULLBUF ;
|
|
|
|
rbuf->cnt = hlen[opcode] ;
|
|
cp = rbuf->data ;
|
|
|
|
cp[4] = hdr->opcode ;
|
|
|
|
switch (opcode) {
|
|
|
|
case NR4OPPID:
|
|
*cp++ = hdr->u.pid.family ;
|
|
*cp = hdr->u.pid.proto ;
|
|
break ;
|
|
|
|
case NR4OPCONRQ:
|
|
*cp++ = hdr->u.conreq.myindex ;
|
|
*cp++ = hdr->u.conreq.myid ;
|
|
cp += 3 ; /* skip to sixth byte */
|
|
*cp++ = hdr->u.conreq.window ;
|
|
cp = putaxaddr(cp, &hdr->u.conreq.user) ;
|
|
(void) putaxaddr(cp, &hdr->u.conreq.node) ;
|
|
break ;
|
|
|
|
case NR4OPCONAK:
|
|
*cp++ = hdr->yourindex ;
|
|
*cp++ = hdr->yourid ;
|
|
*cp++ = hdr->u.conack.myindex ;
|
|
*cp++ = hdr->u.conack.myid ;
|
|
cp++ ; /* already loaded pid */
|
|
*cp = hdr->u.conack.window ;
|
|
break ;
|
|
|
|
case NR4OPDISRQ:
|
|
*cp++ = hdr->yourindex ;
|
|
*cp = hdr->yourid ;
|
|
break ;
|
|
|
|
case NR4OPDISAK:
|
|
*cp++ = hdr->yourindex ;
|
|
*cp = hdr->yourid ;
|
|
break ;
|
|
|
|
case NR4OPINFO:
|
|
*cp++ = hdr->yourindex ;
|
|
*cp++ = hdr->yourid ;
|
|
*cp++ = hdr->u.info.txseq ;
|
|
*cp = hdr->u.info.rxseq ;
|
|
break ;
|
|
|
|
case NR4OPACK:
|
|
*cp++ = hdr->yourindex ;
|
|
*cp++ = hdr->yourid ;
|
|
*++cp = hdr->u.ack.rxseq ; /* skip third byte (tricky yuck) */
|
|
break ;
|
|
|
|
}
|
|
|
|
return rbuf ;
|
|
}
|
|
|
|
|
|
/* Get a free circuit table entry, and allocate a circuit descriptor.
|
|
* Initialize control block circuit number and ID fields.
|
|
* Return a pointer to the circuit control block if successful,
|
|
* NULLNR4CB if not.
|
|
*/
|
|
|
|
struct nr4cb *
|
|
new_n4circ()
|
|
{
|
|
int i ;
|
|
struct nr4cb *cb ;
|
|
|
|
for (i = 0 ; i < NR4MAXCIRC ; i++) /* find a free circuit */
|
|
if (Nr4circuits[i].ccb == NULLNR4CB)
|
|
break ;
|
|
|
|
if (i == NR4MAXCIRC) /* no more circuits */
|
|
return NULLNR4CB ;
|
|
|
|
if ((cb = Nr4circuits[i].ccb =
|
|
(struct nr4cb *)calloc(1,sizeof(struct nr4cb))) == NULLNR4CB)
|
|
return NULLNR4CB ;
|
|
else {
|
|
cb->mynum = i ;
|
|
cb->myid = Nr4circuits[i].cid ;
|
|
return cb ;
|
|
}
|
|
}
|
|
|
|
|
|
/* Set the window size for a circuit and allocate the buffers for
|
|
* the transmit and receive windows. Set the control block window
|
|
* parameter. Return 0 if successful, -1 if not.
|
|
*/
|
|
|
|
int
|
|
init_nr4window(cb, window)
|
|
struct nr4cb *cb ;
|
|
unsigned window ;
|
|
{
|
|
void free();
|
|
|
|
if (window == 0 || window > NR4MAXWIN) /* reject silly window sizes */
|
|
return -1 ;
|
|
|
|
if ((cb->txbufs =
|
|
(struct nr4txbuf *)calloc(window,sizeof(struct nr4txbuf)))
|
|
== (struct nr4txbuf *)0)
|
|
return -1 ;
|
|
|
|
if ((cb->rxbufs =
|
|
(struct nr4rxbuf *)calloc(window,sizeof(struct nr4rxbuf)))
|
|
== (struct nr4rxbuf *)0) {
|
|
free(cb->txbufs) ;
|
|
cb->txbufs = (struct nr4txbuf *)0 ;
|
|
return -1 ;
|
|
}
|
|
|
|
cb->window = window ;
|
|
|
|
return 0 ;
|
|
}
|
|
|
|
|
|
/* Free a circuit. Deallocate the control block and buffers, and
|
|
* increment the circuit ID. No return value.
|
|
*/
|
|
|
|
void
|
|
free_n4circ(cb)
|
|
struct nr4cb *cb ;
|
|
{
|
|
unsigned circ ;
|
|
void free(),free_q();
|
|
|
|
if (cb == NULLNR4CB)
|
|
return ;
|
|
|
|
circ = cb->mynum ;
|
|
|
|
if (cb->txbufs != (struct nr4txbuf *)0)
|
|
free(cb->txbufs) ;
|
|
|
|
if (cb->rxbufs != (struct nr4rxbuf *)0)
|
|
free(cb->rxbufs) ;
|
|
|
|
/* Better be safe than sorry: */
|
|
|
|
free_q(&cb->txq) ;
|
|
free_q(&cb->rxq) ;
|
|
|
|
free(cb) ;
|
|
|
|
if (circ > NR4MAXCIRC) /* Shouldn't happen. */
|
|
return ;
|
|
|
|
Nr4circuits[circ].ccb = NULLNR4CB ;
|
|
|
|
Nr4circuits[circ].cid++ ;
|
|
}
|
|
|
|
/* See if any open circuit matches the given parameters. This is used
|
|
* to prevent opening multiple circuits on a duplicate connect request.
|
|
* Returns the control block address if a match is found, or NULLNR4CB
|
|
* otherwise.
|
|
*/
|
|
|
|
struct nr4cb *
|
|
match_n4circ(index, id, user, node)
|
|
int index ; /* index of remote circuit */
|
|
int id ; /* id of remote circuit */
|
|
struct ax25_addr *user ; /* address of remote user */
|
|
struct ax25_addr *node ; /* address of originating node */
|
|
{
|
|
int i ;
|
|
struct nr4cb *cb ;
|
|
|
|
for (i = 0 ; i < NR4MAXCIRC ; i++) {
|
|
if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
|
|
continue ; /* not an open circuit */
|
|
if (cb->yournum == index && cb->yourid == id
|
|
&& addreq(&cb->user,user) && addreq(&cb->node,node))
|
|
return cb ;
|
|
}
|
|
|
|
/* if we get to here, we didn't find a match */
|
|
|
|
return NULLNR4CB ;
|
|
}
|
|
|
|
/* Validate the index and id of a local circuit, returning the control
|
|
* block if it is valid, or NULLNR4CB if it is not.
|
|
*/
|
|
|
|
struct nr4cb *
|
|
get_n4circ(index, id)
|
|
int index ; /* local circuit index */
|
|
int id ; /* local circuit id */
|
|
{
|
|
struct nr4cb *cb ;
|
|
|
|
if (index >= NR4MAXCIRC)
|
|
return NULLNR4CB ;
|
|
|
|
if ((cb = Nr4circuits[index].ccb) == NULLNR4CB)
|
|
return NULLNR4CB ;
|
|
|
|
if (cb->myid == id)
|
|
return cb ;
|
|
else
|
|
return NULLNR4CB ;
|
|
}
|
|
|
|
/* Return 1 if b is "between" (modulo the size of an unsigned char)
|
|
* a and c, 0 otherwise.
|
|
*/
|
|
|
|
int
|
|
nr4between(a, b, c)
|
|
unsigned a, b, c ;
|
|
{
|
|
if ((a <= b && b < c) || (c < a && a <= b) || (b < c && c < a))
|
|
return 1 ;
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
/* Set up default timer values, etc., in newly connected control block.
|
|
*/
|
|
|
|
void
|
|
nr4defaults(cb)
|
|
struct nr4cb *cb ;
|
|
{
|
|
int i ;
|
|
struct timer *t ;
|
|
|
|
if (cb == NULLNR4CB)
|
|
return ;
|
|
|
|
/* Set up the ACK and CHOKE timers */
|
|
|
|
cb->tack.start = Nr4acktime / MSPTICK ;
|
|
cb->tack.func = nr4ackit ;
|
|
cb->tack.arg = (char *)cb ;
|
|
|
|
cb->tchoke.start = Nr4choketime / MSPTICK ;
|
|
cb->tchoke.func = nr4unchoke ;
|
|
cb->tchoke.arg = (char *)cb ;
|
|
|
|
cb->rxpastwin = cb->window ;
|
|
|
|
/* Don't actually set the timers, since this is done */
|
|
/* in nr4sbuf */
|
|
|
|
for (i = 0 ; i < cb->window ; i++) {
|
|
t = &cb->txbufs[i].tretry ;
|
|
t->func = nr4txtimeout ;
|
|
t->arg = (char *)cb ;
|
|
}
|
|
}
|
|
|
|
/* See if this control block address is valid */
|
|
|
|
int
|
|
nr4valcb(cb)
|
|
struct nr4cb *cb ;
|
|
{
|
|
int i ;
|
|
|
|
if (cb == NULLNR4CB)
|
|
return 0 ;
|
|
|
|
for (i = 0 ; i < NR4MAXCIRC ; i++)
|
|
if (Nr4circuits[i].ccb == cb)
|
|
return 1 ;
|
|
|
|
return 0 ;
|
|
}
|
|
#endif /* NETROM */
|