main.c revision 20813
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 * 2020813Sjkh * $Id: main.c,v 1.25 1996/12/19 00:41:42 nate 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> 316059Samurai#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" 466059Samurai#include "vars.h" 476735Samurai#include "auth.h" 487001Samurai#include "filter.h" 4913389Sphk#include "systems.h" 5013389Sphk#include "ip.h" 5120365Sjkh#include "alias.h" 526059Samurai 536764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 549410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n" 556764Samurai 566735Samurai#ifndef O_NONBLOCK 576735Samurai#ifdef O_NDELAY 586735Samurai#define O_NONBLOCK O_NDELAY 596735Samurai#endif 606735Samurai#endif 616735Samurai 626059Samuraiextern void VjInit(), AsyncInit(); 636059Samuraiextern void AsyncInput(), IpOutput(); 646059Samuraiextern int SelectSystem(); 656059Samurai 666059Samuraiextern void DecodeCommand(), Prompt(); 6718885Sjkhextern int aft_cmd; 686059Samuraiextern int IsInteractive(); 696059Samuraiextern struct in_addr ifnetmask; 706059Samuraistatic void DoLoop(void); 7110528Samuraistatic void TerminalStop(); 726059Samurai 736059Samuraistatic struct termios oldtio; /* Original tty mode */ 746059Samuraistatic struct termios comtio; /* Command level tty mode */ 7514418Sacheint TermMode; 7613379Sphkstatic int server; 7720813Sjkhstatic pid_t BGPid = 0; 786059Samuraistruct sockaddr_in ifsin; 7911336Samuraichar pid_filename[128]; 806059Samurai 816059Samuraistatic void 826059SamuraiTtyInit() 836059Samurai{ 846059Samurai struct termios newtio; 856059Samurai int stat; 866059Samurai 876059Samurai stat = fcntl(0, F_GETFL, 0); 886059Samurai stat |= O_NONBLOCK; 896059Samurai fcntl(0, F_SETFL, stat); 906059Samurai newtio = oldtio; 916059Samurai newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 926059Samurai newtio.c_iflag = 0; 936059Samurai newtio.c_oflag &= ~OPOST; 946059Samurai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 956059Samurai newtio.c_cc[VINTR] = _POSIX_VDISABLE; 966059Samurai newtio.c_cc[VMIN] = 1; 976059Samurai newtio.c_cc[VTIME] = 0; 986059Samurai newtio.c_cflag |= CS8; 996735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1006059Samurai comtio = newtio; 1016059Samurai} 1026059Samurai 1036059Samurai/* 1046059Samurai * Set tty into command mode. We allow canonical input and echo processing. 1056059Samurai */ 10610528Samuraivoid 10710528SamuraiTtyCommandMode(prompt) 10810528Samuraiint prompt; 1096059Samurai{ 1106059Samurai struct termios newtio; 1116059Samurai int stat; 1126059Samurai 1136059Samurai if (!(mode & MODE_INTER)) 1146059Samurai return; 1156735Samurai tcgetattr(0, &newtio); 11610528Samurai newtio.c_lflag |= (ECHO|ISIG|ICANON); 1176059Samurai newtio.c_iflag = oldtio.c_iflag; 1186059Samurai newtio.c_oflag |= OPOST; 1196735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1206059Samurai stat = fcntl(0, F_GETFL, 0); 1216059Samurai stat |= O_NONBLOCK; 1226059Samurai fcntl(0, F_SETFL, stat); 1236059Samurai TermMode = 0; 12410528Samurai if(prompt) Prompt(0); 1256059Samurai} 1266059Samurai 1276059Samurai/* 1286059Samurai * Set tty into terminal mode which is used while we invoke term command. 1296059Samurai */ 1306059Samuraivoid 1316059SamuraiTtyTermMode() 1326059Samurai{ 1336059Samurai int stat; 1346059Samurai 1356735Samurai tcsetattr(0, TCSADRAIN, &comtio); 1366059Samurai stat = fcntl(0, F_GETFL, 0); 1376059Samurai stat &= ~O_NONBLOCK; 1386059Samurai fcntl(0, F_SETFL, stat); 1396059Samurai TermMode = 1; 1406059Samurai} 1416059Samurai 1426059Samuraivoid 14310528SamuraiTtyOldMode() 1446059Samurai{ 1456059Samurai int stat; 1466059Samurai 1476059Samurai stat = fcntl(0, F_GETFL, 0); 1486059Samurai stat &= ~O_NONBLOCK; 1496059Samurai fcntl(0, F_SETFL, stat); 1506735Samurai tcsetattr(0, TCSANOW, &oldtio); 15110528Samurai} 15210528Samurai 15310528Samuraivoid 15410528SamuraiCleanup(excode) 15510528Samuraiint excode; 15610528Samurai{ 15710528Samurai 15810528Samurai OsLinkdown(); 1596059Samurai OsCloseLink(1); 1606059Samurai sleep(1); 16111336Samurai if (mode & MODE_AUTO) { 1626059Samurai DeleteIfRoutes(1); 16320813Sjkh } 16420813Sjkh if (mode & (MODE_AUTO | MODE_BACKGROUND)) { 16511336Samurai unlink(pid_filename); 16611336Samurai } 1676059Samurai OsInterfaceDown(1); 16815738Sphk LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n"); 1696059Samurai LogClose(); 1706059Samurai if (server > 0) 1716059Samurai close(server); 17210528Samurai TtyOldMode(); 1736059Samurai 1746059Samurai exit(excode); 1756059Samurai} 1766059Samurai 1776059Samuraistatic void 17814930SacheHangup(signo) 17914930Sacheint signo; 1806059Samurai{ 18117044Sache if (signo == SIGSEGV) { 18217044Sache LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 18317044Sache LogClose(); 18417044Sache abort(); 18517044Sache } 18620813Sjkh if (BGPid) { 18720813Sjkh kill (BGPid, SIGHUP); 18820813Sjkh exit (EX_HANGUP); 18920813Sjkh } 19020813Sjkh else { 19120813Sjkh LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 19220813Sjkh Cleanup(EX_HANGUP); 19320813Sjkh } 1946059Samurai} 1956059Samurai 1966059Samuraistatic void 19714930SacheCloseSession(signo) 19814930Sacheint signo; 1996059Samurai{ 20020813Sjkh if (BGPid) { 20120813Sjkh kill (BGPid, SIGINT); 20220813Sjkh exit (EX_TERM); 20320813Sjkh } 20420813Sjkh else { 20520813Sjkh LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 20620813Sjkh LcpClose(); 20720813Sjkh Cleanup(EX_TERM); 20820813Sjkh } 2096059Samurai} 2106059Samurai 21110528Samuraistatic void 21210528SamuraiTerminalCont() 21310528Samurai{ 21410528Samurai (void)signal(SIGCONT, SIG_DFL); 21510528Samurai (void)signal(SIGTSTP, TerminalStop); 21610528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 21710528Samurai} 21810528Samurai 21910528Samuraistatic void 22010528SamuraiTerminalStop(signo) 22110528Samuraiint signo; 22210528Samurai{ 22310528Samurai (void)signal(SIGCONT, TerminalCont); 22410528Samurai TtyOldMode(); 22510528Samurai signal(SIGTSTP, SIG_DFL); 22610528Samurai kill(getpid(), signo); 22710528Samurai} 22810528Samurai 22910528Samurai 2306059Samuraivoid 2316059SamuraiUsage() 2326059Samurai{ 23320120Snate fprintf(stderr, 23420813Sjkh "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2356059Samurai exit(EX_START); 2366059Samurai} 2376059Samurai 2386059Samuraivoid 2396059SamuraiProcessArgs(int argc, char **argv) 2406059Samurai{ 2416059Samurai int optc; 2426059Samurai char *cp; 2436059Samurai 2446059Samurai optc = 0; 2456059Samurai while (argc > 0 && **argv == '-') { 2466059Samurai cp = *argv + 1; 2476059Samurai if (strcmp(cp, "auto") == 0) 2486059Samurai mode |= MODE_AUTO; 24920813Sjkh else if (strcmp(cp, "background") == 0) 25020813Sjkh mode |= MODE_BACKGROUND; 2516059Samurai else if (strcmp(cp, "direct") == 0) 2526059Samurai mode |= MODE_DIRECT; 2536059Samurai else if (strcmp(cp, "dedicated") == 0) 2546059Samurai mode |= MODE_DEDICATED; 25520120Snate else if (strcmp(cp, "ddial") == 0) 25620120Snate mode |= MODE_DDIAL|MODE_AUTO; 25720365Sjkh else if (strcmp(cp, "alias") == 0) { 25820365Sjkh mode |= MODE_ALIAS; 25920365Sjkh optc--; /* this option isn't exclusive */ 26020365Sjkh } 2616059Samurai else 2626059Samurai Usage(); 2636059Samurai optc++; 2646059Samurai argv++; argc--; 2656059Samurai } 2666059Samurai if (argc > 1) { 2676059Samurai fprintf(stderr, "specify only one system label.\n"); 2686059Samurai exit(EX_START); 2696059Samurai } 2706059Samurai if (argc == 1) dstsystem = *argv; 2716059Samurai 2726059Samurai if (optc > 1) { 2736059Samurai fprintf(stderr, "specify only one mode.\n"); 2746059Samurai exit(EX_START); 2756059Samurai } 2766059Samurai} 2776059Samurai 2786059Samuraistatic void 2796059SamuraiGreetings() 2806059Samurai{ 2816059Samurai printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 2826059Samurai fflush(stdout); 2836059Samurai} 2846059Samurai 2856059Samuraivoid 2866059Samuraimain(argc, argv) 2876059Samuraiint argc; 2886059Samuraichar **argv; 2896059Samurai{ 2906059Samurai int tunno; 2916059Samurai 2926059Samurai argc--; argv++; 2936059Samurai 2946059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 2956059Samurai netfd = -1; 2966059Samurai ProcessArgs(argc, argv); 2976059Samurai Greetings(); 2986059Samurai GetUid(); 2996059Samurai IpcpDefAddress(); 30020365Sjkh InitAlias(); 3016059Samurai 3026059Samurai if (SelectSystem("default", CONFFILE) < 0) { 3036059Samurai fprintf(stderr, "Warning: No default entry is given in config file.\n"); 3046059Samurai } 3056059Samurai 3066059Samurai if (LogOpen()) 3076059Samurai exit(EX_START); 3086059Samurai 3096735Samurai switch ( LocalAuthInit() ) { 3106735Samurai case NOT_FOUND: 3116764Samurai fprintf(stderr,LAUTH_M1); 3126764Samurai fprintf(stderr,LAUTH_M2); 3136764Samurai fflush (stderr); 3146764Samurai /* Fall down */ 3156764Samurai case VALID: 3166735Samurai VarLocalAuth = LOCAL_AUTH; 3176735Samurai break; 3186735Samurai default: 3196735Samurai break; 3206735Samurai } 3216735Samurai 3226059Samurai if (OpenTunnel(&tunno) < 0) { 3236059Samurai perror("open_tun"); 3246059Samurai exit(EX_START); 3256059Samurai } 3266059Samurai 32720813Sjkh if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND)) 3286059Samurai mode &= ~MODE_INTER; 3296059Samurai if (mode & MODE_INTER) { 3306059Samurai printf("Interactive mode\n"); 3316059Samurai netfd = 0; 3326059Samurai } else if (mode & MODE_AUTO) { 33320120Snate printf("Automatic Dialer mode\n"); 3346059Samurai if (dstsystem == NULL) { 33520120Snate fprintf(stderr, 33620120Snate "Destination system must be specified in auto or ddial mode.\n"); 3376059Samurai exit(EX_START); 3386059Samurai } 33920813Sjkh } else if (mode & MODE_BACKGROUND) { 34020813Sjkh printf("Background mode\n"); 34120813Sjkh if (dstsystem == NULL) { 34220813Sjkh fprintf(stderr, "Destination system must be specified in background mode.\n"); 34320813Sjkh exit(EX_START); 34420813Sjkh } 3456059Samurai } 3466059Samurai 3476735Samurai tcgetattr(0, &oldtio); /* Save original tty mode */ 3486059Samurai 3496059Samurai signal(SIGHUP, Hangup); 3506059Samurai signal(SIGTERM, CloseSession); 3516059Samurai signal(SIGINT, CloseSession); 35210528Samurai signal(SIGQUIT, CloseSession); 3536735Samurai#ifdef SIGSEGV 3546059Samurai signal(SIGSEGV, Hangup); 3556735Samurai#endif 3566735Samurai#ifdef SIGPIPE 3576735Samurai signal(SIGPIPE, Hangup); 3586735Samurai#endif 3596735Samurai#ifdef SIGALRM 3606735Samurai signal(SIGALRM, SIG_IGN); 3616735Samurai#endif 36210528Samurai if(mode & MODE_INTER) 36310528Samurai { 36410528Samurai#ifdef SIGTSTP 36510528Samurai signal(SIGTSTP, TerminalStop); 36610528Samurai#endif 36710528Samurai#ifdef SIGTTIN 36810528Samurai signal(SIGTTIN, TerminalStop); 36910528Samurai#endif 37010528Samurai#ifdef SIGTTOU 37110528Samurai signal(SIGTTOU, SIG_IGN); 37210528Samurai#endif 37310528Samurai } 3746059Samurai 3756059Samurai if (dstsystem) { 3766059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 3776059Samurai fprintf(stderr, "Destination system not found in conf file.\n"); 3786059Samurai Cleanup(EX_START); 3796059Samurai } 3806059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 38120120Snate fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n"); 3826059Samurai Cleanup(EX_START); 3836059Samurai } 3846059Samurai } 3856059Samurai if (mode & MODE_DIRECT) 3866059Samurai printf("Packet mode enabled.\n"); 3876059Samurai 3886059Samurai#ifdef notdef 3896059Samurai if (mode & MODE_AUTO) { 3906059Samurai OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 3916059Samurai } 3926059Samurai#endif 3936059Samurai 3946059Samurai if (!(mode & MODE_INTER)) { 39520813Sjkh int port = SERVER_PORT + tunno; 39620813Sjkh if (mode & MODE_BACKGROUND) { 39720813Sjkh if (pipe (BGFiledes)) { 39820813Sjkh perror("pipe"); 39920813Sjkh Cleanup(EX_SOCK); 40020813Sjkh } 40120813Sjkh server = -1; 4026059Samurai } 40320813Sjkh else { 40420813Sjkh /* 40520813Sjkh * Create server socket and listen at there. 40620813Sjkh */ 40720813Sjkh server = socket(PF_INET, SOCK_STREAM, 0); 40820813Sjkh if (server < 0) { 40920813Sjkh perror("socket"); 41020813Sjkh Cleanup(EX_SOCK); 41120813Sjkh } 41220813Sjkh ifsin.sin_family = AF_INET; 41320813Sjkh ifsin.sin_addr.s_addr = INADDR_ANY; 41420813Sjkh ifsin.sin_port = htons(port); 41520813Sjkh if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 41620813Sjkh perror("bind"); 41720813Sjkh if (errno == EADDRINUSE) 41820813Sjkh fprintf(stderr, "Wait for a while, then try again.\n"); 41920813Sjkh Cleanup(EX_SOCK); 42020813Sjkh } 42120813Sjkh listen(server, 5); 4226059Samurai } 4236059Samurai 4246059Samurai DupLog(); 4256059Samurai if (!(mode & MODE_DIRECT)) { 42611336Samurai int fd; 42711336Samurai char pid[32]; 42820813Sjkh pid_t bgpid; 42911336Samurai 43020813Sjkh bgpid = fork (); 43120813Sjkh if (bgpid == -1) { 43220813Sjkh perror ("fork"); 43320813Sjkh Cleanup (EX_SOCK); 43420813Sjkh } 43520813Sjkh if (bgpid) { 43620813Sjkh char c = EX_NORMAL; 43711336Samurai 43820813Sjkh if (mode & MODE_BACKGROUND) { 43920813Sjkh /* Wait for our child to close its pipe before we exit. */ 44020813Sjkh BGPid = bgpid; 44120813Sjkh read (BGFiledes[0], &c, 1); 44220813Sjkh if (c == EX_NORMAL) 44320813Sjkh LogPrintf (LOG_CHAT, "PPP enabled.\n"); 44420813Sjkh } 44520813Sjkh exit(c); 44620813Sjkh } 44720813Sjkh 44820813Sjkh snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid", 44920813Sjkh _PATH_VARRUN, tunno); 45011336Samurai unlink(pid_filename); 45120120Snate sprintf(pid, "%d\n", (int)getpid()); 45211336Samurai 45311336Samurai if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1) 45411336Samurai { 45511336Samurai write(fd, pid, strlen(pid)); 45611336Samurai close(fd); 45711336Samurai } 4586059Samurai } 45920813Sjkh if (server > 0) 46020813Sjkh LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 4616059Samurai#ifdef DOTTYINIT 4626735Samurai if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 4636059Samurai#else 4646059Samurai if (mode & MODE_DIRECT) { 4656059Samurai#endif 4666059Samurai TtyInit(); 4676059Samurai } else { 46814436Sache int fd; 46914436Sache 4706059Samurai setsid(); /* detach control tty */ 47114436Sache if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 47214436Sache (void)dup2(fd, STDIN_FILENO); 47314436Sache (void)dup2(fd, STDOUT_FILENO); 47414436Sache (void)dup2(fd, STDERR_FILENO); 47514436Sache if (fd > 2) 47614436Sache (void)close (fd); 47714436Sache } 4786059Samurai } 4796059Samurai } else { 4806059Samurai server = -1; 4816059Samurai TtyInit(); 48210528Samurai TtyCommandMode(1); 4836059Samurai } 48415738Sphk LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 4856059Samurai 4866059Samurai 4876059Samurai do 4886059Samurai DoLoop(); 4896059Samurai while (mode & MODE_DEDICATED); 4906059Samurai 4916059Samurai Cleanup(EX_DONE); 4926059Samurai} 4936059Samurai 4946059Samurai/* 49520813Sjkh * Turn into packet mode, where we speak PPP. 4966059Samurai */ 4976059Samuraivoid 4986059SamuraiPacketMode() 4996059Samurai{ 5006059Samurai if (RawModem(modem) < 0) { 5016059Samurai fprintf(stderr, "Not connected.\r\n"); 5026059Samurai return; 5036059Samurai } 5046059Samurai 5056059Samurai AsyncInit(); 5066059Samurai VjInit(); 5076059Samurai LcpInit(); 5086059Samurai IpcpInit(); 5096059Samurai CcpInit(); 5106059Samurai LcpUp(); 5116059Samurai 5126059Samurai if (mode & (MODE_DIRECT|MODE_DEDICATED)) 5136059Samurai LcpOpen(OPEN_ACTIVE); 5146059Samurai else 5156059Samurai LcpOpen(VarOpenMode); 5166059Samurai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 51710528Samurai TtyCommandMode(1); 5186059Samurai fprintf(stderr, "Packet mode.\r\n"); 51918885Sjkh aft_cmd = 1; 5206059Samurai } 5216059Samurai} 5226059Samurai 5236059Samuraistatic void 5246059SamuraiShowHelp() 5256059Samurai{ 52610528Samurai fprintf(stderr, "The following commands are available:\r\n"); 5276059Samurai fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 52814418Sache fprintf(stderr, " ~-\tDecrease log level\r\n"); 52914418Sache fprintf(stderr, " ~+\tIncrease log level\r\n"); 5306059Samurai fprintf(stderr, " ~.\tTerminate program\r\n"); 53114418Sache fprintf(stderr, " ~?\tThis help\r\n"); 5326059Samurai} 5336059Samurai 5346059Samuraistatic void 5356059SamuraiReadTty() 5366059Samurai{ 5376059Samurai int n; 5386059Samurai char ch; 5396059Samurai static int ttystate; 5406059Samurai#define MAXLINESIZE 200 5416059Samurai char linebuff[MAXLINESIZE]; 5426059Samurai 5436059Samurai#ifdef DEBUG 5446059Samurai logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 5456059Samurai#endif 5466059Samurai if (!TermMode) { 5476059Samurai n = read(netfd, linebuff, sizeof(linebuff)-1); 54818885Sjkh aft_cmd = 1; 5496735Samurai if (n > 0) { 5506059Samurai DecodeCommand(linebuff, n, 1); 5516735Samurai } else { 5526059Samurai#ifdef DEBUG 5536059Samurai logprintf("connection closed.\n"); 5546059Samurai#endif 5556059Samurai close(netfd); 5566059Samurai netfd = -1; 5576059Samurai mode &= ~MODE_INTER; 5586059Samurai } 5596059Samurai return; 5606059Samurai } 5616059Samurai 5626059Samurai /* 5636059Samurai * We are in terminal mode, decode special sequences 5646059Samurai */ 5656059Samurai n = read(0, &ch, 1); 5666059Samurai#ifdef DEBUG 5676059Samurai logprintf("got %d bytes\n", n); 5686059Samurai#endif 5696059Samurai 5706059Samurai if (n > 0) { 5716059Samurai switch (ttystate) { 5726059Samurai case 0: 5736059Samurai if (ch == '~') 5746059Samurai ttystate++; 5756059Samurai else 5766059Samurai write(modem, &ch, n); 5776059Samurai break; 5786059Samurai case 1: 5796059Samurai switch (ch) { 5806059Samurai case '?': 5816059Samurai ShowHelp(); 5826059Samurai break; 5836059Samurai case '-': 5846059Samurai if (loglevel > 0) { 5856059Samurai loglevel--; 5866059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 5876059Samurai } 5886059Samurai break; 5896059Samurai case '+': 5906059Samurai loglevel++; 5916059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 5926059Samurai break; 5936059Samurai#ifdef DEBUG 5946059Samurai case 'm': 5956059Samurai ShowMemMap(); 5966059Samurai break; 5976059Samurai#endif 5986059Samurai case 'p': 5996059Samurai /* 6006059Samurai * XXX: Should check carrier. 6016059Samurai */ 6026059Samurai if (LcpFsm.state <= ST_CLOSED) { 6036059Samurai VarOpenMode = OPEN_ACTIVE; 6046059Samurai PacketMode(); 6056059Samurai } 6066059Samurai break; 6076059Samurai#ifdef DEBUG 6086059Samurai case 't': 6096059Samurai ShowTimers(); 6106059Samurai break; 6116059Samurai#endif 6126059Samurai case '.': 6136059Samurai TermMode = 1; 61410528Samurai TtyCommandMode(1); 6156059Samurai break; 6166059Samurai default: 6176059Samurai if (write(modem, &ch, n) < 0) 6186059Samurai fprintf(stderr, "err in write.\r\n"); 6196059Samurai break; 6206059Samurai } 6216059Samurai ttystate = 0; 6226059Samurai break; 6236059Samurai } 6246059Samurai } 6256059Samurai} 6266059Samurai 6276059Samurai 6286059Samurai/* 6296059Samurai * Here, we'll try to detect HDLC frame 6306059Samurai */ 6316059Samurai 6326059Samuraistatic char *FrameHeaders[] = { 6336735Samurai "\176\377\003\300\041", 6346735Samurai "\176\377\175\043\300\041", 6356735Samurai "\176\177\175\043\100\041", 6366735Samurai "\176\175\337\175\043\300\041", 6376735Samurai "\176\175\137\175\043\100\041", 6386059Samurai NULL, 6396059Samurai}; 6406059Samurai 6416059Samuraiu_char * 6426059SamuraiHdlcDetect(cp, n) 6436059Samuraiu_char *cp; 6446059Samuraiint n; 6456059Samurai{ 6466735Samurai char *ptr, *fp, **hp; 6476059Samurai 6486059Samurai cp[n] = '\0'; /* be sure to null terminated */ 6496059Samurai ptr = NULL; 6506059Samurai for (hp = FrameHeaders; *hp; hp++) { 6516735Samurai fp = *hp; 6526735Samurai if (DEV_IS_SYNC) 6536735Samurai fp++; 65413389Sphk ptr = strstr((char *)cp, fp); 65513389Sphk if (ptr) 6566059Samurai break; 6576059Samurai } 6586059Samurai return((u_char *)ptr); 6596059Samurai} 6606059Samurai 6616059Samuraistatic struct pppTimer RedialTimer; 6626059Samurai 6636059Samuraistatic void 6646059SamuraiRedialTimeout() 6656059Samurai{ 6666059Samurai StopTimer(&RedialTimer); 66715738Sphk LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 6686059Samurai} 6696059Samurai 6706059Samuraistatic void 6716059SamuraiStartRedialTimer() 6726059Samurai{ 6736059Samurai StopTimer(&RedialTimer); 67411336Samurai 67511336Samurai if (VarRedialTimeout) { 67615738Sphk LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n"); 67711336Samurai RedialTimer.state = TIMER_STOPPED; 67811336Samurai 67911336Samurai if (VarRedialTimeout > 0) 68011336Samurai RedialTimer.load = VarRedialTimeout * SECTICKS; 68111336Samurai else 68211336Samurai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 68311336Samurai 68411336Samurai RedialTimer.func = RedialTimeout; 68511336Samurai StartTimer(&RedialTimer); 68611336Samurai } 6876059Samurai} 6886059Samurai 6896059Samurai 6906059Samuraistatic void 6916059SamuraiDoLoop() 6926059Samurai{ 6936059Samurai fd_set rfds, wfds, efds; 6946059Samurai int pri, i, n, wfd; 6956059Samurai struct sockaddr_in hisaddr; 6966059Samurai struct timeval timeout, *tp; 6976059Samurai int ssize = sizeof(hisaddr); 6986059Samurai u_char *cp; 6996059Samurai u_char rbuff[MAX_MRU]; 7007001Samurai int dial_up; 70111336Samurai int tries; 7029448Samurai int qlen; 70310528Samurai pid_t pgroup; 7046059Samurai 70510528Samurai pgroup = getpgrp(); 70610528Samurai 7076059Samurai if (mode & MODE_DIRECT) { 7086059Samurai modem = OpenModem(mode); 70915738Sphk LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 71018885Sjkh fflush(stderr); 7116059Samurai PacketMode(); 7126059Samurai } else if (mode & MODE_DEDICATED) { 7136059Samurai if (!modem) 7146059Samurai modem = OpenModem(mode); 7156059Samurai } 7166059Samurai 7176059Samurai fflush(stdout); 7186059Samurai 7197001Samurai timeout.tv_sec = 0; 7206059Samurai timeout.tv_usec = 0; 7216059Samurai 7227001Samurai dial_up = FALSE; /* XXXX */ 72311336Samurai tries = 0; 7246059Samurai for (;;) { 7256059Samurai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 7267001Samurai 72720120Snate /* 72820120Snate * If the link is down and we're in DDIAL mode, bring it back 72920120Snate * up. 73020120Snate */ 73120120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 73220120Snate dial_up = TRUE; 73320120Snate 7347001Samurai /* 7357001Samurai * If Ip packet for output is enqueued and require dial up, 7367001Samurai * Just do it! 7377001Samurai */ 7387001Samurai if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */ 7397001Samurai#ifdef DEBUG 7407001Samurai logprintf("going to dial: modem = %d\n", modem); 7417001Samurai#endif 74211336Samurai modem = OpenModem(mode); 74311336Samurai if (modem < 0) { 74411336Samurai modem = 0; /* Set intial value for next OpenModem */ 74511336Samurai StartRedialTimer(); 74611336Samurai } else { 74711336Samurai tries++; 74815738Sphk LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 74911336Samurai if (DialModem()) { 75011336Samurai sleep(1); /* little pause to allow peer starts */ 75111336Samurai ModemTimeout(); 75211336Samurai PacketMode(); 75311336Samurai dial_up = FALSE; 75411336Samurai tries = 0; 75511336Samurai } else { 75611336Samurai CloseModem(); 75711336Samurai /* Dial failed. Keep quite during redial wait period. */ 75811336Samurai StartRedialTimer(); 75911336Samurai 76011336Samurai if (VarDialTries && tries >= VarDialTries) { 76111336Samurai dial_up = FALSE; 76211336Samurai tries = 0; 76311336Samurai } 76411336Samurai } 76511336Samurai } 7667001Samurai } 7679448Samurai qlen = ModemQlen(); 76813733Sdfr 76913733Sdfr if (qlen == 0) { 77013733Sdfr IpStartOutput(); 77113733Sdfr qlen = ModemQlen(); 77213733Sdfr } 77313733Sdfr 7747001Samurai if (modem) { 7757001Samurai FD_SET(modem, &rfds); 7767001Samurai FD_SET(modem, &efds); 7779448Samurai if (qlen > 0) { 7787001Samurai FD_SET(modem, &wfds); 7797001Samurai } 7807001Samurai } 7816059Samurai if (server > 0) FD_SET(server, &rfds); 7826059Samurai 7836059Samurai /* *** IMPORTANT *** 7846059Samurai * 7856059Samurai * CPU is serviced every TICKUNIT micro seconds. 7866059Samurai * This value must be chosen with great care. If this values is 7876059Samurai * too big, it results loss of characters from modem and poor responce. 7886059Samurai * If this values is too small, ppp process eats many CPU time. 7896059Samurai */ 7906735Samurai#ifndef SIGALRM 7916059Samurai usleep(TICKUNIT); 7926059Samurai TimerService(); 7936735Samurai#endif 79410877Sbde 79510877Sbde /* If there are aren't many packets queued, look for some more. */ 79610877Sbde if (qlen < 20) 79710877Sbde FD_SET(tun_in, &rfds); 79810877Sbde 7996059Samurai if (netfd > -1) { 8006059Samurai FD_SET(netfd, &rfds); 8016059Samurai FD_SET(netfd, &efds); 8026059Samurai } 8037001Samurai 8046735Samurai#ifndef SIGALRM 8056059Samurai /* 8067001Samurai * Normally, select() will not block because modem is writable. 8077001Samurai * In AUTO mode, select will block until we find packet from tun 8086059Samurai */ 8096059Samurai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 8106059Samurai i = select(tun_in+10, &rfds, &wfds, &efds, tp); 8116735Samurai#else 8128857Srgrimes /* 8137001Samurai * When SIGALRM timer is running, a select function will be 8148857Srgrimes * return -1 and EINTR after a Time Service signal hundler 81511336Samurai * is done. If the redial timer is not running and we are 81611336Samurai * trying to dial, poll with a 0 value timer. 8177001Samurai */ 81811336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 81911336Samurai i = select(tun_in+10, &rfds, &wfds, &efds, tp); 8206735Samurai#endif 8217001Samurai if ( i == 0 ) { 8227001Samurai continue; 8236059Samurai } 8246735Samurai 8257001Samurai if ( i < 0 ) { 8267001Samurai if ( errno == EINTR ) { 82711336Samurai continue; /* Got SIGALRM, Do check a queue for dialing */ 8287001Samurai } 8297001Samurai perror("select"); 8307001Samurai break; 8318857Srgrimes } 8327001Samurai 8336059Samurai if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) { 8346059Samurai logprintf("Exception detected.\n"); 8356059Samurai break; 8366059Samurai } 8376059Samurai 8386059Samurai if (server > 0 && FD_ISSET(server, &rfds)) { 8396059Samurai#ifdef DEBUG 8406059Samurai logprintf("connected to client.\n"); 8416059Samurai#endif 8426059Samurai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 8436059Samurai if (netfd > 0) { 8446059Samurai write(wfd, "already in use.\n", 16); 8456059Samurai close(wfd); 8466059Samurai continue; 8476059Samurai } else 8486059Samurai netfd = wfd; 8496059Samurai if (dup2(netfd, 1) < 0) 8506059Samurai perror("dup2"); 8516059Samurai mode |= MODE_INTER; 8526059Samurai Greetings(); 8536764Samurai switch ( LocalAuthInit() ) { 8546764Samurai case NOT_FOUND: 8556764Samurai fprintf(stdout,LAUTH_M1); 8566764Samurai fprintf(stdout,LAUTH_M2); 8576764Samurai fflush(stdout); 8586764Samurai /* Fall down */ 8596764Samurai case VALID: 8606764Samurai VarLocalAuth = LOCAL_AUTH; 8616764Samurai break; 8626764Samurai default: 8636764Samurai break; 8646764Samurai } 8656059Samurai (void) IsInteractive(); 8666059Samurai Prompt(0); 8676059Samurai } 8686059Samurai 86910528Samurai if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) && 87010858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 8716059Samurai /* something to read from tty */ 8726059Samurai ReadTty(); 8736059Samurai } 8746059Samurai if (modem) { 8756059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 8766059Samurai ModemStartOutput(modem); 8776059Samurai } 8786059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 8796735Samurai if (LcpFsm.state <= ST_CLOSED) 8806735Samurai usleep(10000); 8816059Samurai n = read(modem, rbuff, sizeof(rbuff)); 8826059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 8836059Samurai DownConnection(); 8846059Samurai } else 8856059Samurai LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 8866059Samurai 8876059Samurai if (LcpFsm.state <= ST_CLOSED) { 8886059Samurai /* 8896059Samurai * In dedicated mode, we just discard input until LCP is started. 8906059Samurai */ 8916059Samurai if (!(mode & MODE_DEDICATED)) { 8926059Samurai cp = HdlcDetect(rbuff, n); 8936059Samurai if (cp) { 8946059Samurai /* 8956059Samurai * LCP packet is detected. Turn ourselves into packet mode. 8966059Samurai */ 8976059Samurai if (cp != rbuff) { 8986059Samurai write(1, rbuff, cp - rbuff); 8996059Samurai write(1, "\r\n", 2); 9006059Samurai } 9016059Samurai PacketMode(); 9026059Samurai#ifdef notdef 9036059Samurai AsyncInput(cp, n - (cp - rbuff)); 9046059Samurai#endif 9056059Samurai } else 9066059Samurai write(1, rbuff, n); 9076059Samurai } 9086059Samurai } else { 9096059Samurai if (n > 0) 9106059Samurai AsyncInput(rbuff, n); 9116059Samurai#ifdef notdef 9126059Samurai continue; /* THIS LINE RESULT AS POOR PERFORMANCE */ 9136059Samurai#endif 9146059Samurai } 9156059Samurai } 9166059Samurai } 9177001Samurai 9186059Samurai if (FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 9196059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 9206059Samurai if (n < 0) { 9216059Samurai perror("read from tun"); 9226059Samurai continue; 9236059Samurai } 9246059Samurai /* 9256059Samurai * Process on-demand dialup. Output packets are queued within tunnel 9266059Samurai * device until IPCP is opened. 9276059Samurai */ 9286059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 9297001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 9306059Samurai if (pri >= 0) { 93120365Sjkh if (mode & MODE_ALIAS) { 93220666Snate PacketAliasOut((struct ip *)rbuff); 93320666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 93420365Sjkh } 9356059Samurai IpEnqueue(pri, rbuff, n); 93620365Sjkh dial_up = TRUE; /* XXX */ 9376059Samurai } 9386059Samurai continue; 9396059Samurai } 9407001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 94120365Sjkh if (pri >= 0) { 94220365Sjkh if (mode & MODE_ALIAS) { 94320666Snate PacketAliasOut((struct ip *)rbuff); 94420666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 94520365Sjkh } 9466059Samurai IpEnqueue(pri, rbuff, n); 94720365Sjkh } 9486059Samurai } 9496059Samurai } 9506059Samurai logprintf("job done.\n"); 9516059Samurai} 952