main.c revision 30697
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 * 2030697Sbrian * $Id: main.c,v 1.83 1997/10/16 23:55:18 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> 4029083Sbrian#include <sysexits.h> 416059Samurai#include "modem.h" 426059Samurai#include "os.h" 436059Samurai#include "hdlc.h" 4413389Sphk#include "ccp.h" 456059Samurai#include "lcp.h" 466059Samurai#include "ipcp.h" 4726142Sbrian#include "loadalias.h" 486059Samurai#include "vars.h" 496735Samurai#include "auth.h" 507001Samurai#include "filter.h" 5113389Sphk#include "systems.h" 5213389Sphk#include "ip.h" 5323840Sbrian#include "sig.h" 5426940Sbrian#include "server.h" 5528536Sbrian#include "lcpproto.h" 566059Samurai 576735Samurai#ifndef O_NONBLOCK 586735Samurai#ifdef O_NDELAY 596735Samurai#define O_NONBLOCK O_NDELAY 606735Samurai#endif 616735Samurai#endif 626735Samurai 6330187Sbrianextern void VjInit(int), AsyncInit(); 6425630Sbrianextern void AsyncInput(); 6528679Sbrianextern int SelectSystem(); 666059Samurai 676059Samuraiextern void DecodeCommand(), Prompt(); 6818885Sjkhextern int aft_cmd; 696059Samuraiextern int IsInteractive(); 706059Samuraistatic void DoLoop(void); 7110528Samuraistatic void TerminalStop(); 7225908Sbrianstatic char *ex_desc(); 736059Samurai 7428679Sbrianstatic struct termios oldtio; /* Original tty mode */ 7528679Sbrianstatic struct termios comtio; /* Command level tty mode */ 7614418Sacheint TermMode; 7720813Sjkhstatic pid_t BGPid = 0; 7825634Sbrianstatic char pid_filename[MAXPATHLEN]; 7925634Sbrianstatic char if_filename[MAXPATHLEN]; 8025445Sacheint tunno; 8127061Sbrianstatic int dial_up; 826059Samurai 836059Samuraistatic void 8426858SbrianTtyInit(int DontWantInt) 856059Samurai{ 866059Samurai struct termios newtio; 876059Samurai int stat; 886059Samurai 896059Samurai stat = fcntl(0, F_GETFL, 0); 9025630Sbrian if (stat > 0) { 9128679Sbrian stat |= O_NONBLOCK; 9228679Sbrian (void) fcntl(0, F_SETFL, stat); 9325630Sbrian } 946059Samurai newtio = oldtio; 9528679Sbrian newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 966059Samurai newtio.c_iflag = 0; 976059Samurai newtio.c_oflag &= ~OPOST; 986059Samurai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 9926858Sbrian if (DontWantInt) 10026858Sbrian newtio.c_cc[VINTR] = _POSIX_VDISABLE; 1016059Samurai newtio.c_cc[VMIN] = 1; 1026059Samurai newtio.c_cc[VTIME] = 0; 1036059Samurai newtio.c_cflag |= CS8; 1046735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1056059Samurai comtio = newtio; 1066059Samurai} 1076059Samurai 1086059Samurai/* 1096059Samurai * Set tty into command mode. We allow canonical input and echo processing. 1106059Samurai */ 11110528Samuraivoid 11228679SbrianTtyCommandMode(int prompt) 1136059Samurai{ 1146059Samurai struct termios newtio; 1156059Samurai int stat; 1166059Samurai 1176059Samurai if (!(mode & MODE_INTER)) 1186059Samurai return; 1196735Samurai tcgetattr(0, &newtio); 12028679Sbrian newtio.c_lflag |= (ECHO | ISIG | ICANON); 1216059Samurai newtio.c_iflag = oldtio.c_iflag; 1226059Samurai newtio.c_oflag |= OPOST; 1236735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1246059Samurai stat = fcntl(0, F_GETFL, 0); 12525630Sbrian if (stat > 0) { 12628679Sbrian stat |= O_NONBLOCK; 12728679Sbrian (void) fcntl(0, F_SETFL, stat); 12825630Sbrian } 1296059Samurai TermMode = 0; 13028679Sbrian if (prompt) 13128679Sbrian Prompt(); 1326059Samurai} 1336059Samurai 1346059Samurai/* 1356059Samurai * Set tty into terminal mode which is used while we invoke term command. 1366059Samurai */ 1376059Samuraivoid 1386059SamuraiTtyTermMode() 1396059Samurai{ 1406059Samurai int stat; 1416059Samurai 1426735Samurai tcsetattr(0, TCSADRAIN, &comtio); 1436059Samurai stat = fcntl(0, F_GETFL, 0); 14425630Sbrian if (stat > 0) { 14528679Sbrian stat &= ~O_NONBLOCK; 14628679Sbrian (void) fcntl(0, F_SETFL, stat); 14725630Sbrian } 1486059Samurai TermMode = 1; 1496059Samurai} 1506059Samurai 1516059Samuraivoid 15210528SamuraiTtyOldMode() 1536059Samurai{ 1546059Samurai int stat; 1556059Samurai 1566059Samurai stat = fcntl(0, F_GETFL, 0); 15725630Sbrian if (stat > 0) { 15828679Sbrian stat &= ~O_NONBLOCK; 15928679Sbrian (void) fcntl(0, F_SETFL, stat); 16025630Sbrian } 1616735Samurai tcsetattr(0, TCSANOW, &oldtio); 16210528Samurai} 16310528Samurai 16410528Samuraivoid 16528679SbrianCleanup(int excode) 16610528Samurai{ 16710528Samurai OsLinkdown(); 1686059Samurai OsCloseLink(1); 16930697Sbrian nointr_sleep(1); 17025908Sbrian if (mode & MODE_AUTO) 1716059Samurai DeleteIfRoutes(1); 17228679Sbrian (void) unlink(pid_filename); 17328679Sbrian (void) unlink(if_filename); 1746059Samurai OsInterfaceDown(1); 17523863Sbrian if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 17623863Sbrian char c = EX_ERRDEAD; 17728679Sbrian 17828679Sbrian if (write(BGFiledes[1], &c, 1) == 1) 17928679Sbrian LogPrintf(LogPHASE, "Parent notified of failure.\n"); 18023863Sbrian else 18128679Sbrian LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); 18223863Sbrian close(BGFiledes[1]); 18323863Sbrian } 18428679Sbrian LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 1856059Samurai LogClose(); 18626940Sbrian ServerClose(); 18710528Samurai TtyOldMode(); 1886059Samurai 1896059Samurai exit(excode); 1906059Samurai} 1916059Samurai 1926059Samuraistatic void 19328679SbrianCloseConnection(int signo) 1946059Samurai{ 19526858Sbrian /* NOTE, these are manual, we've done a setsid() */ 19627157Sbrian LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 19728679Sbrian reconnectState = RECON_FALSE; 19828684Sbrian reconnectCount = 0; 19928684Sbrian DownConnection(); 20027061Sbrian dial_up = FALSE; 2016059Samurai} 2026059Samurai 2036059Samuraistatic void 20428679SbrianCloseSession(int signo) 2056059Samurai{ 20628679Sbrian if (BGPid) { 20728679Sbrian kill(BGPid, SIGINT); 20828679Sbrian exit(EX_TERM); 20928679Sbrian } 21028679Sbrian LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 21128679Sbrian reconnect(RECON_FALSE); 21228679Sbrian LcpClose(); 21328679Sbrian Cleanup(EX_TERM); 2146059Samurai} 2156059Samurai 21610528Samuraistatic void 21710528SamuraiTerminalCont() 21810528Samurai{ 21923840Sbrian pending_signal(SIGCONT, SIG_DFL); 22023840Sbrian pending_signal(SIGTSTP, TerminalStop); 22110528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 22210528Samurai} 22310528Samurai 22410528Samuraistatic void 22528679SbrianTerminalStop(int signo) 22610528Samurai{ 22723840Sbrian pending_signal(SIGCONT, TerminalCont); 22810528Samurai TtyOldMode(); 22923840Sbrian pending_signal(SIGTSTP, SIG_DFL); 23010528Samurai kill(getpid(), signo); 23110528Samurai} 23210528Samurai 23326940Sbrianstatic void 23428679SbrianSetUpServer(int signo) 23526940Sbrian{ 23626940Sbrian int res; 23728679Sbrian 23828679Sbrian if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) 23929083Sbrian LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 24029083Sbrian res, SERVER_PORT + tunno); 24126940Sbrian} 24226940Sbrian 24325908Sbrianstatic char * 24425908Sbrianex_desc(int ex) 24525908Sbrian{ 24625908Sbrian static char num[12]; 24728679Sbrian static char *desc[] = {"normal", "start", "sock", 24825908Sbrian "modem", "dial", "dead", "done", "reboot", "errdead", 24928679Sbrian "hangup", "term", "nodial", "nologin"}; 25010528Samurai 25128679Sbrian if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc)) 25225908Sbrian return desc[ex]; 25325908Sbrian snprintf(num, sizeof num, "%d", ex); 25425908Sbrian return num; 25525908Sbrian} 25625908Sbrian 2576059Samuraivoid 2586059SamuraiUsage() 2596059Samurai{ 26020120Snate fprintf(stderr, 26128679Sbrian "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2626059Samurai exit(EX_START); 2636059Samurai} 2646059Samurai 2656059Samuraivoid 2666059SamuraiProcessArgs(int argc, char **argv) 2676059Samurai{ 2686059Samurai int optc; 2696059Samurai char *cp; 2706059Samurai 2716059Samurai optc = 0; 2726059Samurai while (argc > 0 && **argv == '-') { 2736059Samurai cp = *argv + 1; 2746059Samurai if (strcmp(cp, "auto") == 0) 2756059Samurai mode |= MODE_AUTO; 27620813Sjkh else if (strcmp(cp, "background") == 0) 27728679Sbrian mode |= MODE_BACKGROUND | MODE_AUTO; 2786059Samurai else if (strcmp(cp, "direct") == 0) 2796059Samurai mode |= MODE_DIRECT; 2806059Samurai else if (strcmp(cp, "dedicated") == 0) 2816059Samurai mode |= MODE_DEDICATED; 28220120Snate else if (strcmp(cp, "ddial") == 0) 28328679Sbrian mode |= MODE_DDIAL | MODE_AUTO; 28420365Sjkh else if (strcmp(cp, "alias") == 0) { 28526142Sbrian if (loadAliasHandlers(&VarAliasHandlers) == 0) 28628679Sbrian mode |= MODE_ALIAS; 28726142Sbrian else 28828679Sbrian LogPrintf(LogWARN, "Cannot load alias library\n"); 28928679Sbrian optc--; /* this option isn't exclusive */ 29028679Sbrian } else 2916059Samurai Usage(); 2926059Samurai optc++; 29328679Sbrian argv++; 29428679Sbrian argc--; 2956059Samurai } 2966059Samurai if (argc > 1) { 2976059Samurai fprintf(stderr, "specify only one system label.\n"); 2986059Samurai exit(EX_START); 2996059Samurai } 30028679Sbrian if (argc == 1) 30128679Sbrian dstsystem = *argv; 3026059Samurai 3036059Samurai if (optc > 1) { 3046059Samurai fprintf(stderr, "specify only one mode.\n"); 3056059Samurai exit(EX_START); 3066059Samurai } 3076059Samurai} 3086059Samurai 3096059Samuraistatic void 3106059SamuraiGreetings() 3116059Samurai{ 31226516Sbrian if (VarTerm) { 31326516Sbrian fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 31426516Sbrian fflush(VarTerm); 31526516Sbrian } 3166059Samurai} 3176059Samurai 31826940Sbrianint 31928679Sbrianmain(int argc, char **argv) 3206059Samurai{ 32125707Sbrian FILE *lockfile; 32226516Sbrian char *name; 32326516Sbrian 32426551Sbrian VarTerm = 0; 32526516Sbrian name = rindex(argv[0], '/'); 32628679Sbrian LogOpen(name ? name + 1 : argv[0]); 32726516Sbrian 32828679Sbrian argc--; 32928679Sbrian argv++; 3306059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 33126940Sbrian netfd = modem = tun_in = -1; 33226940Sbrian server = -2; 3336059Samurai ProcessArgs(argc, argv); 33429083Sbrian if (!(mode & MODE_DIRECT)) { 33529083Sbrian if (getuid() != 0) { 33629083Sbrian fprintf(stderr, "You may only run ppp in client mode as user id 0\n"); 33729083Sbrian LogClose(); 33829083Sbrian return EX_NOPERM; 33929083Sbrian } 34026551Sbrian VarTerm = stdout; 34129083Sbrian } 34226551Sbrian Greetings(); 3436059Samurai GetUid(); 3446059Samurai IpcpDefAddress(); 34529083Sbrian LocalAuthInit(); 3466059Samurai 34726516Sbrian if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 34826516Sbrian fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 3496059Samurai 3506059Samurai if (OpenTunnel(&tunno) < 0) { 35126940Sbrian LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno)); 35226940Sbrian return EX_START; 3536059Samurai } 35428679Sbrian if (mode & (MODE_AUTO | MODE_DIRECT | MODE_DEDICATED)) 3556059Samurai mode &= ~MODE_INTER; 3566059Samurai if (mode & MODE_INTER) { 35726516Sbrian fprintf(VarTerm, "Interactive mode\n"); 35826690Sbrian netfd = STDOUT_FILENO; 3596059Samurai } else if (mode & MODE_AUTO) { 36026516Sbrian fprintf(VarTerm, "Automatic Dialer mode\n"); 3616059Samurai if (dstsystem == NULL) { 36226516Sbrian if (VarTerm) 36328679Sbrian fprintf(VarTerm, "Destination system must be specified in" 36428679Sbrian " auto, background or ddial mode.\n"); 36526940Sbrian return EX_START; 3666059Samurai } 3676059Samurai } 36828679Sbrian tcgetattr(0, &oldtio); /* Save original tty mode */ 3696059Samurai 37027157Sbrian pending_signal(SIGHUP, CloseSession); 37123840Sbrian pending_signal(SIGTERM, CloseSession); 37227157Sbrian pending_signal(SIGINT, CloseConnection); 37323840Sbrian pending_signal(SIGQUIT, CloseSession); 3746735Samurai#ifdef SIGPIPE 37524753Sache signal(SIGPIPE, SIG_IGN); 3766735Samurai#endif 3776735Samurai#ifdef SIGALRM 37823840Sbrian pending_signal(SIGALRM, SIG_IGN); 3796735Samurai#endif 38028679Sbrian if (mode & MODE_INTER) { 38110528Samurai#ifdef SIGTSTP 38226940Sbrian pending_signal(SIGTSTP, TerminalStop); 38310528Samurai#endif 38410528Samurai#ifdef SIGTTIN 38526940Sbrian pending_signal(SIGTTIN, TerminalStop); 38610528Samurai#endif 38710528Samurai#ifdef SIGTTOU 38826940Sbrian pending_signal(SIGTTOU, SIG_IGN); 38910528Samurai#endif 39026940Sbrian } 39126940Sbrian#ifdef SIGUSR1 39226940Sbrian if (mode != MODE_INTER) 39326940Sbrian pending_signal(SIGUSR1, SetUpServer); 39426940Sbrian#endif 3956059Samurai 3966059Samurai if (dstsystem) { 3976059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 39826551Sbrian LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 3996059Samurai Cleanup(EX_START); 4006059Samurai } 4016059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 40226551Sbrian LogPrintf(LogWARN, "Must specify dstaddr with" 40328679Sbrian " auto, background or ddial mode.\n"); 4046059Samurai Cleanup(EX_START); 4056059Samurai } 4066059Samurai } 40726940Sbrian 4086059Samurai if (!(mode & MODE_INTER)) { 40920813Sjkh if (mode & MODE_BACKGROUND) { 41028679Sbrian if (pipe(BGFiledes)) { 41128974Sbrian LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 41220813Sjkh Cleanup(EX_SOCK); 41320813Sjkh } 4146059Samurai } 41526940Sbrian /* Create server socket and listen. */ 41629083Sbrian if (server == -2) 41729083Sbrian ServerTcpOpen(SERVER_PORT + tunno); 4186059Samurai 4196059Samurai if (!(mode & MODE_DIRECT)) { 42020813Sjkh pid_t bgpid; 42111336Samurai 42228679Sbrian bgpid = fork(); 42320813Sjkh if (bgpid == -1) { 42428974Sbrian LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 42528679Sbrian Cleanup(EX_SOCK); 42620813Sjkh } 42720813Sjkh if (bgpid) { 42820813Sjkh char c = EX_NORMAL; 42911336Samurai 43020813Sjkh if (mode & MODE_BACKGROUND) { 43120813Sjkh /* Wait for our child to close its pipe before we exit. */ 43220813Sjkh BGPid = bgpid; 43328679Sbrian close(BGFiledes[1]); 43425908Sbrian if (read(BGFiledes[0], &c, 1) != 1) { 43526516Sbrian fprintf(VarTerm, "Child exit, no status.\n"); 43628679Sbrian LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 43725908Sbrian } else if (c == EX_NORMAL) { 43826516Sbrian fprintf(VarTerm, "PPP enabled.\n"); 43928679Sbrian LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 44025908Sbrian } else { 44128679Sbrian fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 44226516Sbrian LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 44328679Sbrian ex_desc((int) c)); 44428679Sbrian } 44528679Sbrian close(BGFiledes[0]); 44620813Sjkh } 44728679Sbrian return c; 44823863Sbrian } else if (mode & MODE_BACKGROUND) 44928679Sbrian close(BGFiledes[0]); 45025707Sbrian } 45120813Sjkh 45228679Sbrian VarTerm = 0; /* We know it's currently stdout */ 45329551Sbrian close(1); 45426686Sbrian close(2); 45526551Sbrian 4566059Samurai#ifdef DOTTYINIT 45728679Sbrian if (mode & (MODE_DIRECT | MODE_DEDICATED)) 4586059Samurai#else 45926686Sbrian if (mode & MODE_DIRECT) 4606059Samurai#endif 46126858Sbrian TtyInit(1); 46226686Sbrian else { 46326686Sbrian setsid(); 46429551Sbrian close(0); 46526686Sbrian } 4666059Samurai } else { 46726858Sbrian TtyInit(0); 46810528Samurai TtyCommandMode(1); 4696059Samurai } 47029696Sbrian 47129696Sbrian snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid", 47229696Sbrian _PATH_VARRUN, tunno); 47329696Sbrian (void) unlink(pid_filename); 47429696Sbrian 47529696Sbrian if ((lockfile = fopen(pid_filename, "w")) != NULL) { 47629696Sbrian fprintf(lockfile, "%d\n", (int) getpid()); 47729696Sbrian fclose(lockfile); 47829696Sbrian } else 47929696Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 48029696Sbrian pid_filename, strerror(errno)); 48129696Sbrian 48226516Sbrian LogPrintf(LogPHASE, "PPP Started.\n"); 4836059Samurai 4846059Samurai 4856059Samurai do 48628679Sbrian DoLoop(); 4876059Samurai while (mode & MODE_DEDICATED); 4886059Samurai 4896059Samurai Cleanup(EX_DONE); 49026940Sbrian return 0; 4916059Samurai} 4926059Samurai 4936059Samurai/* 49420813Sjkh * Turn into packet mode, where we speak PPP. 4956059Samurai */ 4966059Samuraivoid 4976059SamuraiPacketMode() 4986059Samurai{ 4996059Samurai if (RawModem(modem) < 0) { 50026516Sbrian LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 5016059Samurai return; 5026059Samurai } 5036059Samurai AsyncInit(); 50430187Sbrian VjInit(15); 5056059Samurai LcpInit(); 5066059Samurai IpcpInit(); 5076059Samurai CcpInit(); 5086059Samurai LcpUp(); 5096059Samurai 51025872Sbrian LcpOpen(VarOpenMode); 51128679Sbrian if ((mode & (MODE_INTER | MODE_AUTO)) == MODE_INTER) { 51210528Samurai TtyCommandMode(1); 51326516Sbrian if (VarTerm) { 51426516Sbrian fprintf(VarTerm, "Packet mode.\n"); 51526516Sbrian aft_cmd = 1; 51626516Sbrian } 5176059Samurai } 5186059Samurai} 5196059Samurai 5206059Samuraistatic void 5216059SamuraiShowHelp() 5226059Samurai{ 52326901Sbrian fprintf(stderr, "The following commands are available:\r\n"); 52426901Sbrian fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 52526901Sbrian fprintf(stderr, " ~-\tDecrease log level\r\n"); 52626901Sbrian fprintf(stderr, " ~+\tIncrease log level\r\n"); 52726901Sbrian fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 52826901Sbrian fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 52926901Sbrian fprintf(stderr, " ~.\tTerminate program\r\n"); 53026901Sbrian fprintf(stderr, " ~?\tThis help\r\n"); 5316059Samurai} 5326059Samurai 5336059Samuraistatic void 5346059SamuraiReadTty() 5356059Samurai{ 5366059Samurai int n; 5376059Samurai char ch; 5386059Samurai static int ttystate; 53926516Sbrian FILE *oVarTerm; 54028679Sbrian 5416059Samurai#define MAXLINESIZE 200 5426059Samurai char linebuff[MAXLINESIZE]; 5436059Samurai 54426516Sbrian LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 54528679Sbrian TermMode, netfd, mode); 5466059Samurai if (!TermMode) { 54728679Sbrian n = read(netfd, linebuff, sizeof(linebuff) - 1); 5486735Samurai if (n > 0) { 54926516Sbrian aft_cmd = 1; 55030497Sbrian linebuff[n] = '\0'; 55130497Sbrian LogPrintf(LogCOMMAND, "Client: %s\n", linebuff); 5526059Samurai DecodeCommand(linebuff, n, 1); 5536735Samurai } else { 55426516Sbrian LogPrintf(LogPHASE, "client connection closed.\n"); 55524753Sache VarLocalAuth = LOCAL_NO_AUTH; 55626516Sbrian mode &= ~MODE_INTER; 55726516Sbrian oVarTerm = VarTerm; 55826516Sbrian VarTerm = 0; 55926516Sbrian if (oVarTerm && oVarTerm != stdout) 56028679Sbrian fclose(oVarTerm); 5616059Samurai close(netfd); 5626059Samurai netfd = -1; 5636059Samurai } 5646059Samurai return; 5656059Samurai } 5666059Samurai 5676059Samurai /* 56828679Sbrian * We are in terminal mode, decode special sequences 5696059Samurai */ 57026516Sbrian n = read(fileno(VarTerm), &ch, 1); 57128974Sbrian LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 5726059Samurai 5736059Samurai if (n > 0) { 5746059Samurai switch (ttystate) { 5756059Samurai case 0: 5766059Samurai if (ch == '~') 5776059Samurai ttystate++; 5786059Samurai else 5796059Samurai write(modem, &ch, n); 5806059Samurai break; 5816059Samurai case 1: 5826059Samurai switch (ch) { 5836059Samurai case '?': 5846059Samurai ShowHelp(); 5856059Samurai break; 5866059Samurai case 'p': 58728679Sbrian 5886059Samurai /* 5896059Samurai * XXX: Should check carrier. 5906059Samurai */ 5916059Samurai if (LcpFsm.state <= ST_CLOSED) { 5926059Samurai VarOpenMode = OPEN_ACTIVE; 5936059Samurai PacketMode(); 5946059Samurai } 5956059Samurai break; 5966059Samurai case '.': 5976059Samurai TermMode = 1; 59826516Sbrian aft_cmd = 1; 59910528Samurai TtyCommandMode(1); 6006059Samurai break; 60126516Sbrian case 't': 60226516Sbrian if (LogIsKept(LogDEBUG)) { 60326516Sbrian ShowTimers(); 60426516Sbrian break; 60526516Sbrian } 60626516Sbrian case 'm': 60726516Sbrian if (LogIsKept(LogDEBUG)) { 60826516Sbrian ShowMemMap(); 60926516Sbrian break; 61026516Sbrian } 6116059Samurai default: 6126059Samurai if (write(modem, &ch, n) < 0) 61326516Sbrian LogPrintf(LogERROR, "error writing to modem.\n"); 6146059Samurai break; 6156059Samurai } 6166059Samurai ttystate = 0; 6176059Samurai break; 6186059Samurai } 6196059Samurai } 6206059Samurai} 6216059Samurai 6226059Samurai 6236059Samurai/* 6246059Samurai * Here, we'll try to detect HDLC frame 6256059Samurai */ 6266059Samurai 6276059Samuraistatic char *FrameHeaders[] = { 6286735Samurai "\176\377\003\300\041", 6296735Samurai "\176\377\175\043\300\041", 6306735Samurai "\176\177\175\043\100\041", 6316735Samurai "\176\175\337\175\043\300\041", 6326735Samurai "\176\175\137\175\043\100\041", 6336059Samurai NULL, 6346059Samurai}; 6356059Samurai 6366059Samuraiu_char * 63728679SbrianHdlcDetect(u_char * cp, int n) 6386059Samurai{ 6396735Samurai char *ptr, *fp, **hp; 6406059Samurai 64128679Sbrian cp[n] = '\0'; /* be sure to null terminated */ 6426059Samurai ptr = NULL; 6436059Samurai for (hp = FrameHeaders; *hp; hp++) { 6446735Samurai fp = *hp; 6456735Samurai if (DEV_IS_SYNC) 6466735Samurai fp++; 64728679Sbrian ptr = strstr((char *) cp, fp); 64813389Sphk if (ptr) 6496059Samurai break; 6506059Samurai } 65128679Sbrian return ((u_char *) ptr); 6526059Samurai} 6536059Samurai 6546059Samuraistatic struct pppTimer RedialTimer; 6556059Samurai 6566059Samuraistatic void 6576059SamuraiRedialTimeout() 6586059Samurai{ 6596059Samurai StopTimer(&RedialTimer); 66026516Sbrian LogPrintf(LogPHASE, "Redialing timer expired.\n"); 6616059Samurai} 6626059Samurai 6636059Samuraistatic void 66428679SbrianStartRedialTimer(int Timeout) 6656059Samurai{ 6666059Samurai StopTimer(&RedialTimer); 66711336Samurai 66824939Sbrian if (Timeout) { 66911336Samurai RedialTimer.state = TIMER_STOPPED; 67011336Samurai 67124939Sbrian if (Timeout > 0) 67228679Sbrian RedialTimer.load = Timeout * SECTICKS; 67311336Samurai else 67428679Sbrian RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 67511336Samurai 67626516Sbrian LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 67724939Sbrian RedialTimer.load / SECTICKS); 67824939Sbrian 67911336Samurai RedialTimer.func = RedialTimeout; 68011336Samurai StartTimer(&RedialTimer); 68111336Samurai } 6826059Samurai} 6836059Samurai 6846059Samurai 6856059Samuraistatic void 6866059SamuraiDoLoop() 6876059Samurai{ 6886059Samurai fd_set rfds, wfds, efds; 68923598Sache int pri, i, n, wfd, nfds; 6906059Samurai struct sockaddr_in hisaddr; 6916059Samurai struct timeval timeout, *tp; 6926059Samurai int ssize = sizeof(hisaddr); 6936059Samurai u_char *cp; 6946059Samurai u_char rbuff[MAX_MRU]; 69511336Samurai int tries; 6969448Samurai int qlen; 69726858Sbrian int res; 69810528Samurai pid_t pgroup; 6996059Samurai 70010528Samurai pgroup = getpgrp(); 70110528Samurai 70225908Sbrian if (mode & MODE_DIRECT) { 70326551Sbrian LogPrintf(LogDEBUG, "Opening modem\n"); 70429521Sbrian if (OpenModem(mode) < 0) 70529521Sbrian return; 70626516Sbrian LogPrintf(LogPHASE, "Packet mode enabled\n"); 7076059Samurai PacketMode(); 7086059Samurai } else if (mode & MODE_DEDICATED) { 70923598Sache if (modem < 0) 71029521Sbrian while (OpenModem(mode) < 0) 71130697Sbrian nointr_sleep(VarReconnectTimer); 7126059Samurai } 71326516Sbrian fflush(VarTerm); 7146059Samurai 7157001Samurai timeout.tv_sec = 0; 7166059Samurai timeout.tv_usec = 0; 71726098Sbrian reconnectState = RECON_UNKNOWN; 7186059Samurai 71923863Sbrian if (mode & MODE_BACKGROUND) 72028679Sbrian dial_up = TRUE; /* Bring the line up */ 72123863Sbrian else 72228679Sbrian dial_up = FALSE; /* XXXX */ 72311336Samurai tries = 0; 7246059Samurai for (;;) { 72523598Sache nfds = 0; 72628679Sbrian FD_ZERO(&rfds); 72728679Sbrian FD_ZERO(&wfds); 72828679Sbrian FD_ZERO(&efds); 7297001Samurai 73028679Sbrian /* 73128679Sbrian * If the link is down and we're in DDIAL mode, bring it back up. 73220120Snate */ 73320120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 73428679Sbrian dial_up = TRUE; 73520120Snate 73625067Sbrian /* 73728679Sbrian * If we lost carrier and want to re-establish the connection due to the 73828679Sbrian * "set reconnect" value, we'd better bring the line back up. 73925067Sbrian */ 74025908Sbrian if (LcpFsm.state <= ST_CLOSED) { 74126098Sbrian if (dial_up != TRUE && reconnectState == RECON_TRUE) { 74228679Sbrian if (++reconnectCount <= VarReconnectTries) { 74328679Sbrian LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 74428679Sbrian reconnectCount, VarReconnectTries); 74525908Sbrian StartRedialTimer(VarReconnectTimer); 74628679Sbrian dial_up = TRUE; 74728679Sbrian } else { 74828679Sbrian if (VarReconnectTries) 74928679Sbrian LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 75028679Sbrian VarReconnectTries); 75128679Sbrian reconnectCount = 0; 75228679Sbrian if (mode & MODE_BACKGROUND) 75328679Sbrian Cleanup(EX_DEAD); 75428679Sbrian } 75528679Sbrian reconnectState = RECON_ENVOKED; 75625801Sbrian } 75725908Sbrian } 75825067Sbrian 75928679Sbrian /* 76028679Sbrian * If Ip packet for output is enqueued and require dial up, Just do it! 76128679Sbrian */ 76228679Sbrian if (dial_up && RedialTimer.state != TIMER_RUNNING) { 76326516Sbrian LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 76429521Sbrian if (OpenModem(mode) < 0) { 76528679Sbrian tries++; 76628679Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 76728679Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 76828679Sbrian tries, VarDialTries); 76928679Sbrian else 77028679Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 77126551Sbrian 77226696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 77326551Sbrian if (mode & MODE_BACKGROUND) 77428679Sbrian Cleanup(EX_DIAL); /* Can't get the modem */ 77526551Sbrian dial_up = FALSE; 77628679Sbrian reconnectState = RECON_UNKNOWN; 77728679Sbrian reconnectCount = 0; 77826551Sbrian tries = 0; 77928679Sbrian } else 78026551Sbrian StartRedialTimer(VarRedialTimeout); 78111336Samurai } else { 78228679Sbrian tries++; /* Tries are per number, not per list of 78328679Sbrian * numbers. */ 78428679Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 78526696Sbrian LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 78628679Sbrian else 78728679Sbrian LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 78826696Sbrian 78926858Sbrian if ((res = DialModem()) == EX_DONE) { 79030697Sbrian nointr_sleep(1); /* little pause to allow peer starts */ 79111336Samurai ModemTimeout(); 79211336Samurai PacketMode(); 79311336Samurai dial_up = FALSE; 79428679Sbrian reconnectState = RECON_UNKNOWN; 79511336Samurai tries = 0; 79611336Samurai } else { 79711336Samurai CloseModem(); 79824844Sbrian if (mode & MODE_BACKGROUND) { 79926858Sbrian if (VarNextPhone == NULL || res == EX_SIG) 80028679Sbrian Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 80124844Sbrian else 80224939Sbrian /* Try all numbers in background mode */ 80324939Sbrian StartRedialTimer(VarRedialNextTimeout); 80426858Sbrian } else if (!(mode & MODE_DDIAL) && 80528679Sbrian ((VarDialTries && tries >= VarDialTries) || 80628679Sbrian res == EX_SIG)) { 80724843Sbrian /* I give up ! Can't get through :( */ 80824939Sbrian StartRedialTimer(VarRedialTimeout); 80924843Sbrian dial_up = FALSE; 81028679Sbrian reconnectState = RECON_UNKNOWN; 81128679Sbrian reconnectCount = 0; 81224843Sbrian tries = 0; 81324843Sbrian } else if (VarNextPhone == NULL) 81424843Sbrian /* Dial failed. Keep quite during redial wait period. */ 81524939Sbrian StartRedialTimer(VarRedialTimeout); 81624843Sbrian else 81724939Sbrian StartRedialTimer(VarRedialNextTimeout); 81811336Samurai } 81911336Samurai } 8207001Samurai } 8219448Samurai qlen = ModemQlen(); 82213733Sdfr 82313733Sdfr if (qlen == 0) { 82413733Sdfr IpStartOutput(); 82513733Sdfr qlen = ModemQlen(); 82613733Sdfr } 82723598Sache if (modem >= 0) { 82823598Sache if (modem + 1 > nfds) 82923598Sache nfds = modem + 1; 8307001Samurai FD_SET(modem, &rfds); 8317001Samurai FD_SET(modem, &efds); 8329448Samurai if (qlen > 0) { 8337001Samurai FD_SET(modem, &wfds); 8347001Samurai } 8357001Samurai } 83623598Sache if (server >= 0) { 83723598Sache if (server + 1 > nfds) 83823598Sache nfds = server + 1; 83923598Sache FD_SET(server, &rfds); 84023598Sache } 8416059Samurai 84228679Sbrian /* 84328679Sbrian * *** IMPORTANT *** 84428679Sbrian * 84528679Sbrian * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 84628679Sbrian * with great care. If this values is too big, it results loss of 84728679Sbrian * characters from modem and poor responce. If this values is too small, 84828679Sbrian * ppp process eats many CPU time. 8496059Samurai */ 8506735Samurai#ifndef SIGALRM 85130697Sbrian nointr_usleep(TICKUNIT); 8526059Samurai TimerService(); 85323840Sbrian#else 85423840Sbrian handle_signals(); 8556735Samurai#endif 85610877Sbde 85710877Sbde /* If there are aren't many packets queued, look for some more. */ 85823598Sache if (qlen < 20 && tun_in >= 0) { 85923598Sache if (tun_in + 1 > nfds) 86023598Sache nfds = tun_in + 1; 86110877Sbde FD_SET(tun_in, &rfds); 86223598Sache } 86323598Sache if (netfd >= 0) { 86423598Sache if (netfd + 1 > nfds) 86523598Sache nfds = netfd + 1; 8666059Samurai FD_SET(netfd, &rfds); 8676059Samurai FD_SET(netfd, &efds); 8686059Samurai } 86928679Sbrian#ifndef SIGALRM 8707001Samurai 8716059Samurai /* 87228679Sbrian * Normally, select() will not block because modem is writable. In AUTO 87328679Sbrian * mode, select will block until we find packet from tun 8746059Samurai */ 87528679Sbrian tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 87623598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 8776735Samurai#else 87828679Sbrian 8798857Srgrimes /* 88028679Sbrian * When SIGALRM timer is running, a select function will be return -1 and 88128679Sbrian * EINTR after a Time Service signal hundler is done. If the redial 88228679Sbrian * timer is not running and we are trying to dial, poll with a 0 value 88328679Sbrian * timer. 8847001Samurai */ 88511336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 88623598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 8876735Samurai#endif 88822074Sbrian 88928679Sbrian if (i == 0) { 89028679Sbrian continue; 8916059Samurai } 89228679Sbrian if (i < 0) { 89328679Sbrian if (errno == EINTR) { 89428679Sbrian handle_signals(); 89528679Sbrian continue; 89628679Sbrian } 89728974Sbrian LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 89828679Sbrian break; 8998857Srgrimes } 90023598Sache if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 90126516Sbrian LogPrintf(LogALERT, "Exception detected.\n"); 9026059Samurai break; 9036059Samurai } 90423598Sache if (server >= 0 && FD_ISSET(server, &rfds)) { 90526516Sbrian LogPrintf(LogPHASE, "connected to client.\n"); 90628679Sbrian wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 90724753Sache if (wfd < 0) { 90828974Sbrian LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 90924753Sache continue; 91024753Sache } 91123598Sache if (netfd >= 0) { 9126059Samurai write(wfd, "already in use.\n", 16); 9136059Samurai close(wfd); 9146059Samurai continue; 9156059Samurai } else 9166059Samurai netfd = wfd; 91726516Sbrian VarTerm = fdopen(netfd, "a+"); 9186059Samurai mode |= MODE_INTER; 9196059Samurai Greetings(); 9206059Samurai (void) IsInteractive(); 92125630Sbrian Prompt(); 9226059Samurai } 92323598Sache if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 92410858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 9256059Samurai /* something to read from tty */ 9266059Samurai ReadTty(); 9276059Samurai } 92823598Sache if (modem >= 0) { 9296059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 93028679Sbrian ModemStartOutput(modem); 9316059Samurai } 9326059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 9336735Samurai if (LcpFsm.state <= ST_CLOSED) 93430697Sbrian nointr_usleep(10000); 9356059Samurai n = read(modem, rbuff, sizeof(rbuff)); 9366059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 9376059Samurai DownConnection(); 9386059Samurai } else 93928679Sbrian LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 9406059Samurai 9416059Samurai if (LcpFsm.state <= ST_CLOSED) { 94228679Sbrian 9436059Samurai /* 94428679Sbrian * In dedicated mode, we just discard input until LCP is started. 9456059Samurai */ 9466059Samurai if (!(mode & MODE_DEDICATED)) { 9476059Samurai cp = HdlcDetect(rbuff, n); 9486059Samurai if (cp) { 94928679Sbrian 9506059Samurai /* 9516059Samurai * LCP packet is detected. Turn ourselves into packet mode. 9526059Samurai */ 9536059Samurai if (cp != rbuff) { 95428679Sbrian write(modem, rbuff, cp - rbuff); 95528679Sbrian write(modem, "\r\n", 2); 9566059Samurai } 9576059Samurai PacketMode(); 9586059Samurai } else 95926516Sbrian write(fileno(VarTerm), rbuff, n); 9606059Samurai } 9616059Samurai } else { 9626059Samurai if (n > 0) 9636059Samurai AsyncInput(rbuff, n); 9646059Samurai } 9656059Samurai } 9666059Samurai } 96728679Sbrian if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 96828679Sbrian * from tun */ 9696059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 9706059Samurai if (n < 0) { 97128974Sbrian LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 9726059Samurai continue; 9736059Samurai } 97428679Sbrian if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 97528536Sbrian /* we've been asked to send something addressed *to* us :( */ 97628536Sbrian if (VarLoopback) { 97728536Sbrian pri = PacketCheck(rbuff, n, FL_IN); 97828536Sbrian if (pri >= 0) { 97928536Sbrian struct mbuf *bp; 98028679Sbrian 98128536Sbrian if (mode & MODE_ALIAS) { 98228536Sbrian VarPacketAliasIn(rbuff, sizeof rbuff); 98328679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 98428536Sbrian } 98528536Sbrian bp = mballoc(n, MB_IPIN); 98628536Sbrian bcopy(rbuff, MBUF_CTOP(bp), n); 98728536Sbrian IpInput(bp); 98828536Sbrian LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 98928536Sbrian } 99028536Sbrian continue; 99128679Sbrian } else 99228536Sbrian LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 99328536Sbrian } 99428536Sbrian 9956059Samurai /* 99628679Sbrian * Process on-demand dialup. Output packets are queued within tunnel 99728679Sbrian * device until IPCP is opened. 9986059Samurai */ 9996059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 10007001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 10016059Samurai if (pri >= 0) { 100220365Sjkh if (mode & MODE_ALIAS) { 100326142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 100428679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 100520365Sjkh } 10066059Samurai IpEnqueue(pri, rbuff, n); 100728679Sbrian dial_up = TRUE; /* XXX */ 10086059Samurai } 10096059Samurai continue; 10106059Samurai } 10117001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 101220365Sjkh if (pri >= 0) { 101328679Sbrian if (mode & MODE_ALIAS) { 101428679Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 101528679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 101628679Sbrian } 10176059Samurai IpEnqueue(pri, rbuff, n); 101820365Sjkh } 10196059Samurai } 10206059Samurai } 102126516Sbrian LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 10226059Samurai} 1023