main.c revision 30715
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 * 2030715Sbrian * $Id: main.c,v 1.84 1997/10/24 22:36:30 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Add commands for traffic summary, version display, etc. 246059Samurai * o Add signal handler for misc controls. 256059Samurai */ 2630715Sbrian#include <sys/param.h> 2730715Sbrian#include <sys/socket.h> 2830715Sbrian#include <netinet/in.h> 2930715Sbrian#include <netinet/in_systm.h> 3030715Sbrian#include <netinet/ip.h> 3130715Sbrian#include <arpa/inet.h> 3230715Sbrian#include <netdb.h> 3330715Sbrian 3430715Sbrian#include <errno.h> 356059Samurai#include <fcntl.h> 3611336Samurai#include <paths.h> 3730715Sbrian#include <signal.h> 3830715Sbrian#include <stdio.h> 3930715Sbrian#include <stdlib.h> 4030715Sbrian#include <string.h> 416059Samurai#include <sys/time.h> 4230715Sbrian#include <sys/wait.h> 4330715Sbrian#include <sysexits.h> 446059Samurai#include <termios.h> 4518786Sjkh#include <unistd.h> 4630715Sbrian 4730715Sbrian#include "mbuf.h" 4830715Sbrian#include "log.h" 4930715Sbrian#include "defs.h" 5030715Sbrian#include "timer.h" 5130715Sbrian#include "fsm.h" 526059Samurai#include "modem.h" 536059Samurai#include "os.h" 546059Samurai#include "hdlc.h" 5513389Sphk#include "ccp.h" 566059Samurai#include "lcp.h" 576059Samurai#include "ipcp.h" 5826142Sbrian#include "loadalias.h" 5930715Sbrian#include "command.h" 606059Samurai#include "vars.h" 616735Samurai#include "auth.h" 627001Samurai#include "filter.h" 6313389Sphk#include "systems.h" 6413389Sphk#include "ip.h" 6523840Sbrian#include "sig.h" 6626940Sbrian#include "server.h" 6728536Sbrian#include "lcpproto.h" 6830715Sbrian#include "main.h" 6930715Sbrian#include "vjcomp.h" 7030715Sbrian#include "async.h" 716059Samurai 726735Samurai#ifndef O_NONBLOCK 736735Samurai#ifdef O_NDELAY 746735Samurai#define O_NONBLOCK O_NDELAY 756735Samurai#endif 766735Samurai#endif 776735Samurai 7830715Sbrianint TermMode = 0; 7930715Sbrianint tunno = 0; 806059Samurai 8128679Sbrianstatic struct termios oldtio; /* Original tty mode */ 8228679Sbrianstatic struct termios comtio; /* Command level tty mode */ 8320813Sjkhstatic pid_t BGPid = 0; 8425634Sbrianstatic char pid_filename[MAXPATHLEN]; 8525634Sbrianstatic char if_filename[MAXPATHLEN]; 8627061Sbrianstatic int dial_up; 876059Samurai 8830715Sbrianstatic void DoLoop(void); 8930715Sbrianstatic void TerminalStop(int); 9030715Sbrianstatic char *ex_desc(int); 9130715Sbrian 926059Samuraistatic void 9326858SbrianTtyInit(int DontWantInt) 946059Samurai{ 956059Samurai struct termios newtio; 966059Samurai int stat; 976059Samurai 986059Samurai stat = fcntl(0, F_GETFL, 0); 9925630Sbrian if (stat > 0) { 10028679Sbrian stat |= O_NONBLOCK; 10128679Sbrian (void) fcntl(0, F_SETFL, stat); 10225630Sbrian } 1036059Samurai newtio = oldtio; 10428679Sbrian newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 1056059Samurai newtio.c_iflag = 0; 1066059Samurai newtio.c_oflag &= ~OPOST; 1076059Samurai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 10826858Sbrian if (DontWantInt) 10926858Sbrian newtio.c_cc[VINTR] = _POSIX_VDISABLE; 1106059Samurai newtio.c_cc[VMIN] = 1; 1116059Samurai newtio.c_cc[VTIME] = 0; 1126059Samurai newtio.c_cflag |= CS8; 1136735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1146059Samurai comtio = newtio; 1156059Samurai} 1166059Samurai 1176059Samurai/* 1186059Samurai * Set tty into command mode. We allow canonical input and echo processing. 1196059Samurai */ 12010528Samuraivoid 12128679SbrianTtyCommandMode(int prompt) 1226059Samurai{ 1236059Samurai struct termios newtio; 1246059Samurai int stat; 1256059Samurai 1266059Samurai if (!(mode & MODE_INTER)) 1276059Samurai return; 1286735Samurai tcgetattr(0, &newtio); 12928679Sbrian newtio.c_lflag |= (ECHO | ISIG | ICANON); 1306059Samurai newtio.c_iflag = oldtio.c_iflag; 1316059Samurai newtio.c_oflag |= OPOST; 1326735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1336059Samurai stat = fcntl(0, F_GETFL, 0); 13425630Sbrian if (stat > 0) { 13528679Sbrian stat |= O_NONBLOCK; 13628679Sbrian (void) fcntl(0, F_SETFL, stat); 13725630Sbrian } 1386059Samurai TermMode = 0; 13928679Sbrian if (prompt) 14028679Sbrian Prompt(); 1416059Samurai} 1426059Samurai 1436059Samurai/* 1446059Samurai * Set tty into terminal mode which is used while we invoke term command. 1456059Samurai */ 1466059Samuraivoid 1476059SamuraiTtyTermMode() 1486059Samurai{ 1496059Samurai int stat; 1506059Samurai 1516735Samurai tcsetattr(0, TCSADRAIN, &comtio); 1526059Samurai stat = fcntl(0, F_GETFL, 0); 15325630Sbrian if (stat > 0) { 15428679Sbrian stat &= ~O_NONBLOCK; 15528679Sbrian (void) fcntl(0, F_SETFL, stat); 15625630Sbrian } 1576059Samurai TermMode = 1; 1586059Samurai} 1596059Samurai 1606059Samuraivoid 16110528SamuraiTtyOldMode() 1626059Samurai{ 1636059Samurai int stat; 1646059Samurai 1656059Samurai stat = fcntl(0, F_GETFL, 0); 16625630Sbrian if (stat > 0) { 16728679Sbrian stat &= ~O_NONBLOCK; 16828679Sbrian (void) fcntl(0, F_SETFL, stat); 16925630Sbrian } 1706735Samurai tcsetattr(0, TCSANOW, &oldtio); 17110528Samurai} 17210528Samurai 17310528Samuraivoid 17428679SbrianCleanup(int excode) 17510528Samurai{ 17610528Samurai OsLinkdown(); 1776059Samurai OsCloseLink(1); 17830697Sbrian nointr_sleep(1); 17925908Sbrian if (mode & MODE_AUTO) 1806059Samurai DeleteIfRoutes(1); 18128679Sbrian (void) unlink(pid_filename); 18228679Sbrian (void) unlink(if_filename); 1836059Samurai OsInterfaceDown(1); 18423863Sbrian if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 18523863Sbrian char c = EX_ERRDEAD; 18628679Sbrian 18728679Sbrian if (write(BGFiledes[1], &c, 1) == 1) 18828679Sbrian LogPrintf(LogPHASE, "Parent notified of failure.\n"); 18923863Sbrian else 19028679Sbrian LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); 19123863Sbrian close(BGFiledes[1]); 19223863Sbrian } 19328679Sbrian LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 1946059Samurai LogClose(); 19526940Sbrian ServerClose(); 19610528Samurai TtyOldMode(); 1976059Samurai 1986059Samurai exit(excode); 1996059Samurai} 2006059Samurai 2016059Samuraistatic void 20228679SbrianCloseConnection(int signo) 2036059Samurai{ 20426858Sbrian /* NOTE, these are manual, we've done a setsid() */ 20527157Sbrian LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 20628679Sbrian reconnectState = RECON_FALSE; 20728684Sbrian reconnectCount = 0; 20828684Sbrian DownConnection(); 20930715Sbrian dial_up = 0; 2106059Samurai} 2116059Samurai 2126059Samuraistatic void 21328679SbrianCloseSession(int signo) 2146059Samurai{ 21528679Sbrian if (BGPid) { 21628679Sbrian kill(BGPid, SIGINT); 21728679Sbrian exit(EX_TERM); 21828679Sbrian } 21928679Sbrian LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 22028679Sbrian reconnect(RECON_FALSE); 22128679Sbrian LcpClose(); 22228679Sbrian Cleanup(EX_TERM); 2236059Samurai} 2246059Samurai 22510528Samuraistatic void 22610528SamuraiTerminalCont() 22710528Samurai{ 22823840Sbrian pending_signal(SIGCONT, SIG_DFL); 22923840Sbrian pending_signal(SIGTSTP, TerminalStop); 23010528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 23110528Samurai} 23210528Samurai 23310528Samuraistatic void 23428679SbrianTerminalStop(int signo) 23510528Samurai{ 23623840Sbrian pending_signal(SIGCONT, TerminalCont); 23710528Samurai TtyOldMode(); 23823840Sbrian pending_signal(SIGTSTP, SIG_DFL); 23910528Samurai kill(getpid(), signo); 24010528Samurai} 24110528Samurai 24226940Sbrianstatic void 24328679SbrianSetUpServer(int signo) 24426940Sbrian{ 24526940Sbrian int res; 24628679Sbrian 24728679Sbrian if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) 24829083Sbrian LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 24929083Sbrian res, SERVER_PORT + tunno); 25026940Sbrian} 25126940Sbrian 25225908Sbrianstatic char * 25325908Sbrianex_desc(int ex) 25425908Sbrian{ 25525908Sbrian static char num[12]; 25628679Sbrian static char *desc[] = {"normal", "start", "sock", 25725908Sbrian "modem", "dial", "dead", "done", "reboot", "errdead", 25828679Sbrian "hangup", "term", "nodial", "nologin"}; 25910528Samurai 26028679Sbrian if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc)) 26125908Sbrian return desc[ex]; 26225908Sbrian snprintf(num, sizeof num, "%d", ex); 26325908Sbrian return num; 26425908Sbrian} 26525908Sbrian 26630715Sbrianstatic void 2676059SamuraiUsage() 2686059Samurai{ 26920120Snate fprintf(stderr, 27028679Sbrian "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2716059Samurai exit(EX_START); 2726059Samurai} 2736059Samurai 27430715Sbrianstatic void 2756059SamuraiProcessArgs(int argc, char **argv) 2766059Samurai{ 2776059Samurai int optc; 2786059Samurai char *cp; 2796059Samurai 2806059Samurai optc = 0; 2816059Samurai while (argc > 0 && **argv == '-') { 2826059Samurai cp = *argv + 1; 2836059Samurai if (strcmp(cp, "auto") == 0) 2846059Samurai mode |= MODE_AUTO; 28520813Sjkh else if (strcmp(cp, "background") == 0) 28628679Sbrian mode |= MODE_BACKGROUND | MODE_AUTO; 2876059Samurai else if (strcmp(cp, "direct") == 0) 2886059Samurai mode |= MODE_DIRECT; 2896059Samurai else if (strcmp(cp, "dedicated") == 0) 2906059Samurai mode |= MODE_DEDICATED; 29120120Snate else if (strcmp(cp, "ddial") == 0) 29228679Sbrian mode |= MODE_DDIAL | MODE_AUTO; 29320365Sjkh else if (strcmp(cp, "alias") == 0) { 29426142Sbrian if (loadAliasHandlers(&VarAliasHandlers) == 0) 29528679Sbrian mode |= MODE_ALIAS; 29626142Sbrian else 29728679Sbrian LogPrintf(LogWARN, "Cannot load alias library\n"); 29828679Sbrian optc--; /* this option isn't exclusive */ 29928679Sbrian } else 3006059Samurai Usage(); 3016059Samurai optc++; 30228679Sbrian argv++; 30328679Sbrian argc--; 3046059Samurai } 3056059Samurai if (argc > 1) { 3066059Samurai fprintf(stderr, "specify only one system label.\n"); 3076059Samurai exit(EX_START); 3086059Samurai } 30928679Sbrian if (argc == 1) 31028679Sbrian dstsystem = *argv; 3116059Samurai 3126059Samurai if (optc > 1) { 3136059Samurai fprintf(stderr, "specify only one mode.\n"); 3146059Samurai exit(EX_START); 3156059Samurai } 3166059Samurai} 3176059Samurai 3186059Samuraistatic void 3196059SamuraiGreetings() 3206059Samurai{ 32126516Sbrian if (VarTerm) { 32226516Sbrian fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 32326516Sbrian fflush(VarTerm); 32426516Sbrian } 3256059Samurai} 3266059Samurai 32726940Sbrianint 32828679Sbrianmain(int argc, char **argv) 3296059Samurai{ 33025707Sbrian FILE *lockfile; 33126516Sbrian char *name; 33226516Sbrian 33326551Sbrian VarTerm = 0; 33430715Sbrian name = strrchr(argv[0], '/'); 33528679Sbrian LogOpen(name ? name + 1 : argv[0]); 33626516Sbrian 33728679Sbrian argc--; 33828679Sbrian argv++; 3396059Samurai ProcessArgs(argc, argv); 34029083Sbrian if (!(mode & MODE_DIRECT)) { 34129083Sbrian if (getuid() != 0) { 34229083Sbrian fprintf(stderr, "You may only run ppp in client mode as user id 0\n"); 34329083Sbrian LogClose(); 34429083Sbrian return EX_NOPERM; 34529083Sbrian } 34626551Sbrian VarTerm = stdout; 34729083Sbrian } 34826551Sbrian Greetings(); 3496059Samurai GetUid(); 3506059Samurai IpcpDefAddress(); 35129083Sbrian LocalAuthInit(); 3526059Samurai 35326516Sbrian if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 35426516Sbrian fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 3556059Samurai 3566059Samurai if (OpenTunnel(&tunno) < 0) { 35726940Sbrian LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno)); 35826940Sbrian return EX_START; 3596059Samurai } 36028679Sbrian if (mode & (MODE_AUTO | MODE_DIRECT | MODE_DEDICATED)) 3616059Samurai mode &= ~MODE_INTER; 3626059Samurai if (mode & MODE_INTER) { 36326516Sbrian fprintf(VarTerm, "Interactive mode\n"); 36426690Sbrian netfd = STDOUT_FILENO; 3656059Samurai } else if (mode & MODE_AUTO) { 36626516Sbrian fprintf(VarTerm, "Automatic Dialer mode\n"); 3676059Samurai if (dstsystem == NULL) { 36826516Sbrian if (VarTerm) 36928679Sbrian fprintf(VarTerm, "Destination system must be specified in" 37028679Sbrian " auto, background or ddial mode.\n"); 37126940Sbrian return EX_START; 3726059Samurai } 3736059Samurai } 37428679Sbrian tcgetattr(0, &oldtio); /* Save original tty mode */ 3756059Samurai 37627157Sbrian pending_signal(SIGHUP, CloseSession); 37723840Sbrian pending_signal(SIGTERM, CloseSession); 37827157Sbrian pending_signal(SIGINT, CloseConnection); 37923840Sbrian pending_signal(SIGQUIT, CloseSession); 3806735Samurai#ifdef SIGPIPE 38124753Sache signal(SIGPIPE, SIG_IGN); 3826735Samurai#endif 3836735Samurai#ifdef SIGALRM 38423840Sbrian pending_signal(SIGALRM, SIG_IGN); 3856735Samurai#endif 38628679Sbrian if (mode & MODE_INTER) { 38710528Samurai#ifdef SIGTSTP 38826940Sbrian pending_signal(SIGTSTP, TerminalStop); 38910528Samurai#endif 39010528Samurai#ifdef SIGTTIN 39126940Sbrian pending_signal(SIGTTIN, TerminalStop); 39210528Samurai#endif 39310528Samurai#ifdef SIGTTOU 39426940Sbrian pending_signal(SIGTTOU, SIG_IGN); 39510528Samurai#endif 39626940Sbrian } 39726940Sbrian#ifdef SIGUSR1 39826940Sbrian if (mode != MODE_INTER) 39926940Sbrian pending_signal(SIGUSR1, SetUpServer); 40026940Sbrian#endif 4016059Samurai 4026059Samurai if (dstsystem) { 4036059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 40426551Sbrian LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 4056059Samurai Cleanup(EX_START); 4066059Samurai } 4076059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 40826551Sbrian LogPrintf(LogWARN, "Must specify dstaddr with" 40928679Sbrian " auto, background or ddial mode.\n"); 4106059Samurai Cleanup(EX_START); 4116059Samurai } 4126059Samurai } 41326940Sbrian 4146059Samurai if (!(mode & MODE_INTER)) { 41520813Sjkh if (mode & MODE_BACKGROUND) { 41628679Sbrian if (pipe(BGFiledes)) { 41728974Sbrian LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 41820813Sjkh Cleanup(EX_SOCK); 41920813Sjkh } 4206059Samurai } 42130715Sbrian /* Create server socket and listen (initial value is -2) */ 42229083Sbrian if (server == -2) 42329083Sbrian ServerTcpOpen(SERVER_PORT + tunno); 4246059Samurai 4256059Samurai if (!(mode & MODE_DIRECT)) { 42620813Sjkh pid_t bgpid; 42711336Samurai 42828679Sbrian bgpid = fork(); 42920813Sjkh if (bgpid == -1) { 43028974Sbrian LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 43128679Sbrian Cleanup(EX_SOCK); 43220813Sjkh } 43320813Sjkh if (bgpid) { 43420813Sjkh char c = EX_NORMAL; 43511336Samurai 43620813Sjkh if (mode & MODE_BACKGROUND) { 43720813Sjkh /* Wait for our child to close its pipe before we exit. */ 43820813Sjkh BGPid = bgpid; 43928679Sbrian close(BGFiledes[1]); 44025908Sbrian if (read(BGFiledes[0], &c, 1) != 1) { 44126516Sbrian fprintf(VarTerm, "Child exit, no status.\n"); 44228679Sbrian LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 44325908Sbrian } else if (c == EX_NORMAL) { 44426516Sbrian fprintf(VarTerm, "PPP enabled.\n"); 44528679Sbrian LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 44625908Sbrian } else { 44728679Sbrian fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 44826516Sbrian LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 44928679Sbrian ex_desc((int) c)); 45028679Sbrian } 45128679Sbrian close(BGFiledes[0]); 45220813Sjkh } 45328679Sbrian return c; 45423863Sbrian } else if (mode & MODE_BACKGROUND) 45528679Sbrian close(BGFiledes[0]); 45625707Sbrian } 45720813Sjkh 45828679Sbrian VarTerm = 0; /* We know it's currently stdout */ 45929551Sbrian close(1); 46026686Sbrian close(2); 46126551Sbrian 4626059Samurai#ifdef DOTTYINIT 46328679Sbrian if (mode & (MODE_DIRECT | MODE_DEDICATED)) 4646059Samurai#else 46526686Sbrian if (mode & MODE_DIRECT) 4666059Samurai#endif 46726858Sbrian TtyInit(1); 46826686Sbrian else { 46926686Sbrian setsid(); 47029551Sbrian close(0); 47126686Sbrian } 4726059Samurai } else { 47326858Sbrian TtyInit(0); 47410528Samurai TtyCommandMode(1); 4756059Samurai } 47629696Sbrian 47729696Sbrian snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid", 47829696Sbrian _PATH_VARRUN, tunno); 47929696Sbrian (void) unlink(pid_filename); 48029696Sbrian 48129696Sbrian if ((lockfile = fopen(pid_filename, "w")) != NULL) { 48229696Sbrian fprintf(lockfile, "%d\n", (int) getpid()); 48329696Sbrian fclose(lockfile); 48429696Sbrian } else 48529696Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 48629696Sbrian pid_filename, strerror(errno)); 48729696Sbrian 48826516Sbrian LogPrintf(LogPHASE, "PPP Started.\n"); 4896059Samurai 4906059Samurai 4916059Samurai do 49228679Sbrian DoLoop(); 4936059Samurai while (mode & MODE_DEDICATED); 4946059Samurai 4956059Samurai Cleanup(EX_DONE); 49626940Sbrian return 0; 4976059Samurai} 4986059Samurai 4996059Samurai/* 50020813Sjkh * Turn into packet mode, where we speak PPP. 5016059Samurai */ 5026059Samuraivoid 5036059SamuraiPacketMode() 5046059Samurai{ 5056059Samurai if (RawModem(modem) < 0) { 50626516Sbrian LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 5076059Samurai return; 5086059Samurai } 5096059Samurai AsyncInit(); 51030187Sbrian VjInit(15); 5116059Samurai LcpInit(); 5126059Samurai IpcpInit(); 5136059Samurai CcpInit(); 5146059Samurai LcpUp(); 5156059Samurai 51625872Sbrian LcpOpen(VarOpenMode); 51728679Sbrian if ((mode & (MODE_INTER | MODE_AUTO)) == MODE_INTER) { 51810528Samurai TtyCommandMode(1); 51926516Sbrian if (VarTerm) { 52026516Sbrian fprintf(VarTerm, "Packet mode.\n"); 52126516Sbrian aft_cmd = 1; 52226516Sbrian } 5236059Samurai } 5246059Samurai} 5256059Samurai 5266059Samuraistatic void 5276059SamuraiShowHelp() 5286059Samurai{ 52926901Sbrian fprintf(stderr, "The following commands are available:\r\n"); 53026901Sbrian fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 53126901Sbrian fprintf(stderr, " ~-\tDecrease log level\r\n"); 53226901Sbrian fprintf(stderr, " ~+\tIncrease log level\r\n"); 53326901Sbrian fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 53426901Sbrian fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 53526901Sbrian fprintf(stderr, " ~.\tTerminate program\r\n"); 53626901Sbrian fprintf(stderr, " ~?\tThis help\r\n"); 5376059Samurai} 5386059Samurai 5396059Samuraistatic void 5406059SamuraiReadTty() 5416059Samurai{ 5426059Samurai int n; 5436059Samurai char ch; 5446059Samurai static int ttystate; 54526516Sbrian FILE *oVarTerm; 54628679Sbrian 5476059Samurai#define MAXLINESIZE 200 5486059Samurai char linebuff[MAXLINESIZE]; 5496059Samurai 55026516Sbrian LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 55128679Sbrian TermMode, netfd, mode); 5526059Samurai if (!TermMode) { 55328679Sbrian n = read(netfd, linebuff, sizeof(linebuff) - 1); 5546735Samurai if (n > 0) { 55526516Sbrian aft_cmd = 1; 55630497Sbrian linebuff[n] = '\0'; 55730497Sbrian LogPrintf(LogCOMMAND, "Client: %s\n", linebuff); 5586059Samurai DecodeCommand(linebuff, n, 1); 5596735Samurai } else { 56026516Sbrian LogPrintf(LogPHASE, "client connection closed.\n"); 56124753Sache VarLocalAuth = LOCAL_NO_AUTH; 56226516Sbrian mode &= ~MODE_INTER; 56326516Sbrian oVarTerm = VarTerm; 56426516Sbrian VarTerm = 0; 56526516Sbrian if (oVarTerm && oVarTerm != stdout) 56628679Sbrian fclose(oVarTerm); 5676059Samurai close(netfd); 5686059Samurai netfd = -1; 5696059Samurai } 5706059Samurai return; 5716059Samurai } 5726059Samurai 5736059Samurai /* 57428679Sbrian * We are in terminal mode, decode special sequences 5756059Samurai */ 57626516Sbrian n = read(fileno(VarTerm), &ch, 1); 57728974Sbrian LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 5786059Samurai 5796059Samurai if (n > 0) { 5806059Samurai switch (ttystate) { 5816059Samurai case 0: 5826059Samurai if (ch == '~') 5836059Samurai ttystate++; 5846059Samurai else 5856059Samurai write(modem, &ch, n); 5866059Samurai break; 5876059Samurai case 1: 5886059Samurai switch (ch) { 5896059Samurai case '?': 5906059Samurai ShowHelp(); 5916059Samurai break; 5926059Samurai case 'p': 59328679Sbrian 5946059Samurai /* 5956059Samurai * XXX: Should check carrier. 5966059Samurai */ 5976059Samurai if (LcpFsm.state <= ST_CLOSED) { 5986059Samurai VarOpenMode = OPEN_ACTIVE; 5996059Samurai PacketMode(); 6006059Samurai } 6016059Samurai break; 6026059Samurai case '.': 6036059Samurai TermMode = 1; 60426516Sbrian aft_cmd = 1; 60510528Samurai TtyCommandMode(1); 6066059Samurai break; 60726516Sbrian case 't': 60826516Sbrian if (LogIsKept(LogDEBUG)) { 60926516Sbrian ShowTimers(); 61026516Sbrian break; 61126516Sbrian } 61226516Sbrian case 'm': 61326516Sbrian if (LogIsKept(LogDEBUG)) { 61426516Sbrian ShowMemMap(); 61526516Sbrian break; 61626516Sbrian } 6176059Samurai default: 6186059Samurai if (write(modem, &ch, n) < 0) 61926516Sbrian LogPrintf(LogERROR, "error writing to modem.\n"); 6206059Samurai break; 6216059Samurai } 6226059Samurai ttystate = 0; 6236059Samurai break; 6246059Samurai } 6256059Samurai } 6266059Samurai} 6276059Samurai 6286059Samurai 6296059Samurai/* 6306059Samurai * Here, we'll try to detect HDLC frame 6316059Samurai */ 6326059Samurai 6336059Samuraistatic char *FrameHeaders[] = { 6346735Samurai "\176\377\003\300\041", 6356735Samurai "\176\377\175\043\300\041", 6366735Samurai "\176\177\175\043\100\041", 6376735Samurai "\176\175\337\175\043\300\041", 6386735Samurai "\176\175\137\175\043\100\041", 6396059Samurai NULL, 6406059Samurai}; 6416059Samurai 64230715Sbrianstatic u_char * 64328679SbrianHdlcDetect(u_char * cp, int n) 6446059Samurai{ 6456735Samurai char *ptr, *fp, **hp; 6466059Samurai 64728679Sbrian cp[n] = '\0'; /* be sure to null terminated */ 6486059Samurai ptr = NULL; 6496059Samurai for (hp = FrameHeaders; *hp; hp++) { 6506735Samurai fp = *hp; 6516735Samurai if (DEV_IS_SYNC) 6526735Samurai fp++; 65328679Sbrian ptr = strstr((char *) cp, fp); 65413389Sphk if (ptr) 6556059Samurai break; 6566059Samurai } 65728679Sbrian return ((u_char *) ptr); 6586059Samurai} 6596059Samurai 6606059Samuraistatic struct pppTimer RedialTimer; 6616059Samurai 6626059Samuraistatic void 6636059SamuraiRedialTimeout() 6646059Samurai{ 6656059Samurai StopTimer(&RedialTimer); 66626516Sbrian LogPrintf(LogPHASE, "Redialing timer expired.\n"); 6676059Samurai} 6686059Samurai 6696059Samuraistatic void 67028679SbrianStartRedialTimer(int Timeout) 6716059Samurai{ 6726059Samurai StopTimer(&RedialTimer); 67311336Samurai 67424939Sbrian if (Timeout) { 67511336Samurai RedialTimer.state = TIMER_STOPPED; 67611336Samurai 67724939Sbrian if (Timeout > 0) 67828679Sbrian RedialTimer.load = Timeout * SECTICKS; 67911336Samurai else 68028679Sbrian RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 68111336Samurai 68226516Sbrian LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 68324939Sbrian RedialTimer.load / SECTICKS); 68424939Sbrian 68511336Samurai RedialTimer.func = RedialTimeout; 68611336Samurai StartTimer(&RedialTimer); 68711336Samurai } 6886059Samurai} 6896059Samurai 6906059Samurai 6916059Samuraistatic void 6926059SamuraiDoLoop() 6936059Samurai{ 6946059Samurai fd_set rfds, wfds, efds; 69523598Sache int pri, i, n, wfd, nfds; 6966059Samurai struct sockaddr_in hisaddr; 6976059Samurai struct timeval timeout, *tp; 6986059Samurai int ssize = sizeof(hisaddr); 6996059Samurai u_char *cp; 7006059Samurai u_char rbuff[MAX_MRU]; 70111336Samurai int tries; 7029448Samurai int qlen; 70326858Sbrian int res; 70410528Samurai pid_t pgroup; 7056059Samurai 70610528Samurai pgroup = getpgrp(); 70710528Samurai 70825908Sbrian if (mode & MODE_DIRECT) { 70926551Sbrian LogPrintf(LogDEBUG, "Opening modem\n"); 71029521Sbrian if (OpenModem(mode) < 0) 71129521Sbrian return; 71226516Sbrian LogPrintf(LogPHASE, "Packet mode enabled\n"); 7136059Samurai PacketMode(); 7146059Samurai } else if (mode & MODE_DEDICATED) { 71523598Sache if (modem < 0) 71629521Sbrian while (OpenModem(mode) < 0) 71730697Sbrian nointr_sleep(VarReconnectTimer); 7186059Samurai } 71926516Sbrian fflush(VarTerm); 7206059Samurai 7217001Samurai timeout.tv_sec = 0; 7226059Samurai timeout.tv_usec = 0; 72326098Sbrian reconnectState = RECON_UNKNOWN; 7246059Samurai 72523863Sbrian if (mode & MODE_BACKGROUND) 72630715Sbrian dial_up = 1; /* Bring the line up */ 72723863Sbrian else 72830715Sbrian dial_up = 0; /* XXXX */ 72911336Samurai tries = 0; 7306059Samurai for (;;) { 73123598Sache nfds = 0; 73228679Sbrian FD_ZERO(&rfds); 73328679Sbrian FD_ZERO(&wfds); 73428679Sbrian FD_ZERO(&efds); 7357001Samurai 73628679Sbrian /* 73728679Sbrian * If the link is down and we're in DDIAL mode, bring it back up. 73820120Snate */ 73920120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 74030715Sbrian dial_up = 1; 74120120Snate 74225067Sbrian /* 74328679Sbrian * If we lost carrier and want to re-establish the connection due to the 74428679Sbrian * "set reconnect" value, we'd better bring the line back up. 74525067Sbrian */ 74625908Sbrian if (LcpFsm.state <= ST_CLOSED) { 74730715Sbrian if (!dial_up && reconnectState == RECON_TRUE) { 74828679Sbrian if (++reconnectCount <= VarReconnectTries) { 74928679Sbrian LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 75028679Sbrian reconnectCount, VarReconnectTries); 75125908Sbrian StartRedialTimer(VarReconnectTimer); 75230715Sbrian dial_up = 1; 75328679Sbrian } else { 75428679Sbrian if (VarReconnectTries) 75528679Sbrian LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 75628679Sbrian VarReconnectTries); 75728679Sbrian reconnectCount = 0; 75828679Sbrian if (mode & MODE_BACKGROUND) 75928679Sbrian Cleanup(EX_DEAD); 76028679Sbrian } 76128679Sbrian reconnectState = RECON_ENVOKED; 76225801Sbrian } 76325908Sbrian } 76425067Sbrian 76528679Sbrian /* 76628679Sbrian * If Ip packet for output is enqueued and require dial up, Just do it! 76728679Sbrian */ 76828679Sbrian if (dial_up && RedialTimer.state != TIMER_RUNNING) { 76926516Sbrian LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 77029521Sbrian if (OpenModem(mode) < 0) { 77128679Sbrian tries++; 77228679Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 77328679Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 77428679Sbrian tries, VarDialTries); 77528679Sbrian else 77628679Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 77726551Sbrian 77826696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 77926551Sbrian if (mode & MODE_BACKGROUND) 78028679Sbrian Cleanup(EX_DIAL); /* Can't get the modem */ 78130715Sbrian dial_up = 0; 78228679Sbrian reconnectState = RECON_UNKNOWN; 78328679Sbrian reconnectCount = 0; 78426551Sbrian tries = 0; 78528679Sbrian } else 78626551Sbrian StartRedialTimer(VarRedialTimeout); 78711336Samurai } else { 78828679Sbrian tries++; /* Tries are per number, not per list of 78928679Sbrian * numbers. */ 79028679Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 79126696Sbrian LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 79228679Sbrian else 79328679Sbrian LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 79426696Sbrian 79526858Sbrian if ((res = DialModem()) == EX_DONE) { 79630697Sbrian nointr_sleep(1); /* little pause to allow peer starts */ 79711336Samurai ModemTimeout(); 79811336Samurai PacketMode(); 79930715Sbrian dial_up = 0; 80028679Sbrian reconnectState = RECON_UNKNOWN; 80111336Samurai tries = 0; 80211336Samurai } else { 80311336Samurai CloseModem(); 80424844Sbrian if (mode & MODE_BACKGROUND) { 80526858Sbrian if (VarNextPhone == NULL || res == EX_SIG) 80628679Sbrian Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 80724844Sbrian else 80824939Sbrian /* Try all numbers in background mode */ 80924939Sbrian StartRedialTimer(VarRedialNextTimeout); 81026858Sbrian } else if (!(mode & MODE_DDIAL) && 81128679Sbrian ((VarDialTries && tries >= VarDialTries) || 81228679Sbrian res == EX_SIG)) { 81324843Sbrian /* I give up ! Can't get through :( */ 81424939Sbrian StartRedialTimer(VarRedialTimeout); 81530715Sbrian dial_up = 0; 81628679Sbrian reconnectState = RECON_UNKNOWN; 81728679Sbrian reconnectCount = 0; 81824843Sbrian tries = 0; 81924843Sbrian } else if (VarNextPhone == NULL) 82024843Sbrian /* Dial failed. Keep quite during redial wait period. */ 82124939Sbrian StartRedialTimer(VarRedialTimeout); 82224843Sbrian else 82324939Sbrian StartRedialTimer(VarRedialNextTimeout); 82411336Samurai } 82511336Samurai } 8267001Samurai } 8279448Samurai qlen = ModemQlen(); 82813733Sdfr 82913733Sdfr if (qlen == 0) { 83013733Sdfr IpStartOutput(); 83113733Sdfr qlen = ModemQlen(); 83213733Sdfr } 83323598Sache if (modem >= 0) { 83423598Sache if (modem + 1 > nfds) 83523598Sache nfds = modem + 1; 8367001Samurai FD_SET(modem, &rfds); 8377001Samurai FD_SET(modem, &efds); 8389448Samurai if (qlen > 0) { 8397001Samurai FD_SET(modem, &wfds); 8407001Samurai } 8417001Samurai } 84223598Sache if (server >= 0) { 84323598Sache if (server + 1 > nfds) 84423598Sache nfds = server + 1; 84523598Sache FD_SET(server, &rfds); 84623598Sache } 8476059Samurai 84828679Sbrian /* 84928679Sbrian * *** IMPORTANT *** 85028679Sbrian * 85128679Sbrian * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 85228679Sbrian * with great care. If this values is too big, it results loss of 85328679Sbrian * characters from modem and poor responce. If this values is too small, 85428679Sbrian * ppp process eats many CPU time. 8556059Samurai */ 8566735Samurai#ifndef SIGALRM 85730697Sbrian nointr_usleep(TICKUNIT); 8586059Samurai TimerService(); 85923840Sbrian#else 86023840Sbrian handle_signals(); 8616735Samurai#endif 86210877Sbde 86310877Sbde /* If there are aren't many packets queued, look for some more. */ 86423598Sache if (qlen < 20 && tun_in >= 0) { 86523598Sache if (tun_in + 1 > nfds) 86623598Sache nfds = tun_in + 1; 86710877Sbde FD_SET(tun_in, &rfds); 86823598Sache } 86923598Sache if (netfd >= 0) { 87023598Sache if (netfd + 1 > nfds) 87123598Sache nfds = netfd + 1; 8726059Samurai FD_SET(netfd, &rfds); 8736059Samurai FD_SET(netfd, &efds); 8746059Samurai } 87528679Sbrian#ifndef SIGALRM 8767001Samurai 8776059Samurai /* 87828679Sbrian * Normally, select() will not block because modem is writable. In AUTO 87928679Sbrian * mode, select will block until we find packet from tun 8806059Samurai */ 88128679Sbrian tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 88223598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 8836735Samurai#else 88428679Sbrian 8858857Srgrimes /* 88628679Sbrian * When SIGALRM timer is running, a select function will be return -1 and 88728679Sbrian * EINTR after a Time Service signal hundler is done. If the redial 88828679Sbrian * timer is not running and we are trying to dial, poll with a 0 value 88928679Sbrian * timer. 8907001Samurai */ 89111336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 89223598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 8936735Samurai#endif 89422074Sbrian 89528679Sbrian if (i == 0) { 89628679Sbrian continue; 8976059Samurai } 89828679Sbrian if (i < 0) { 89928679Sbrian if (errno == EINTR) { 90028679Sbrian handle_signals(); 90128679Sbrian continue; 90228679Sbrian } 90328974Sbrian LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 90428679Sbrian break; 9058857Srgrimes } 90623598Sache if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 90726516Sbrian LogPrintf(LogALERT, "Exception detected.\n"); 9086059Samurai break; 9096059Samurai } 91023598Sache if (server >= 0 && FD_ISSET(server, &rfds)) { 91126516Sbrian LogPrintf(LogPHASE, "connected to client.\n"); 91228679Sbrian wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 91324753Sache if (wfd < 0) { 91428974Sbrian LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 91524753Sache continue; 91624753Sache } 91723598Sache if (netfd >= 0) { 9186059Samurai write(wfd, "already in use.\n", 16); 9196059Samurai close(wfd); 9206059Samurai continue; 9216059Samurai } else 9226059Samurai netfd = wfd; 92326516Sbrian VarTerm = fdopen(netfd, "a+"); 9246059Samurai mode |= MODE_INTER; 9256059Samurai Greetings(); 9266059Samurai (void) IsInteractive(); 92725630Sbrian Prompt(); 9286059Samurai } 92923598Sache if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 93010858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 9316059Samurai /* something to read from tty */ 9326059Samurai ReadTty(); 9336059Samurai } 93423598Sache if (modem >= 0) { 9356059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 93628679Sbrian ModemStartOutput(modem); 9376059Samurai } 9386059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 9396735Samurai if (LcpFsm.state <= ST_CLOSED) 94030697Sbrian nointr_usleep(10000); 9416059Samurai n = read(modem, rbuff, sizeof(rbuff)); 9426059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 9436059Samurai DownConnection(); 9446059Samurai } else 94528679Sbrian LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 9466059Samurai 9476059Samurai if (LcpFsm.state <= ST_CLOSED) { 94828679Sbrian 9496059Samurai /* 95028679Sbrian * In dedicated mode, we just discard input until LCP is started. 9516059Samurai */ 9526059Samurai if (!(mode & MODE_DEDICATED)) { 9536059Samurai cp = HdlcDetect(rbuff, n); 9546059Samurai if (cp) { 95528679Sbrian 9566059Samurai /* 9576059Samurai * LCP packet is detected. Turn ourselves into packet mode. 9586059Samurai */ 9596059Samurai if (cp != rbuff) { 96028679Sbrian write(modem, rbuff, cp - rbuff); 96128679Sbrian write(modem, "\r\n", 2); 9626059Samurai } 9636059Samurai PacketMode(); 9646059Samurai } else 96526516Sbrian write(fileno(VarTerm), rbuff, n); 9666059Samurai } 9676059Samurai } else { 9686059Samurai if (n > 0) 9696059Samurai AsyncInput(rbuff, n); 9706059Samurai } 9716059Samurai } 9726059Samurai } 97328679Sbrian if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 97428679Sbrian * from tun */ 9756059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 9766059Samurai if (n < 0) { 97728974Sbrian LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 9786059Samurai continue; 9796059Samurai } 98028679Sbrian if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 98128536Sbrian /* we've been asked to send something addressed *to* us :( */ 98228536Sbrian if (VarLoopback) { 98328536Sbrian pri = PacketCheck(rbuff, n, FL_IN); 98428536Sbrian if (pri >= 0) { 98528536Sbrian struct mbuf *bp; 98628679Sbrian 98728536Sbrian if (mode & MODE_ALIAS) { 98828536Sbrian VarPacketAliasIn(rbuff, sizeof rbuff); 98928679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 99028536Sbrian } 99128536Sbrian bp = mballoc(n, MB_IPIN); 99230715Sbrian memcpy(MBUF_CTOP(bp), rbuff, n); 99328536Sbrian IpInput(bp); 99428536Sbrian LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 99528536Sbrian } 99628536Sbrian continue; 99728679Sbrian } else 99828536Sbrian LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 99928536Sbrian } 100028536Sbrian 10016059Samurai /* 100228679Sbrian * Process on-demand dialup. Output packets are queued within tunnel 100328679Sbrian * device until IPCP is opened. 10046059Samurai */ 10056059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 10067001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 10076059Samurai if (pri >= 0) { 100820365Sjkh if (mode & MODE_ALIAS) { 100926142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 101028679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 101120365Sjkh } 10126059Samurai IpEnqueue(pri, rbuff, n); 101330715Sbrian dial_up = 1; /* XXX */ 10146059Samurai } 10156059Samurai continue; 10166059Samurai } 10177001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 101820365Sjkh if (pri >= 0) { 101928679Sbrian if (mode & MODE_ALIAS) { 102028679Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 102128679Sbrian n = ntohs(((struct ip *) rbuff)->ip_len); 102228679Sbrian } 10236059Samurai IpEnqueue(pri, rbuff, n); 102420365Sjkh } 10256059Samurai } 10266059Samurai } 102726516Sbrian LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 10286059Samurai} 1029