home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
src0131
/
ax25user.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-26
|
5KB
|
219 lines
/* User interface subroutines for AX.25
* Copyright 1991 Phil Karn, KA9Q
*/
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "iface.h"
#include "lapb.h"
#include "ax25.h"
#include "lapb.h"
#include <ctype.h>
/* Open an AX.25 connection */
struct ax25_cb *
open_ax25(iface,local,remote,mode,window,r_upcall,t_upcall,s_upcall,user)
struct iface *iface; /* Interface */
char *local; /* Local address */
char *remote; /* Remote address */
int mode; /* active/passive/server */
int16 window; /* Window size in bytes */
void (*r_upcall)(); /* Receiver upcall handler */
void (*t_upcall)(); /* Transmitter upcall handler */
void (*s_upcall)(); /* State-change upcall handler */
int user; /* User linkage area */
{
struct ax25_cb *axp;
char remtmp[AXALEN];
if(remote == NULLCHAR){
remote = remtmp;
setcall(remote," ");
}
if((axp = find_ax25(remote)) != NULLAX25 && axp->state != LAPB_DISCONNECTED)
return NULLAX25; /* Only one to a customer */
if(axp == NULLAX25 && (axp = cr_ax25(remote)) == NULLAX25)
return NULLAX25;
memcpy(axp->remote,remote,AXALEN);
memcpy(axp->local,local,AXALEN);
axp->iface = iface;
axp->window = window;
axp->r_upcall = r_upcall;
axp->t_upcall = t_upcall;
axp->s_upcall = s_upcall;
axp->user = user;
switch(mode){
case AX_SERVER:
axp->flags.clone = 1;
case AX_PASSIVE: /* Note fall-thru */
axp->state = LAPB_LISTEN;
return axp;
case AX_ACTIVE:
break;
}
switch(axp->state){
case LAPB_DISCONNECTED:
est_link(axp);
lapbstate(axp,LAPB_SETUP);
break;
case LAPB_SETUP:
free_q(&axp->txq);
break;
case LAPB_DISCPENDING: /* Ignore */
break;
case LAPB_RECOVERY:
case LAPB_CONNECTED:
free_q(&axp->txq);
est_link(axp);
lapbstate(axp,LAPB_SETUP);
break;
}
return axp;
}
/* Send data on an AX.25 connection. Caller provides optional PID. If
* a PID is provided, then operate in stream mode, i.e., a large packet
* is automatically packetized into a series of paclen-sized data fields.
*
* If pid == -1, it is assumed the packet (which may actually be a queue
* of distinct packets) already has a PID on the front and it is passed
* through directly even if it is very large.
*/
int
send_ax25(axp,bp,pid)
struct ax25_cb *axp;
struct mbuf *bp;
int pid;
{
struct mbuf *bp1;
int16 offset,len,size;
if(axp == NULLAX25 || bp == NULLBUF)
return -1;
if(pid != -1){
offset = 0;
len = len_p(bp);
/* It is important that all the pushdowns be done before
* any part of the original packet is freed.
* Otherwise the pushdown might erroneously overwrite
* a part of the packet that had been duped and freed.
*/
while(len != 0){
size = min(len,axp->paclen);
dup_p(&bp1,bp,offset,size);
len -= size;
offset += size;
bp1 = pushdown(bp1,1);
bp1->data[0] = pid;
enqueue(&axp->txq,bp1);
}
free_p(bp);
} else {
enqueue(&axp->txq,bp);
}
return lapb_output(axp);
}
/* Receive incoming data on an AX.25 connection */
struct mbuf *
recv_ax25(axp,cnt)
struct ax25_cb *axp;
int16 cnt;
{
struct mbuf *bp;
if(axp->rxq == NULLBUF)
return NULLBUF;
if(cnt == 0){
/* This means we want it all */
bp = axp->rxq;
axp->rxq = NULLBUF;
} else {
bp = ambufw(cnt);
bp->cnt = pullup(&axp->rxq,bp->data,cnt);
}
/* If this has un-busied us, send a RR to reopen the window */
if(len_p(axp->rxq) < axp->window
&& (len_p(axp->rxq) + bp->cnt) >= axp->window)
sendctl(axp,LAPB_RESPONSE,RR);
return bp;
}
/* Close an AX.25 connection */
int
disc_ax25(axp)
struct ax25_cb *axp;
{
if(axp == NULLAX25)
return -1;
switch(axp->state){
case LAPB_DISCONNECTED:
break; /* Ignored */
case LAPB_LISTEN:
del_ax25(axp);
break;
case LAPB_DISCPENDING:
lapbstate(axp,LAPB_DISCONNECTED);
break;
case LAPB_CONNECTED:
case LAPB_RECOVERY:
free_q(&axp->txq);
axp->retries = 0;
sendctl(axp,LAPB_COMMAND,DISC|PF);
stop_timer(&axp->t3);
start_timer(&axp->t1);
lapbstate(axp,LAPB_DISCPENDING);
break;
}
return 0;
}
/* Verify that axp points to a valid ax25 control block */
int
ax25val(axp)
struct ax25_cb *axp;
{
register struct ax25_cb *axp1;
register int i;
if(axp == NULLAX25)
return 0; /* Null pointer can't be valid */
for(i=0; i < NHASH; i++)
for(axp1 = Ax25_cb[i];axp1 != NULLAX25; axp1 = axp1->next)
if(axp1 == axp)
return 1;
return 0;
}
/* Force a retransmission */
int
kick_ax25(axp)
struct ax25_cb *axp;
{
if(!ax25val(axp))
return -1;
recover(axp);
return 0;
}
/* Abruptly terminate an AX.25 connection */
int
reset_ax25(axp)
struct ax25_cb *axp;
{
void (*upcall)();
if(axp == NULLAX25)
return -1;
upcall = axp->s_upcall;
lapbstate(axp,LAPB_DISCONNECTED);
/* Clean up if the standard upcall isn't in use */
if(upcall != s_ascall)
del_ax25(axp);
return 0;
}