main.c revision 26858
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 * 2026858Sbrian * $Id: main.c,v 1.64 1997/06/17 01:46:05 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" 536059Samurai 546764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 5526516Sbrian#define LAUTH_M2 "Warning: Manipulation is allowed by anyone\n" 566764Samurai 576735Samurai#ifndef O_NONBLOCK 586735Samurai#ifdef O_NDELAY 596735Samurai#define O_NONBLOCK O_NDELAY 606735Samurai#endif 616735Samurai#endif 626735Samurai 636059Samuraiextern void VjInit(), AsyncInit(); 6425630Sbrianextern void AsyncInput(); 656059Samuraiextern 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 746059Samuraistatic struct termios oldtio; /* Original tty mode */ 756059Samuraistatic struct termios comtio; /* Command level tty mode */ 7614418Sacheint TermMode; 7713379Sphkstatic int server; 7820813Sjkhstatic pid_t BGPid = 0; 796059Samuraistruct sockaddr_in ifsin; 8025634Sbrianstatic char pid_filename[MAXPATHLEN]; 8125634Sbrianstatic char if_filename[MAXPATHLEN]; 8225445Sacheint tunno; 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(); 18823598Sache if (server >= 0) { 1896059Samurai close(server); 19023598Sache server = -1; 19123598Sache } 19225707Sbrian 19310528Samurai TtyOldMode(); 1946059Samurai 1956059Samurai exit(excode); 1966059Samurai} 1976059Samurai 1986059Samuraistatic void 19914930SacheHangup(signo) 20014930Sacheint signo; 2016059Samurai{ 20226858Sbrian /* NOTE, these are manual, we've done a setsid() */ 20326858Sbrian reconnect(RECON_FALSE); 20426858Sbrian DownConnection(); 2056059Samurai} 2066059Samurai 2076059Samuraistatic void 20814930SacheCloseSession(signo) 20914930Sacheint signo; 2106059Samurai{ 21120813Sjkh if (BGPid) { 21220813Sjkh kill (BGPid, SIGINT); 21320813Sjkh exit (EX_TERM); 21420813Sjkh } 21526516Sbrian LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 21626516Sbrian reconnect(RECON_FALSE); 21726516Sbrian LcpClose(); 21826516Sbrian Cleanup(EX_TERM); 2196059Samurai} 2206059Samurai 22110528Samuraistatic void 22210528SamuraiTerminalCont() 22310528Samurai{ 22423840Sbrian pending_signal(SIGCONT, SIG_DFL); 22523840Sbrian pending_signal(SIGTSTP, TerminalStop); 22610528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 22710528Samurai} 22810528Samurai 22910528Samuraistatic void 23010528SamuraiTerminalStop(signo) 23110528Samuraiint signo; 23210528Samurai{ 23323840Sbrian pending_signal(SIGCONT, TerminalCont); 23410528Samurai TtyOldMode(); 23523840Sbrian pending_signal(SIGTSTP, SIG_DFL); 23610528Samurai kill(getpid(), signo); 23710528Samurai} 23810528Samurai 23925908Sbrianstatic char * 24025908Sbrianex_desc(int ex) 24125908Sbrian{ 24225908Sbrian static char num[12]; 24325908Sbrian static char *desc[] = { "normal", "start", "sock", 24425908Sbrian "modem", "dial", "dead", "done", "reboot", "errdead", 24525908Sbrian "hangup", "term", "nodial", "nologin" }; 24610528Samurai 24725908Sbrian if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 24825908Sbrian return desc[ex]; 24925908Sbrian snprintf(num, sizeof num, "%d", ex); 25025908Sbrian return num; 25125908Sbrian} 25225908Sbrian 2536059Samuraivoid 2546059SamuraiUsage() 2556059Samurai{ 25620120Snate fprintf(stderr, 25720813Sjkh "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2586059Samurai exit(EX_START); 2596059Samurai} 2606059Samurai 2616059Samuraivoid 2626059SamuraiProcessArgs(int argc, char **argv) 2636059Samurai{ 2646059Samurai int optc; 2656059Samurai char *cp; 2666059Samurai 2676059Samurai optc = 0; 2686059Samurai while (argc > 0 && **argv == '-') { 2696059Samurai cp = *argv + 1; 2706059Samurai if (strcmp(cp, "auto") == 0) 2716059Samurai mode |= MODE_AUTO; 27220813Sjkh else if (strcmp(cp, "background") == 0) 27325908Sbrian mode |= MODE_BACKGROUND|MODE_AUTO; 2746059Samurai else if (strcmp(cp, "direct") == 0) 2756059Samurai mode |= MODE_DIRECT; 2766059Samurai else if (strcmp(cp, "dedicated") == 0) 2776059Samurai mode |= MODE_DEDICATED; 27820120Snate else if (strcmp(cp, "ddial") == 0) 27920120Snate mode |= MODE_DDIAL|MODE_AUTO; 28020365Sjkh else if (strcmp(cp, "alias") == 0) { 28126142Sbrian if (loadAliasHandlers(&VarAliasHandlers) == 0) 28226142Sbrian mode |= MODE_ALIAS; 28326142Sbrian else 28426516Sbrian LogPrintf(LogWARN, "Cannot load alias library\n"); 28520365Sjkh optc--; /* this option isn't exclusive */ 28620365Sjkh } 2876059Samurai else 2886059Samurai Usage(); 2896059Samurai optc++; 2906059Samurai argv++; argc--; 2916059Samurai } 2926059Samurai if (argc > 1) { 2936059Samurai fprintf(stderr, "specify only one system label.\n"); 2946059Samurai exit(EX_START); 2956059Samurai } 2966059Samurai if (argc == 1) dstsystem = *argv; 2976059Samurai 2986059Samurai if (optc > 1) { 2996059Samurai fprintf(stderr, "specify only one mode.\n"); 3006059Samurai exit(EX_START); 3016059Samurai } 3026059Samurai} 3036059Samurai 3046059Samuraistatic void 3056059SamuraiGreetings() 3066059Samurai{ 30726516Sbrian if (VarTerm) { 30826516Sbrian fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 30926516Sbrian fflush(VarTerm); 31026516Sbrian } 3116059Samurai} 3126059Samurai 3136059Samuraivoid 3146059Samuraimain(argc, argv) 3156059Samuraiint argc; 3166059Samuraichar **argv; 3176059Samurai{ 31825707Sbrian FILE *lockfile; 31926516Sbrian char *name; 32026516Sbrian 32126551Sbrian VarTerm = 0; 32226516Sbrian name = rindex(argv[0], '/'); 32326516Sbrian LogOpen(name ? name+1 : argv[0]); 32426516Sbrian 3256059Samurai argc--; argv++; 3266059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 32723598Sache netfd = server = modem = tun_in = -1; 3286059Samurai ProcessArgs(argc, argv); 32926328Sbrian if (!(mode & MODE_DIRECT)) 33026551Sbrian VarTerm = stdout; 33126551Sbrian Greetings(); 3326059Samurai GetUid(); 3336059Samurai IpcpDefAddress(); 3346059Samurai 33526516Sbrian if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 33626516Sbrian fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 3376059Samurai 3386735Samurai switch ( LocalAuthInit() ) { 3396735Samurai case NOT_FOUND: 34026516Sbrian if (VarTerm) { 34126516Sbrian fprintf(VarTerm,LAUTH_M1); 34226516Sbrian fprintf(VarTerm,LAUTH_M2); 34326551Sbrian fflush(VarTerm); 34426328Sbrian } 3456764Samurai /* Fall down */ 3466764Samurai case VALID: 3476735Samurai VarLocalAuth = LOCAL_AUTH; 3486735Samurai break; 3496735Samurai default: 3506735Samurai break; 3516735Samurai } 3526735Samurai 3536059Samurai if (OpenTunnel(&tunno) < 0) { 35426516Sbrian LogPrintf(LogWARN, "open_tun: %s", strerror(errno)); 3556059Samurai exit(EX_START); 3566059Samurai } 3576059Samurai 35825908Sbrian if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 3596059Samurai mode &= ~MODE_INTER; 3606059Samurai if (mode & MODE_INTER) { 36126516Sbrian fprintf(VarTerm, "Interactive mode\n"); 36226690Sbrian netfd = STDOUT_FILENO; 3636059Samurai } else if (mode & MODE_AUTO) { 36426516Sbrian fprintf(VarTerm, "Automatic Dialer mode\n"); 3656059Samurai if (dstsystem == NULL) { 36626516Sbrian if (VarTerm) 36726516Sbrian fprintf(VarTerm, "Destination system must be specified in" 36825908Sbrian " auto, background or ddial mode.\n"); 3696059Samurai exit(EX_START); 3706059Samurai } 3716059Samurai } 3726059Samurai 3736735Samurai tcgetattr(0, &oldtio); /* Save original tty mode */ 3746059Samurai 37526516Sbrian pending_signal(SIGHUP, Hangup); 37623840Sbrian pending_signal(SIGTERM, CloseSession); 37723840Sbrian pending_signal(SIGINT, CloseSession); 37823840Sbrian pending_signal(SIGQUIT, CloseSession); 3796735Samurai#ifdef SIGPIPE 38024753Sache signal(SIGPIPE, SIG_IGN); 3816735Samurai#endif 3826735Samurai#ifdef SIGALRM 38323840Sbrian pending_signal(SIGALRM, SIG_IGN); 3846735Samurai#endif 38510528Samurai if(mode & MODE_INTER) 38610528Samurai { 38710528Samurai#ifdef SIGTSTP 38823840Sbrian pending_signal(SIGTSTP, TerminalStop); 38910528Samurai#endif 39010528Samurai#ifdef SIGTTIN 39123840Sbrian pending_signal(SIGTTIN, TerminalStop); 39210528Samurai#endif 39310528Samurai#ifdef SIGTTOU 39423840Sbrian pending_signal(SIGTTOU, SIG_IGN); 39510528Samurai#endif 39610528Samurai } 3976059Samurai 3986059Samurai if (dstsystem) { 3996059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 40026551Sbrian LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 4016059Samurai Cleanup(EX_START); 4026059Samurai } 4036059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 40426551Sbrian LogPrintf(LogWARN, "Must specify dstaddr with" 40525908Sbrian " auto, background or ddial mode.\n"); 4066059Samurai Cleanup(EX_START); 4076059Samurai } 4086059Samurai } 4096059Samurai 4106059Samurai if (!(mode & MODE_INTER)) { 41120813Sjkh int port = SERVER_PORT + tunno; 41225908Sbrian 41320813Sjkh if (mode & MODE_BACKGROUND) { 41420813Sjkh if (pipe (BGFiledes)) { 41526516Sbrian LogPrintf(LogERROR, "pipe: %s", strerror(errno)); 41620813Sjkh Cleanup(EX_SOCK); 41720813Sjkh } 4186059Samurai } 41925908Sbrian 42025908Sbrian /* Create server socket and listen at there. */ 42125908Sbrian server = socket(PF_INET, SOCK_STREAM, 0); 42225908Sbrian if (server < 0) { 42326516Sbrian LogPrintf(LogERROR, "socket: %s", strerror(errno)); 42425908Sbrian Cleanup(EX_SOCK); 4256059Samurai } 42625908Sbrian ifsin.sin_family = AF_INET; 42725908Sbrian ifsin.sin_addr.s_addr = INADDR_ANY; 42825908Sbrian ifsin.sin_port = htons(port); 42926032Sbrian setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server); 43025908Sbrian if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 43126516Sbrian LogPrintf(LogERROR, "bind: %s", strerror(errno)); 43226516Sbrian if (errno == EADDRINUSE && VarTerm) 43326516Sbrian fprintf(VarTerm, "Wait for a while, then try again.\n"); 43425908Sbrian Cleanup(EX_SOCK); 43525908Sbrian } 43625908Sbrian if (listen(server, 5) != 0) { 43726516Sbrian LogPrintf(LogERROR, "Unable to listen to socket - OS overload?\n"); 43826516Sbrian Cleanup(EX_SOCK); 43925908Sbrian } 4406059Samurai 4416059Samurai if (!(mode & MODE_DIRECT)) { 44220813Sjkh pid_t bgpid; 44311336Samurai 44420813Sjkh bgpid = fork (); 44520813Sjkh if (bgpid == -1) { 44626516Sbrian LogPrintf(LogERROR, "fork: %s", strerror(errno)); 44720813Sjkh Cleanup (EX_SOCK); 44820813Sjkh } 44920813Sjkh if (bgpid) { 45020813Sjkh char c = EX_NORMAL; 45111336Samurai 45220813Sjkh if (mode & MODE_BACKGROUND) { 45320813Sjkh /* Wait for our child to close its pipe before we exit. */ 45420813Sjkh BGPid = bgpid; 45526516Sbrian close(BGFiledes[1]); 45625908Sbrian if (read(BGFiledes[0], &c, 1) != 1) { 45726516Sbrian fprintf(VarTerm, "Child exit, no status.\n"); 45826516Sbrian LogPrintf (LogPHASE, "Parent: Child exit, no status.\n"); 45925908Sbrian } else if (c == EX_NORMAL) { 46026516Sbrian fprintf(VarTerm, "PPP enabled.\n"); 46126516Sbrian LogPrintf (LogPHASE, "Parent: PPP enabled.\n"); 46225908Sbrian } else { 46326516Sbrian fprintf(VarTerm, "Child failed (%s).\n",ex_desc((int)c)); 46426516Sbrian LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 46525910Sbrian ex_desc((int)c)); 46625908Sbrian } 46726516Sbrian close(BGFiledes[0]); 46820813Sjkh } 46920813Sjkh exit(c); 47023863Sbrian } else if (mode & MODE_BACKGROUND) 47123863Sbrian close(BGFiledes[0]); 47225707Sbrian } 47320813Sjkh 47425801Sbrian snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 47525707Sbrian _PATH_VARRUN, tunno); 47625707Sbrian (void)unlink(pid_filename); 47711336Samurai 47825707Sbrian if ((lockfile = fopen(pid_filename, "w")) != NULL) { 47925707Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 48025707Sbrian fclose(lockfile); 48125707Sbrian } else 48226516Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 48326516Sbrian pid_filename, strerror(errno)); 48425634Sbrian 48525707Sbrian snprintf(if_filename, sizeof if_filename, "%s%s.if", 48625707Sbrian _PATH_VARRUN, VarBaseDevice); 48725707Sbrian (void)unlink(if_filename); 48825634Sbrian 48925707Sbrian if ((lockfile = fopen(if_filename, "w")) != NULL) { 49025707Sbrian fprintf(lockfile, "tun%d\n", tunno); 49125707Sbrian fclose(lockfile); 49225707Sbrian } else 49326516Sbrian LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 49426516Sbrian if_filename, strerror(errno)); 49525707Sbrian 49623598Sache if (server >= 0) 49726516Sbrian LogPrintf(LogPHASE, "Listening at %d.\n", port); 49826551Sbrian 49926686Sbrian VarTerm = 0; /* We know it's currently stdout */ 50026686Sbrian close(0); 50126686Sbrian close(2); 50226551Sbrian 5036059Samurai#ifdef DOTTYINIT 50426686Sbrian if (mode & (MODE_DIRECT|MODE_DEDICATED)) 5056059Samurai#else 50626686Sbrian if (mode & MODE_DIRECT) 5076059Samurai#endif 50826858Sbrian TtyInit(1); 50926686Sbrian else { 51026686Sbrian setsid(); 51126686Sbrian close(1); 51226686Sbrian } 5136059Samurai } else { 51426858Sbrian TtyInit(0); 51510528Samurai TtyCommandMode(1); 5166059Samurai } 51726516Sbrian LogPrintf(LogPHASE, "PPP Started.\n"); 5186059Samurai 5196059Samurai 5206059Samurai do 5216059Samurai DoLoop(); 5226059Samurai while (mode & MODE_DEDICATED); 5236059Samurai 5246059Samurai Cleanup(EX_DONE); 5256059Samurai} 5266059Samurai 5276059Samurai/* 52820813Sjkh * Turn into packet mode, where we speak PPP. 5296059Samurai */ 5306059Samuraivoid 5316059SamuraiPacketMode() 5326059Samurai{ 5336059Samurai if (RawModem(modem) < 0) { 53426516Sbrian LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 5356059Samurai return; 5366059Samurai } 5376059Samurai 5386059Samurai AsyncInit(); 5396059Samurai VjInit(); 5406059Samurai LcpInit(); 5416059Samurai IpcpInit(); 5426059Samurai CcpInit(); 5436059Samurai LcpUp(); 5446059Samurai 54525872Sbrian LcpOpen(VarOpenMode); 5466059Samurai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 54710528Samurai TtyCommandMode(1); 54826516Sbrian if (VarTerm) { 54926516Sbrian fprintf(VarTerm, "Packet mode.\n"); 55026516Sbrian aft_cmd = 1; 55126516Sbrian } 5526059Samurai } 5536059Samurai} 5546059Samurai 5556059Samuraistatic void 5566059SamuraiShowHelp() 5576059Samurai{ 55826516Sbrian fprintf(stderr, "The following commands are available:\n"); 55926516Sbrian fprintf(stderr, " ~p\tEnter Packet mode\n"); 56026516Sbrian fprintf(stderr, " ~-\tDecrease log level\n"); 56126516Sbrian fprintf(stderr, " ~+\tIncrease log level\n"); 56226516Sbrian fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\n"); 56326516Sbrian fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\n"); 56426516Sbrian fprintf(stderr, " ~.\tTerminate program\n"); 56526516Sbrian fprintf(stderr, " ~?\tThis help\n"); 5666059Samurai} 5676059Samurai 5686059Samuraistatic void 5696059SamuraiReadTty() 5706059Samurai{ 5716059Samurai int n; 5726059Samurai char ch; 5736059Samurai static int ttystate; 57426516Sbrian FILE *oVarTerm; 5756059Samurai#define MAXLINESIZE 200 5766059Samurai char linebuff[MAXLINESIZE]; 5776059Samurai 57826516Sbrian LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 57926516Sbrian TermMode, netfd, mode); 5806059Samurai if (!TermMode) { 5816059Samurai n = read(netfd, linebuff, sizeof(linebuff)-1); 5826735Samurai if (n > 0) { 58326516Sbrian aft_cmd = 1; 5846059Samurai DecodeCommand(linebuff, n, 1); 5856735Samurai } else { 58626516Sbrian LogPrintf(LogPHASE, "client connection closed.\n"); 58724753Sache VarLocalAuth = LOCAL_NO_AUTH; 58826516Sbrian mode &= ~MODE_INTER; 58926516Sbrian oVarTerm = VarTerm; 59026516Sbrian VarTerm = 0; 59126516Sbrian if (oVarTerm && oVarTerm != stdout) 59226516Sbrian fclose(oVarTerm); 5936059Samurai close(netfd); 5946059Samurai netfd = -1; 5956059Samurai } 5966059Samurai return; 5976059Samurai } 5986059Samurai 5996059Samurai /* 6006059Samurai * We are in terminal mode, decode special sequences 6016059Samurai */ 60226516Sbrian n = read(fileno(VarTerm), &ch, 1); 60326516Sbrian LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)", n); 6046059Samurai 6056059Samurai if (n > 0) { 6066059Samurai switch (ttystate) { 6076059Samurai case 0: 6086059Samurai if (ch == '~') 6096059Samurai ttystate++; 6106059Samurai else 6116059Samurai write(modem, &ch, n); 6126059Samurai break; 6136059Samurai case 1: 6146059Samurai switch (ch) { 6156059Samurai case '?': 6166059Samurai ShowHelp(); 6176059Samurai break; 6186059Samurai case 'p': 6196059Samurai /* 6206059Samurai * XXX: Should check carrier. 6216059Samurai */ 6226059Samurai if (LcpFsm.state <= ST_CLOSED) { 6236059Samurai VarOpenMode = OPEN_ACTIVE; 6246059Samurai PacketMode(); 6256059Samurai } 6266059Samurai break; 6276059Samurai case '.': 6286059Samurai TermMode = 1; 62926516Sbrian aft_cmd = 1; 63010528Samurai TtyCommandMode(1); 6316059Samurai break; 63226516Sbrian case 't': 63326516Sbrian if (LogIsKept(LogDEBUG)) { 63426516Sbrian ShowTimers(); 63526516Sbrian break; 63626516Sbrian } 63726516Sbrian case 'm': 63826516Sbrian if (LogIsKept(LogDEBUG)) { 63926516Sbrian ShowMemMap(); 64026516Sbrian break; 64126516Sbrian } 6426059Samurai default: 6436059Samurai if (write(modem, &ch, n) < 0) 64426516Sbrian LogPrintf(LogERROR, "error writing to modem.\n"); 6456059Samurai break; 6466059Samurai } 6476059Samurai ttystate = 0; 6486059Samurai break; 6496059Samurai } 6506059Samurai } 6516059Samurai} 6526059Samurai 6536059Samurai 6546059Samurai/* 6556059Samurai * Here, we'll try to detect HDLC frame 6566059Samurai */ 6576059Samurai 6586059Samuraistatic char *FrameHeaders[] = { 6596735Samurai "\176\377\003\300\041", 6606735Samurai "\176\377\175\043\300\041", 6616735Samurai "\176\177\175\043\100\041", 6626735Samurai "\176\175\337\175\043\300\041", 6636735Samurai "\176\175\137\175\043\100\041", 6646059Samurai NULL, 6656059Samurai}; 6666059Samurai 6676059Samuraiu_char * 6686059SamuraiHdlcDetect(cp, n) 6696059Samuraiu_char *cp; 6706059Samuraiint n; 6716059Samurai{ 6726735Samurai char *ptr, *fp, **hp; 6736059Samurai 6746059Samurai cp[n] = '\0'; /* be sure to null terminated */ 6756059Samurai ptr = NULL; 6766059Samurai for (hp = FrameHeaders; *hp; hp++) { 6776735Samurai fp = *hp; 6786735Samurai if (DEV_IS_SYNC) 6796735Samurai fp++; 68013389Sphk ptr = strstr((char *)cp, fp); 68113389Sphk if (ptr) 6826059Samurai break; 6836059Samurai } 6846059Samurai return((u_char *)ptr); 6856059Samurai} 6866059Samurai 6876059Samuraistatic struct pppTimer RedialTimer; 6886059Samurai 6896059Samuraistatic void 6906059SamuraiRedialTimeout() 6916059Samurai{ 6926059Samurai StopTimer(&RedialTimer); 69326516Sbrian LogPrintf(LogPHASE, "Redialing timer expired.\n"); 6946059Samurai} 6956059Samurai 6966059Samuraistatic void 69724939SbrianStartRedialTimer(Timeout) 69824939Sbrian int Timeout; 6996059Samurai{ 7006059Samurai StopTimer(&RedialTimer); 70111336Samurai 70224939Sbrian if (Timeout) { 70311336Samurai RedialTimer.state = TIMER_STOPPED; 70411336Samurai 70524939Sbrian if (Timeout > 0) 70624939Sbrian RedialTimer.load = Timeout * SECTICKS; 70711336Samurai else 70811336Samurai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 70911336Samurai 71026516Sbrian LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 71124939Sbrian RedialTimer.load / SECTICKS); 71224939Sbrian 71311336Samurai RedialTimer.func = RedialTimeout; 71411336Samurai StartTimer(&RedialTimer); 71511336Samurai } 7166059Samurai} 7176059Samurai 7186059Samurai 7196059Samuraistatic void 7206059SamuraiDoLoop() 7216059Samurai{ 7226059Samurai fd_set rfds, wfds, efds; 72323598Sache int pri, i, n, wfd, nfds; 7246059Samurai struct sockaddr_in hisaddr; 7256059Samurai struct timeval timeout, *tp; 7266059Samurai int ssize = sizeof(hisaddr); 7276059Samurai u_char *cp; 7286059Samurai u_char rbuff[MAX_MRU]; 7297001Samurai int dial_up; 73011336Samurai int tries; 7319448Samurai int qlen; 73226858Sbrian int res; 73310528Samurai pid_t pgroup; 7346059Samurai 73510528Samurai pgroup = getpgrp(); 73610528Samurai 73725908Sbrian if (mode & MODE_DIRECT) { 73826551Sbrian LogPrintf(LogDEBUG, "Opening modem\n"); 7396059Samurai modem = OpenModem(mode); 74026516Sbrian LogPrintf(LogPHASE, "Packet mode enabled\n"); 7416059Samurai PacketMode(); 7426059Samurai } else if (mode & MODE_DEDICATED) { 74323598Sache if (modem < 0) 7446059Samurai modem = OpenModem(mode); 7456059Samurai } 7466059Samurai 74726516Sbrian fflush(VarTerm); 7486059Samurai 7497001Samurai timeout.tv_sec = 0; 7506059Samurai timeout.tv_usec = 0; 75126098Sbrian reconnectState = RECON_UNKNOWN; 7526059Samurai 75323863Sbrian if (mode & MODE_BACKGROUND) 75423863Sbrian dial_up = TRUE; /* Bring the line up */ 75523863Sbrian else 75623863Sbrian dial_up = FALSE; /* XXXX */ 75711336Samurai tries = 0; 7586059Samurai for (;;) { 75923598Sache nfds = 0; 7606059Samurai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 7617001Samurai 76220120Snate /* 76320120Snate * If the link is down and we're in DDIAL mode, bring it back 76420120Snate * up. 76520120Snate */ 76620120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 76720120Snate dial_up = TRUE; 76820120Snate 76925067Sbrian /* 77025067Sbrian * If we lost carrier and want to re-establish the connection 77125067Sbrian * due to the "set reconnect" value, we'd better bring the line 77225908Sbrian * back up. 77325067Sbrian */ 77425908Sbrian if (LcpFsm.state <= ST_CLOSED) { 77526098Sbrian if (dial_up != TRUE && reconnectState == RECON_TRUE) { 77625908Sbrian if (++reconnectCount <= VarReconnectTries) { 77726516Sbrian LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 77825908Sbrian reconnectCount, VarReconnectTries); 77925908Sbrian StartRedialTimer(VarReconnectTimer); 78025908Sbrian dial_up = TRUE; 78125908Sbrian } else { 78225908Sbrian if (VarReconnectTries) 78326516Sbrian LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 78425908Sbrian VarReconnectTries); 78525908Sbrian reconnectCount = 0; 78625908Sbrian if (mode & MODE_BACKGROUND) 78725908Sbrian Cleanup(EX_DEAD); 78825908Sbrian } 78926098Sbrian reconnectState = RECON_ENVOKED; 79025801Sbrian } 79125908Sbrian } 79225067Sbrian 7937001Samurai /* 79425067Sbrian * If Ip packet for output is enqueued and require dial up, 7957001Samurai * Just do it! 7967001Samurai */ 79725067Sbrian if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 79826516Sbrian LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 79911336Samurai modem = OpenModem(mode); 80011336Samurai if (modem < 0) { 80126551Sbrian tries++; 80226696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 80326551Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 80426696Sbrian tries, VarDialTries); 80526551Sbrian else 80626696Sbrian LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 80726551Sbrian 80826696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 80926551Sbrian if (mode & MODE_BACKGROUND) 81026551Sbrian Cleanup(EX_DIAL); /* Can't get the modem */ 81126551Sbrian dial_up = FALSE; 81226551Sbrian reconnectState = RECON_UNKNOWN; 81326551Sbrian reconnectCount = 0; 81426551Sbrian tries = 0; 81526551Sbrian } else 81626551Sbrian StartRedialTimer(VarRedialTimeout); 81711336Samurai } else { 81824843Sbrian tries++; /* Tries are per number, not per list of numbers. */ 81926696Sbrian if (!(mode & MODE_DDIAL) && VarDialTries) 82026696Sbrian LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 82124843Sbrian else 82226696Sbrian LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 82326696Sbrian 82426858Sbrian if ((res = DialModem()) == EX_DONE) { 82511336Samurai sleep(1); /* little pause to allow peer starts */ 82611336Samurai ModemTimeout(); 82711336Samurai PacketMode(); 82811336Samurai dial_up = FALSE; 82926098Sbrian reconnectState = RECON_UNKNOWN; 83011336Samurai tries = 0; 83111336Samurai } else { 83211336Samurai CloseModem(); 83324844Sbrian if (mode & MODE_BACKGROUND) { 83426858Sbrian if (VarNextPhone == NULL || res == EX_SIG) 83524844Sbrian Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 83624844Sbrian else 83724939Sbrian /* Try all numbers in background mode */ 83824939Sbrian StartRedialTimer(VarRedialNextTimeout); 83926858Sbrian } else if (!(mode & MODE_DDIAL) && 84026858Sbrian ((VarDialTries && tries >= VarDialTries) || 84126858Sbrian res == EX_SIG)) { 84224843Sbrian /* I give up ! Can't get through :( */ 84324939Sbrian StartRedialTimer(VarRedialTimeout); 84424843Sbrian dial_up = FALSE; 84526098Sbrian reconnectState = RECON_UNKNOWN; 84626098Sbrian reconnectCount = 0; 84724843Sbrian tries = 0; 84824843Sbrian } else if (VarNextPhone == NULL) 84924843Sbrian /* Dial failed. Keep quite during redial wait period. */ 85024939Sbrian StartRedialTimer(VarRedialTimeout); 85124843Sbrian else 85224939Sbrian StartRedialTimer(VarRedialNextTimeout); 85311336Samurai } 85411336Samurai } 8557001Samurai } 8569448Samurai qlen = ModemQlen(); 85713733Sdfr 85813733Sdfr if (qlen == 0) { 85913733Sdfr IpStartOutput(); 86013733Sdfr qlen = ModemQlen(); 86113733Sdfr } 86213733Sdfr 86323598Sache if (modem >= 0) { 86423598Sache if (modem + 1 > nfds) 86523598Sache nfds = modem + 1; 8667001Samurai FD_SET(modem, &rfds); 8677001Samurai FD_SET(modem, &efds); 8689448Samurai if (qlen > 0) { 8697001Samurai FD_SET(modem, &wfds); 8707001Samurai } 8717001Samurai } 87223598Sache if (server >= 0) { 87323598Sache if (server + 1 > nfds) 87423598Sache nfds = server + 1; 87523598Sache FD_SET(server, &rfds); 87623598Sache } 8776059Samurai 8786059Samurai /* *** IMPORTANT *** 8796059Samurai * 8806059Samurai * CPU is serviced every TICKUNIT micro seconds. 8816059Samurai * This value must be chosen with great care. If this values is 8826059Samurai * too big, it results loss of characters from modem and poor responce. 8836059Samurai * If this values is too small, ppp process eats many CPU time. 8846059Samurai */ 8856735Samurai#ifndef SIGALRM 8866059Samurai usleep(TICKUNIT); 8876059Samurai TimerService(); 88823840Sbrian#else 88923840Sbrian handle_signals(); 8906735Samurai#endif 89110877Sbde 89210877Sbde /* If there are aren't many packets queued, look for some more. */ 89323598Sache if (qlen < 20 && tun_in >= 0) { 89423598Sache if (tun_in + 1 > nfds) 89523598Sache nfds = tun_in + 1; 89610877Sbde FD_SET(tun_in, &rfds); 89723598Sache } 89810877Sbde 89923598Sache if (netfd >= 0) { 90023598Sache if (netfd + 1 > nfds) 90123598Sache nfds = netfd + 1; 9026059Samurai FD_SET(netfd, &rfds); 9036059Samurai FD_SET(netfd, &efds); 9046059Samurai } 9057001Samurai 9066735Samurai#ifndef SIGALRM 9076059Samurai /* 9087001Samurai * Normally, select() will not block because modem is writable. 9097001Samurai * In AUTO mode, select will block until we find packet from tun 9106059Samurai */ 9116059Samurai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 91223598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9136735Samurai#else 9148857Srgrimes /* 9157001Samurai * When SIGALRM timer is running, a select function will be 9168857Srgrimes * return -1 and EINTR after a Time Service signal hundler 91711336Samurai * is done. If the redial timer is not running and we are 91811336Samurai * trying to dial, poll with a 0 value timer. 9197001Samurai */ 92011336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 92123598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9226735Samurai#endif 92322074Sbrian 9247001Samurai if ( i == 0 ) { 9257001Samurai continue; 9266059Samurai } 9276735Samurai 9287001Samurai if ( i < 0 ) { 9297001Samurai if ( errno == EINTR ) { 93023840Sbrian handle_signals(); 93123840Sbrian continue; 9327001Samurai } 93326516Sbrian LogPrintf(LogERROR, "select: %s", strerror(errno)); 9347001Samurai break; 9358857Srgrimes } 9367001Samurai 93723598Sache if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 93826516Sbrian LogPrintf(LogALERT, "Exception detected.\n"); 9396059Samurai break; 9406059Samurai } 9416059Samurai 94223598Sache if (server >= 0 && FD_ISSET(server, &rfds)) { 94326516Sbrian LogPrintf(LogPHASE, "connected to client.\n"); 9446059Samurai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 94524753Sache if (wfd < 0) { 94626516Sbrian LogPrintf(LogERROR, "accept: %s", strerror(errno)); 94724753Sache continue; 94824753Sache } 94923598Sache if (netfd >= 0) { 9506059Samurai write(wfd, "already in use.\n", 16); 9516059Samurai close(wfd); 9526059Samurai continue; 9536059Samurai } else 9546059Samurai netfd = wfd; 95526516Sbrian VarTerm = fdopen(netfd, "a+"); 9566059Samurai mode |= MODE_INTER; 9576059Samurai Greetings(); 9586764Samurai switch ( LocalAuthInit() ) { 9596764Samurai case NOT_FOUND: 96026516Sbrian if (VarTerm) { 96126516Sbrian fprintf(VarTerm,LAUTH_M1); 96226516Sbrian fprintf(VarTerm,LAUTH_M2); 96326516Sbrian fflush(VarTerm); 96426516Sbrian } 9656764Samurai /* Fall down */ 9666764Samurai case VALID: 9676764Samurai VarLocalAuth = LOCAL_AUTH; 9686764Samurai break; 9696764Samurai default: 9706764Samurai break; 9716764Samurai } 9726059Samurai (void) IsInteractive(); 97325630Sbrian Prompt(); 9746059Samurai } 9756059Samurai 97623598Sache if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 97710858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 9786059Samurai /* something to read from tty */ 9796059Samurai ReadTty(); 9806059Samurai } 98123598Sache if (modem >= 0) { 9826059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 9836059Samurai ModemStartOutput(modem); 9846059Samurai } 9856059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 9866735Samurai if (LcpFsm.state <= ST_CLOSED) 9876735Samurai usleep(10000); 9886059Samurai n = read(modem, rbuff, sizeof(rbuff)); 9896059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 9906059Samurai DownConnection(); 9916059Samurai } else 99226516Sbrian LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 9936059Samurai 9946059Samurai if (LcpFsm.state <= ST_CLOSED) { 9956059Samurai /* 9966059Samurai * In dedicated mode, we just discard input until LCP is started. 9976059Samurai */ 9986059Samurai if (!(mode & MODE_DEDICATED)) { 9996059Samurai cp = HdlcDetect(rbuff, n); 10006059Samurai if (cp) { 10016059Samurai /* 10026059Samurai * LCP packet is detected. Turn ourselves into packet mode. 10036059Samurai */ 10046059Samurai if (cp != rbuff) { 100526516Sbrian write(modem, rbuff, cp - rbuff); 100626516Sbrian write(modem, "\r\n", 2); 10076059Samurai } 10086059Samurai PacketMode(); 10096059Samurai } else 101026516Sbrian write(fileno(VarTerm), rbuff, n); 10116059Samurai } 10126059Samurai } else { 10136059Samurai if (n > 0) 10146059Samurai AsyncInput(rbuff, n); 10156059Samurai } 10166059Samurai } 10176059Samurai } 10187001Samurai 101923598Sache if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 10206059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 10216059Samurai if (n < 0) { 102226516Sbrian LogPrintf(LogERROR, "read from tun: %s", strerror(errno)); 10236059Samurai continue; 10246059Samurai } 10256059Samurai /* 10266059Samurai * Process on-demand dialup. Output packets are queued within tunnel 10276059Samurai * device until IPCP is opened. 10286059Samurai */ 10296059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 10307001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 10316059Samurai if (pri >= 0) { 103220365Sjkh if (mode & MODE_ALIAS) { 103326142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 103420666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 103520365Sjkh } 10366059Samurai IpEnqueue(pri, rbuff, n); 103720365Sjkh dial_up = TRUE; /* XXX */ 10386059Samurai } 10396059Samurai continue; 10406059Samurai } 10417001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 104220365Sjkh if (pri >= 0) { 104320365Sjkh if (mode & MODE_ALIAS) { 104426142Sbrian VarPacketAliasOut(rbuff, sizeof rbuff); 104520666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 104620365Sjkh } 10476059Samurai IpEnqueue(pri, rbuff, n); 104820365Sjkh } 10496059Samurai } 10506059Samurai } 105126516Sbrian LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 10526059Samurai} 1053