/* 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. */ /* mods by PA0GRI */ #include #include #include "global.h" #include "config.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 "session.h" #include "socket.h" #include "cmdparse.h" #include "devparam.h" #include "icmp.h" #include "files.h" #include "main.h" #include "trace.h" #define MIN_INTERVAL 5L static int redial __ARGS((struct iface *ifp,char *file)); 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_wait __ARGS((int argc,char *argv[],void *p)); static struct cmds dial_cmds[] = { "control", dodial_control, 0, 2, "control up | down", "send", dodial_send, 0, 2, "send \"string\" []", "speed", dodial_speed, 0, 2, "speed ", "wait", dodial_wait, 0, 2, "wait [ \"string\" [speed] ]", NULLCHAR, NULLFP, 0, 0, "Unknown command", }; /* dial [ [ [] ] ] * must be asy type * contains commands which are executed. * missing: kill outstanding dialer. * interval to check for activity on . * number of missed pings before redial. * interface to ping. */ int dodialer(argc,argv,p) int argc; char *argv[]; void *p; { struct iface *ifp; int32 interval = 0L; /* in seconds */ int32 last_wait = 0L; int32 target = 0L; int pings = 0; int countdown; char *filename; char *ifn; int result; int s; 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; } if(ifp->supv != NULLPROC){ while ( ifp->supv != NULLPROC ) { alert(ifp->supv, EABORT); pwait(NULL); } tprintf("dialer terminated on %s\n",argv[1]); } if ( argc < 3 ) { /* just terminating */ return 0; } chname( Curproc, ifn = if_name( ifp, " dialer" ) ); free( ifn ); filename = rootdircat(argv[2]); /* handle minimal command (just thru filename) */ if ( argc < 4 ) { /* just dialing */ result = redial(ifp, filename); if ( filename != argv[2] ) free(filename); return result; /* get polling interval (arg 3) */ } else if ( (interval = atol(argv[3])) <= MIN_INTERVAL ) { tprintf("interval must be > %d seconds\n", MIN_INTERVAL); return 1; } /* get the number of pings before redialing (arg 4) */ if ( argc < 5 ) { } else if ( (pings = atoi(argv[4])) <= 0 ){ tprintf("pings must be > 0\n"); return 1; } /* retrieve the host name (arg 5) */ if ( argc < 6 ) { } else if ( (target = resolve(argv[5])) == 0L ) { tprintf(Badhost,argv[5]); return 1; } countdown = pings; ifp->supv = Curproc; while ( !main_exit ) { int32 wait_for = interval; if ( Asy[ ifp->dev ].rlsd_line_control == RLSD_DOWN ) { /* definitely down */ if ( redial(ifp,filename) < 0 ) break; } else if ( ifp->lastrecv >= last_wait ) { /* got something recently */ wait_for -= secclock() - ifp->lastrecv; countdown = pings; } else if ( countdown < 1 ) { /* we're down, or host we ping is down */ if ( redial(ifp,filename) < 0 ) break; } else if ( target != 0L && (s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) != -1 ) { pingem(s,target,0,(int16)s,0); close_s(s); countdown--; } else if ( ifp->echo != NULLFP ) { (*ifp->echo)(ifp,NULLBUF); countdown--; } last_wait = secclock(); if ( wait_for != 0L ) { alarm( wait_for * 1000L ); if ( pwait( &(ifp->supv) ) == EABORT ) break; alarm(0L); /* clear alarm */ } } if ( filename != argv[2] ) free(filename); ifp->supv = NULLPROC; /* We're being terminated */ return 0; } /* 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 *)); struct session *sp; int result = 0; int save_input = Curproc->input; int save_output = Curproc->output; if((fp = fopen(file,READ_TEXT)) == NULLFILE){ tprintf("redial: can't read %s\n",file); return -1; /* Causes dialer proc to terminate */ } /* Save output handler and temporarily redirect output to null */ if(ifp->raw == bitbucket){ tprintf("redial: tip or dialer already active on %s\n",ifp->name); return -1; } /* allocate a session descriptor */ if ( (sp = newsession( ifp->name, DIAL, 0 )) == NULLSESSION ) { tprintf( "Too many sessions\n" ); return 1; } tprintf( "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); if( (result = cmdparse(dial_cmds,inbuf,ifp)) != 0 ){ tprintf("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); tprintf( "\nDial %s complete\n", ifp->name ); /* Wait for awhile, so the user can read the screen, * AND to give it time to send some packets on the new connection! */ pause( 10000L ); freesession( sp ); 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++){ bp = qdata(cp,1); asy_send(ifp->dev,bp); pause(cdelay); } } else { bp = qdata( argv[1], strlen(argv[1]) ); if (ifp->trace & IF_TRACE_RAW) raw_dump( ifp, IF_TRACE_OUT, bp ); asy_send( ifp->dev, bp ); } return 0; } static int dodial_speed(argc,argv,p) int argc; char *argv[]; void *p; { struct iface *ifp = p; if ( argc < 2 ) { tprintf( "current speed = %u bps\n", Asy[ifp->dev].speed ); return 0; } return asy_speed( ifp->dev, (int16)atol( argv[1] ) ); } 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 ) { tputc( c &= 0x7F ); tflush(); } alarm( 0L ); return 0; } else { register char *cp = argv[2]; while ( *cp != '\0' && (c = get_asy(ifp->dev)) != -1 ) { tputc( c &= 0x7F ); tflush(); 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 ) { tputc( c &= 0x7F ); tflush(); 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 ); }