main.c revision 26032
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 * 2026032Sbrian * $Id: main.c,v 1.54 1997/05/23 04:54:03 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> 4026031Sbrian#include <alias.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" 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" 559410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\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 856059SamuraiTtyInit() 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; 1006059Samurai 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 11210528SamuraiTtyCommandMode(prompt) 11310528Samuraiint prompt; 1146059Samurai{ 1156059Samurai struct termios newtio; 1166059Samurai int stat; 1176059Samurai 1186059Samurai if (!(mode & MODE_INTER)) 1196059Samurai return; 1206735Samurai tcgetattr(0, &newtio); 12110528Samurai newtio.c_lflag |= (ECHO|ISIG|ICANON); 1226059Samurai newtio.c_iflag = oldtio.c_iflag; 1236059Samurai newtio.c_oflag |= OPOST; 1246735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1256059Samurai stat = fcntl(0, F_GETFL, 0); 12625630Sbrian if (stat > 0) { 12725630Sbrian stat |= O_NONBLOCK; 12825630Sbrian (void)fcntl(0, F_SETFL, stat); 12925630Sbrian } 1306059Samurai TermMode = 0; 13125630Sbrian if(prompt) 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) { 14525630Sbrian stat &= ~O_NONBLOCK; 14625630Sbrian (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) { 15825630Sbrian stat &= ~O_NONBLOCK; 15925630Sbrian (void)fcntl(0, F_SETFL, stat); 16025630Sbrian } 1616735Samurai tcsetattr(0, TCSANOW, &oldtio); 16210528Samurai} 16310528Samurai 16410528Samuraivoid 16510528SamuraiCleanup(excode) 16610528Samuraiint excode; 16710528Samurai{ 16810528Samurai 16910528Samurai OsLinkdown(); 1706059Samurai OsCloseLink(1); 1716059Samurai sleep(1); 17225908Sbrian if (mode & MODE_AUTO) 1736059Samurai DeleteIfRoutes(1); 17425707Sbrian (void)unlink(pid_filename); 17525707Sbrian (void)unlink(if_filename); 1766059Samurai OsInterfaceDown(1); 17723863Sbrian if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 17823863Sbrian char c = EX_ERRDEAD; 17923863Sbrian if (write(BGFiledes[1],&c,1) == 1) 18023863Sbrian LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n"); 18123863Sbrian else 18223863Sbrian LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n"); 18323863Sbrian close(BGFiledes[1]); 18423863Sbrian } 18525908Sbrian LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode)); 1866059Samurai LogClose(); 18723598Sache if (server >= 0) { 1886059Samurai close(server); 18923598Sache server = -1; 19023598Sache } 19125707Sbrian 19210528Samurai TtyOldMode(); 1936059Samurai 1946059Samurai exit(excode); 1956059Samurai} 1966059Samurai 1976059Samuraistatic void 19814930SacheHangup(signo) 19914930Sacheint signo; 2006059Samurai{ 20117044Sache if (signo == SIGSEGV) { 20217044Sache LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 20317044Sache LogClose(); 20417044Sache abort(); 20517044Sache } 20620813Sjkh if (BGPid) { 20723842Sbrian kill (BGPid, SIGTERM); 20820813Sjkh exit (EX_HANGUP); 20920813Sjkh } 21020813Sjkh else { 21120813Sjkh LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 21220813Sjkh Cleanup(EX_HANGUP); 21320813Sjkh } 2146059Samurai} 2156059Samurai 2166059Samuraistatic void 21714930SacheCloseSession(signo) 21814930Sacheint signo; 2196059Samurai{ 22020813Sjkh if (BGPid) { 22120813Sjkh kill (BGPid, SIGINT); 22220813Sjkh exit (EX_TERM); 22320813Sjkh } 22420813Sjkh else { 22520813Sjkh LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 22620813Sjkh LcpClose(); 22725908Sbrian reconnectCount = 0; 22820813Sjkh Cleanup(EX_TERM); 22920813Sjkh } 2306059Samurai} 2316059Samurai 23210528Samuraistatic void 23310528SamuraiTerminalCont() 23410528Samurai{ 23523840Sbrian pending_signal(SIGCONT, SIG_DFL); 23623840Sbrian pending_signal(SIGTSTP, TerminalStop); 23710528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 23810528Samurai} 23910528Samurai 24010528Samuraistatic void 24110528SamuraiTerminalStop(signo) 24210528Samuraiint signo; 24310528Samurai{ 24423840Sbrian pending_signal(SIGCONT, TerminalCont); 24510528Samurai TtyOldMode(); 24623840Sbrian pending_signal(SIGTSTP, SIG_DFL); 24710528Samurai kill(getpid(), signo); 24810528Samurai} 24910528Samurai 25025908Sbrianstatic char * 25125908Sbrianex_desc(int ex) 25225908Sbrian{ 25325908Sbrian static char num[12]; 25425908Sbrian static char *desc[] = { "normal", "start", "sock", 25525908Sbrian "modem", "dial", "dead", "done", "reboot", "errdead", 25625908Sbrian "hangup", "term", "nodial", "nologin" }; 25710528Samurai 25825908Sbrian if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 25925908Sbrian return desc[ex]; 26025908Sbrian snprintf(num, sizeof num, "%d", ex); 26125908Sbrian return num; 26225908Sbrian} 26325908Sbrian 2646059Samuraivoid 2656059SamuraiUsage() 2666059Samurai{ 26720120Snate fprintf(stderr, 26820813Sjkh "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2696059Samurai exit(EX_START); 2706059Samurai} 2716059Samurai 2726059Samuraivoid 2736059SamuraiProcessArgs(int argc, char **argv) 2746059Samurai{ 2756059Samurai int optc; 2766059Samurai char *cp; 2776059Samurai 2786059Samurai optc = 0; 2796059Samurai while (argc > 0 && **argv == '-') { 2806059Samurai cp = *argv + 1; 2816059Samurai if (strcmp(cp, "auto") == 0) 2826059Samurai mode |= MODE_AUTO; 28320813Sjkh else if (strcmp(cp, "background") == 0) 28425908Sbrian mode |= MODE_BACKGROUND|MODE_AUTO; 2856059Samurai else if (strcmp(cp, "direct") == 0) 2866059Samurai mode |= MODE_DIRECT; 2876059Samurai else if (strcmp(cp, "dedicated") == 0) 2886059Samurai mode |= MODE_DEDICATED; 28920120Snate else if (strcmp(cp, "ddial") == 0) 29020120Snate mode |= MODE_DDIAL|MODE_AUTO; 29120365Sjkh else if (strcmp(cp, "alias") == 0) { 29220365Sjkh mode |= MODE_ALIAS; 29320365Sjkh optc--; /* this option isn't exclusive */ 29420365Sjkh } 2956059Samurai else 2966059Samurai Usage(); 2976059Samurai optc++; 2986059Samurai argv++; argc--; 2996059Samurai } 3006059Samurai if (argc > 1) { 3016059Samurai fprintf(stderr, "specify only one system label.\n"); 3026059Samurai exit(EX_START); 3036059Samurai } 3046059Samurai if (argc == 1) dstsystem = *argv; 3056059Samurai 3066059Samurai if (optc > 1) { 3076059Samurai fprintf(stderr, "specify only one mode.\n"); 3086059Samurai exit(EX_START); 3096059Samurai } 3106059Samurai} 3116059Samurai 3126059Samuraistatic void 3136059SamuraiGreetings() 3146059Samurai{ 3156059Samurai printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 3166059Samurai fflush(stdout); 3176059Samurai} 3186059Samurai 3196059Samuraivoid 3206059Samuraimain(argc, argv) 3216059Samuraiint argc; 3226059Samuraichar **argv; 3236059Samurai{ 32425707Sbrian FILE *lockfile; 3256059Samurai argc--; argv++; 3266059Samurai 3276059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 32823598Sache netfd = server = modem = tun_in = -1; 3296059Samurai ProcessArgs(argc, argv); 3306059Samurai Greetings(); 3316059Samurai GetUid(); 3326059Samurai IpcpDefAddress(); 33326031Sbrian InitPacketAlias(); 3346059Samurai 3356059Samurai if (SelectSystem("default", CONFFILE) < 0) { 3366059Samurai fprintf(stderr, "Warning: No default entry is given in config file.\n"); 3376059Samurai } 3386059Samurai 3396735Samurai switch ( LocalAuthInit() ) { 3406735Samurai case NOT_FOUND: 3416764Samurai fprintf(stderr,LAUTH_M1); 3426764Samurai fprintf(stderr,LAUTH_M2); 3436764Samurai fflush (stderr); 3446764Samurai /* Fall down */ 3456764Samurai case VALID: 3466735Samurai VarLocalAuth = LOCAL_AUTH; 3476735Samurai break; 3486735Samurai default: 3496735Samurai break; 3506735Samurai } 3516735Samurai 3526059Samurai if (OpenTunnel(&tunno) < 0) { 3536059Samurai perror("open_tun"); 3546059Samurai exit(EX_START); 3556059Samurai } 3566059Samurai 35725908Sbrian if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 3586059Samurai mode &= ~MODE_INTER; 3596059Samurai if (mode & MODE_INTER) { 3606059Samurai printf("Interactive mode\n"); 36123598Sache netfd = STDIN_FILENO; 3626059Samurai } else if (mode & MODE_AUTO) { 36320120Snate printf("Automatic Dialer mode\n"); 3646059Samurai if (dstsystem == NULL) { 36525908Sbrian fprintf(stderr, "Destination system must be specified in" 36625908Sbrian " auto, background or ddial mode.\n"); 3676059Samurai exit(EX_START); 3686059Samurai } 3696059Samurai } 3706059Samurai 3716735Samurai tcgetattr(0, &oldtio); /* Save original tty mode */ 3726059Samurai 37323842Sbrian pending_signal(SIGHUP, LogReOpen); 37423840Sbrian pending_signal(SIGTERM, CloseSession); 37523840Sbrian pending_signal(SIGINT, CloseSession); 37623840Sbrian pending_signal(SIGQUIT, CloseSession); 3776735Samurai#ifdef SIGSEGV 37823513Sache signal(SIGSEGV, Hangup); 3796735Samurai#endif 3806735Samurai#ifdef SIGPIPE 38124753Sache signal(SIGPIPE, SIG_IGN); 3826735Samurai#endif 3836735Samurai#ifdef SIGALRM 38423840Sbrian pending_signal(SIGALRM, SIG_IGN); 3856735Samurai#endif 38610528Samurai if(mode & MODE_INTER) 38710528Samurai { 38810528Samurai#ifdef SIGTSTP 38923840Sbrian pending_signal(SIGTSTP, TerminalStop); 39010528Samurai#endif 39110528Samurai#ifdef SIGTTIN 39223840Sbrian pending_signal(SIGTTIN, TerminalStop); 39310528Samurai#endif 39410528Samurai#ifdef SIGTTOU 39523840Sbrian pending_signal(SIGTTOU, SIG_IGN); 39610528Samurai#endif 39710528Samurai } 3986059Samurai 3996059Samurai if (dstsystem) { 4006059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 4016059Samurai fprintf(stderr, "Destination system not found in conf file.\n"); 4026059Samurai Cleanup(EX_START); 4036059Samurai } 4046059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 40525908Sbrian fprintf(stderr, "Must specify dstaddr with" 40625908Sbrian " auto, background or ddial mode.\n"); 4076059Samurai Cleanup(EX_START); 4086059Samurai } 4096059Samurai } 4106059Samurai if (mode & MODE_DIRECT) 4116059Samurai printf("Packet mode enabled.\n"); 4126059Samurai 4136059Samurai if (!(mode & MODE_INTER)) { 41420813Sjkh int port = SERVER_PORT + tunno; 41525908Sbrian 41620813Sjkh if (mode & MODE_BACKGROUND) { 41720813Sjkh if (pipe (BGFiledes)) { 41820813Sjkh perror("pipe"); 41920813Sjkh Cleanup(EX_SOCK); 42020813Sjkh } 4216059Samurai } 42225908Sbrian 42325908Sbrian /* Create server socket and listen at there. */ 42425908Sbrian server = socket(PF_INET, SOCK_STREAM, 0); 42525908Sbrian if (server < 0) { 42625908Sbrian perror("socket"); 42725908Sbrian Cleanup(EX_SOCK); 4286059Samurai } 42925908Sbrian ifsin.sin_family = AF_INET; 43025908Sbrian ifsin.sin_addr.s_addr = INADDR_ANY; 43125908Sbrian ifsin.sin_port = htons(port); 43226032Sbrian setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server); 43325908Sbrian if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 43425908Sbrian perror("bind"); 43525908Sbrian if (errno == EADDRINUSE) 43625908Sbrian fprintf(stderr, "Wait for a while, then try again.\n"); 43725908Sbrian Cleanup(EX_SOCK); 43825908Sbrian } 43925908Sbrian if (listen(server, 5) != 0) { 44025908Sbrian fprintf(stderr, "Unable to listen to socket - OS overload?\n"); 44125908Sbrian } 4426059Samurai 4436059Samurai DupLog(); 4446059Samurai if (!(mode & MODE_DIRECT)) { 44520813Sjkh pid_t bgpid; 44611336Samurai 44720813Sjkh bgpid = fork (); 44820813Sjkh if (bgpid == -1) { 44920813Sjkh perror ("fork"); 45020813Sjkh Cleanup (EX_SOCK); 45120813Sjkh } 45220813Sjkh if (bgpid) { 45320813Sjkh char c = EX_NORMAL; 45411336Samurai 45520813Sjkh if (mode & MODE_BACKGROUND) { 45620813Sjkh /* Wait for our child to close its pipe before we exit. */ 45720813Sjkh BGPid = bgpid; 45823863Sbrian close (BGFiledes[1]); 45925908Sbrian if (read(BGFiledes[0], &c, 1) != 1) { 46025908Sbrian printf("Child exit, no status.\n"); 46123863Sbrian LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n"); 46225908Sbrian } else if (c == EX_NORMAL) { 46325908Sbrian printf("PPP enabled.\n"); 46423863Sbrian LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n"); 46525908Sbrian } else { 46625910Sbrian printf("Child failed (%s).\n",ex_desc((int)c)); 46725910Sbrian LogPrintf(LOG_PHASE_BIT, "Parent: Child failed (%s).\n", 46825910Sbrian ex_desc((int)c)); 46925908Sbrian } 47023863Sbrian close (BGFiledes[0]); 47120813Sjkh } 47220813Sjkh exit(c); 47323863Sbrian } else if (mode & MODE_BACKGROUND) 47423863Sbrian close(BGFiledes[0]); 47525707Sbrian } 47620813Sjkh 47725801Sbrian snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 47825707Sbrian _PATH_VARRUN, tunno); 47925707Sbrian (void)unlink(pid_filename); 48011336Samurai 48125707Sbrian if ((lockfile = fopen(pid_filename, "w")) != NULL) { 48225707Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 48325707Sbrian fclose(lockfile); 48425707Sbrian } else 48525707Sbrian logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno)); 48625634Sbrian 48725707Sbrian snprintf(if_filename, sizeof if_filename, "%s%s.if", 48825707Sbrian _PATH_VARRUN, VarBaseDevice); 48925707Sbrian (void)unlink(if_filename); 49025634Sbrian 49125707Sbrian if ((lockfile = fopen(if_filename, "w")) != NULL) { 49225707Sbrian fprintf(lockfile, "tun%d\n", tunno); 49325707Sbrian fclose(lockfile); 49425707Sbrian } else 49525707Sbrian logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno)); 49625707Sbrian 49723598Sache if (server >= 0) 49820813Sjkh LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 4996059Samurai#ifdef DOTTYINIT 5006735Samurai if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 5016059Samurai#else 5026059Samurai if (mode & MODE_DIRECT) { 5036059Samurai#endif 5046059Samurai TtyInit(); 5056059Samurai } else { 50614436Sache int fd; 50714436Sache 5086059Samurai setsid(); /* detach control tty */ 50914436Sache if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 51014436Sache (void)dup2(fd, STDIN_FILENO); 51114436Sache (void)dup2(fd, STDOUT_FILENO); 51214436Sache (void)dup2(fd, STDERR_FILENO); 51314436Sache if (fd > 2) 51414436Sache (void)close (fd); 51514436Sache } 5166059Samurai } 5176059Samurai } else { 5186059Samurai TtyInit(); 51910528Samurai TtyCommandMode(1); 5206059Samurai } 52115738Sphk LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 5226059Samurai 5236059Samurai 5246059Samurai do 5256059Samurai DoLoop(); 5266059Samurai while (mode & MODE_DEDICATED); 5276059Samurai 5286059Samurai Cleanup(EX_DONE); 5296059Samurai} 5306059Samurai 5316059Samurai/* 53220813Sjkh * Turn into packet mode, where we speak PPP. 5336059Samurai */ 5346059Samuraivoid 5356059SamuraiPacketMode() 5366059Samurai{ 5376059Samurai if (RawModem(modem) < 0) { 5386059Samurai fprintf(stderr, "Not connected.\r\n"); 5396059Samurai return; 5406059Samurai } 5416059Samurai 5426059Samurai AsyncInit(); 5436059Samurai VjInit(); 5446059Samurai LcpInit(); 5456059Samurai IpcpInit(); 5466059Samurai CcpInit(); 5476059Samurai LcpUp(); 5486059Samurai 54925872Sbrian LcpOpen(VarOpenMode); 5506059Samurai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 55110528Samurai TtyCommandMode(1); 5526059Samurai fprintf(stderr, "Packet mode.\r\n"); 55318885Sjkh aft_cmd = 1; 5546059Samurai } 5556059Samurai} 5566059Samurai 5576059Samuraistatic void 5586059SamuraiShowHelp() 5596059Samurai{ 56010528Samurai fprintf(stderr, "The following commands are available:\r\n"); 5616059Samurai fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 56214418Sache fprintf(stderr, " ~-\tDecrease log level\r\n"); 56314418Sache fprintf(stderr, " ~+\tIncrease log level\r\n"); 5646059Samurai fprintf(stderr, " ~.\tTerminate program\r\n"); 56514418Sache fprintf(stderr, " ~?\tThis help\r\n"); 5666059Samurai} 5676059Samurai 5686059Samuraistatic void 5696059SamuraiReadTty() 5706059Samurai{ 5716059Samurai int n; 5726059Samurai char ch; 5736059Samurai static int ttystate; 5746059Samurai#define MAXLINESIZE 200 5756059Samurai char linebuff[MAXLINESIZE]; 5766059Samurai 5776059Samurai#ifdef DEBUG 5786059Samurai logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 5796059Samurai#endif 5806059Samurai if (!TermMode) { 5816059Samurai n = read(netfd, linebuff, sizeof(linebuff)-1); 58218885Sjkh aft_cmd = 1; 5836735Samurai if (n > 0) { 5846059Samurai DecodeCommand(linebuff, n, 1); 5856735Samurai } else { 58624753Sache LogPrintf(LOG_PHASE_BIT, "client connection closed.\n"); 58724753Sache VarLocalAuth = LOCAL_NO_AUTH; 5886059Samurai close(netfd); 58924753Sache close(1); 59024753Sache dup2(2, 1); /* Have to have something here or the modem will be 1 */ 5916059Samurai netfd = -1; 5926059Samurai mode &= ~MODE_INTER; 5936059Samurai } 5946059Samurai return; 5956059Samurai } 5966059Samurai 5976059Samurai /* 5986059Samurai * We are in terminal mode, decode special sequences 5996059Samurai */ 6006059Samurai n = read(0, &ch, 1); 6016059Samurai#ifdef DEBUG 6026059Samurai logprintf("got %d bytes\n", n); 6036059Samurai#endif 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 '-': 6196059Samurai if (loglevel > 0) { 6206059Samurai loglevel--; 6216059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 6226059Samurai } 6236059Samurai break; 6246059Samurai case '+': 6256059Samurai loglevel++; 6266059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 6276059Samurai break; 6286059Samurai#ifdef DEBUG 6296059Samurai case 'm': 6306059Samurai ShowMemMap(); 6316059Samurai break; 6326059Samurai#endif 6336059Samurai case 'p': 6346059Samurai /* 6356059Samurai * XXX: Should check carrier. 6366059Samurai */ 6376059Samurai if (LcpFsm.state <= ST_CLOSED) { 6386059Samurai VarOpenMode = OPEN_ACTIVE; 6396059Samurai PacketMode(); 6406059Samurai } 6416059Samurai break; 6426059Samurai#ifdef DEBUG 6436059Samurai case 't': 6446059Samurai ShowTimers(); 6456059Samurai break; 6466059Samurai#endif 6476059Samurai case '.': 6486059Samurai TermMode = 1; 64910528Samurai TtyCommandMode(1); 6506059Samurai break; 6516059Samurai default: 6526059Samurai if (write(modem, &ch, n) < 0) 6536059Samurai fprintf(stderr, "err in write.\r\n"); 6546059Samurai break; 6556059Samurai } 6566059Samurai ttystate = 0; 6576059Samurai break; 6586059Samurai } 6596059Samurai } 6606059Samurai} 6616059Samurai 6626059Samurai 6636059Samurai/* 6646059Samurai * Here, we'll try to detect HDLC frame 6656059Samurai */ 6666059Samurai 6676059Samuraistatic char *FrameHeaders[] = { 6686735Samurai "\176\377\003\300\041", 6696735Samurai "\176\377\175\043\300\041", 6706735Samurai "\176\177\175\043\100\041", 6716735Samurai "\176\175\337\175\043\300\041", 6726735Samurai "\176\175\137\175\043\100\041", 6736059Samurai NULL, 6746059Samurai}; 6756059Samurai 6766059Samuraiu_char * 6776059SamuraiHdlcDetect(cp, n) 6786059Samuraiu_char *cp; 6796059Samuraiint n; 6806059Samurai{ 6816735Samurai char *ptr, *fp, **hp; 6826059Samurai 6836059Samurai cp[n] = '\0'; /* be sure to null terminated */ 6846059Samurai ptr = NULL; 6856059Samurai for (hp = FrameHeaders; *hp; hp++) { 6866735Samurai fp = *hp; 6876735Samurai if (DEV_IS_SYNC) 6886735Samurai fp++; 68913389Sphk ptr = strstr((char *)cp, fp); 69013389Sphk if (ptr) 6916059Samurai break; 6926059Samurai } 6936059Samurai return((u_char *)ptr); 6946059Samurai} 6956059Samurai 6966059Samuraistatic struct pppTimer RedialTimer; 6976059Samurai 6986059Samuraistatic void 6996059SamuraiRedialTimeout() 7006059Samurai{ 7016059Samurai StopTimer(&RedialTimer); 70215738Sphk LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 7036059Samurai} 7046059Samurai 7056059Samuraistatic void 70624939SbrianStartRedialTimer(Timeout) 70724939Sbrian int Timeout; 7086059Samurai{ 7096059Samurai StopTimer(&RedialTimer); 71011336Samurai 71124939Sbrian if (Timeout) { 71211336Samurai RedialTimer.state = TIMER_STOPPED; 71311336Samurai 71424939Sbrian if (Timeout > 0) 71524939Sbrian RedialTimer.load = Timeout * SECTICKS; 71611336Samurai else 71711336Samurai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 71811336Samurai 71924939Sbrian LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n", 72024939Sbrian RedialTimer.load / SECTICKS); 72124939Sbrian 72211336Samurai RedialTimer.func = RedialTimeout; 72311336Samurai StartTimer(&RedialTimer); 72411336Samurai } 7256059Samurai} 7266059Samurai 7276059Samurai 7286059Samuraistatic void 7296059SamuraiDoLoop() 7306059Samurai{ 7316059Samurai fd_set rfds, wfds, efds; 73223598Sache int pri, i, n, wfd, nfds; 7336059Samurai struct sockaddr_in hisaddr; 7346059Samurai struct timeval timeout, *tp; 7356059Samurai int ssize = sizeof(hisaddr); 7366059Samurai u_char *cp; 7376059Samurai u_char rbuff[MAX_MRU]; 7387001Samurai int dial_up; 73911336Samurai int tries; 7409448Samurai int qlen; 74110528Samurai pid_t pgroup; 7426059Samurai 74310528Samurai pgroup = getpgrp(); 74410528Samurai 74525908Sbrian if (mode & MODE_DIRECT) { 7466059Samurai modem = OpenModem(mode); 74715738Sphk LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 74818885Sjkh fflush(stderr); 7496059Samurai PacketMode(); 7506059Samurai } else if (mode & MODE_DEDICATED) { 75123598Sache if (modem < 0) 7526059Samurai modem = OpenModem(mode); 7536059Samurai } 7546059Samurai 7556059Samurai fflush(stdout); 7566059Samurai 7577001Samurai timeout.tv_sec = 0; 7586059Samurai timeout.tv_usec = 0; 75925908Sbrian reconnectRequired = 0; 7606059Samurai 76123863Sbrian if (mode & MODE_BACKGROUND) 76223863Sbrian dial_up = TRUE; /* Bring the line up */ 76323863Sbrian else 76423863Sbrian dial_up = FALSE; /* XXXX */ 76511336Samurai tries = 0; 7666059Samurai for (;;) { 76723598Sache nfds = 0; 7686059Samurai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 7697001Samurai 77020120Snate /* 77120120Snate * If the link is down and we're in DDIAL mode, bring it back 77220120Snate * up. 77320120Snate */ 77420120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 77520120Snate dial_up = TRUE; 77620120Snate 77725067Sbrian /* 77825067Sbrian * If we lost carrier and want to re-establish the connection 77925067Sbrian * due to the "set reconnect" value, we'd better bring the line 78025908Sbrian * back up. 78125067Sbrian */ 78225908Sbrian if (LcpFsm.state <= ST_CLOSED) { 78325908Sbrian if (dial_up != TRUE && reconnectRequired) { 78425908Sbrian if (++reconnectCount <= VarReconnectTries) { 78525908Sbrian LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n", 78625908Sbrian reconnectCount, VarReconnectTries); 78725908Sbrian StartRedialTimer(VarReconnectTimer); 78825908Sbrian dial_up = TRUE; 78925908Sbrian } else { 79025908Sbrian if (VarReconnectTries) 79125908Sbrian LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n", 79225908Sbrian VarReconnectTries); 79325908Sbrian reconnectCount = 0; 79425908Sbrian if (mode & MODE_BACKGROUND) 79525908Sbrian Cleanup(EX_DEAD); 79625908Sbrian } 79725801Sbrian } 79825908Sbrian reconnectRequired = 0; 79925908Sbrian } 80025067Sbrian 8017001Samurai /* 80225067Sbrian * If Ip packet for output is enqueued and require dial up, 8037001Samurai * Just do it! 8047001Samurai */ 80525067Sbrian if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 8067001Samurai#ifdef DEBUG 8077001Samurai logprintf("going to dial: modem = %d\n", modem); 8087001Samurai#endif 80911336Samurai modem = OpenModem(mode); 81011336Samurai if (modem < 0) { 81124939Sbrian StartRedialTimer(VarRedialTimeout); 81211336Samurai } else { 81324843Sbrian tries++; /* Tries are per number, not per list of numbers. */ 81424843Sbrian if (VarDialTries) 81524843Sbrian LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries, 81624843Sbrian VarDialTries); 81724843Sbrian else 81824843Sbrian LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 81911336Samurai if (DialModem()) { 82011336Samurai sleep(1); /* little pause to allow peer starts */ 82111336Samurai ModemTimeout(); 82211336Samurai PacketMode(); 82311336Samurai dial_up = FALSE; 82411336Samurai tries = 0; 82511336Samurai } else { 82611336Samurai CloseModem(); 82724844Sbrian if (mode & MODE_BACKGROUND) { 82824844Sbrian if (VarNextPhone == NULL) 82924844Sbrian Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 83024844Sbrian else 83124939Sbrian /* Try all numbers in background mode */ 83224939Sbrian StartRedialTimer(VarRedialNextTimeout); 83324844Sbrian } else if (VarDialTries && tries >= VarDialTries) { 83424843Sbrian /* I give up ! Can't get through :( */ 83524939Sbrian StartRedialTimer(VarRedialTimeout); 83624843Sbrian dial_up = FALSE; 83724843Sbrian tries = 0; 83824843Sbrian } else if (VarNextPhone == NULL) 83924843Sbrian /* Dial failed. Keep quite during redial wait period. */ 84024939Sbrian StartRedialTimer(VarRedialTimeout); 84124843Sbrian else 84224939Sbrian StartRedialTimer(VarRedialNextTimeout); 84311336Samurai } 84411336Samurai } 8457001Samurai } 8469448Samurai qlen = ModemQlen(); 84713733Sdfr 84813733Sdfr if (qlen == 0) { 84913733Sdfr IpStartOutput(); 85013733Sdfr qlen = ModemQlen(); 85113733Sdfr } 85213733Sdfr 85323598Sache if (modem >= 0) { 85423598Sache if (modem + 1 > nfds) 85523598Sache nfds = modem + 1; 8567001Samurai FD_SET(modem, &rfds); 8577001Samurai FD_SET(modem, &efds); 8589448Samurai if (qlen > 0) { 8597001Samurai FD_SET(modem, &wfds); 8607001Samurai } 8617001Samurai } 86223598Sache if (server >= 0) { 86323598Sache if (server + 1 > nfds) 86423598Sache nfds = server + 1; 86523598Sache FD_SET(server, &rfds); 86623598Sache } 8676059Samurai 8686059Samurai /* *** IMPORTANT *** 8696059Samurai * 8706059Samurai * CPU is serviced every TICKUNIT micro seconds. 8716059Samurai * This value must be chosen with great care. If this values is 8726059Samurai * too big, it results loss of characters from modem and poor responce. 8736059Samurai * If this values is too small, ppp process eats many CPU time. 8746059Samurai */ 8756735Samurai#ifndef SIGALRM 8766059Samurai usleep(TICKUNIT); 8776059Samurai TimerService(); 87823840Sbrian#else 87923840Sbrian handle_signals(); 8806735Samurai#endif 88110877Sbde 88210877Sbde /* If there are aren't many packets queued, look for some more. */ 88323598Sache if (qlen < 20 && tun_in >= 0) { 88423598Sache if (tun_in + 1 > nfds) 88523598Sache nfds = tun_in + 1; 88610877Sbde FD_SET(tun_in, &rfds); 88723598Sache } 88810877Sbde 88923598Sache if (netfd >= 0) { 89023598Sache if (netfd + 1 > nfds) 89123598Sache nfds = netfd + 1; 8926059Samurai FD_SET(netfd, &rfds); 8936059Samurai FD_SET(netfd, &efds); 8946059Samurai } 8957001Samurai 8966735Samurai#ifndef SIGALRM 8976059Samurai /* 8987001Samurai * Normally, select() will not block because modem is writable. 8997001Samurai * In AUTO mode, select will block until we find packet from tun 9006059Samurai */ 9016059Samurai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 90223598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9036735Samurai#else 9048857Srgrimes /* 9057001Samurai * When SIGALRM timer is running, a select function will be 9068857Srgrimes * return -1 and EINTR after a Time Service signal hundler 90711336Samurai * is done. If the redial timer is not running and we are 90811336Samurai * trying to dial, poll with a 0 value timer. 9097001Samurai */ 91011336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 91123598Sache i = select(nfds, &rfds, &wfds, &efds, tp); 9126735Samurai#endif 91322074Sbrian 9147001Samurai if ( i == 0 ) { 9157001Samurai continue; 9166059Samurai } 9176735Samurai 9187001Samurai if ( i < 0 ) { 9197001Samurai if ( errno == EINTR ) { 92023840Sbrian handle_signals(); 92123840Sbrian continue; 9227001Samurai } 9237001Samurai perror("select"); 9247001Samurai break; 9258857Srgrimes } 9267001Samurai 92723598Sache if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 9286059Samurai logprintf("Exception detected.\n"); 9296059Samurai break; 9306059Samurai } 9316059Samurai 93223598Sache if (server >= 0 && FD_ISSET(server, &rfds)) { 93324753Sache LogPrintf(LOG_PHASE_BIT, "connected to client.\n"); 9346059Samurai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 93524753Sache if (wfd < 0) { 93624753Sache perror("accept"); 93724753Sache continue; 93824753Sache } 93923598Sache if (netfd >= 0) { 9406059Samurai write(wfd, "already in use.\n", 16); 9416059Samurai close(wfd); 9426059Samurai continue; 9436059Samurai } else 9446059Samurai netfd = wfd; 94524753Sache if (dup2(netfd, 1) < 0) { 9466059Samurai perror("dup2"); 94724753Sache close(netfd); 94824753Sache netfd = -1; 94924753Sache continue; 95024753Sache } 9516059Samurai mode |= MODE_INTER; 9526059Samurai Greetings(); 9536764Samurai switch ( LocalAuthInit() ) { 9546764Samurai case NOT_FOUND: 9556764Samurai fprintf(stdout,LAUTH_M1); 9566764Samurai fprintf(stdout,LAUTH_M2); 9576764Samurai fflush(stdout); 9586764Samurai /* Fall down */ 9596764Samurai case VALID: 9606764Samurai VarLocalAuth = LOCAL_AUTH; 9616764Samurai break; 9626764Samurai default: 9636764Samurai break; 9646764Samurai } 9656059Samurai (void) IsInteractive(); 96625630Sbrian Prompt(); 9676059Samurai } 9686059Samurai 96923598Sache if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 97010858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 9716059Samurai /* something to read from tty */ 9726059Samurai ReadTty(); 9736059Samurai } 97423598Sache if (modem >= 0) { 9756059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 9766059Samurai ModemStartOutput(modem); 9776059Samurai } 9786059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 9796735Samurai if (LcpFsm.state <= ST_CLOSED) 9806735Samurai usleep(10000); 9816059Samurai n = read(modem, rbuff, sizeof(rbuff)); 9826059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 9836059Samurai DownConnection(); 9846059Samurai } else 9856059Samurai LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 9866059Samurai 9876059Samurai if (LcpFsm.state <= ST_CLOSED) { 9886059Samurai /* 9896059Samurai * In dedicated mode, we just discard input until LCP is started. 9906059Samurai */ 9916059Samurai if (!(mode & MODE_DEDICATED)) { 9926059Samurai cp = HdlcDetect(rbuff, n); 9936059Samurai if (cp) { 9946059Samurai /* 9956059Samurai * LCP packet is detected. Turn ourselves into packet mode. 9966059Samurai */ 9976059Samurai if (cp != rbuff) { 9986059Samurai write(1, rbuff, cp - rbuff); 9996059Samurai write(1, "\r\n", 2); 10006059Samurai } 10016059Samurai PacketMode(); 10026059Samurai } else 10036059Samurai write(1, rbuff, n); 10046059Samurai } 10056059Samurai } else { 10066059Samurai if (n > 0) 10076059Samurai AsyncInput(rbuff, n); 10086059Samurai } 10096059Samurai } 10106059Samurai } 10117001Samurai 101223598Sache if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 10136059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 10146059Samurai if (n < 0) { 10156059Samurai perror("read from tun"); 10166059Samurai continue; 10176059Samurai } 10186059Samurai /* 10196059Samurai * Process on-demand dialup. Output packets are queued within tunnel 10206059Samurai * device until IPCP is opened. 10216059Samurai */ 10226059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 10237001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 10246059Samurai if (pri >= 0) { 102520365Sjkh if (mode & MODE_ALIAS) { 102626031Sbrian PacketAliasOut(rbuff, sizeof rbuff); 102720666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 102820365Sjkh } 10296059Samurai IpEnqueue(pri, rbuff, n); 103020365Sjkh dial_up = TRUE; /* XXX */ 10316059Samurai } 10326059Samurai continue; 10336059Samurai } 10347001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 103520365Sjkh if (pri >= 0) { 103620365Sjkh if (mode & MODE_ALIAS) { 103726031Sbrian PacketAliasOut(rbuff, sizeof rbuff); 103820666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 103920365Sjkh } 10406059Samurai IpEnqueue(pri, rbuff, n); 104120365Sjkh } 10426059Samurai } 10436059Samurai } 10446059Samurai logprintf("job done.\n"); 10456059Samurai} 1046