P8000/WEGA/contrib/K5JB/ax25cmd.c

915 lines
19 KiB
C

#include <stdio.h>
#include <string.h>
#include "global.h"
#include "options.h"
#include "config.h"
#ifdef AX25
#include "mbuf.h"
#include "ax25.h"
#include "timer.h"
#include "netuser.h"
#include "ftp.h"
#include "tcp.h"
#include "telnet.h"
#include "iface.h"
#include "lapb.h"
#include "finger.h"
#include "cmdparse.h"
#include "session.h"
#include "nr4.h"
#include "arp.h"
#ifdef AX25_HEARD
#include <time.h>
#include "heard.h"
#endif
long htol(),atol(); /* K5JB to fix t3 a little bit */
#ifdef SYS5
#include <sys/inode.h> /* Need flag to detect pipe fd */
#include <sys/stat.h>
#endif
char badcall[] = "Call?";
extern char notval[];
char *ax25states[] = {
"Disconnected",
"Conn pending",
"Disc pending",
"Connected",
"Recovery",
"Frame Reject"
};
int domycall(),dodigipeat(),doaxstat(),dot1(),dot2(),dot3(),dot4(),
domaxframe(),doaxwindow(),dopaclen(),don2(),doaxreset(),dopthresh(),
doaxvers();
#if defined(SEGMENT) && defined(SEG_CMD)
int dosegment();
#endif
extern char ouraxvers;
#ifdef AX25_HEARD
int doheard();
#endif
#ifdef SID2
int dombxcall();
extern struct ax25_addr bbscall;
int bbscall_set; /* k36 */
#endif
#ifdef VCIP_SSID
extern struct ax25_addr ip_call;
int doipcall();
#endif
void pax25(),send_ax25(),freesession();
int setcall();
static struct cmds axcmds[] = {
"digipeat", dodigipeat, 0, NULLCHAR, NULLCHAR,
#ifdef AX25_HEARD /* heard stuff */
"heard", doheard, 0, NULLCHAR, "ax25 heard [on|off|clear]",
#endif
"maxframe", domaxframe, 0, NULLCHAR, NULLCHAR,
"mycall", domycall, 0, NULLCHAR, badcall,
#ifdef SID2
"mboxcall", dombxcall, 0, NULLCHAR, badcall,
#endif
"paclen", dopaclen, 0, NULLCHAR, NULLCHAR,
"pthresh", dopthresh, 0, NULLCHAR, NULLCHAR,
"reset", doaxreset, 2, "ax25 reset <cb#>", notval,
"retry", don2, 0, NULLCHAR, NULLCHAR,
"status", doaxstat, 0, NULLCHAR, notval,
#if defined(SEGMENT) && defined(SEG_CMD) /* want status to come up with "s" */
"segment", dosegment, 0, NULLCHAR, NULLCHAR,
#endif
"t1", dot1, 0, NULLCHAR, NULLCHAR,
"t2", dot2, 0, NULLCHAR, NULLCHAR,
"t3", dot3, 0, NULLCHAR, NULLCHAR,
"t4", dot4, 0, NULLCHAR, NULLCHAR,
#ifdef VCIP_SSID
"vcipcall", doipcall, 0, NULLCHAR, badcall,
#endif
"vers", doaxvers,0, NULLCHAR, NULLCHAR,
"window", doaxwindow, 0, NULLCHAR, NULLCHAR,
NULLCHAR, NULLFP,0, AXCMDDISP, NULLCHAR /* AXCMDLIST in options.h */
};
/* Multiplexer for top-level ax25 command */
doax25(argc,argv)
int argc;
char *argv[];
{
int subcmd();
return subcmd(axcmds,argc,argv);
}
/* give this a number from 1 to ..., this will return a axp if there is one */
struct ax25_cb *
simple_getax(arg)
int arg;
{
int i,j;
struct ax25_cb *axp;
for(i=0,j=1;i<NHASH;i++)
for(axp=ax25_cb[i];axp != NULLAX25;axp = axp->next)
if(j++ == arg)
return axp;
return NULLAX25;
}
static
doaxreset(argc,argv)
int argc;
char *argv[];
{
int atoi();
struct ax25_cb *axp;
int ax25val(),reset_ax25();
extern int noprompt; /* k35 */
if((axp = simple_getax(atoi(argv[1]))) == NULLAX25)
/* || !ax25val(axp) I doubt we need this test */
return -1;
else{
if(current == (struct session *)axp->user) /* k35 */
noprompt = 1;
reset_ax25(axp);
}
return 0;
}
/* Display AX.25 link level control blocks */
static
doaxstat(argc,argv)
int argc;
char *argv[];
{
register int i;
register struct ax25_cb *axp;
char tmp[10];
extern char notval[];
int ax25val();
void dumpstat();
if(argc < 2){
printf("AXB# IF Snd-Q Rcv-Q Local Remote V State\n");
for(i=1;;i++){
if((axp = simple_getax(i)) == NULLAX25)
break;
pax25(tmp,&axp->addr.source);
printf(" %3d %-5s%-7d%-7d%-10s",i,axp->interface->name,
len_q(axp->txq),len_mbuf(axp->rxq),tmp);
pax25(tmp,&axp->addr.dest);
printf("%-10s%-2d%s\n",tmp,axp->proto,ax25states[axp->state]);
}
return 0;
}
if((axp = simple_getax(atoi(argv[1]))) == NULLAX25)
/* || !ax25val(axp) try without this */
return -1;
else
dumpstat(axp);
return 0;
}
/* Dump one control block */
static void
dumpstat(axp)
register struct ax25_cb *axp;
{
char tmp[10];
int i;
if(axp == NULLAX25 || axp->interface == NULLIF)
return;
printf(" &AXB IF Remote RB N(S) N(R) Unack V Retry State\n");
pax25(tmp,&axp->addr.dest);
printf("%8lx %-5s%-9s%c%c",(long)axp,axp->interface->name,tmp,
axp->rejsent ? 'R' : ' ',axp->remotebusy ? 'B' : ' ');
printf(" %-4d %-4d %02u/%02u %u %02u/%02u %s\n",
axp->vs,axp->vr,axp->unack,axp->maxframe,axp->proto,
axp->retries,axp->n2,ax25states[axp->state]);
printf("T1: ");
if(run_timer(&axp->t1))
printf("%lu",(axp->t1.start - axp->t1.count) * MSPTICK);
else
printf("stop");
printf("/%lu ms; ",axp->t1.start * MSPTICK);
printf("T2: ");
if(run_timer(&axp->t2))
printf("%lu",(axp->t2.start - axp->t2.count) * MSPTICK);
else
printf("stop");
printf("/%lu ms; ",axp->t2.start * MSPTICK);
printf("T3: ");
if(run_timer(&axp->t3))
printf("%lu",(axp->t3.start - axp->t3.count) * MSPTICK);
else
printf("stop");
printf("/%lu ms; ",axp->t3.start * MSPTICK);
printf("T4: ");
if(run_timer(&axp->t4))
printf("%lu",((axp->t4.start - axp->t4.count) * MSPTICK) / 1000L);
else
printf("stop");
printf("/%lu sec\n",(axp->t4.start * MSPTICK) / 1000L);
if(axp->addr.ndigis == 0)
return;
printf("Digipeaters:");
for(i=0;i<axp->addr.ndigis;i++){
pax25(tmp,&axp->addr.digis[i]);
printf(" %s",tmp);
}
printf("\n");
}
/* Display or change our AX.25 address */
static
domycall(argc,argv)
int argc;
char *argv[];
{
char buf[15];
if(argc < 2){
pax25(buf,&mycall);
printf("%s\n",buf);
return 0;
}
if(setcall(&mycall,argv[1]) == -1)
return -1;
mycall.ssid |= E;
bbscall_set = 0; /* k36 */
return 0;
}
#ifdef SID2
/* Display or change our AX.25 BBS Address */
static
dombxcall(argc,argv)
int argc;
char *argv[];
{
char buf[15];
if(argc < 2){
pax25(buf,&bbscall);
printf("%s\n",buf);
return 0;
}
if(setcall(&bbscall,argv[1]) == -1)
return -1;
bbscall.ssid |= E;
bbscall_set = 1; /* k36 */
return 0;
}
#endif
#ifdef VCIP_SSID
/* Display or change our AX.25 IP only Call */
static
doipcall(argc,argv)
int argc;
char *argv[];
{
char buf[15];
int psax25(), setpath(), arp_init();
if(argc < 2){
pax25(buf,&ip_call);
printf("%s\n",buf);
return 0;
}
if(setcall(&ip_call,argv[1]) == -1)
return -1;
ip_call.ssid |= E; /* oops! K35 */
return 0;
}
#endif
/* Display or change our default AX.25 protocol version */
static
doaxvers(argc,argv)
int argc;
char *argv[];
{
if(argc == 2)
ouraxvers = argv[1][1] == '2' ? V2 : V1; /* see my bias? */
else
printf("AX.25 version is %s\n",ouraxvers == V1 ? "V1" : "V2");
return 0;
}
#if defined(SEGMENT) && defined(SEG_CMD)
extern int rx_segment;
/* Display or change our AX.25 RX Segmentation */
static
dosegment(argc,argv)
int argc;
char *argv[];
{
if(argc == 2)
rx_segment = argv[1][1] == 'n' ? 1 : 0;
else
printf("AX.25 RX segmentation is %s\n",rx_segment ? "on" : "off");
return 0;
}
#endif
/* Control AX.25 digipeating */
static
dodigipeat(argc,argv)
int argc;
char *argv[];
{
extern int digipeat;
if(argc == 1)
printf("digipeat %s\n",digipeat ? "on" : "off");
else
digipeat = argv[1][1] == 'n' ? 1 : 0; /* k34 */
}
/* Setting t1 or t2 too short causes real subtile problems. Setting
* t3 or t4 too small causes the user to get what he deserves - K5JB
* (I guess that applys to the other parameters too)
*/
#define MIN_T1_TIMER 5000 /* milliseconds -- even this is kinda short */
#ifndef MIN_T2_TIMER
#define MIN_T2_TIMER 1000
#endif
/* Set retransmission timer */
static
dot1(argc,argv)
int argc;
char *argv[];
{
extern int16 t1init;
if(argc == 1) {
printf("T1 %lu ms\n",(long)t1init * MSPTICK);
} else {
if((t1init = atol(argv[1])) < MIN_T1_TIMER)
t1init = MIN_T1_TIMER;
t1init /= MSPTICK;
}
}
/* Set acknowledgement delay timer */
static
dot2(argc,argv)
int argc;
char *argv[];
{
extern int16 t2init;
int16 tmpt2;
if(argc == 1)
printf("T2 %lu ms\n",(long)t2init * MSPTICK);
else
if((tmpt2 = atol(argv[1])) >= MIN_T2_TIMER)
t2init = tmpt2 / MSPTICK;
}
/* Set idle timer */
static
dot3(argc,argv)
int argc;
char *argv[];
{
extern int16 t3init;
if(argc == 1) {
printf("T3 %lu ms\n",(long)t3init * MSPTICK);
} else {
t3init = atol(argv[1]) / MSPTICK;
}
}
/* Set stale ckt timer */
static
dot4(argc,argv)
int argc;
char *argv[];
{
extern int32 t4init;
if(argc == 1) {
printf("T4 %lu sec\n",(t4init * MSPTICK)/1000L);
} else {
t4init = (1000L * atol(argv[1])) / MSPTICK;
}
}
/* Set retry limit count */
static
don2(argc,argv)
int argc;
char *argv[];
{
extern int16 n2;
int atoi();
if(argc == 1)
printf("Retry %u\n",n2);
else
if(!((n2 = atoi(argv[1])) > 0 && n2 < 16))
n2 = 10;
return 0;
}
/* Set maximum number of frames that will be allowed in flight */
static
domaxframe(argc,argv)
int argc;
char *argv[];
{
extern int16 maxframe;
if(argc == 1)
printf("Maxframe %u\n",maxframe);
else
maxframe = atoi(argv[1]);
}
/* Set maximum length of I-frame data field */
static
dopaclen(argc,argv)
int argc;
char *argv[];
{
extern int16 paclen;
if(argc == 1)
printf("Paclen %u\n",paclen);
else
paclen = atoi(argv[1]);
}
/* Set size of I-frame above which polls will be sent after a timeout */
static
dopthresh(argc,argv)
int argc;
char *argv[];
{
extern int16 pthresh;
if(argc == 1)
printf("Pthresh %u\n",pthresh);
else
pthresh = atoi(argv[1]);
}
/* Set high water mark on receive queue that triggers RNR */
static
doaxwindow(argc,argv)
int argc;
char *argv[];
{
extern int16 axwindow;
if(argc == 1)
printf("Axwindow %u\n",axwindow);
else
axwindow = atoi(argv[1]);
}
/* End of ax25 subcommands */
/* Initiate interactive AX.25 connect to remote station */
int
doconnect(argc,argv)
int argc;
char *argv[];
{
void ax_rx(),ax_tx(),ax_state(),free();
int ax_parse();
struct ax25_addr dest;
struct ax25 addr;
struct ax25_cb *open_ax25();
struct interface *ifp;
struct session *s,*ps; /* k34 added prior session in case of bad call */
extern int16 axwindow;
int i, addreq(),go();
if (strcmp(argv[1],"netrom") == 0) {
printf("Connect on netrom interface not supported\n") ;
return 1 ;
}
for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next)
if(strcmp(argv[1],ifp->name) == 0)
break;
if(ifp == NULLIF){
printf("Interface %s unknown\n",argv[1]);
return 1;
}
if(setcall(&dest,argv[2])) /* k34 */
return -1;
/* See if a session already exists */
for(s = sessions; s < &sessions[nsessions]; s++){
if(s->type == AX25TNC
&& addreq(&s->cb.ax25_cb->addr.dest,&dest)){
printf("Session %u to %s already exists\n",s - sessions,argv[2]);
return 1;
}
}
/* Allocate a session descriptor */
if((s = newsession()) == NULLSESSION){
printf("Too many sessions\n");
return 1;
}
if((s->name = malloc((unsigned)strlen(argv[2])+1)) != NULLCHAR)
strcpy(s->name,argv[2]);
s->type = AX25TNC;
s->parse = ax_parse;
ps = current; /* save ps in case a call is bad k34 */
current = s;
ASSIGN(addr.source,mycall);
ASSIGN(addr.dest,dest);
for(i=3; i < argc; i++)
if(setcall(&addr.digis[i-3],argv[i])){ /* k34 */
current = ps;
freesession(s); /* will free name */
return -1;
}
addr.ndigis = i - 3;
s->cb.ax25_cb = open_ax25(&addr,axwindow,ax_rx,ax_tx,ax_state,ifp,(char *)s);
go();
return 0;
}
/* Display changes in AX.25 state */
void
ax_state(axp,old,new)
struct ax25_cb *axp;
int old,new;
{
struct session *s;
int cmdmode();
s = (struct session *)axp->user;
if(current != NULLSESSION && current->type == AX25TNC && current == s){
/* Don't print transitions between CONNECTED and RECOVERY */
if(new != RECOVERY && !(old == RECOVERY && new == CONNECTED))
printf("%s\n",ax25states[new]);
#ifdef PESKYPROMPT
printf("<%s %s>\n",ax25states[old],ax25states[new]);
#endif
fflush(stdout); /* moved up - k35 */
if(new == DISCONNECTED || new == DISCPENDING)
cmdmode();
}
if(new == DISCONNECTED){
axp->user = NULLCHAR;
freesession(s);
}
}
/* Handle typed characters on AX.25 connection */
int
ax_parse(buf,cnt)
char *buf;
int16 cnt;
{
struct mbuf *bp;
void term_send();
if(current == NULLSESSION || current->type != AX25TNC)
return; /* "can't happen" */
/* Allocate buffer and start it with the PID */
bp = alloc_mbuf(cnt+1);
*bp->data = PID_NO_L3;
bp->cnt++;
term_send(bp,buf,cnt,1);
send_ax25(current->cb.ax25_cb,bp);
}
/* Handle new incoming terminal sessions
* This is the default receive upcall function, used when
* someone else connects to us
*/
void
ax_incom(axp,cnt)
register struct ax25_cb *axp;
int16 cnt;
{
void ax_session() ;
#ifdef AXMBX
extern int ax25mbox;
void mbx_incom();
if (ax25mbox)
mbx_incom(axp,cnt) ;
else
#endif
ax_session(axp,cnt) ;
return ;
}
/* This function sets up an ax25 chat session */
void
ax_session(axp,unused)
register struct ax25_cb *axp ;
int16 unused;
{
struct session *s;
#ifdef POLITE
struct session *tmpsession;
#endif
char remote[10];
void ax_rx(),ax_state(),ax_tx();
int disc_ax25(),go();
extern struct session *current;
#ifdef AX_MOTD
extern char ax_motd[];
#endif
pax25(remote,&axp->addr.dest);
if((s = newsession()) == NULLSESSION){
/* Out of sessions */
disc_ax25(axp);
return;
}
s->type = AX25TNC;
s->name = malloc((int16)strlen(remote)+1);
s->cb.ax25_cb = axp;
s->parse = ax_parse;
strcpy(s->name,remote);
axp->r_upcall = ax_rx;
axp->s_upcall = ax_state;
axp->t_upcall = ax_tx;
axp->user = (char *)s;
printf("\007Incoming AX25 session %u from %s\n",s - sessions,remote);
fflush(stdout);
#ifdef POLITE
tmpsession = current; /* may need this later */
#endif
current = s; /* this may be only temporary if we are busy */
#ifdef AX_MOTD
if(ax_motd[0])
ax_parse(ax_motd,strlen(ax_motd));
#endif
#ifdef POLITE
if((s - sessions) == 0) /* will prevent us from doing self test */
go();
else
current = tmpsession;
#else
go();
#endif
}
/* Handle incoming terminal traffic */
void
ax_rx(axp,cnt)
struct ax25_cb *axp;
int16 cnt;
{
register struct mbuf *bp;
struct mbuf *recv_ax25();
void term_recv();
#ifdef FLOW
extern int ttyflow; /* added - K5JB */
#endif
/* Hold output if we're not the current session */
if(mode != CONV_MODE || current == NULLSESSION
#ifdef FLOW
|| !ttyflow /* Or if blocked by keyboard input -- hyc - K5JB */
#endif
|| current->type != AX25TNC || current->cb.ax25_cb != axp)
return;
if((bp = recv_ax25(axp,cnt)) == NULLBUF)
return;
term_recv(bp,current->record);
}
/* Handle transmit upcalls. Used only for file uploading */
void
ax_tx(axp,cnt)
struct ax25_cb *axp;
int16 cnt;
{
register char *cp;
struct session *s;
register struct mbuf *bp;
int16 size;
int c;
void free();
#ifdef SYS5
struct stat ss_buf;
#endif
if((s = (struct session *)axp->user) == NULLSESSION
|| s->upload == NULLFILE)
return;
while(cnt != 0){
size = min(cnt,axp->paclen+1);
if((bp = alloc_mbuf(size)) == NULLBUF)
break;
cp = bp->data;
/* Start with the PID */
*cp++ = PID_NO_L3;
bp->cnt++;
/* Now send data characters, translating between local
* keyboard end-of-line sequences and the (unwritten)
* AX.25 convention, which is carriage-return only
*/
while(bp->cnt < size){
if((c = getc(s->upload)) == EOF)
break;
#if defined(MSDOS) || defined(_OSK)
/* Explicit octals given because OS9/K compiler defines \n as a carriage
* return - N0QBJ
*/
/* MS-DOS gives cr-lf */
if(c == '\012')
continue;
#endif
#ifdef UNIX
/* These give lf only */
if(c == '\012')
c = '\015';
#endif
*cp++ = c;
bp->cnt++;
}
if(bp->cnt > 1) {
send_ax25(axp,bp);
} else {
/* Empty frame, don't bother sending */
free_p(bp);
break;
}
cnt -= bp->cnt;
}
if(cnt != 0){
#if defined(_OSK) && !defined(_UCC)
tmpclose(s->upload);
#else
/* Note that this area is VERY Unix system-dependent. If you aren't
* using the shell escape, you can just do pclose(), and if err, do
* fclose, but this method messes up the forked child doing shell.
* Note also that I included ionode.h, not types.h.
*/
#ifdef SYS5
if(fstat(fileno(s->upload),&ss_buf) < 0)
perror("ax_tx");
#ifdef COH386
if ((ss_buf.st_mode & S_IFPIP) == S_IFPIP)
#else
if((ss_buf.st_mode & IFIFO) == IFIFO)
#endif
pclose(s->upload); /* close pipe from dir */
else
#endif
fclose(s->upload);
#endif /* _OSK */
s->upload = NULLFILE;
free(s->ufile);
s->ufile = NULLCHAR;
}
}
#ifdef AX25_HEARD
/* heard stuff -- Initially dredged up and contributed by N4HXH */
struct ax25_heard heard = {1,0,-1}; /* initially enabled */
/* build a file, heard.hlp, readable by ax24 heard, mailbox jheard, or
help heard. File is over-written with each call. Return a null pointer
if heard is not enabled, or unable to open file */
char *
buildheard(mbox)
int mbox;
{
struct heard_stuff *hp;
struct ax25_addr *dp;
extern struct ax25_heard heard;
char *pp;
extern char *homedir;
extern char *make_path();
void free();
FILE *hfp;
char tmp[32];
int curr;
time_t t;
/* we use a file so net isn't tied up so long with screen */
if(!heard.enabled)
return(NULLCHAR);
if((pp = make_path(homedir,"heard.hlp",1)) == NULLCHAR)
return(NULLCHAR);
#ifdef MSDOS
if((hfp = fopen(pp,"w+t")) == NULL)
#else
if((hfp = fopen(pp,"w+")) == NULL)
#endif
{
if(!mbox)
printf("doheard: Cannot open file: %s\n",pp);
free(pp);
return(NULLCHAR);
}
time(&t);
fprintf(hfp,"Heard list (info frames only) Saved at %s",ctime(&t));
curr = heard.first;
while (curr != -1) {
hp = &heard.list[curr];
fprintf(hfp,"%4s: ",hp->ifacename); /* max length enforced elsewhere */
sprintf(tmp,ctime((time_t *)&hp->htime));
tmp[19] = '\0'; /* shorten up time string a bit */
fprintf(hfp,"%s ",&tmp[4]);
if (hp->flags) {
fprintf(hfp,"%-4s%-3s%-4s%-5s", /* Note that these are accumulated */
(hp->flags & HEARD_ARP) ? "ARP" : "",
(hp->flags & HEARD_IP) ? "IP" : "",
(hp->flags & HEARD_NETROM) ? "N/R" : "",
(hp->flags & HEARD_ROSE) ? "ROSE" : "");
}else
fprintf(hfp,"............... ");
pax25(tmp,&hp->info.source);
fprintf(hfp,"%s>",tmp);
pax25(tmp,&hp->info.dest);
fprintf(hfp,"%s",tmp);
if(hp->info.ndigis > 0){
/* print digi string */
for(dp = &hp->info.digis[0];
dp < &hp->info.digis[hp->info.ndigis]; dp++){
pax25(tmp,dp);
fprintf(hfp," %s",tmp);
if (dp->ssid & REPEATED)
fprintf(hfp,"*");
}
}
fprintf(hfp,"\n");
curr = hp->next;
} /* while */
fprintf(hfp,"End of heard list\n");
fclose(hfp);
return(pp); /* a non null pp will be freed by caller */
}
/* Display AX.25 heard list */
static
doheard(argc,argv)
int argc;
char *argv[];
{
extern struct ax25_heard heard;
void free();
char *pp;
extern int dohelpfile();
if(argc < 2) {
if((pp = buildheard(0)) != NULLCHAR){
dohelpfile(pp,0); /* ignore return value */
free(pp);
}else
printf("not enabled\n");
}else if(argv[1][1] == 'l'){ /* ell */
heard.cnt = 0;
heard.first = -1;
} else if(argv[1][1] == 'n'){
if (!heard.enabled) {
heard.enabled = 1;
heard.cnt = 0;
heard.first = -1;
}
} else if(argv[1][1] == 'f'){
heard.enabled = 0;
} else
return -1;
return 0;
}
/* heard stuff */
#endif /* AX25_HEARD */
#endif /* AX25 */