/* 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 #include #include "global.h" #include "mbuf.h" #include "timer.h" #include "proc.h" #include "iface.h" #include "netuser.h" #include "8250.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\" []", "speed", dodial_speed, 0, 2, "speed ", "status", dodial_status, 0, 2, "status up | down", "wait", dodial_wait, 0, 2, "wait [ \"string\" [speed] ]", NULLCHAR, NULLFP, 0, 0, "Unknown command", }; /* * dial * dial * dial 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){ tprintf("Interface %s unknown\n",argv[1]); return 1; } if(ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp){ tprintf("Interface %s not asy port\n",argv[1]); return 1; } ap = &Asy[ifp->dev]; if(argc < 3){ tprintf("%s: %s",ifp->name,(ap->msr & MSR_RLSD) ? "UP":"DOWN"); tprintf(", idle timer %ld/%ld",read_timer(&ap->idle)/1000L, dur_timer(&ap->idle)/1000L); if(ap->actfile != NULLCHAR) tprintf(", up script: %s",ap->actfile); if(ap->dropfile != NULLCHAR) tprintf(", down script: %s\n",ap->dropfile); else tprintf("\n"); tprintf("Calls originated %ld, carrier up transitions %ld\n", ap->originates,ap->answers); tprintf("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){ tprintf("Usage: dial \n"); tprintf(" dial 0\n"); return 1; } if(!ap->rlsd){ tprintf("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; { stop_timer(&asyp->idle); while(asyp->rlsd && (asyp->msr & MSR_RLSD) == 0 && asyp->actfile != NULLCHAR){ /* Line down, need to redial it */ 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; int save_input = Curproc->input; int save_output = Curproc->output; if((fp = fopen(file,READ_TEXT)) == NULLFILE){ if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT)) fprintf(ifp->trfp,"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)) fprintf(ifp->trfp,"redial: tip or dialer already active on %s\n",ifp->name); return -1; } if(ifp->trace & (IF_TRACE_IN|IF_TRACE_OUT)) fprintf(ifp->trfp,"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)) fprintf(ifp->trfp,"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)) fprintf(ifp->trfp,"\nDial %s complete\n",ifp->name); Curproc->input = save_input; Curproc->output = save_output; 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 ); 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)) fprintf(ifp->trfp,"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); }