main.c revision 27157
16059Samurai/* 26059Samurai * User Process PPP 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan, Inc. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 196059Samurai * 2027157Sbrian * $Id: main.c,v 1.68 1997/06/29 13:54:31 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Add commands for traffic summary, version display, etc. 246059Samurai * o Add signal handler for misc controls. 256059Samurai */ 266059Samurai#include "fsm.h" 276059Samurai#include <fcntl.h> 2811336Samurai#include <paths.h> 296059Samurai#include <sys/time.h> 306059Samurai#include <termios.h> 3123114Sbrian#include <signal.h> 326059Samurai#include <sys/wait.h> 336059Samurai#include <errno.h> 346059Samurai#include <netdb.h> 3518786Sjkh#include <unistd.h> 366059Samurai#include <sys/socket.h> 376059Samurai#include <arpa/inet.h> 3820365Sjkh#include <netinet/in_systm.h> 3920365Sjkh#include <netinet/ip.h> 406059Samurai#include "modem.h" 416059Samurai#include "os.h" 426059Samurai#include "hdlc.h" 4313389Sphk#include "ccp.h" 446059Samurai#include "lcp.h" 456059Samurai#include "ipcp.h" 4626142Sbrian#include "loadalias.h" 476059Samurai#include "vars.h" 486735Samurai#include "auth.h" 497001Samurai#include "filter.h" 5013389Sphk#include "systems.h" 5113389Sphk#include "ip.h" 5223840Sbrian#include "sig.h" 5326940Sbrian#include "server.h" 546059Samurai 556764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 5626516Sbrian#define LAUTH_M2 "Warning: Manipulation is allowed by anyone\n" 576764Samurai 586735Samurai#ifndef O_NONBLOCK 596735Samurai#ifdef O_NDELAY 606735Samurai#define O_NONBLOCK O_NDELAY 616735Samurai#endif 626735Samurai#endif 636735Samurai 646059Samuraiextern void VjInit(), AsyncInit(); 6525630Sbrianextern void AsyncInput(); 666059Samuraiextern int SelectSystem(); 676059Samurai 686059Samuraiextern void DecodeCommand(), Prompt(); 6918885Sjkhextern int aft_cmd; 706059Samuraiextern int IsInteractive(); 716059Samuraistatic void DoLoop(void); 7210528Samuraistatic void TerminalStop(); 7325908Sbrianstatic char *ex_desc(); 746059Samurai 756059Samuraistatic struct termios oldtio; /* Original tty mode */ 766059Samuraistatic struct termios comtio; /* Command level tty mode */ 7714418Sacheint TermMode; 7820813Sjkhstatic pid_t BGPid = 0; 7925634Sbrianstatic char pid_filename[MAXPATHLEN]; 8025634Sbrianstatic char if_filename[MAXPATHLEN]; 8125445Sacheint tunno; 8227061Sbrianstatic int dial_up; 836059Samurai 846059Samuraistatic void 8526858SbrianTtyInit(int DontWantInt) 866059Samurai{ 876059Samurai struct termios newtio; 886059Samurai int stat; 896059Samurai 906059Samurai stat = fcntl(0, F_GETFL, 0); 9125630Sbrian if (stat > 0) { 9225630Sbrian stat |= O_NONBLOCK; 9325630Sbrian (void)fcntl(0, F_SETFL, stat); 9425630Sbrian } 956059Samurai newtio = oldtio; 966059Samurai newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 976059Samurai newtio.c_iflag = 0; 986059Samurai newtio.c_oflag &= ~OPOST; 996059Samurai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 10026858Sbrian if (DontWantInt) 10126858Sbrian newtio.c_cc[VINTR] = _POSIX_VDISABLE; 1026059Samurai newtio.c_cc[VMIN] = 1; 1036059Samurai newtio.c_cc[VTIME] = 0; 1046059Samurai newtio.c_cflag |= CS8; 1056735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1066059Samurai comtio = newtio; 1076059Samurai} 1086059Samurai 1096059Samurai/* 1106059Samurai * Set tty into command mode. We allow canonical input and echo processing. 1116059Samurai */ 11210528Samuraivoid 11310528SamuraiTtyCommandMode(prompt) 11410528Samuraiint prompt; 1156059Samurai{ 1166059Samurai struct termios newtio; 1176059Samurai int stat; 1186059Samurai 1196059Samurai if (!(mode & MODE_INTER)) 1206059Samurai return; 1216735Samurai tcgetattr(0, &newtio); 12210528Samurai newtio.c_lflag |= (ECHO|ISIG|ICANON); 1236059Samurai newtio.c_iflag = oldtio.c_iflag; 1246059Samurai newtio.c_oflag |= OPOST; 1256735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1266059Samurai stat = fcntl(0, F_GETFL, 0); 12725630Sbrian if (stat > 0) { 12825630Sbrian stat |= O_NONBLOCK; 12925630Sbrian (void)fcntl(0, F_SETFL, stat); 13025630Sbrian } 1316059Samurai TermMode = 0; 13225630Sbrian if(prompt) Prompt(); 1336059Samurai} 1346059Samurai 1356059Samurai/* 1366059Samurai * Set tty into terminal mode which is used while we invoke term command. 1376059Samurai */ 1386059Samuraivoid 1396059SamuraiTtyTermMode() 1406059Samurai{ 1416059Samurai int stat; 1426059Samurai 1436735Samurai tcsetattr(0, TCSADRAIN, &comtio); 1446059Samurai stat = fcntl(0, F_GETFL, 0); 14525630Sbrian if (stat > 0) { 14625630Sbrian stat &= ~O_NONBLOCK; 14725630Sbrian (void)fcntl(0, F_SETFL, stat); 14825630Sbrian } 1496059Samurai TermMode = 1; 1506059Samurai} 1516059Samurai 1526059Samuraivoid 15310528SamuraiTtyOldMode() 1546059Samurai{ 1556059Samurai int stat; 1566059Samurai 1576059Samurai stat = fcntl(0, F_GETFL, 0); 15825630Sbrian if (stat > 0) { 15925630Sbrian stat &= ~O_NONBLOCK; 16025630Sbrian (void)fcntl(0, F_SETFL, stat); 16125630Sbrian } 1626735Samurai tcsetattr(0, TCSANOW, &oldtio); 16310528Samurai} 16410528Samurai 16510528Samuraivoid 16610528SamuraiCleanup(excode) 16710528Samuraiint excode; 16810528Samurai{ 16910528Samurai 17010528Samurai OsLinkdown(); 1716059Samurai OsCloseLink(1); 1726059Samurai sleep(1); 17325908Sbrian if (mode & MODE_AUTO) 1746059Samurai DeleteIfRoutes(1); 17525707Sbrian (void)unlink(pid_filename); 17625707Sbrian (void)unlink(if_filename); 1776059Samurai OsInterfaceDown(1); 17823863Sbrian if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 17923863Sbrian char c = EX_ERRDEAD; 18023863Sbrian if (write(BGFiledes[1],&c,1) == 1) 18126516Sbrian LogPrintf(LogPHASE,"Parent notified of failure.\n"); 18223863Sbrian else 18326516Sbrian LogPrintf(LogPHASE,"Failed to notify parent of failure.\n"); 18423863Sbrian close(BGFiledes[1]); 18523863Sbrian } 18626516Sbrian LogPrintf(LogPHASE, "PPP Terminated (%s).\n",ex_desc(excode)); 1876059Samurai LogClose(); 18826940Sbrian ServerClose(); 18910528Samurai TtyOldMode(); 1906059Samurai 1916059Samurai exit(excode); 1926059Samurai} 1936059Samurai 1946059Samuraistatic void 19527157SbrianCloseConnection(signo) 19614930Sacheint signo; 1976059Samurai{ 19826858Sbrian /* NOTE, these are manual, we've done a setsid() */ 19927157Sbrian LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 20027061Sbrian reconnectState = RECON_FALSE; \ 20127061Sbrian reconnectCount = 0; \ 20226858Sbrian DownConnection(); 20327061Sbrian dial_up = FALSE; 2046059Samurai} 2056059Samurai 2066059Samuraistatic void 20714930SacheCloseSession(signo) 20814930Sacheint signo; 2096059Samurai{ 21020813Sjkh if (BGPid) { 21120813Sjkh kill (BGPid, SIGINT); 21220813Sjkh exit (EX_TERM); 21320813Sjkh } 21426516Sbrian LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 21526516Sbrian reconnect(RECON_FALSE); 21626516Sbrian LcpClose(); 21726516Sbrian Cleanup(EX_TERM); 2186059Samurai} 2196059Samurai 22010528Samuraistatic void 22110528SamuraiTerminalCont() 22210528Samurai{ 22323840Sbrian pending_signal(SIGCONT, SIG_DFL); 22423840Sbrian pending_signal(SIGTSTP, TerminalStop); 22510528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 22610528Samurai} 22710528Samurai 22810528Samuraistatic void 22910528SamuraiTerminalStop(signo) 23010528Samuraiint signo; 23110528Samurai{ 23223840Sbrian pending_signal(SIGCONT, TerminalCont); 23310528Samurai TtyOldMode(); 23423840Sbrian pending_signal(SIGTSTP, SIG_DFL); 23510528Samurai kill(getpid(), signo); 23610528Samurai} 23710528Samurai 23826940Sbrianstatic void 23926940SbrianSetUpServer(signo) 24026940Sbrianint signo; 24126940Sbrian{ 24226940Sbrian int res; 24326940Sbrian if ((res = ServerTcpOpen(SERVER_PORT+tunno)) != 0) 24426940Sbrian LogPrintf(LogERROR, "Failed %d to open port %d\n", res, SERVER_PORT+tunno); 24526940Sbrian} 24626940Sbrian 24725908Sbrianstatic char * 24825908Sbrianex_desc(int ex) 24925908Sbrian{ 25025908Sbrian static char num[12]; 25125908Sbrian static char *desc[] = { "normal", "start", "sock", 25225908Sbrian "modem", "dial", "dead", "done", "reboot", "errdead", 25325908Sbrian "hangup", "term", "nodial", "nologin" }; 25410528Samurai 25525908Sbrian if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 25625908Sbrian return desc[ex]; 25725908Sbrian snprintf(num, sizeof num, "%d", ex); 25825908Sbrian return num; 25925908Sbrian} 26025908Sbrian 2616059Samuraivoid 2626059SamuraiUsage() 2636059Samurai{ 26420120Snate fprintf(stderr, 26520813Sjkh "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2666059Samurai exit(EX_START); 2676059Samurai} 2686059Samurai 2696059Samuraivoid 2706059SamuraiProcessArgs(int argc, char **argv) 2716059Samurai{ 2726059Samurai int optc; 2736059Samurai char *cp; 2746059Samurai 2756059Samurai optc = 0; 2766059Samurai while (argc > 0 && **argv == '-') { 2776059Samurai cp = *argv + 1; 2786059Samurai if (strcmp(cp, "auto") == 0) 2796059Samurai mode |= MODE_AUTO; 28020813Sjkh else if (strcmp(cp, "background") == 0) 28125908Sbrian mode |= MODE_BACKGROUND|MODE_AUTO; 2826059Samurai else if (strcmp(cp, "direct") == 0) 2836059Samurai mode |= MODE_DIRECT; 2846059Samurai else if (strcmp(cp, "dedicated") == 0) 2856059Samurai mode |= MODE_DEDICATED; 28620120Snate else if (strcmp(cp, "ddial") == 0) 28720120Snate mode |= MODE_DDIAL|MODE_AUTO; 28820365Sjkh else if (strcmp(cp, "alias") == 0) { 28926142Sbrian if (loadAliasHandlers(&VarAliasHandlers) == 0) 29026142Sbrian mode |= MODE_ALIAS; 29126142Sbrian else 29226516Sbrian LogPrintf(LogWARN, "Cannot load alias library\n"); 29320365Sjkh optc--; /* this option isn't exclusive */ 29420365Sjkh } 2956059Samurai else 2966059Samurai Usage(); 2976059Samurai optc++; 2986059Samurai argv++; argc--; 2996059Samurai } 3006059Samurai if (argc > 1) { 3016059Samurai fprintf(stderr, "specify only one system label.\n"); 3026059Samurai exit(EX_START); 3036059Samurai } 3046059Samurai if (argc == 1) dstsystem = *argv; 3056059Samurai 3066059Samurai if (optc > 1) { 3076059Samurai fprintf(stderr, "specify only one mode.\n"); 3086059Samurai exit(EX_START); 3096059Samurai } 3106059Samurai} 3116059Samurai 3126059Samuraistatic void 3136059SamuraiGreetings() 3146059Samurai{ 31526516Sbrian if (VarTerm) { 31626516Sbrian fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 31726516Sbrian fflush(VarTerm); 31826516Sbrian } 3196059Samurai} 3206059Samurai 32126940Sbrianint 3226059Samuraimain(argc, argv) 3236059Samuraiint argc; 3246059Samuraichar **argv; 3256059Samurai{ 32625707Sbrian FILE *lockfile; 32726516Sbrian char *name; 32826516Sbrian 32926551Sbrian VarTerm = 0; 33026516Sbrian name = rindex(argv[0], '/'); 33126516Sbrian LogOpen(name ? name+1 : argv[0]); 33226516Sbrian 3336059Samurai argc--; argv++; 3346059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 33526940Sbrian netfd = modem = tun_in = -1; 33626940Sbrian server = -2; 3376059Samurai ProcessArgs(argc, argv); 33826328Sbrian if (!(mode & MODE_DIRECT)) 33926551Sbrian VarTerm = stdout; 34026551Sbrian Greetings(); 3416059Samurai GetUid(); 3426059Samurai IpcpDefAddress(); 3436059Samurai 34426516Sbrian if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 34526516Sbrian fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 3466059Samurai 3476059Samurai if (OpenTunnel(&tunno) < 0) { 34826940Sbrian LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno)); 34926940Sbrian return EX_START; 3506059Samurai } 3516059Samurai 35225908Sbrian if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 3536059Samurai mode &= ~MODE_INTER; 3546059Samurai if (mode & MODE_INTER) { 35526516Sbrian fprintf(VarTerm, "Interactive mode\n"); 35626690Sbrian netfd = STDOUT_FILENO; 3576059Samurai } else if (mode & MODE_AUTO) { 35826516Sbrian fprintf(VarTerm, "Automatic Dialer mode\n"); 3596059Samurai if (dstsystem == NULL) { 36026516Sbrian if (VarTerm) 36126516Sbrian fprintf(VarTerm, "Destination system must be specified in" 36225908Sbrian " auto, background or ddial mode.\n"); 36326940Sbrian return EX_START; 3646059Samurai } 3656059Samurai } 3666059Samurai 3676735Samurai tcgetattr(0, &oldtio); /* Save original tty mode */ 3686059Samurai 36927157Sbrian pending_signal(SIGHUP, CloseSession); 37023840Sbrian pending_signal(SIGTERM, CloseSession); 37127157Sbrian pending_signal(SIGINT, CloseConnection); 37223840Sbrian pending_signal(SIGQUIT, CloseSession); 3736735Samurai#ifdef SIGPIPE 37424753Sache signal(SIGPIPE, SIG_IGN); 3756735Samurai#endif 3766735Samurai#ifdef SIGALRM 37723840Sbrian pending_signal(SIGALRM, SIG_IGN); 3786735Samurai#endif 37926940Sbrian if(mode & MODE_INTER) { 38010528Samurai#ifdef SIGTSTP 38126940Sbrian pending_signal(SIGTSTP, TerminalStop); 38210528Samurai#endif 38310528Samurai#ifdef SIGTTIN 38426940Sbrian pending_signal(SIGTTIN, TerminalStop); 38510528Samurai#endif 38610528Samurai#ifdef SIGTTOU 38726940Sbrian pending_signal(SIGTTOU, SIG_IGN); 38810528Samurai#endif 38926940Sbrian } 39026940Sbrian#ifdef SIGUSR1 39126940Sbrian if (mode != MODE_INTER) 39226940Sbrian pending_signal(SIGUSR1, SetUpServer); 39326940Sbrian#endif 3946059Samurai 3956059Samurai if (dstsystem) { 3966059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 39726551Sbrian LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 3986059Samurai Cleanup(EX_START); 3996059Samurai } 4006059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 40126551Sbrian LogPrintf(LogWARN, "Must specify dstaddr with" 40225908Sbrian " auto, background or ddial mode.\n"); 4036059Samurai Cleanup(EX_START); 4046059Samurai } 4056059Samurai } 4066059Samurai 40726940Sbrian if (ServerType() != NO_SERVER) 40826940Sbrian switch ( LocalAuthInit() ) { 40926940Sbrian case NOT_FOUND: 41026940Sbrian if (VarTerm) { 41126940Sbrian fprintf(VarTerm,LAUTH_M1); 41226940Sbrian fprintf(VarTerm,LAUTH_M2); 41326940Sbrian fflush(VarTerm); 41426940Sbrian } 41526940Sbrian /* Fall down */ 41626940Sbrian case VALID: 41726940Sbrian VarLocalAuth = LOCAL_AUTH; 41826940Sbrian break; 41926940Sbrian default: 42026940Sbrian break; 42126940Sbrian } 42226940Sbrian 4236059Samurai if (!(mode & MODE_INTER)) { 42420813Sjkh if (mode & MODE_BACKGROUND) { 42520813Sjkh if (pipe (BGFiledes)) { 42626516Sbrian LogPrintf(LogERROR, "pipe: %s", strerror(errno)); 42720813Sjkh Cleanup(EX_SOCK); 42820813Sjkh } 4296059Samurai } 43025908Sbrian 43126940Sbrian /* Create server socket and listen. */ 43226940Sbrian if (server == -2 && ServerTcpOpen(SERVER_PORT + tunno) != 0) 43326940Sbrian Cleanup(EX_SOCK); 4346059Samurai 4356059Samurai if (!(mode & MODE_DIRECT)) { 43620813Sjkh pid_t bgpid; 43711336Samurai 43820813Sjkh bgpid = fork (); 43920813Sjkh if (bgpid == -1) { 44026516Sbrian LogPrintf(LogERROR, "fork: %s", strerror(errno)); 44120813Sjkh Cleanup (EX_SOCK); 44220813Sjkh } 44320813Sjkh if (bgpid) { 44420813Sjkh char c = EX_NORMAL; 44511336Samurai 44620813Sjkh if (mode & MODE_BACKGROUND) { 44720813Sjkh /* Wait for our child to close its pipe before we exit. */ 44820813Sjkh BGPid = bgpid; 44926516Sbrian close(BGFiledes[1]); 45025908Sbrian if (read(BGFiledes[0], &c, 1) != 1) { 45126516Sbrian fprintf(VarTerm, "Child exit, no status.\n"); 45226516Sbrian LogPrintf (LogPHASE, "Parent: Child exit, no status.\n"); 45325908Sbrian } else if (c == EX_NORMAL) { 45426516Sbrian fprintf(VarTerm, "PPP enabled.\n"); 45526516Sbrian LogPrintf (LogPHASE, "Parent: PPP enabled.\n"); 45625908Sbrian } else { 45726516Sbrian fprintf(VarTerm, "Child failed (%s).\n",ex_desc((int)c)); 45826516Sbrian LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 45925910Sbrian ex_desc((int)c)); 46025908Sbrian } 46126516Sbrian close(BGFiledes[0]); 46220813Sjkh } 46326940Sbrian return c; 46423863Sbrian } else if (mode & MODE_BACKGROUND) 46523863Sbrian close(BGFiledes[0]); 46625707Sbrian } 46720813Sjkh 46825801Sbrian snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 46925707Sbrian _PATH_VARRUN, tunno); 47025707Sbrian (void)unlink(pid_filename); 47111336Samurai 47225707Sbrian if ((lockfile = fopen(pid_filename, "w")) != NULL) { 47325707Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 47425707Sbrian fclose(lockfile); 47525707Sbrian } else 47626516Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 47726516Sbrian pid_filename, strerror(errno)); 47825634Sbrian 47925707Sbrian snprintf(if_filename, sizeof if_filename, "%s%s.if", 48025707Sbrian _PATH_VARRUN, VarBaseDevice); 48125707Sbrian (void)unlink(if_filename); 48225634Sbrian 48325707Sbrian if ((lockfile = fopen(if_filename, "w")) != NULL) { 48425707Sbrian fprintf(lockfile, "tun%d\n", tunno); 48525707Sbrian fclose(lockfile); 48625707Sbrian } else 48726516Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 48826516Sbrian if_filename, strerror(errno)); 48925707Sbrian 49026686Sbrian VarTerm = 0; /* We know it's currently stdout */ 49126686Sbrian close(0); 49226686Sbrian close(2); 49326551Sbrian 4946059Samurai#ifdef DOTTYINIT 49526686Sbrian if (mode & (MODE_DIRECT|MODE_DEDICATED)) 4966059Samurai#else 49726686Sbrian if (mode & MODE_DIRECT) 4986059Samurai#endif 49926858Sbrian TtyInit(1); 50026686Sbrian else { 50126686Sbrian setsid(); 50226686Sbrian close(1); 50326686Sbrian } 5046059Samurai } else { 50526858Sbrian TtyInit(0); 50610528Samurai TtyCommandMode(1); 5076059Samurai } 50826516Sbrian LogPrintf(LogPHASE, "PPP Started.\n"); 5096059Samurai 5106059Samurai 5116059Samurai do 5126059Samurai DoLoop(); 5136059Samurai while (mode & MODE_DEDICATED); 5146059Samurai 5156059Samurai Cleanup(EX_DONE); 51626940Sbrian return 0; 5176059Samurai} 5186059Samurai 5196059Samurai/* 52020813Sjkh * Turn into packet mode, where we speak PPP. 5216059Samurai */ 5226059Samuraivoid 5236059SamuraiPacketMode() 5246059Samurai{ 5256059Samurai if (RawModem(modem) < 0) { 52626516Sbrian LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 5276059Samurai return; 5286059Samurai } 5296059Samurai 5306059Samurai AsyncInit(); 5316059Samurai VjInit(); 5326059Samurai LcpInit(); 5336059Samurai IpcpInit(); 5346059Samurai CcpInit(); 5356059Samurai LcpUp(); 5366059Samurai 53725872Sbrian LcpOpen(VarOpenMode); 5386059Samurai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 53910528Samurai TtyCommandMode(1); 54026516Sbrian if (VarTerm) { 54126516Sbrian fprintf(VarTerm, "Packet mode.\n"); 54226516Sbrian aft_cmd = 1; 54326516Sbrian } 5446059Samurai } 5456059Samurai} 5466059Samurai 5476059Samuraistatic void 5486059SamuraiShowHelp() 5496059Samurai{ 55026901Sbrian fprintf(stderr, "The following commands are available:\r\n"); 55126901Sbrian fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 55226901Sbrian fprintf(stderr, " ~-\tDecrease log level\r\n"); 55326901Sbrian fprintf(stderr, " ~+\tIncrease log level\r\n"); 55426901Sbrian fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 55526901Sbrian fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 55626901Sbrian fprintf(stderr, " ~.\tTerminate program\r\n"); 55726901Sbrian fprintf(stderr, " ~?\tThis help\r\n"); 5586059Samurai} 5596059Samurai 5606059Samuraistatic void 5616059SamuraiReadTty() 5626059Samurai{ 5636059Samurai int n; 5646059Samurai char ch; 5656059Samurai static int ttystate; 56626516Sbrian FILE *oVarTerm; 5676059Samurai#define MAXLINESIZE 200 5686059Samurai char linebuff[MAXLINESIZE]; 5696059Samurai 57026516Sbrian LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 57126516Sbrian TermMode, netfd, mode); 5726059Samurai if (!TermMode) { 5736059Samurai n = read(netfd, linebuff, sizeof(linebuff)-1); 5746735Samurai if (n > 0) { 57526516Sbrian aft_cmd = 1; 5766059Samurai DecodeCommand(linebuff, n, 1); 5776735Samurai } else { 57826516Sbrian LogPrintf(LogPHASE, "client connection closed.\n"); 57924753Sache VarLocalAuth = LOCAL_NO_AUTH; 58026516Sbrian mode &= ~MODE_INTER; 58126516Sbrian oVarTerm = VarTerm; 58226516Sbrian VarTerm = 0; 58326516Sbrian if (oVarTerm && oVarTerm != stdout) 58426516Sbrian fclose(oVarTerm); 5856059Samurai close(netfd); 5866059Samurai netfd = -1; 5876059Samurai } 5886059Samurai return; 5896059Samurai } 5906059Samurai 5916059Samurai /* 5926059Samurai * We are in terminal mode, decode special sequences 5936059Samurai */ 59426516Sbrian n = read(fileno(VarTerm), &ch, 1); 59526516Sbrian LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)", n); 5966059Samurai 5976059Samurai if (n > 0) { 5986059Samurai switch (ttystate) { 5996059Samurai case 0: 6006059Samurai if (ch == '~') 6016059Samurai ttystate++; 6026059Samurai else 6036059Samurai write(modem, &ch, n); 6046059Samurai break; 6056059Samurai case 1: 6066059Samurai switch (ch) { 6076059Samurai case '?': 6086059Samurai ShowHelp(); 6096059Samurai break; 6106059Samurai case 'p': 6116059Samurai /* 6126059Samurai * XXX: Should check carrier. 6136059Samurai */ 6146059Samurai if (LcpFsm.state <= ST_CLOSED) { 6156059Samurai VarOpenMode = OPEN_ACTIVE; 6166059Samurai PacketMode(); 6176059Samurai } 6186059Samurai break; 6196059Samurai case '.': 6206059Samurai TermMode = 1; 62126516Sbrian aft_cmd = 1; 62210528Samurai TtyCommandMode(1); 6236059Samurai break; 62426516Sbrian case 't': 62526516Sbrian if (LogIsKept(LogDEBUG)) { 62626516Sbrian ShowTimers(); 62726516Sbrian break; 62826516Sbrian } 62926516Sbrian case 'm': 63026516Sbrian if (LogIsKept(LogDEBUG)) { 63126516Sbrian ShowMemMap(); 63226516Sbrian break; 63326516Sbrian } 6346059Samurai default: 6356059Samurai if (write(modem, &ch, n) < 0) 63626516Sbrian LogPrintf(LogERROR, "error writing to modem.\n"); 6376059Samurai break; 6386059Samurai } 6396059Samurai ttystate = 0; 6406059Samurai break; 6416059Samurai } 6426059Samurai } 6436059Samurai} 6446059Samurai 6456059Samurai 6466059Samurai/* 6476059Samurai * Here, we'll try to detect HDLC frame 6486059Samurai */ 6496059Samurai 6506059Samuraistatic char *FrameHeaders[] = { 6516735Samurai "\176\377\003\300\041", 6526735Samurai "\176\377\175\043\300\041", 6536735Samurai "\176\177\175\043\100\041", 6546735Samurai "\176\175\337\175\043\300\041", 6556735Samurai "\176\175\137\175\043\100\041", 6566059Samurai NULL, 6576059Samurai}; 6586059Samurai 6596059Samuraiu_char * 6606059SamuraiHdlcDetect(cp, n) 6616059Samuraiu_char *cp; 6626059Samuraiint n; 6636059Samurai{ 6646735Samurai char *ptr, *fp, **hp; 6656059Samurai 6666059Samurai cp[n] = '\0'; /* be sure to null terminated */ 6676059Samurai ptr = NULL; 6686059Samurai for (hp = FrameHeaders; *hp; hp++) { 6696735Samurai fp = *hp; 6706735Samurai if (DEV_IS_SYNC) 6716735Samurai fp++; 67213389Sphk ptr = strstr((char *)cp, fp); 67313389Sphk if (ptr) 6746059Samurai break; 6756059Samurai } 6766059Samurai return((u_char *)ptr); 6776059Samurai} 6786059Samurai 6796059Samuraistatic struct pppTimer RedialTimer; 6806059Samurai 6816059Samuraistatic void 6826059SamuraiRedialTimeout() 6836059Samurai{ 6846059Samurai StopTimer(&RedialTimer); 68526516Sbrian LogPrintf(LogPHASE, "Redialing timer expired.\n"); 6866059Samurai} 6876059Samurai 6886059Samuraistatic void 68924939SbrianStartRedialTimer(Timeout) 69024939Sbrian int Timeout; 6916059Samurai{ 6926059Samurai StopTimer(&RedialTimer); 69311336Samurai 69424939Sbrian if (Timeout) { 69511336Samurai RedialTimer.state = TIMER_STOPPED; 69611336Samurai 69724939Sbrian if (Timeout > 0) 69824939Sbrian RedialTimer.load = Timeout * SECTICKS; 69911336Samurai else 70011336Samurai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 70111336Samurai 70226516Sbrian LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 70324939Sbrian RedialTimer.load / SECTICKS); 70424939Sbrian 70511336Samurai RedialTimer.func = RedialTimeout; 70611336Samurai StartTimer(&RedialTimer); 70711336Samurai } 7086059Samurai} 7096059Samurai 7106059Samurai 7116059Samuraistatic void 7126059SamuraiDoLoop() 7136059Samurai{ 7146059Samurai fd_set rfds, wfds, efds; 71523598Sache int pri, i, n, wfd, nfds; 7166059Samurai struct sockaddr_in hisaddr; 7176059Samurai struct timeval timeout, *tp; 7186059Samurai int ssize = sizeof(hisaddr); 7196059Samurai u_char *cp; 7206059Samurai u_char rbuff[MAX_MRU]; 72111336Samurai int tries; 7229448Samurai int qlen; 72326858Sbrian int res; 72410528Samurai pid_t pgroup; 7256059Samurai 72610528Samurai pgroup = getpgrp(); 72710528Samurai 72825908Sbrian if (mode & MODE_DIRECT) { 72926551Sbrian LogPrintf(LogDEBUG, "Opening modem\n"); 7306059Samurai modem = OpenModem(mode); 73126516Sbrian LogPrintf(LogPHASE, "Packet mode enabled\n"); 7326059Samurai PacketMode(); 7336059Samurai } else if (mode & MODE_DEDICATED) { 73423598Sache if (modem < 0) 7356059Samurai modem = OpenModem(mode); 7366059Samurai } 7376059Samurai 73826516Sbrian fflush(VarTerm); 7396059Samurai 7407001Samurai timeout.tv_sec = 0; 7416059Samurai timeout.tv_usec = 0; 74226098Sbrian reconnectState = RECON_UNKNOWN; 7436059Samurai 74423863Sbrian if (mode & MODE_BACKGROUND) 74523863Sbrian dial_up = TRUE; /* Bring the line up */ 74623863Sbrian else 74723863Sbrian dial_up = FALSE; /* XXXX */ 74811336Samurai tries = 0; 7496059Samurai for (;;) { 75023598Sache nfds = 0; 7516059Samurai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 7527001Samurai 75320120Snate /* 75420120Snate * If the link is down and we're in DDIAL mode, bring it back 75520120Snate * up. 75620120Snate */ 75720120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 75820120Snate dial_up = TRUE; 75920120Snate 76025067Sbrian /* 76125067Sbrian * If we lost carrier and want to re-establish the connection 76225067Sbrian * due to the "set reconnect" value, we'd better bring the line 76325908Sbrian * back up. 76425067Sbrian */ 76525908Sbrian if (LcpFsm.state <= ST_CLOSED) { 76626098Sbrian if (dial_up != TRUE && reconnectState == RECON_TRUE) { 76725908Sbrian if (++reconnectCount <= VarReconnectTries) { 76826516Sbrian LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 76925908Sbrian reconnectCount, VarReconnectTries); 77025908Sbrian StartRedialTimer(VarReconnectTimer); 77125908Sbrian dial_up = TRUE; 77225908Sbrian } else { 77325908Sbrian if (VarReconnectTries) 77426516Sbrian LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 77525908Sbrian VarReconnectTries); 77625908Sbrian reconnectCount = 0; 77725908Sbrian if (mode & MODE_BACKGROUND) 77825908Sbrian Cleanup(EX_DEAD); 77925908Sbrian } 78026098Sbrian reconnectState = RECON_ENVOKED; 78125801Sbrian } 78225908Sbrian } 78325067Sbrian 7847001Samurai /* 78525067Sbrian * If Ip packet for output is enqueued and require dial up, 7867001Samurai * Just do it! 7877001Samurai */ 78825067Sbrian if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 78926516Sbrian LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 79011336Samurai modem = OpenModem(mode); 79111336Samurai if (modem < 0) { 79226551Sbrian tries++; 79326696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 79426551Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 79526696Sbrian tries, VarDialTries); 79626551Sbrian else 79726696Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 79826551Sbrian 79926696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 80026551Sbrian if (mode & MODE_BACKGROUND) 80126551Sbrian Cleanup(EX_DIAL); /* Can't get the modem */ 80226551Sbrian dial_up = FALSE; 80326551Sbrian reconnectState = RECON_UNKNOWN; 80426551Sbrian reconnectCount = 0; 80526551Sbrian tries = 0; 80626551Sbrian } else 80726551Sbrian StartRedialTimer(VarRedialTimeout); 80811336Samurai } else { 80924843Sbrian tries++; /* Tries are per number, not per list of numbers. */ 81026696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 81126696Sbrian LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 81224843Sbrian else 81326696Sbrian LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 81426696Sbrian 81526858Sbrian if ((res = DialModem()) == EX_DONE) { 81611336Samurai sleep(1); /* little pause to allow peer starts */ 81711336Samurai ModemTimeout(); 81811336Samurai PacketMode(); 81911336Samurai dial_up = FALSE; 82026098Sbrian reconnectState = RECON_UNKNOWN; 82111336Samurai tries = 0; 82211336Samurai } else { 82311336Samurai CloseModem(); 82424844Sbrian if (mode & MODE_BACKGROUND) { 82526858Sbrian if (VarNextPhone == NULL || res == EX_SIG) 82624844Sbrian Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 82724844Sbrian else 82824939Sbrian /* Try all numbers in background mode */ 82924939Sbrian StartRedialTimer(VarRedialNextTimeout); 83026858Sbrian } else if (!(mode & MODE_DDIAL) && 83126858Sbrian ((VarDialTries && tries >= VarDialTries) || 83226858Sbrian res == EX_SIG)) { 83324843Sbrian /* I give up ! Can't get through :( */ 83424939Sbrian StartRedialTimer(VarRedialTimeout); 83524843Sbrian dial_up = FALSE; 83626098Sbrian reconnectState = RECON_UNKNOWN; 83726098Sbrian reconnectCount = 0; 83824843Sbrian tries = 0; 83924843Sbrian } else if (VarNextPhone == NULL) 84024843Sbrian /* Dial failed. Keep quite during redial wait period. */ 84124939Sbrian StartRedialTimer(VarRedialTimeout); 84224843Sbrian else 84324939Sbrian StartRedialTimer(VarRedialNextTimeout); 84411336Samurai } 84511336Samurai } 8467001Samurai } 8479448Samurai qlen = ModemQlen(); 84813733Sdfr 84913733Sdfr if (qlen == 0) { 85013733Sdfr IpStartOutput(); 85113733Sdfr qlen = ModemQlen(); 85213733Sdfr } 85313733Sdfr 85423598Sache if (modem >= 0) { 85523598Sache if (modem + 1 > nfds) 85623598Sache nfds = modem + 1; 8577001Samurai FD_SET(modem, &rfds); 8587001Samurai FD_SET(modem, &efds); 8599448Samurai if (qlen > 0) { 8607001Samurai FD_SET(modem, &wfds); 8617001Samurai } 8627001Samurai } 86323598Sache if (server >= 0) { 86423598Sache if (server + 1 > nfds) 86523598Sache nfds = server + 1; 86623598Sache FD_SET(server, &rfds); 86723598Sache } 8686059Samurai 8696059Samurai /* *** IMPORTANT *** 8706059Samurai * 8716059Samurai * CPU is serviced every TICKUNIT micro seconds. 8726059Samurai * This value must be chosen with great care. If this values is 8736059Samurai * too big, it results loss of characters from modem and poor responce. 8746059Samurai * If this values is too small, ppp process eats many CPU time. 8756059Samurai */ 8766735Samurai#ifndef SIGALRM 8776059Samurai usleep(TICKUNIT); 8786059Samurai TimerService(); 87923840Sbrian#else 88023840Sbrian handle_signals(); 8816735Samurai#endif 88210877Sbde 88310877Sbde /* If there are aren't many packets queued, look for some more. */ 88423598Sache if (qlen < 20 && tun_in >= 0) { 88523598Sache if (tun_in + 1 > nfds) 88623598Sache nfds = tun_in + 1; 88710877Sbde FD_SET(tun_in, &rfds); 88823598Sache } 88910877Sbde 89023598Sache if (netfd >= 0) { 89123598Sache if (netfd + 1 > nfds) 89223598Sache nfds = netfd + 1; 8936059Samurai FD_SET(netfd, &rfds); 8946059Samurai FD_SET(netfd, &efds); 8956059Samurai } 8967001Samurai 8976735Samurai#ifndef SIGALRM 8986059Samurai /* 8997001Samurai * Normally, select() will not block because modem is writable. 9007001Samurai * In AUTO mode, select will block until we find packet from tun 9016059Samurai */ 9026059Samurai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 90323598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9046735Samurai#else 9058857Srgrimes /* 9067001Samurai * When SIGALRM timer is running, a select function will be 9078857Srgrimes * return -1 and EINTR after a Time Service signal hundler 90811336Samurai * is done. If the redial timer is not running and we are 90911336Samurai * trying to dial, poll with a 0 value timer. 9107001Samurai */ 91111336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 91223598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9136735Samurai#endif 91422074Sbrian 9157001Samurai if ( i == 0 ) { 9167001Samurai continue; 9176059Samurai } 9186735Samurai 9197001Samurai if ( i < 0 ) { 9207001Samurai if ( errno == EINTR ) { 92123840Sbrian handle_signals(); 92223840Sbrian continue; 9237001Samurai } 92426516Sbrian LogPrintf(LogERROR, "select: %s", strerror(errno)); 9257001Samurai break; 9268857Srgrimes } 9277001Samurai 92823598Sache if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 92926516Sbrian LogPrintf(LogALERT, "Exception detected.\n"); 9306059Samurai break; 9316059Samurai } 9326059Samurai 93323598Sache if (server >= 0 && FD_ISSET(server, &rfds)) { 93426516Sbrian LogPrintf(LogPHASE, "connected to client.\n"); 9356059Samurai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 93624753Sache if (wfd < 0) { 93726516Sbrian LogPrintf(LogERROR, "accept: %s", strerror(errno)); 93824753Sache continue; 93924753Sache } 94023598Sache if (netfd >= 0) { 9416059Samurai write(wfd, "already in use.\n", 16); 9426059Samurai close(wfd); 9436059Samurai continue; 9446059Samurai } else 9456059Samurai netfd = wfd; 94626516Sbrian VarTerm = fdopen(netfd, "a+"); 9476059Samurai mode |= MODE_INTER; 9486059Samurai Greetings(); 9496764Samurai switch ( LocalAuthInit() ) { 9506764Samurai case NOT_FOUND: 95126516Sbrian if (VarTerm) { 95226516Sbrian fprintf(VarTerm,LAUTH_M1); 95326516Sbrian fprintf(VarTerm,LAUTH_M2); 95426516Sbrian fflush(VarTerm); 95526516Sbrian } 9566764Samurai /* Fall down */ 9576764Samurai case VALID: 9586764Samurai VarLocalAuth = LOCAL_AUTH; 9596764Samurai break; 9606764Samurai default: 9616764Samurai break; 9626764Samurai } 9636059Samurai (void) IsInteractive(); 96425630Sbrian Prompt(); 9656059Samurai } 9666059Samurai 96723598Sache if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 96810858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 9696059Samurai /* something to read from tty */ 9706059Samurai ReadTty(); 9716059Samurai } 97223598Sache if (modem >= 0) { 9736059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 9746059Samurai ModemStartOutput(modem); 9756059Samurai } 9766059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 9776735Samurai if (LcpFsm.state <= ST_CLOSED) 9786735Samurai usleep(10000); 9796059Samurai n = read(modem, rbuff, sizeof(rbuff)); 9806059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 9816059Samurai DownConnection(); 9826059Samurai } else 98326516Sbrian LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 9846059Samurai 9856059Samurai if (LcpFsm.state <= ST_CLOSED) { 9866059Samurai /* 9876059Samurai * In dedicated mode, we just discard input until LCP is started. 9886059Samurai */ 9896059Samurai if (!(mode & MODE_DEDICATED)) { 9906059Samurai cp = HdlcDetect(rbuff, n); 9916059Samurai if (cp) { 9926059Samurai /* 9936059Samurai * LCP packet is detected. Turn ourselves into packet mode. 9946059Samurai */ 9956059Samurai if (cp != rbuff) { 99626516Sbrian write(modem, rbuff, cp - rbuff); 99726516Sbrian write(modem, "\r\n", 2); 9986059Samurai } 9996059Samurai PacketMode(); 10006059Samurai } else 100126516Sbrian write(fileno(VarTerm), rbuff, n); 10026059Samurai } 10036059Samurai } else { 10046059Samurai if (n > 0) 10056059Samurai AsyncInput(rbuff, n); 10066059Samurai } 10076059Samurai } 10086059Samurai } 10097001Samurai 101023598Sache if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 10116059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 10126059Samurai if (n < 0) { 101326516Sbrian LogPrintf(LogERROR, "read from tun: %s", strerror(errno)); 10146059Samurai continue; 10156059Samurai } 10166059Samurai /* 10176059Samurai * Process on-demand dialup. Output packets are queued within tunnel 10186059Samurai * device until IPCP is opened. 10196059Samurai */ 10206059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 10217001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 10226059Samurai if (pri >= 0) { 102320365Sjkh if (mode & MODE_ALIAS) { 102426142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 102520666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 102620365Sjkh } 10276059Samurai IpEnqueue(pri, rbuff, n); 102820365Sjkh dial_up = TRUE; /* XXX */ 10296059Samurai } 10306059Samurai continue; 10316059Samurai } 10327001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 103320365Sjkh if (pri >= 0) { 103420365Sjkh if (mode & MODE_ALIAS) { 103526142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 103620666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 103720365Sjkh } 10386059Samurai IpEnqueue(pri, rbuff, n); 103920365Sjkh } 10406059Samurai } 10416059Samurai } 104226516Sbrian LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 10436059Samurai} 1044