P8000/WEGA/contrib/K5JB/ax25user.c

168 lines
3.3 KiB
C

/* User subroutines for AX.25 */
#include "config.h"
#ifdef AX25
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "iface.h"
#include "ax25.h"
#include "lapb.h"
#ifdef COH386 /* avoid a redefinition */
#undef __ARGS
#endif
#include <ctype.h>
void free_q(),lapb_output(),est_link();
int sendctl(),start_timer(),stop_timer();
/* Open an AX.25 connection */
struct ax25_cb *
open_ax25(addr,window,r_upcall,t_upcall,s_upcall,iface,user)
struct ax25 *addr; /* Addresses */
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 */
struct interface *iface; /* Hardware interface structure */
char *user; /* User linkage area */
{
struct ax25_cb *axp,*cr_ax25();
void lapbstate();
if((axp = cr_ax25(&addr->dest)) == NULLAX25)
return NULLAX25;
ASSIGN(axp->addr,*addr);
if(addr->ndigis != 0){
axp->t1.start *= (addr->ndigis + 1);
/* why would we want to scale these?
axp->t2.start *= (addr->ndigis + 1);
axp->t3.start *= (addr->ndigis + 1);
*/
}
axp->window = window;
axp->r_upcall = r_upcall;
axp->t_upcall = t_upcall;
axp->s_upcall = s_upcall;
axp->interface = iface;
axp->user = user;
switch(axp->state){
case DISCONNECTED:
/* Don't send anything if the connection already exists */
est_link(axp);
lapbstate(axp,SETUP);
break;
case SETUP:
free_q(&axp->txq);
break;
case DISCPENDING: /* Ignore */
case FRAMEREJECT:
break;
case RECOVERY:
case CONNECTED:
free_q(&axp->txq);
est_link(axp);
lapbstate(axp,SETUP);
break;
}
return axp;
}
/* Send data on an AX.25 connection. Caller must provide PID */
void
send_ax25(axp,bp)
struct ax25_cb *axp;
struct mbuf *bp;
{
if(axp == NULLAX25 || bp == NULLBUF)
return;
enqueue(&axp->txq,bp);
lapb_output(axp);
}
/* Receive incoming data on an AX.25 connection */
struct mbuf *
recv_ax25(axp,unused)
register struct ax25_cb *axp;
int16 unused;
{
struct mbuf *bp;
if(axp->rxq == NULLBUF)
return NULLBUF;
bp = axp->rxq;
axp->rxq = NULLBUF;
/* If this has un-busied us, send a RR to reopen the window */
if(len_mbuf(bp) >= axp->window)
sendctl(axp,RESPONSE,RR); /* note that this didn't have PF */
return bp;
}
/* Close an AX.25 connection */
disc_ax25(axp)
struct ax25_cb *axp;
{
void lapbstate(),del_ax25();
switch(axp->state){
case DISCONNECTED:
break; /* Ignored */
case DISCPENDING:
lapbstate(axp,DISCONNECTED);
del_ax25(axp);
break;
case SETUP:
case CONNECTED:
case RECOVERY:
case FRAMEREJECT:
free_q(&axp->txq);
axp->retries = 0;
sendctl(axp,COMMAND,DISC);
stop_timer(&axp->t3);
start_timer(&axp->t1);
lapbstate(axp,DISCPENDING);
break;
}
}
/* Verify that axp points to a valid ax25 control block */
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 */
kick_ax25(axp)
struct ax25_cb *axp;
{
void recover();
if(!ax25val(axp))
return -1;
recover((int *)axp);
return 0;
}
/* Abruptly terminate an AX.25 connection */
reset_ax25(axp)
struct ax25_cb *axp;
{
void lapbstate(),del_ax25();
lapbstate(axp,DISCONNECTED);
del_ax25(axp);
}
#endif /* AX25 */