/* AX25 control commands * Copyright 1991 Phil Karn, KA9Q */ #include #include "global.h" #include "mbuf.h" #include "timer.h" #include "proc.h" #include "iface.h" #include "ax25.h" #include "lapb.h" #include "cmdparse.h" #include "socket.h" #include "mailbox.h" #include "session.h" #include "tty.h" #include "nr4.h" #include "commands.h" static int axdest __ARGS((struct iface *ifp)); static int axheard __ARGS((struct iface *ifp)); static void axflush __ARGS((struct iface *ifp)); static int doaxflush __ARGS((int argc,char *argv[],void *p)); static int doaxirtt __ARGS((int argc,char *argv[],void *p)); static int doaxkick __ARGS((int argc,char *argv[],void *p)); static int doaxreset __ARGS((int argc,char *argv[],void *p)); static int doaxroute __ARGS((int argc,char *argv[],void *p)); static int doaxstat __ARGS((int argc,char *argv[],void *p)); static int doaxwindow __ARGS((int argc,char *argv[],void *p)); static int doblimit __ARGS((int argc,char *argv[],void *p)); static int dodigipeat __ARGS((int argc,char *argv[],void *p)); static int domaxframe __ARGS((int argc,char *argv[],void *p)); static int domycall __ARGS((int argc,char *argv[],void *p)); static int don2 __ARGS((int argc,char *argv[],void *p)); static int dopaclen __ARGS((int argc,char *argv[],void *p)); static int dopthresh __ARGS((int argc,char *argv[],void *p)); static int dot3 __ARGS((int argc,char *argv[],void *p)); static int doversion __ARGS((int argc,char *argv[],void *p)); char *Ax25states[] = { "", "Disconnected", "Listening", "Conn pending", "Disc pending", "Connected", "Recovery", }; /* Ascii explanations for the disconnect reasons listed in lapb.h under * "reason" in ax25_cb */ char *Axreasons[] = { "Normal", "DM received", "Timeout" }; static struct cmds Axcmds[] = { "blimit", doblimit, 0, 0, NULLCHAR, "destlist", doaxdest, 0, 0, NULLCHAR, "digipeat", dodigipeat, 0, 0, NULLCHAR, "flush", doaxflush, 0, 0, NULLCHAR, "heard", doaxheard, 0, 0, NULLCHAR, "irtt", doaxirtt, 0, 0, NULLCHAR, "kick", doaxkick, 0, 2, "ax25 kick ", "maxframe", domaxframe, 0, 0, NULLCHAR, "mycall", domycall, 0, 0, NULLCHAR, "paclen", dopaclen, 0, 0, NULLCHAR, "pthresh", dopthresh, 0, 0, NULLCHAR, "reset", doaxreset, 0, 2, "ax25 reset ", "retry", don2, 0, 0, NULLCHAR, "route", doaxroute, 0, 0, NULLCHAR, "status", doaxstat, 0, 0, NULLCHAR, "t3", dot3, 0, 0, NULLCHAR, "version", doversion, 0, 0, NULLCHAR, "window", doaxwindow, 0, 0, NULLCHAR, NULLCHAR, }; /* Multiplexer for top-level ax25 command */ int doax25(argc,argv,p) int argc; char *argv[]; void *p; { return subcmd(Axcmds,argc,argv,p); } int doaxheard(argc,argv,p) int argc; char *argv[]; void *p; { struct iface *ifp; if(argc > 1){ if((ifp = if_lookup(argv[1])) == NULLIF){ tprintf("Interface %s unknown\n",argv[1]); return 1; } if(ifp->output != ax_output){ tprintf("Interface %s not AX.25\n",argv[1]); return 1; } axheard(ifp); return 0; } for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){ if(ifp->output != ax_output) continue; /* Not an ax.25 interface */ if(axheard(ifp) == EOF) break; } return 0; } static int axheard(ifp) struct iface *ifp; { struct lq *lp; char tmp[AXBUF]; if(ifp->hwaddr == NULLCHAR) return 0; tprintf("%s:\n",ifp->name); tprintf("Station Last heard Pkts\n"); for(lp = Lq;lp != NULLLQ;lp = lp->next){ if(lp->iface != ifp) continue; if(tprintf("%-10s%-17s%8lu\n",pax25(tmp,lp->addr), tformat(secclock() - lp->time),lp->currxcnt) == EOF) return EOF; } return 0; } int doaxdest(argc,argv,p) int argc; char *argv[]; void *p; { struct iface *ifp; if(argc > 1){ if((ifp = if_lookup(argv[1])) == NULLIF){ tprintf("Interface %s unknown\n",argv[1]); return 1; } if(ifp->output != ax_output){ tprintf("Interface %s not AX.25\n",argv[1]); return 1; } axdest(ifp); return 0; } for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){ if(ifp->output != ax_output) continue; /* Not an ax.25 interface */ if(axdest(ifp) == EOF) break; } return 0; } static int axdest(ifp) struct iface *ifp; { struct ld *lp; struct lq *lq; char tmp[AXBUF]; if(ifp->hwaddr == NULLCHAR) return 0; tprintf("%s:\n",ifp->name); tprintf("Station Last ref Last heard Pkts\n"); for(lp = Ld;lp != NULLLD;lp = lp->next){ if(lp->iface != ifp) continue; tprintf("%-10s%-17s", pax25(tmp,lp->addr),tformat(secclock() - lp->time)); if(addreq(lp->addr,ifp->hwaddr)){ /* Special case; it's our address */ tprintf("%-17s",tformat(secclock() - ifp->lastsent)); } else if((lq = al_lookup(ifp,lp->addr,0)) == NULLLQ){ tprintf("%-17s",""); } else { tprintf("%-17s",tformat(secclock() - lq->time)); } if(tprintf("%8lu\n",lp->currxcnt) == EOF) return EOF; } return 0; } static int doaxflush(argc,argv,p) int argc; char *argv[]; void *p; { struct iface *ifp; for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){ if(ifp->output != ax_output) continue; /* Not an ax.25 interface */ axflush(ifp); } return 0; } static void axflush(ifp) struct iface *ifp; { struct lq *lp,*lp1; struct ld *ld,*ld1; ifp->rawsndcnt = 0; for(lp = Lq;lp != NULLLQ;lp = lp1){ lp1 = lp->next; free((char *)lp); } Lq = NULLLQ; for(ld = Ld;ld != NULLLD;ld = ld1){ ld1 = ld->next; free((char *)ld); } Ld = NULLLD; } static doaxreset(argc,argv,p) int argc; char *argv[]; void *p; { struct ax25_cb *axp; axp = (struct ax25_cb *)ltop(htol(argv[1])); if(!ax25val(axp)){ tprintf(Notval); return 1; } reset_ax25(axp); return 0; } /* Display AX.25 link level control blocks */ static doaxstat(argc,argv,p) int argc; char *argv[]; void *p; { register struct ax25_cb *axp; char tmp[AXBUF]; if(argc < 2){ tprintf(" &AXB Snd-Q Rcv-Q Remote State\n"); for(axp = Ax25_cb;axp != NULLAX25; axp = axp->next){ if(tprintf("%8lx %-8d%-8d%-10s%s\n", ptol(axp), len_q(axp->txq),len_p(axp->rxq), pax25(tmp,axp->remote), Ax25states[axp->state]) == EOF) return 0; } return 0; } axp = (struct ax25_cb *)ltop(htol(argv[1])); if(!ax25val(axp)){ tprintf(Notval); return 1; } st_ax25(axp); return 0; } /* Dump one control block */ void st_ax25(axp) register struct ax25_cb *axp; { char tmp[AXBUF]; if(axp == NULLAX25) return; tprintf(" &AXB Remote RB V(S) V(R) Unack P Retry State\n"); tprintf("%8lx %-9s%c%c",ptol(axp),pax25(tmp,axp->remote), axp->flags.rejsent ? 'R' : ' ', axp->flags.remotebusy ? 'B' : ' '); tprintf(" %4d %4d",axp->vs,axp->vr); tprintf(" %02u/%02u %u",axp->unack,axp->maxframe,axp->proto); tprintf(" %02u/%02u",axp->retries,axp->n2); tprintf(" %s\n",Ax25states[axp->state]); tprintf("srtt = %lu mdev = %lu ",axp->srt,axp->mdev); tprintf("T1: "); if(run_timer(&axp->t1)) tprintf("%lu",read_timer(&axp->t1)); else tprintf("stop"); tprintf("/%lu ms; ",dur_timer(&axp->t1)); tprintf("T3: "); if(run_timer(&axp->t3)) tprintf("%lu",read_timer(&axp->t3)); else tprintf("stop"); tprintf("/%lu ms\n",dur_timer(&axp->t3)); } /* Display or change our AX.25 address */ static domycall(argc,argv,p) int argc; char *argv[]; void *p; { char tmp[AXBUF]; if(argc < 2){ tprintf("%s\n",pax25(tmp,Mycall)); return 0; } if(setcall(Mycall,argv[1]) == -1) return -1; return 0; } /* Control AX.25 digipeating */ static dodigipeat(argc,argv,p) int argc; char *argv[]; void *p; { return setbool(&Digipeat,"Digipeat",argc,argv); } /* Set limit on retransmission backoff */ static doblimit(argc,argv,p) int argc; char *argv[]; void *p; { return setlong(&Blimit,"blimit",argc,argv); } static doversion(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Axversion,"AX25 version",argc,argv); } static doaxirtt(argc,argv,p) int argc; char *argv[]; void *p; { return setlong(&Axirtt,"Initial RTT (ms)",argc,argv); } /* Set idle timer */ static dot3(argc,argv,p) int argc; char *argv[]; void *p; { return setlong(&T3init,"Idle poll timer (ms)",argc,argv); } /* Set retry limit count */ static don2(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&N2,"Retry limit",argc,argv); } /* Force a retransmission */ static doaxkick(argc,argv,p) int argc; char *argv[]; void *p; { struct ax25_cb *axp; axp = (struct ax25_cb *)ltop(htol(argv[1])); if(!ax25val(axp)){ tprintf(Notval); return 1; } kick_ax25(axp); return 0; } /* Set maximum number of frames that will be allowed in flight */ static domaxframe(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Maxframe,"Window size (frames)",argc,argv); } /* Set maximum length of I-frame data field */ static dopaclen(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Paclen,"Max frame length (bytes)",argc,argv); } /* Set size of I-frame above which polls will be sent after a timeout */ static dopthresh(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Pthresh,"Poll threshold (bytes)",argc,argv); } /* Set high water mark on receive queue that triggers RNR */ static doaxwindow(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Axwindow,"AX25 receive window (bytes)",argc,argv); } /* End of ax25 subcommands */ /* Initiate interactive AX.25 connect to remote station */ int doconnect(argc,argv,p) int argc; char *argv[]; void *p; { struct sockaddr_ax fsocket; struct session *sp; int ndigis,i; char digis[MAXDIGIS][AXALEN]; char target[AXALEN]; /* If digipeaters are given, put them in the routing table */ if(argc > 3){ setcall(target,argv[2]); ndigis = argc - 3; if(ndigis > MAXDIGIS){ tprintf("Too many digipeaters\n"); return 1; } for(i=0;iflowmode = 0; if((sp->s = socket(AF_AX25,SOCK_STREAM,0)) == -1){ tprintf("Can't create socket\n"); freesession(sp); keywait(NULLCHAR,1); return 1; } fsocket.sax_family = AF_AX25; setcall(fsocket.ax25_addr,argv[2]); strncpy(fsocket.iface,argv[1],ILEN); return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_ax)); } /* Display and modify AX.25 routing table */ static int doaxroute(argc,argv,p) int argc; char *argv[]; void *p; { char tmp[AXBUF]; int i,ndigis; register struct ax_route *axr; char target[AXALEN],digis[MAXDIGIS][AXALEN]; if(argc < 2){ tprintf("Target Type Digipeaters\n"); for(axr = Ax_routes;axr != NULLAXR;axr = axr->next){ tprintf("%-10s%-6s",pax25(tmp,axr->target), axr->type == AX_LOCAL ? "Local":"Auto"); for(i=0;indigis;i++){ tprintf(" %s",pax25(tmp,axr->digis[i])); } if(tprintf("\n") == EOF) return 0; } return 0; } if(argc < 3){ tprintf("Usage: ax25 route add [digis...]\n"); tprintf(" ax25 route drop \n"); return 1; } if(setcall(target,argv[2]) == -1){ tprintf("Bad target %s\n",argv[2]); return 1; } switch(argv[1][0]){ case 'a': /* Add route */ if(argc < 3){ tprintf("Usage: ax25 route add [digis...]\n"); return 1; } ndigis = argc - 3; if(ndigis > MAXDIGIS){ tprintf("Too many digipeaters\n"); return 1; } for(i=0;i