main.c revision 20666
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 * 2020666Snate * $Id: main.c,v 1.24 1996/12/12 14:39:45 jkh 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; 776059Samuraistruct sockaddr_in ifsin; 7811336Samuraichar pid_filename[128]; 796059Samurai 806059Samuraistatic void 816059SamuraiTtyInit() 826059Samurai{ 836059Samurai struct termios newtio; 846059Samurai int stat; 856059Samurai 866059Samurai stat = fcntl(0, F_GETFL, 0); 876059Samurai stat |= O_NONBLOCK; 886059Samurai fcntl(0, F_SETFL, stat); 896059Samurai newtio = oldtio; 906059Samurai newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 916059Samurai newtio.c_iflag = 0; 926059Samurai newtio.c_oflag &= ~OPOST; 936059Samurai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 946059Samurai newtio.c_cc[VINTR] = _POSIX_VDISABLE; 956059Samurai newtio.c_cc[VMIN] = 1; 966059Samurai newtio.c_cc[VTIME] = 0; 976059Samurai newtio.c_cflag |= CS8; 986735Samurai tcsetattr(0, TCSADRAIN, &newtio); 996059Samurai comtio = newtio; 1006059Samurai} 1016059Samurai 1026059Samurai/* 1036059Samurai * Set tty into command mode. We allow canonical input and echo processing. 1046059Samurai */ 10510528Samuraivoid 10610528SamuraiTtyCommandMode(prompt) 10710528Samuraiint prompt; 1086059Samurai{ 1096059Samurai struct termios newtio; 1106059Samurai int stat; 1116059Samurai 1126059Samurai if (!(mode & MODE_INTER)) 1136059Samurai return; 1146735Samurai tcgetattr(0, &newtio); 11510528Samurai newtio.c_lflag |= (ECHO|ISIG|ICANON); 1166059Samurai newtio.c_iflag = oldtio.c_iflag; 1176059Samurai newtio.c_oflag |= OPOST; 1186735Samurai tcsetattr(0, TCSADRAIN, &newtio); 1196059Samurai stat = fcntl(0, F_GETFL, 0); 1206059Samurai stat |= O_NONBLOCK; 1216059Samurai fcntl(0, F_SETFL, stat); 1226059Samurai TermMode = 0; 12310528Samurai if(prompt) Prompt(0); 1246059Samurai} 1256059Samurai 1266059Samurai/* 1276059Samurai * Set tty into terminal mode which is used while we invoke term command. 1286059Samurai */ 1296059Samuraivoid 1306059SamuraiTtyTermMode() 1316059Samurai{ 1326059Samurai int stat; 1336059Samurai 1346735Samurai tcsetattr(0, TCSADRAIN, &comtio); 1356059Samurai stat = fcntl(0, F_GETFL, 0); 1366059Samurai stat &= ~O_NONBLOCK; 1376059Samurai fcntl(0, F_SETFL, stat); 1386059Samurai TermMode = 1; 1396059Samurai} 1406059Samurai 1416059Samuraivoid 14210528SamuraiTtyOldMode() 1436059Samurai{ 1446059Samurai int stat; 1456059Samurai 1466059Samurai stat = fcntl(0, F_GETFL, 0); 1476059Samurai stat &= ~O_NONBLOCK; 1486059Samurai fcntl(0, F_SETFL, stat); 1496735Samurai tcsetattr(0, TCSANOW, &oldtio); 15010528Samurai} 15110528Samurai 15210528Samuraivoid 15310528SamuraiCleanup(excode) 15410528Samuraiint excode; 15510528Samurai{ 15610528Samurai 15710528Samurai OsLinkdown(); 1586059Samurai OsCloseLink(1); 1596059Samurai sleep(1); 16011336Samurai if (mode & MODE_AUTO) { 1616059Samurai DeleteIfRoutes(1); 16211336Samurai unlink(pid_filename); 16311336Samurai } 1646059Samurai OsInterfaceDown(1); 16515738Sphk LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n"); 1666059Samurai LogClose(); 1676059Samurai if (server > 0) 1686059Samurai close(server); 16910528Samurai TtyOldMode(); 1706059Samurai 1716059Samurai exit(excode); 1726059Samurai} 1736059Samurai 1746059Samuraistatic void 17514930SacheHangup(signo) 17614930Sacheint signo; 1776059Samurai{ 17817044Sache if (signo == SIGSEGV) { 17917044Sache LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 18017044Sache LogClose(); 18117044Sache abort(); 18217044Sache } 18315738Sphk LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 1846059Samurai Cleanup(EX_HANGUP); 1856059Samurai} 1866059Samurai 1876059Samuraistatic void 18814930SacheCloseSession(signo) 18914930Sacheint signo; 1906059Samurai{ 19115738Sphk LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 1926059Samurai LcpClose(); 1936059Samurai Cleanup(EX_TERM); 1946059Samurai} 1956059Samurai 19610528Samurai 19710528Samuraistatic void 19810528SamuraiTerminalCont() 19910528Samurai{ 20010528Samurai (void)signal(SIGCONT, SIG_DFL); 20110528Samurai (void)signal(SIGTSTP, TerminalStop); 20210528Samurai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 20310528Samurai} 20410528Samurai 20510528Samuraistatic void 20610528SamuraiTerminalStop(signo) 20710528Samuraiint signo; 20810528Samurai{ 20910528Samurai (void)signal(SIGCONT, TerminalCont); 21010528Samurai TtyOldMode(); 21110528Samurai signal(SIGTSTP, SIG_DFL); 21210528Samurai kill(getpid(), signo); 21310528Samurai} 21410528Samurai 21510528Samurai 2166059Samuraivoid 2176059SamuraiUsage() 2186059Samurai{ 21920120Snate fprintf(stderr, 22020365Sjkh "Usage: ppp [-auto | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 2216059Samurai exit(EX_START); 2226059Samurai} 2236059Samurai 2246059Samuraivoid 2256059SamuraiProcessArgs(int argc, char **argv) 2266059Samurai{ 2276059Samurai int optc; 2286059Samurai char *cp; 2296059Samurai 2306059Samurai optc = 0; 2316059Samurai while (argc > 0 && **argv == '-') { 2326059Samurai cp = *argv + 1; 2336059Samurai if (strcmp(cp, "auto") == 0) 2346059Samurai mode |= MODE_AUTO; 2356059Samurai else if (strcmp(cp, "direct") == 0) 2366059Samurai mode |= MODE_DIRECT; 2376059Samurai else if (strcmp(cp, "dedicated") == 0) 2386059Samurai mode |= MODE_DEDICATED; 23920120Snate else if (strcmp(cp, "ddial") == 0) 24020120Snate mode |= MODE_DDIAL|MODE_AUTO; 24120365Sjkh else if (strcmp(cp, "alias") == 0) { 24220365Sjkh mode |= MODE_ALIAS; 24320365Sjkh optc--; /* this option isn't exclusive */ 24420365Sjkh } 2456059Samurai else 2466059Samurai Usage(); 2476059Samurai optc++; 2486059Samurai argv++; argc--; 2496059Samurai } 2506059Samurai if (argc > 1) { 2516059Samurai fprintf(stderr, "specify only one system label.\n"); 2526059Samurai exit(EX_START); 2536059Samurai } 2546059Samurai if (argc == 1) dstsystem = *argv; 2556059Samurai 2566059Samurai if (optc > 1) { 2576059Samurai fprintf(stderr, "specify only one mode.\n"); 2586059Samurai exit(EX_START); 2596059Samurai } 2606059Samurai} 2616059Samurai 2626059Samuraistatic void 2636059SamuraiGreetings() 2646059Samurai{ 2656059Samurai printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 2666059Samurai fflush(stdout); 2676059Samurai} 2686059Samurai 2696059Samuraivoid 2706059Samuraimain(argc, argv) 2716059Samuraiint argc; 2726059Samuraichar **argv; 2736059Samurai{ 2746059Samurai int tunno; 2756059Samurai 2766059Samurai argc--; argv++; 2776059Samurai 2786059Samurai mode = MODE_INTER; /* default operation is interactive mode */ 2796059Samurai netfd = -1; 2806059Samurai ProcessArgs(argc, argv); 2816059Samurai Greetings(); 2826059Samurai GetUid(); 2836059Samurai IpcpDefAddress(); 28420365Sjkh InitAlias(); 2856059Samurai 2866059Samurai if (SelectSystem("default", CONFFILE) < 0) { 2876059Samurai fprintf(stderr, "Warning: No default entry is given in config file.\n"); 2886059Samurai } 2896059Samurai 2906059Samurai if (LogOpen()) 2916059Samurai exit(EX_START); 2926059Samurai 2936735Samurai switch ( LocalAuthInit() ) { 2946735Samurai case NOT_FOUND: 2956764Samurai fprintf(stderr,LAUTH_M1); 2966764Samurai fprintf(stderr,LAUTH_M2); 2976764Samurai fflush (stderr); 2986764Samurai /* Fall down */ 2996764Samurai case VALID: 3006735Samurai VarLocalAuth = LOCAL_AUTH; 3016735Samurai break; 3026735Samurai default: 3036735Samurai break; 3046735Samurai } 3056735Samurai 3066059Samurai if (OpenTunnel(&tunno) < 0) { 3076059Samurai perror("open_tun"); 3086059Samurai exit(EX_START); 3096059Samurai } 3106059Samurai 3116059Samurai if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 3126059Samurai mode &= ~MODE_INTER; 3136059Samurai if (mode & MODE_INTER) { 3146059Samurai printf("Interactive mode\n"); 3156059Samurai netfd = 0; 3166059Samurai } else if (mode & MODE_AUTO) { 31720120Snate printf("Automatic Dialer mode\n"); 3186059Samurai if (dstsystem == NULL) { 31920120Snate fprintf(stderr, 32020120Snate "Destination system must be specified in auto or ddial mode.\n"); 3216059Samurai exit(EX_START); 3226059Samurai } 3236059Samurai } 3246059Samurai 3256735Samurai tcgetattr(0, &oldtio); /* Save original tty mode */ 3266059Samurai 3276059Samurai signal(SIGHUP, Hangup); 3286059Samurai signal(SIGTERM, CloseSession); 3296059Samurai signal(SIGINT, CloseSession); 33010528Samurai signal(SIGQUIT, CloseSession); 3316735Samurai#ifdef SIGSEGV 3326059Samurai signal(SIGSEGV, Hangup); 3336735Samurai#endif 3346735Samurai#ifdef SIGPIPE 3356735Samurai signal(SIGPIPE, Hangup); 3366735Samurai#endif 3376735Samurai#ifdef SIGALRM 3386735Samurai signal(SIGALRM, SIG_IGN); 3396735Samurai#endif 34010528Samurai if(mode & MODE_INTER) 34110528Samurai { 34210528Samurai#ifdef SIGTSTP 34310528Samurai signal(SIGTSTP, TerminalStop); 34410528Samurai#endif 34510528Samurai#ifdef SIGTTIN 34610528Samurai signal(SIGTTIN, TerminalStop); 34710528Samurai#endif 34810528Samurai#ifdef SIGTTOU 34910528Samurai signal(SIGTTOU, SIG_IGN); 35010528Samurai#endif 35110528Samurai } 3526059Samurai 3536059Samurai if (dstsystem) { 3546059Samurai if (SelectSystem(dstsystem, CONFFILE) < 0) { 3556059Samurai fprintf(stderr, "Destination system not found in conf file.\n"); 3566059Samurai Cleanup(EX_START); 3576059Samurai } 3586059Samurai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 35920120Snate fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n"); 3606059Samurai Cleanup(EX_START); 3616059Samurai } 3626059Samurai } 3636059Samurai if (mode & MODE_DIRECT) 3646059Samurai printf("Packet mode enabled.\n"); 3656059Samurai 3666059Samurai#ifdef notdef 3676059Samurai if (mode & MODE_AUTO) { 3686059Samurai OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 3696059Samurai } 3706059Samurai#endif 3716059Samurai 3726059Samurai if (!(mode & MODE_INTER)) { 3736059Samurai int port = SERVER_PORT + tunno; 3746059Samurai /* 3756059Samurai * Create server socket and listen at there. 3766059Samurai */ 3776059Samurai server = socket(PF_INET, SOCK_STREAM, 0); 3786059Samurai if (server < 0) { 3796059Samurai perror("socket"); 3806059Samurai Cleanup(EX_SOCK); 3816059Samurai } 3826059Samurai ifsin.sin_family = AF_INET; 3836059Samurai ifsin.sin_addr.s_addr = INADDR_ANY; 3846059Samurai ifsin.sin_port = htons(port); 3856059Samurai if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 3866059Samurai perror("bind"); 3876059Samurai if (errno == EADDRINUSE) 3886059Samurai fprintf(stderr, "Wait for a while, then try again.\n"); 3896059Samurai Cleanup(EX_SOCK); 3906059Samurai } 3916059Samurai listen(server, 5); 3926059Samurai 3936059Samurai DupLog(); 3946059Samurai if (!(mode & MODE_DIRECT)) { 39511336Samurai int fd; 39611336Samurai char pid[32]; 39711336Samurai 3986059Samurai if (fork()) 3996059Samurai exit(0); 40011336Samurai 40111336Samurai snprintf(pid_filename, sizeof (pid_filename), "%s/PPP.%s", 40211336Samurai _PATH_VARRUN, dstsystem); 40311336Samurai unlink(pid_filename); 40420120Snate sprintf(pid, "%d\n", (int)getpid()); 40511336Samurai 40611336Samurai if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1) 40711336Samurai { 40811336Samurai write(fd, pid, strlen(pid)); 40911336Samurai close(fd); 41011336Samurai } 4116059Samurai } 41215738Sphk LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 4136059Samurai#ifdef DOTTYINIT 4146735Samurai if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 4156059Samurai#else 4166059Samurai if (mode & MODE_DIRECT) { 4176059Samurai#endif 4186059Samurai TtyInit(); 4196059Samurai } else { 42014436Sache int fd; 42114436Sache 4226059Samurai setsid(); /* detach control tty */ 42314436Sache if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 42414436Sache (void)dup2(fd, STDIN_FILENO); 42514436Sache (void)dup2(fd, STDOUT_FILENO); 42614436Sache (void)dup2(fd, STDERR_FILENO); 42714436Sache if (fd > 2) 42814436Sache (void)close (fd); 42914436Sache } 4306059Samurai } 4316059Samurai } else { 4326059Samurai server = -1; 4336059Samurai TtyInit(); 43410528Samurai TtyCommandMode(1); 4356059Samurai } 43615738Sphk LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 4376059Samurai 4386059Samurai 4396059Samurai do 4406059Samurai DoLoop(); 4416059Samurai while (mode & MODE_DEDICATED); 4426059Samurai 4436059Samurai Cleanup(EX_DONE); 4446059Samurai} 4456059Samurai 4466059Samurai/* 4476059Samurai * Turn into packet mode, where we speek PPP. 4486059Samurai */ 4496059Samuraivoid 4506059SamuraiPacketMode() 4516059Samurai{ 4526059Samurai if (RawModem(modem) < 0) { 4536059Samurai fprintf(stderr, "Not connected.\r\n"); 4546059Samurai return; 4556059Samurai } 4566059Samurai 4576059Samurai AsyncInit(); 4586059Samurai VjInit(); 4596059Samurai LcpInit(); 4606059Samurai IpcpInit(); 4616059Samurai CcpInit(); 4626059Samurai LcpUp(); 4636059Samurai 4646059Samurai if (mode & (MODE_DIRECT|MODE_DEDICATED)) 4656059Samurai LcpOpen(OPEN_ACTIVE); 4666059Samurai else 4676059Samurai LcpOpen(VarOpenMode); 4686059Samurai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 46910528Samurai TtyCommandMode(1); 4706059Samurai fprintf(stderr, "Packet mode.\r\n"); 47118885Sjkh aft_cmd = 1; 4726059Samurai } 4736059Samurai} 4746059Samurai 4756059Samuraistatic void 4766059SamuraiShowHelp() 4776059Samurai{ 47810528Samurai fprintf(stderr, "The following commands are available:\r\n"); 4796059Samurai fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 48014418Sache fprintf(stderr, " ~-\tDecrease log level\r\n"); 48114418Sache fprintf(stderr, " ~+\tIncrease log level\r\n"); 4826059Samurai fprintf(stderr, " ~.\tTerminate program\r\n"); 48314418Sache fprintf(stderr, " ~?\tThis help\r\n"); 4846059Samurai} 4856059Samurai 4866059Samuraistatic void 4876059SamuraiReadTty() 4886059Samurai{ 4896059Samurai int n; 4906059Samurai char ch; 4916059Samurai static int ttystate; 4926059Samurai#define MAXLINESIZE 200 4936059Samurai char linebuff[MAXLINESIZE]; 4946059Samurai 4956059Samurai#ifdef DEBUG 4966059Samurai logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 4976059Samurai#endif 4986059Samurai if (!TermMode) { 4996059Samurai n = read(netfd, linebuff, sizeof(linebuff)-1); 50018885Sjkh aft_cmd = 1; 5016735Samurai if (n > 0) { 5026059Samurai DecodeCommand(linebuff, n, 1); 5036735Samurai } else { 5046059Samurai#ifdef DEBUG 5056059Samurai logprintf("connection closed.\n"); 5066059Samurai#endif 5076059Samurai close(netfd); 5086059Samurai netfd = -1; 5096059Samurai mode &= ~MODE_INTER; 5106059Samurai } 5116059Samurai return; 5126059Samurai } 5136059Samurai 5146059Samurai /* 5156059Samurai * We are in terminal mode, decode special sequences 5166059Samurai */ 5176059Samurai n = read(0, &ch, 1); 5186059Samurai#ifdef DEBUG 5196059Samurai logprintf("got %d bytes\n", n); 5206059Samurai#endif 5216059Samurai 5226059Samurai if (n > 0) { 5236059Samurai switch (ttystate) { 5246059Samurai case 0: 5256059Samurai if (ch == '~') 5266059Samurai ttystate++; 5276059Samurai else 5286059Samurai write(modem, &ch, n); 5296059Samurai break; 5306059Samurai case 1: 5316059Samurai switch (ch) { 5326059Samurai case '?': 5336059Samurai ShowHelp(); 5346059Samurai break; 5356059Samurai case '-': 5366059Samurai if (loglevel > 0) { 5376059Samurai loglevel--; 5386059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 5396059Samurai } 5406059Samurai break; 5416059Samurai case '+': 5426059Samurai loglevel++; 5436059Samurai fprintf(stderr, "New loglevel is %d\r\n", loglevel); 5446059Samurai break; 5456059Samurai#ifdef DEBUG 5466059Samurai case 'm': 5476059Samurai ShowMemMap(); 5486059Samurai break; 5496059Samurai#endif 5506059Samurai case 'p': 5516059Samurai /* 5526059Samurai * XXX: Should check carrier. 5536059Samurai */ 5546059Samurai if (LcpFsm.state <= ST_CLOSED) { 5556059Samurai VarOpenMode = OPEN_ACTIVE; 5566059Samurai PacketMode(); 5576059Samurai } 5586059Samurai break; 5596059Samurai#ifdef DEBUG 5606059Samurai case 't': 5616059Samurai ShowTimers(); 5626059Samurai break; 5636059Samurai#endif 5646059Samurai case '.': 5656059Samurai TermMode = 1; 56610528Samurai TtyCommandMode(1); 5676059Samurai break; 5686059Samurai default: 5696059Samurai if (write(modem, &ch, n) < 0) 5706059Samurai fprintf(stderr, "err in write.\r\n"); 5716059Samurai break; 5726059Samurai } 5736059Samurai ttystate = 0; 5746059Samurai break; 5756059Samurai } 5766059Samurai } 5776059Samurai} 5786059Samurai 5796059Samurai 5806059Samurai/* 5816059Samurai * Here, we'll try to detect HDLC frame 5826059Samurai */ 5836059Samurai 5846059Samuraistatic char *FrameHeaders[] = { 5856735Samurai "\176\377\003\300\041", 5866735Samurai "\176\377\175\043\300\041", 5876735Samurai "\176\177\175\043\100\041", 5886735Samurai "\176\175\337\175\043\300\041", 5896735Samurai "\176\175\137\175\043\100\041", 5906059Samurai NULL, 5916059Samurai}; 5926059Samurai 5936059Samuraiu_char * 5946059SamuraiHdlcDetect(cp, n) 5956059Samuraiu_char *cp; 5966059Samuraiint n; 5976059Samurai{ 5986735Samurai char *ptr, *fp, **hp; 5996059Samurai 6006059Samurai cp[n] = '\0'; /* be sure to null terminated */ 6016059Samurai ptr = NULL; 6026059Samurai for (hp = FrameHeaders; *hp; hp++) { 6036735Samurai fp = *hp; 6046735Samurai if (DEV_IS_SYNC) 6056735Samurai fp++; 60613389Sphk ptr = strstr((char *)cp, fp); 60713389Sphk if (ptr) 6086059Samurai break; 6096059Samurai } 6106059Samurai return((u_char *)ptr); 6116059Samurai} 6126059Samurai 6136059Samuraistatic struct pppTimer RedialTimer; 6146059Samurai 6156059Samuraistatic void 6166059SamuraiRedialTimeout() 6176059Samurai{ 6186059Samurai StopTimer(&RedialTimer); 61915738Sphk LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 6206059Samurai} 6216059Samurai 6226059Samuraistatic void 6236059SamuraiStartRedialTimer() 6246059Samurai{ 6256059Samurai StopTimer(&RedialTimer); 62611336Samurai 62711336Samurai if (VarRedialTimeout) { 62815738Sphk LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n"); 62911336Samurai RedialTimer.state = TIMER_STOPPED; 63011336Samurai 63111336Samurai if (VarRedialTimeout > 0) 63211336Samurai RedialTimer.load = VarRedialTimeout * SECTICKS; 63311336Samurai else 63411336Samurai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 63511336Samurai 63611336Samurai RedialTimer.func = RedialTimeout; 63711336Samurai StartTimer(&RedialTimer); 63811336Samurai } 6396059Samurai} 6406059Samurai 6416059Samurai 6426059Samuraistatic void 6436059SamuraiDoLoop() 6446059Samurai{ 6456059Samurai fd_set rfds, wfds, efds; 6466059Samurai int pri, i, n, wfd; 6476059Samurai struct sockaddr_in hisaddr; 6486059Samurai struct timeval timeout, *tp; 6496059Samurai int ssize = sizeof(hisaddr); 6506059Samurai u_char *cp; 6516059Samurai u_char rbuff[MAX_MRU]; 6527001Samurai int dial_up; 65311336Samurai int tries; 6549448Samurai int qlen; 65510528Samurai pid_t pgroup; 6566059Samurai 65710528Samurai pgroup = getpgrp(); 65810528Samurai 6596059Samurai if (mode & MODE_DIRECT) { 6606059Samurai modem = OpenModem(mode); 66115738Sphk LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 66218885Sjkh fflush(stderr); 6636059Samurai PacketMode(); 6646059Samurai } else if (mode & MODE_DEDICATED) { 6656059Samurai if (!modem) 6666059Samurai modem = OpenModem(mode); 6676059Samurai } 6686059Samurai 6696059Samurai fflush(stdout); 6706059Samurai 6717001Samurai timeout.tv_sec = 0; 6726059Samurai timeout.tv_usec = 0; 6736059Samurai 6747001Samurai dial_up = FALSE; /* XXXX */ 67511336Samurai tries = 0; 6766059Samurai for (;;) { 6776059Samurai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 6787001Samurai 67920120Snate /* 68020120Snate * If the link is down and we're in DDIAL mode, bring it back 68120120Snate * up. 68220120Snate */ 68320120Snate if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 68420120Snate dial_up = TRUE; 68520120Snate 6867001Samurai /* 6877001Samurai * If Ip packet for output is enqueued and require dial up, 6887001Samurai * Just do it! 6897001Samurai */ 6907001Samurai if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */ 6917001Samurai#ifdef DEBUG 6927001Samurai logprintf("going to dial: modem = %d\n", modem); 6937001Samurai#endif 69411336Samurai modem = OpenModem(mode); 69511336Samurai if (modem < 0) { 69611336Samurai modem = 0; /* Set intial value for next OpenModem */ 69711336Samurai StartRedialTimer(); 69811336Samurai } else { 69911336Samurai tries++; 70015738Sphk LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 70111336Samurai if (DialModem()) { 70211336Samurai sleep(1); /* little pause to allow peer starts */ 70311336Samurai ModemTimeout(); 70411336Samurai PacketMode(); 70511336Samurai dial_up = FALSE; 70611336Samurai tries = 0; 70711336Samurai } else { 70811336Samurai CloseModem(); 70911336Samurai /* Dial failed. Keep quite during redial wait period. */ 71011336Samurai StartRedialTimer(); 71111336Samurai 71211336Samurai if (VarDialTries && tries >= VarDialTries) { 71311336Samurai dial_up = FALSE; 71411336Samurai tries = 0; 71511336Samurai } 71611336Samurai } 71711336Samurai } 7187001Samurai } 7199448Samurai qlen = ModemQlen(); 72013733Sdfr 72113733Sdfr if (qlen == 0) { 72213733Sdfr IpStartOutput(); 72313733Sdfr qlen = ModemQlen(); 72413733Sdfr } 72513733Sdfr 7267001Samurai if (modem) { 7277001Samurai FD_SET(modem, &rfds); 7287001Samurai FD_SET(modem, &efds); 7299448Samurai if (qlen > 0) { 7307001Samurai FD_SET(modem, &wfds); 7317001Samurai } 7327001Samurai } 7336059Samurai if (server > 0) FD_SET(server, &rfds); 7346059Samurai 7356059Samurai /* *** IMPORTANT *** 7366059Samurai * 7376059Samurai * CPU is serviced every TICKUNIT micro seconds. 7386059Samurai * This value must be chosen with great care. If this values is 7396059Samurai * too big, it results loss of characters from modem and poor responce. 7406059Samurai * If this values is too small, ppp process eats many CPU time. 7416059Samurai */ 7426735Samurai#ifndef SIGALRM 7436059Samurai usleep(TICKUNIT); 7446059Samurai TimerService(); 7456735Samurai#endif 74610877Sbde 74710877Sbde /* If there are aren't many packets queued, look for some more. */ 74810877Sbde if (qlen < 20) 74910877Sbde FD_SET(tun_in, &rfds); 75010877Sbde 7516059Samurai if (netfd > -1) { 7526059Samurai FD_SET(netfd, &rfds); 7536059Samurai FD_SET(netfd, &efds); 7546059Samurai } 7557001Samurai 7566735Samurai#ifndef SIGALRM 7576059Samurai /* 7587001Samurai * Normally, select() will not block because modem is writable. 7597001Samurai * In AUTO mode, select will block until we find packet from tun 7606059Samurai */ 7616059Samurai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 7626059Samurai i = select(tun_in+10, &rfds, &wfds, &efds, tp); 7636735Samurai#else 7648857Srgrimes /* 7657001Samurai * When SIGALRM timer is running, a select function will be 7668857Srgrimes * return -1 and EINTR after a Time Service signal hundler 76711336Samurai * is done. If the redial timer is not running and we are 76811336Samurai * trying to dial, poll with a 0 value timer. 7697001Samurai */ 77011336Samurai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 77111336Samurai i = select(tun_in+10, &rfds, &wfds, &efds, tp); 7726735Samurai#endif 7737001Samurai if ( i == 0 ) { 7747001Samurai continue; 7756059Samurai } 7766735Samurai 7777001Samurai if ( i < 0 ) { 7787001Samurai if ( errno == EINTR ) { 77911336Samurai continue; /* Got SIGALRM, Do check a queue for dialing */ 7807001Samurai } 7817001Samurai perror("select"); 7827001Samurai break; 7838857Srgrimes } 7847001Samurai 7856059Samurai if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) { 7866059Samurai logprintf("Exception detected.\n"); 7876059Samurai break; 7886059Samurai } 7896059Samurai 7906059Samurai if (server > 0 && FD_ISSET(server, &rfds)) { 7916059Samurai#ifdef DEBUG 7926059Samurai logprintf("connected to client.\n"); 7936059Samurai#endif 7946059Samurai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 7956059Samurai if (netfd > 0) { 7966059Samurai write(wfd, "already in use.\n", 16); 7976059Samurai close(wfd); 7986059Samurai continue; 7996059Samurai } else 8006059Samurai netfd = wfd; 8016059Samurai if (dup2(netfd, 1) < 0) 8026059Samurai perror("dup2"); 8036059Samurai mode |= MODE_INTER; 8046059Samurai Greetings(); 8056764Samurai switch ( LocalAuthInit() ) { 8066764Samurai case NOT_FOUND: 8076764Samurai fprintf(stdout,LAUTH_M1); 8086764Samurai fprintf(stdout,LAUTH_M2); 8096764Samurai fflush(stdout); 8106764Samurai /* Fall down */ 8116764Samurai case VALID: 8126764Samurai VarLocalAuth = LOCAL_AUTH; 8136764Samurai break; 8146764Samurai default: 8156764Samurai break; 8166764Samurai } 8176059Samurai (void) IsInteractive(); 8186059Samurai Prompt(0); 8196059Samurai } 8206059Samurai 82110528Samurai if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) && 82210858Samurai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 8236059Samurai /* something to read from tty */ 8246059Samurai ReadTty(); 8256059Samurai } 8266059Samurai if (modem) { 8276059Samurai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 8286059Samurai ModemStartOutput(modem); 8296059Samurai } 8306059Samurai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 8316735Samurai if (LcpFsm.state <= ST_CLOSED) 8326735Samurai usleep(10000); 8336059Samurai n = read(modem, rbuff, sizeof(rbuff)); 8346059Samurai if ((mode & MODE_DIRECT) && n <= 0) { 8356059Samurai DownConnection(); 8366059Samurai } else 8376059Samurai LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 8386059Samurai 8396059Samurai if (LcpFsm.state <= ST_CLOSED) { 8406059Samurai /* 8416059Samurai * In dedicated mode, we just discard input until LCP is started. 8426059Samurai */ 8436059Samurai if (!(mode & MODE_DEDICATED)) { 8446059Samurai cp = HdlcDetect(rbuff, n); 8456059Samurai if (cp) { 8466059Samurai /* 8476059Samurai * LCP packet is detected. Turn ourselves into packet mode. 8486059Samurai */ 8496059Samurai if (cp != rbuff) { 8506059Samurai write(1, rbuff, cp - rbuff); 8516059Samurai write(1, "\r\n", 2); 8526059Samurai } 8536059Samurai PacketMode(); 8546059Samurai#ifdef notdef 8556059Samurai AsyncInput(cp, n - (cp - rbuff)); 8566059Samurai#endif 8576059Samurai } else 8586059Samurai write(1, rbuff, n); 8596059Samurai } 8606059Samurai } else { 8616059Samurai if (n > 0) 8626059Samurai AsyncInput(rbuff, n); 8636059Samurai#ifdef notdef 8646059Samurai continue; /* THIS LINE RESULT AS POOR PERFORMANCE */ 8656059Samurai#endif 8666059Samurai } 8676059Samurai } 8686059Samurai } 8697001Samurai 8706059Samurai if (FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 8716059Samurai n = read(tun_in, rbuff, sizeof(rbuff)); 8726059Samurai if (n < 0) { 8736059Samurai perror("read from tun"); 8746059Samurai continue; 8756059Samurai } 8766059Samurai /* 8776059Samurai * Process on-demand dialup. Output packets are queued within tunnel 8786059Samurai * device until IPCP is opened. 8796059Samurai */ 8806059Samurai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 8817001Samurai pri = PacketCheck(rbuff, n, FL_DIAL); 8826059Samurai if (pri >= 0) { 88320365Sjkh if (mode & MODE_ALIAS) { 88420666Snate PacketAliasOut((struct ip *)rbuff); 88520666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 88620365Sjkh } 8876059Samurai IpEnqueue(pri, rbuff, n); 88820365Sjkh dial_up = TRUE; /* XXX */ 8896059Samurai } 8906059Samurai continue; 8916059Samurai } 8927001Samurai pri = PacketCheck(rbuff, n, FL_OUT); 89320365Sjkh if (pri >= 0) { 89420365Sjkh if (mode & MODE_ALIAS) { 89520666Snate PacketAliasOut((struct ip *)rbuff); 89620666Snate n = ntohs(((struct ip *)rbuff)->ip_len); 89720365Sjkh } 8986059Samurai IpEnqueue(pri, rbuff, n); 89920365Sjkh } 9006059Samurai } 9016059Samurai } 9026059Samurai logprintf("job done.\n"); 9036059Samurai} 904