home *** CD-ROM | disk | FTP | other *** search
- /* Automatic SLIP/PPP line dialer.
- *
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mar '91 Bill Simpson & Glenn McGregor
- * completely re-written;
- * human readable control file;
- * includes wait for string, and speed sense;
- * dials immediately when invoked.
- * May '91 Bill Simpson
- * re-ordered command line;
- * allow dial only;
- * allow inactivity timeout without ping.
- * Sep '91 Bill Simpson
- * Check known DTR & RSLD state for redial decision
- * Mar '92 Phil Karn
- * autosense modem control stuff removed
- * Largely rewritten to do demand dialing
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "proc.h"
- #include "iface.h"
- #include "netuser.h"
- #include "n8250.h"
- #include "asy.h"
- #include "tty.h"
- #include "socket.h"
- #include "cmdparse.h"
- #include "devparam.h"
- #include "files.h"
- #include "main.h"
- #include "trace.h"
- #include "commands.h"
-
- static int redial __ARGS((struct iface *ifp,char *file));
- static void dropline __ARGS((void *));
- static void dropit(int,void *,void *);
-
- static int dodial_control __ARGS((int argc,char *argv[],void *p));
- static int dodial_send __ARGS((int argc,char *argv[],void *p));
- static int dodial_speed __ARGS((int argc,char *argv[],void *p));
- static int dodial_status __ARGS((int argc,char *argv[],void *p));
- static int dodial_wait __ARGS((int argc,char *argv[],void *p));
-
- static struct cmds dial_cmds[] = {
- "", donothing, 0, 0, "",
- "control", dodial_control, 0, 2, "control up | down",
- "send", dodial_send, 0, 2,
- "send \"string\" [<milliseconds>]",
- "speed", dodial_speed, 0, 2, "speed <bps>",
- "status", dodial_status, 0, 2, "status up | down",
- "wait", dodial_wait, 0, 2,
- "wait <milliseconds> [ \"string\" [speed] ]",
- NULLCHAR, NULLFP, 0, 0, "Unknown command",
- };
- /*
- * dial <iface> <seconds> <raisefile> <dropfile>
- * dial <iface>
- * dial <iface> 0
- */
- int
- dodialer(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp;
- struct asy *ap;
- int32 timeout;
-
- if((ifp = if_lookup(argv[1])) == NULLIF){
- printf("Interface %s unknown\n",argv[1]);
- return 1;
- }
- if(ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp){
- printf("Interface %s not asy port\n",argv[1]);
- return 1;
- }
- ap = &Asy[ifp->dev];
- if(argc < 3){
- printf("%s: %s",ifp->name,(ap->msr & MSR_RLSD) ? "UP":"DOWN");
- printf(", idle timer %ld/%ld",read_timer(&ap->idle)/1000L,
- dur_timer(&ap->idle)/1000L);
- if(ap->actfile != NULLCHAR)
- printf(", up script: %s",ap->actfile);
- if(ap->dropfile != NULLCHAR)
- printf(", down script: %s\n",ap->dropfile);
- else
- printf("\n");
-
- printf("Calls originated %ld, carrier up transitions %ld\n",
- ap->originates,ap->answers);
- printf("Calls timed out %ld, carrier down transitions %ld\n",
- ap->localdrops,ap->remdrops);
- return 0;
- }
- timeout = atol(argv[2]) * 1000L;
- if(timeout != 0 && argc < 5){
- printf("Usage: dial <iface> <timeout> <raisefile> <dropfile>\n");
- printf(" dial <iface> 0\n");
- return 1;
- }
- if(!ap->rlsd){
- printf("Must set 'r' flag at attach time\n");
- return 1;
- }
- stop_timer(&ap->idle);
- set_timer(&ap->idle,timeout);
- ap->idle.func = dropline;
- ap->idle.arg = ifp;
- if(ap->actfile != NULLCHAR){
- free(ap->actfile);
- ap->actfile = NULLCHAR;
- }
- if(ap->dropfile != NULLCHAR){
- free(ap->dropfile);
- ap->dropfile = NULLCHAR;
- }
- if(timeout != 0){
- ap->actfile = strdup(argv[3]);
- ap->dropfile = strdup(argv[4]);
- start_timer(&ap->idle);
- }
- return 0;
- }
- void
- dialer_kick(asyp)
- struct asy *asyp;
- {
- int backoff = -1;
- int pw;
-
- stop_timer(&asyp->idle);
- while(asyp->rlsd && (asyp->msr & MSR_RLSD) == 0
- && asyp->actfile != NULLCHAR){
- /* Line down, we need to redial
- * But if it's failing, perform random binary
- * exponential backoff
- */
- if(backoff++ >= 0){
- alarm(1000L*random(30L << backoff));
- pw = pwait(&asyp->rlsd);
- alarm(0L);
- if(pw == 0)
- continue; /* CD changed, maybe we got called */
- }
- asyp->originates++;
- redial(asyp->iface,asyp->actfile);
- }
- }
-
- /* Called when idle line timer expires -- executes script to drop line */
- static void
- dropline(p)
- void *p;
- {
- /* Fork this off to prevent wedging the timer task */
- newproc("dropit",512,dropit,0,p,NULL,0);
- }
-
- static void
- dropit(i,p,u)
- int i;
- void *p;
- void *u;
- {
- struct iface *ifp = p;
- struct asy *ap;
-
- ap = &Asy[ifp->dev];
- if(ap->msr & MSR_RLSD){
- ap->localdrops++;
- redial(ifp,ap->dropfile); /* Drop only if still up */
- }
- }
-
- /* execute dialer commands
- * returns: -1 fatal error, 0 OK, 1 try again
- */
- static int
- redial(ifp,file)
- struct iface *ifp;
- char *file;
- {
- char *inbuf, *intmp;
- FILE *fp;
- int (*rawsave) __ARGS((struct iface *,struct mbuf *));
- int result = 0;
-
- if((fp = fopen(file,READ_TEXT)) == NULLFILE){
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"redial: can't read %s\n",file);
- return -1;
- }
- /* Save output handler and temporarily redirect output to null */
- if(ifp->raw == bitbucket){
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"redial: tip or dialer already active on %s\n",ifp->name);
-
- return -1;
- }
-
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"Dialing on %s\n\n",ifp->name);
-
- /* Save output handler and temporarily redirect output to null */
- rawsave = ifp->raw;
- ifp->raw = bitbucket;
-
- /* Suspend the packet input driver. Note that the transmit driver
- * is left running since we use it to send buffers to the line.
- */
- suspend(ifp->rxproc);
-
- inbuf = mallocw(BUFSIZ);
- intmp = mallocw(BUFSIZ);
- while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
- strcpy(intmp,inbuf);
- rip(intmp);
- log(-1,"%s dialer: %s",ifp->name,intmp);
- if((result = cmdparse(dial_cmds,inbuf,ifp)) != 0){
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"input line: %s",intmp);
- break;
- }
- }
- free(inbuf);
- free(intmp);
- fclose(fp);
-
- if(result == 0){
- ifp->lastsent = ifp->lastrecv = secclock();
- }
- ifp->raw = rawsave;
- resume(ifp->rxproc);
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"\nDial %s complete\n",ifp->name);
-
- return result;
- }
-
-
- static int
- dodial_control(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp = p;
- int param;
-
- if ( ifp->ioctl == NULL )
- return -1;
-
- if ( (param = devparam( argv[1] )) == -1 )
- return -1;
-
- (*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
- return 0;
- }
-
-
- static int
- dodial_send(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp = p;
- struct mbuf *bp;
-
- if(argc > 2){
- /* Send characters with inter-character delay
- * (for dealing with prehistoric Micom switches that
- * can't take back-to-back characters...yes, they
- * still exist.)
- */
- char *cp;
- int32 cdelay = atol(argv[2]);
-
- for(cp = argv[1];*cp != '\0';cp++){
- asy_write(ifp->dev,cp,1);
- pause(cdelay);
- }
- } else {
- /*if (ifp->trace & IF_TRACE_RAW)
- raw_dump( ifp, IF_TRACE_OUT, bp ); bp is uninitialised */
- asy_write(ifp->dev,argv[1],strlen(argv[1]));
- }
- return 0;
- }
-
-
- static int
- dodial_speed(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp = p;
-
- if ( argc < 2 ) {
- if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT))
- tprintf(ifp,"current speed = %u bps\n", Asy[ifp->dev].speed);
- return 0;
- }
- return asy_speed( ifp->dev, (int16)atol( argv[1] ) );
- }
-
-
- static int
- dodial_status(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp = p;
- int param;
-
- if ( ifp->iostatus == NULL )
- return -1;
-
- if ( (param = devparam( argv[1] )) == -1 )
- return -1;
-
- (*ifp->iostatus)( ifp, param, atol( argv[2] ) );
- return 0;
- }
-
-
- static int
- dodial_wait(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp = p;
- register int c = -1;
-
- alarm(atol(argv[1]));
-
- if(argc == 2){
- while((c = get_asy(ifp->dev)) != -1 ){
- c &= 0x7f;
- if(ifp->trace & IF_TRACE_IN){
- fputc(c,ifp->trfp);
- fflush(ifp->trfp);
- }
- }
- alarm(0L);
- return 0;
- } else {
- register char *cp = argv[2];
-
- while(*cp != '\0' && (c = get_asy(ifp->dev)) != -1){
- c &= 0x7f;
- if(ifp->trace & IF_TRACE_IN){
- fputc(c,ifp->trfp);
- fflush(ifp->trfp);
- }
- if(*cp++ != c){
- cp = argv[2];
- }
- }
-
- if(argc > 3){
- if(stricmp( argv[3], "speed") == 0){
- int16 speed = 0;
-
- while((c = get_asy(ifp->dev)) != -1){
- c &= 0x7f;
- if(ifp->trace & IF_TRACE_IN){
- fputc(c,ifp->trfp);
- fflush(ifp->trfp);
- }
- if(isdigit(c)){
- speed *= 10;
- speed += c - '0';
- } else {
- alarm(0L);
- return asy_speed( ifp->dev, speed );
- }
- }
- } else {
- return -1;
- }
- }
- }
- alarm(0L);
- return (c == -1);
- }
-
-
-