#include #include "global.h" #include "mbuf.h" #include "ax25.h" #include "timer.h" #include "iface.h" #include "lapb.h" #include "cmdparse.h" #include "session.h" #include "st.h" /* DG2KK */ extern struct tcb; #define NULLTCB (struct tcb *)0 #ifdef FLOW extern int ttyflow; /* DG2KK (output flowcontrol) */ #endif char *ax25states[] = { "Disconnected", "Conn pending", "Disc pending", "Connected", "Frame Reject", }; int domycall(),dodigipeat(),doaxstat(),dot1(),dot2(),dot3(),domaxframe(), doaxwindow(),dopaclen(),don2(),doaxreset(),doconok(); /* DG2KK */ static struct cmds axcmds[] = { "conok", doconok, 0, NULLCHAR, NULLCHAR, /* DG2KK */ "digipeat", dodigipeat, 0, NULLCHAR, NULLCHAR, "maxframe", domaxframe, 0, NULLCHAR, NULLCHAR, "mycall", domycall, 0, NULLCHAR, NULLCHAR, "paclen", dopaclen, 0, NULLCHAR, NULLCHAR, "reset", doaxreset, 2, "ax25 reset ", NULLCHAR, "retry", don2, 0, NULLCHAR, NULLCHAR, "status", doaxstat, 0, NULLCHAR, NULLCHAR, "t1", dot1, 0, NULLCHAR, NULLCHAR, "t2", dot2, 0, NULLCHAR, NULLCHAR, "t3", dot3, 0, NULLCHAR, NULLCHAR, "window", doaxwindow, 0, NULLCHAR, NULLCHAR, NULLCHAR, NULLFP, 0, "ax25 subcommands: digipeat maxframe mycall paclen reset retry status\n\tt1 t2 t3 window", NULLCHAR, }; /* Multiplexer for top-level ax25 command */ doax25(argc,argv) int argc; char *argv[]; { return subcmd(axcmds,argc,argv); } static doaxreset(argc,argv) int argc; char *argv[]; { struct ax25_cb *axp; extern char notval[]; long htol(); axp = (struct ax25_cb *)htol(argv[1]); if(!ax25val(axp)){ printf(notval); return 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[]; long htol(); if(argc < 2){ printf(" &AXB IF Snd-Q Rcv-Q Remote State\n"); for(i=0;inext){ pax25(tmp,&axp->addr.dest); printf("%8lx %-5s%-8d%-8d%-10s%s\n", (long)axp,axp->interface->name, len_q(axp->txq),len_mbuf(axp->rxq), tmp,ax25states[axp->state]); } } return 0; } axp = (struct ax25_cb *)htol(argv[1]); if(!ax25val(axp)){ printf(notval); return 1; } dumpstat(axp); return 0; } /* Dump one control block */ static dumpstat(axp) register struct ax25_cb *axp; { char tmp[10]; int i; if(axp == NULLAX25 || axp->interface == NULLIF) return; /* DG2KK: changed "&AXB IF..." to " &AXB IF..." (Atari has 5 digit addr. */ printf(" &AXB IF Remote RBW V(S) V(R) Unack P Retry T1 T2 T3 State\n"); pax25(tmp,&axp->addr.dest); printf("%4x %-5s%-9s",(int)axp,axp->interface->name,tmp); putchar(axp->rejsent ? 'R' : ' '); putchar(axp->remotebusy ? 'B' : ' '); putchar(axp->waitack ? 'W' : ' '); printf(" %4d %4d",axp->vs,axp->vr); printf(" %02d/%02d %d",axp->unack,axp->maxframe,axp->proto); printf(" %02d/%02d",axp->retries,axp->n2); if(run_timer(&axp->t1)) printf(" %02d/%02d",axp->t1.start - axp->t1.count, axp->t1.start); else printf(" /%02d",axp->t1.start); if(run_timer(&axp->t2)) printf(" %02d/%02d",axp->t2.start - axp->t2.count, axp->t2.start); else printf(" /%02d",axp->t2.start); if(run_timer(&axp->t3)) printf(" %02d/%02d",axp->t3.start - axp->t3.count, axp->t3.start); else printf(" /%02d",axp->t3.start); printf(" %s\n",ax25states[axp->state]); if(axp->addr.ndigis == 0) return; printf("Digipeaters:"); for(i=0;iaddr.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; return 0; } /* 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 { if(strcmp(argv[1],"on") == 0) digipeat = 1; else digipeat = 0; } } /* Set retransmission timer */ static dot1(argc,argv) int argc; char *argv[]; { extern int16 t1init; if(argc == 1) { printf("T1 %d\n",t1init); } else { t1init = atoi(argv[1]); } } /* Set acknowledgement delay timer */ static dot2(argc,argv) int argc; char *argv[]; { extern int16 t2init; if(argc == 1) { printf("T2 %d\n",t2init); } else { t2init = atoi(argv[1]); } } /* Set idle timer */ static dot3(argc,argv) int argc; char *argv[]; { extern int16 t3init; if(argc == 1) { printf("T3 %d\n",t3init); } else { t3init = atoi(argv[1]); } } /* Set retry limit count */ static don2(argc,argv) int argc; char *argv[]; { extern int16 n2; if(argc == 1) { printf("Retry %d\n",n2); } else { n2 = atoi(argv[1]); } } /* 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 %d\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 %d\n",paclen); } else { paclen = 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 %d\n",axwindow); } else { axwindow = atoi(argv[1]); } } /* End of ax25 subcommands */ /* Initiate interactive AX.25 connect to remote station */ doconnect(argc,argv) int argc; char *argv[]; { void ax_rx(),ax_tx(),ax_state(); int ax_parse(); struct ax25_addr dest; struct ax25 addr; struct ax25_cb *open_ax25(); struct interface *ifp; struct session *s; extern int16 axwindow; int i; 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; } setcall(&dest,argv[2]); /* 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)){ #if ( MAC || AMIGA ) printf("Session %lu to %s already exists\n", #else printf("Session %u to %s already exists\n", #endif 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; current = s; ASSIGN(addr.source,mycall); /* DG2KK: should be changed */ setcall(&addr.dest,argv[2]); for(i=3; i < argc; i++) setcall(&addr.digis[i-3],argv[i]); 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; char remote[10]; /* DG2KK */ s = (struct session *)axp->user; if(current != NULLSESSION && current->type == AX25TNC && current == s){ printf("%s\n",ax25states[new]); /* added to enable a 'bell' when state is connected */ /* ---- DG2KK: AX25 logging ---- */ if(new == CONNECTED) { printf("\007"); pax25(remote,&axp->addr.dest); log(NULLTCB,"Connected to %s",remote); } if(new == DISCONNECTED) { pax25(remote,&axp->addr.dest); log(NULLTCB,"Disconnected from %s",remote); cmdmode(); } /* ----- */ fflush(stdout); } 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; register char *cp; char c; if(current == NULLSESSION || current->type != AX25TNC) return; /* "can't happen" */ /* If recording is on, record outgoing stuff too */ if(current->record != NULLFILE) fwrite(buf,1,cnt,current->record); /* Allocate buffer and start it with the PID */ bp = alloc_mbuf(cnt+1); *bp->data = PID_FIRST | PID_LAST | PID_NO_L3; bp->cnt++; /* Copy keyboard buffer to output, stripping line feeds */ cp = bp->data + 1; while(cnt-- != 0){ c = *buf++; if(c != '\n'){ *cp++ = c; bp->cnt++; } } send_ax25(current->cb.ax25_cb,bp); } /* 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; { /* temporary hack - replace with a switch */ mbx_incom(axp,cnt); return; } /* This function sets up an ax25 chat session. * (Formerly ax_incom())! * Handle new incoming terminal sessions * This is the default receive upcall function, used when * someone else connects to us */ void ax_session(axp,cnt) /* DG2KK: was ax_income() */ register struct ax25_cb *axp; int16 cnt; { struct session *s; char remote[10]; void ax_rx(),ax_state(); 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->user = (char *)s; #if ( MAC || AMIGA ) /* was: (defined(MAC) || defined(AMIGA)) DG2KK */ printf("\007Incoming AX25 session %lu from %s\n",s - sessions,remote); #else printf("\007Incoming AX25 session %u from %s\n",s - sessions,remote); #endif fflush(stdout); } /* Handle incoming terminal traffic */ void ax_rx(axp,cnt) struct ax25_cb *axp; int16 cnt; { register struct mbuf *bp; struct mbuf *recv_ax25(); char c; /* Hold output if we're not the current session */ if(mode != CONV_MODE || current == NULLSESSION || current->type != AX25TNC || current->cb.ax25_cb != axp) return; #ifdef FLOW if (ttyflow == 0) /* DG2KK */ return; #endif FLOW if((bp = recv_ax25(axp,cnt)) == NULLBUF) return; /* Display received characters, translating CR's to CR/LF */ while(bp != NULLBUF){ while(bp->cnt-- != 0){ c = *bp->data++; putc(c,stdout); if(current->record){ fputc(c,current->record); if(c == '\r') fputc('\n',current->record); } if(c == '\r') putc('\n',stdout); } bp = free_mbuf(bp); } if(current->record) fflush(current->record); fflush(stdout); } /* 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; 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_FIRST | PID_LAST | 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; #ifdef MSDOS /* MS-DOS gives cr-lf */ if(c == '\n') continue; #endif #if (UNIX || MAC || AMIGA) /*(defined(UNIX) || defined(MAC) || defined(AMIGA))*/ /* These give lf only */ if(c == '\n') c = '\r'; #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){ /* Error or end-of-file */ fclose(s->upload); s->upload = NULLFILE; free(s->ufile); s->ufile = NULLCHAR; } } /* Control AX.25 connects (DG2KK) */ static doconok(argc,argv) int argc; char *argv[]; { extern int conok; if(argc == 1) { printf("conok %s\n",conok ? "on" : "off"); } else { if(strcmp(argv[1],"on") == 0) conok = 1; else conok = 0; } }