main.c revision 24844
1169689Skan/* 2169689Skan * User Process PPP 3169689Skan * 4169689Skan * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5169689Skan * 6169689Skan * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7169689Skan * 8169689Skan * Redistribution and use in source and binary forms are permitted 9169689Skan * provided that the above copyright notice and this paragraph are 10169689Skan * duplicated in all such forms and that any documentation, 11169689Skan * advertising materials, and other materials related to such 12169689Skan * distribution and use acknowledge that the software was developed 13169689Skan * by the Internet Initiative Japan, Inc. The name of the 14169689Skan * IIJ may not be used to endorse or promote products derived 15169689Skan * from this software without specific prior written permission. 16169689Skan * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17169689Skan * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18169689Skan * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19169689Skan * 20169689Skan * $Id: main.c,v 1.42 1997/04/12 22:58:39 brian Exp $ 21169689Skan * 22169689Skan * TODO: 23169689Skan * o Add commands for traffic summary, version display, etc. 24169689Skan * o Add signal handler for misc controls. 25169689Skan */ 26169689Skan#include "fsm.h" 27169689Skan#include <fcntl.h> 28169689Skan#include <paths.h> 29169689Skan#include <sys/time.h> 30169689Skan#include <termios.h> 31169689Skan#include <signal.h> 32169689Skan#include <sys/wait.h> 33169689Skan#include <errno.h> 34169689Skan#include <netdb.h> 35169689Skan#include <unistd.h> 36169689Skan#include <sys/socket.h> 37169689Skan#include <arpa/inet.h> 38169689Skan#include <netinet/in_systm.h> 39169689Skan#include <netinet/ip.h> 40169689Skan#include "modem.h" 41169689Skan#include "os.h" 42169689Skan#include "hdlc.h" 43169689Skan#include "ccp.h" 44169689Skan#include "lcp.h" 45169689Skan#include "ipcp.h" 46169689Skan#include "vars.h" 47169689Skan#include "auth.h" 48169689Skan#include "filter.h" 49169689Skan#include "systems.h" 50169689Skan#include "ip.h" 51169689Skan#include "alias.h" 52169689Skan#include "sig.h" 53169689Skan 54169689Skan#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 55169689Skan#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n" 56169689Skan 57169689Skan#ifndef O_NONBLOCK 58169689Skan#ifdef O_NDELAY 59169689Skan#define O_NONBLOCK O_NDELAY 60169689Skan#endif 61169689Skan#endif 62169689Skan 63169689Skanextern void VjInit(), AsyncInit(); 64169689Skanextern void AsyncInput(), IpOutput(); 65169689Skanextern int SelectSystem(); 66169689Skan 67169689Skanextern void DecodeCommand(), Prompt(); 68169689Skanextern int aft_cmd; 69169689Skanextern int IsInteractive(); 70169689Skanextern struct in_addr ifnetmask; 71169689Skanstatic void DoLoop(void); 72169689Skanstatic void TerminalStop(); 73169689Skan 74169689Skanstatic struct termios oldtio; /* Original tty mode */ 75169689Skanstatic struct termios comtio; /* Command level tty mode */ 76169689Skanint TermMode; 77169689Skanstatic int server; 78169689Skanstatic pid_t BGPid = 0; 79169689Skanstruct sockaddr_in ifsin; 80169689Skanchar pid_filename[128]; 81169689Skan 82169689Skanstatic void 83169689SkanTtyInit() 84169689Skan{ 85169689Skan struct termios newtio; 86169689Skan int stat; 87169689Skan 88169689Skan stat = fcntl(0, F_GETFL, 0); 89169689Skan stat |= O_NONBLOCK; 90169689Skan fcntl(0, F_SETFL, stat); 91169689Skan newtio = oldtio; 92169689Skan newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 93169689Skan newtio.c_iflag = 0; 94169689Skan newtio.c_oflag &= ~OPOST; 95169689Skan newtio.c_cc[VEOF] = _POSIX_VDISABLE; 96169689Skan newtio.c_cc[VINTR] = _POSIX_VDISABLE; 97169689Skan newtio.c_cc[VMIN] = 1; 98169689Skan newtio.c_cc[VTIME] = 0; 99169689Skan newtio.c_cflag |= CS8; 100169689Skan tcsetattr(0, TCSADRAIN, &newtio); 101169689Skan comtio = newtio; 102169689Skan} 103169689Skan 104169689Skan/* 105169689Skan * Set tty into command mode. We allow canonical input and echo processing. 106169689Skan */ 107169689Skanvoid 108169689SkanTtyCommandMode(prompt) 109169689Skanint prompt; 110169689Skan{ 111169689Skan struct termios newtio; 112169689Skan int stat; 113169689Skan 114169689Skan if (!(mode & MODE_INTER)) 115169689Skan return; 116169689Skan tcgetattr(0, &newtio); 117169689Skan newtio.c_lflag |= (ECHO|ISIG|ICANON); 118169689Skan newtio.c_iflag = oldtio.c_iflag; 119169689Skan newtio.c_oflag |= OPOST; 120169689Skan tcsetattr(0, TCSADRAIN, &newtio); 121169689Skan stat = fcntl(0, F_GETFL, 0); 122169689Skan stat |= O_NONBLOCK; 123169689Skan fcntl(0, F_SETFL, stat); 124169689Skan TermMode = 0; 125169689Skan if(prompt) Prompt(0); 126169689Skan} 127169689Skan 128169689Skan/* 129169689Skan * Set tty into terminal mode which is used while we invoke term command. 130169689Skan */ 131169689Skanvoid 132169689SkanTtyTermMode() 133169689Skan{ 134169689Skan int stat; 135169689Skan 136169689Skan tcsetattr(0, TCSADRAIN, &comtio); 137169689Skan stat = fcntl(0, F_GETFL, 0); 138169689Skan stat &= ~O_NONBLOCK; 139169689Skan fcntl(0, F_SETFL, stat); 140169689Skan TermMode = 1; 141169689Skan} 142169689Skan 143169689Skanvoid 144169689SkanTtyOldMode() 145169689Skan{ 146169689Skan int stat; 147169689Skan 148169689Skan stat = fcntl(0, F_GETFL, 0); 149169689Skan stat &= ~O_NONBLOCK; 150169689Skan fcntl(0, F_SETFL, stat); 151169689Skan tcsetattr(0, TCSANOW, &oldtio); 152169689Skan} 153169689Skan 154169689Skanvoid 155169689SkanCleanup(excode) 156169689Skanint excode; 157169689Skan{ 158169689Skan 159169689Skan OsLinkdown(); 160169689Skan OsCloseLink(1); 161169689Skan sleep(1); 162169689Skan if (mode & (MODE_AUTO | MODE_BACKGROUND)) { 163169689Skan DeleteIfRoutes(1); 164169689Skan unlink(pid_filename); 165169689Skan } 166169689Skan OsInterfaceDown(1); 167169689Skan if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 168169689Skan char c = EX_ERRDEAD; 169169689Skan if (write(BGFiledes[1],&c,1) == 1) 170169689Skan LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n"); 171169689Skan else 172169689Skan LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n"); 173169689Skan close(BGFiledes[1]); 174169689Skan } 175169689Skan LogPrintf(LOG_PHASE_BIT, "PPP Terminated %d.\n",excode); 176169689Skan LogClose(); 177169689Skan if (server >= 0) { 178169689Skan close(server); 179169689Skan server = -1; 180169689Skan } 181169689Skan TtyOldMode(); 182169689Skan 183169689Skan exit(excode); 184169689Skan} 185169689Skan 186169689Skanstatic void 187169689SkanHangup(signo) 188169689Skanint signo; 189169689Skan{ 190169689Skan if (signo == SIGSEGV) { 191169689Skan LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 192169689Skan LogClose(); 193169689Skan abort(); 194169689Skan } 195169689Skan if (BGPid) { 196169689Skan kill (BGPid, SIGTERM); 197169689Skan exit (EX_HANGUP); 198169689Skan } 199169689Skan else { 200169689Skan LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 201169689Skan Cleanup(EX_HANGUP); 202169689Skan } 203169689Skan} 204169689Skan 205169689Skanstatic void 206169689SkanCloseSession(signo) 207169689Skanint signo; 208169689Skan{ 209169689Skan if (BGPid) { 210169689Skan kill (BGPid, SIGINT); 211169689Skan exit (EX_TERM); 212169689Skan } 213169689Skan else { 214169689Skan LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 215169689Skan LcpClose(); 216169689Skan Cleanup(EX_TERM); 217169689Skan } 218169689Skan} 219169689Skan 220169689Skanstatic void 221169689SkanTerminalCont() 222169689Skan{ 223169689Skan pending_signal(SIGCONT, SIG_DFL); 224169689Skan pending_signal(SIGTSTP, TerminalStop); 225169689Skan TtyCommandMode(getpgrp() == tcgetpgrp(0)); 226169689Skan} 227169689Skan 228169689Skanstatic void 229169689SkanTerminalStop(signo) 230169689Skanint signo; 231169689Skan{ 232169689Skan pending_signal(SIGCONT, TerminalCont); 233169689Skan TtyOldMode(); 234169689Skan pending_signal(SIGTSTP, SIG_DFL); 235169689Skan kill(getpid(), signo); 236169689Skan} 237169689Skan 238169689Skan 239169689Skanvoid 240169689SkanUsage() 241169689Skan{ 242169689Skan fprintf(stderr, 243169689Skan "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 244169689Skan exit(EX_START); 245169689Skan} 246169689Skan 247169689Skanvoid 248169689SkanProcessArgs(int argc, char **argv) 249169689Skan{ 250169689Skan int optc; 251169689Skan char *cp; 252169689Skan 253169689Skan optc = 0; 254169689Skan while (argc > 0 && **argv == '-') { 255169689Skan cp = *argv + 1; 256169689Skan if (strcmp(cp, "auto") == 0) 257169689Skan mode |= MODE_AUTO; 258169689Skan else if (strcmp(cp, "background") == 0) 259169689Skan mode |= MODE_BACKGROUND; 260169689Skan else if (strcmp(cp, "direct") == 0) 261169689Skan mode |= MODE_DIRECT; 262169689Skan else if (strcmp(cp, "dedicated") == 0) 263169689Skan mode |= MODE_DEDICATED; 264169689Skan else if (strcmp(cp, "ddial") == 0) 265169689Skan mode |= MODE_DDIAL|MODE_AUTO; 266169689Skan else if (strcmp(cp, "alias") == 0) { 267169689Skan mode |= MODE_ALIAS; 268169689Skan optc--; /* this option isn't exclusive */ 269169689Skan } 270169689Skan else 271169689Skan Usage(); 272169689Skan optc++; 273169689Skan argv++; argc--; 274169689Skan } 275169689Skan if (argc > 1) { 276169689Skan fprintf(stderr, "specify only one system label.\n"); 277169689Skan exit(EX_START); 278169689Skan } 279169689Skan if (argc == 1) dstsystem = *argv; 280169689Skan 281169689Skan if (optc > 1) { 282169689Skan fprintf(stderr, "specify only one mode.\n"); 283169689Skan exit(EX_START); 284169689Skan } 285169689Skan} 286169689Skan 287169689Skanstatic void 288169689SkanGreetings() 289169689Skan{ 290169689Skan printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 291169689Skan fflush(stdout); 292169689Skan} 293169689Skan 294169689Skanvoid 295169689Skanmain(argc, argv) 296169689Skanint argc; 297169689Skanchar **argv; 298169689Skan{ 299169689Skan int tunno; 300169689Skan 301169689Skan argc--; argv++; 302169689Skan 303169689Skan mode = MODE_INTER; /* default operation is interactive mode */ 304169689Skan netfd = server = modem = tun_in = -1; 305169689Skan ProcessArgs(argc, argv); 306169689Skan Greetings(); 307169689Skan GetUid(); 308169689Skan IpcpDefAddress(); 309169689Skan InitAlias(); 310169689Skan 311169689Skan if (SelectSystem("default", CONFFILE) < 0) { 312169689Skan fprintf(stderr, "Warning: No default entry is given in config file.\n"); 313169689Skan } 314169689Skan 315169689Skan if (LogOpen()) 316169689Skan exit(EX_START); 317169689Skan 318169689Skan switch ( LocalAuthInit() ) { 319169689Skan case NOT_FOUND: 320169689Skan fprintf(stderr,LAUTH_M1); 321169689Skan fprintf(stderr,LAUTH_M2); 322169689Skan fflush (stderr); 323169689Skan /* Fall down */ 324169689Skan case VALID: 325169689Skan VarLocalAuth = LOCAL_AUTH; 326169689Skan break; 327169689Skan default: 328169689Skan break; 329169689Skan } 330169689Skan 331169689Skan if (OpenTunnel(&tunno) < 0) { 332169689Skan perror("open_tun"); 333169689Skan exit(EX_START); 334169689Skan } 335169689Skan 336169689Skan if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND)) 337169689Skan mode &= ~MODE_INTER; 338169689Skan if (mode & MODE_INTER) { 339169689Skan printf("Interactive mode\n"); 340169689Skan netfd = STDIN_FILENO; 341169689Skan } else if (mode & MODE_AUTO) { 342169689Skan printf("Automatic Dialer mode\n"); 343169689Skan if (dstsystem == NULL) { 344169689Skan fprintf(stderr, 345169689Skan "Destination system must be specified in auto or ddial mode.\n"); 346169689Skan exit(EX_START); 347169689Skan } 348169689Skan } else if (mode & MODE_BACKGROUND) { 349169689Skan printf("Background mode\n"); 350169689Skan if (dstsystem == NULL) { 351169689Skan fprintf(stderr, "Destination system must be specified in background mode.\n"); 352169689Skan exit(EX_START); 353169689Skan } 354169689Skan } 355169689Skan 356169689Skan tcgetattr(0, &oldtio); /* Save original tty mode */ 357169689Skan 358169689Skan pending_signal(SIGHUP, LogReOpen); 359169689Skan pending_signal(SIGTERM, CloseSession); 360169689Skan pending_signal(SIGINT, CloseSession); 361169689Skan pending_signal(SIGQUIT, CloseSession); 362169689Skan#ifdef SIGSEGV 363169689Skan signal(SIGSEGV, Hangup); 364169689Skan#endif 365169689Skan#ifdef SIGPIPE 366169689Skan signal(SIGPIPE, SIG_IGN); 367169689Skan#endif 368169689Skan#ifdef SIGALRM 369169689Skan pending_signal(SIGALRM, SIG_IGN); 370169689Skan#endif 371169689Skan if(mode & MODE_INTER) 372169689Skan { 373169689Skan#ifdef SIGTSTP 374169689Skan pending_signal(SIGTSTP, TerminalStop); 375169689Skan#endif 376169689Skan#ifdef SIGTTIN 377169689Skan pending_signal(SIGTTIN, TerminalStop); 378169689Skan#endif 379169689Skan#ifdef SIGTTOU 380169689Skan pending_signal(SIGTTOU, SIG_IGN); 381169689Skan#endif 382169689Skan } 383169689Skan 384169689Skan if (dstsystem) { 385169689Skan if (SelectSystem(dstsystem, CONFFILE) < 0) { 386169689Skan fprintf(stderr, "Destination system not found in conf file.\n"); 387169689Skan Cleanup(EX_START); 388169689Skan } 389169689Skan if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 390169689Skan fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n"); 391169689Skan Cleanup(EX_START); 392169689Skan } 393169689Skan } 394169689Skan if (mode & MODE_DIRECT) 395169689Skan printf("Packet mode enabled.\n"); 396169689Skan 397169689Skan#ifdef notdef 398169689Skan if (mode & MODE_AUTO) { 399169689Skan OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 400169689Skan } 401169689Skan#endif 402169689Skan 403169689Skan if (!(mode & MODE_INTER)) { 404169689Skan int port = SERVER_PORT + tunno; 405169689Skan if (mode & MODE_BACKGROUND) { 406169689Skan if (pipe (BGFiledes)) { 407169689Skan perror("pipe"); 408169689Skan Cleanup(EX_SOCK); 409169689Skan } 410169689Skan } 411169689Skan else { 412169689Skan /* 413169689Skan * Create server socket and listen at there. 414169689Skan */ 415169689Skan server = socket(PF_INET, SOCK_STREAM, 0); 416169689Skan if (server < 0) { 417169689Skan perror("socket"); 418169689Skan Cleanup(EX_SOCK); 419169689Skan } 420169689Skan ifsin.sin_family = AF_INET; 421169689Skan ifsin.sin_addr.s_addr = INADDR_ANY; 422169689Skan ifsin.sin_port = htons(port); 423169689Skan if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 424169689Skan perror("bind"); 425169689Skan if (errno == EADDRINUSE) 426169689Skan fprintf(stderr, "Wait for a while, then try again.\n"); 427169689Skan Cleanup(EX_SOCK); 428169689Skan } 429169689Skan listen(server, 5); 430169689Skan } 431169689Skan 432169689Skan DupLog(); 433169689Skan if (!(mode & MODE_DIRECT)) { 434169689Skan int fd; 435169689Skan char pid[32]; 436169689Skan pid_t bgpid; 437169689Skan 438169689Skan bgpid = fork (); 439169689Skan if (bgpid == -1) { 440169689Skan perror ("fork"); 441169689Skan Cleanup (EX_SOCK); 442169689Skan } 443169689Skan if (bgpid) { 444169689Skan char c = EX_NORMAL; 445169689Skan 446169689Skan if (mode & MODE_BACKGROUND) { 447169689Skan /* Wait for our child to close its pipe before we exit. */ 448169689Skan BGPid = bgpid; 449169689Skan close (BGFiledes[1]); 450169689Skan if (read(BGFiledes[0], &c, 1) != 1) 451169689Skan LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n"); 452169689Skan else if (c == EX_NORMAL) 453169689Skan LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n"); 454169689Skan else 455169689Skan LogPrintf (LOG_PHASE_BIT, "Parent: Child failed %d.\n",(int)c); 456169689Skan close (BGFiledes[0]); 457169689Skan } 458169689Skan exit(c); 459169689Skan } else if (mode & MODE_BACKGROUND) 460169689Skan close(BGFiledes[0]); 461169689Skan 462169689Skan snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid", 463169689Skan _PATH_VARRUN, tunno); 464169689Skan unlink(pid_filename); 465169689Skan snprintf(pid, sizeof(pid), "%d\n", (int)getpid()); 466169689Skan 467169689Skan if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1) 468169689Skan { 469169689Skan write(fd, pid, strlen(pid)); 470169689Skan close(fd); 471169689Skan } 472169689Skan } 473169689Skan if (server >= 0) 474169689Skan LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 475169689Skan#ifdef DOTTYINIT 476169689Skan if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 477169689Skan#else 478169689Skan if (mode & MODE_DIRECT) { 479169689Skan#endif 480169689Skan TtyInit(); 481169689Skan } else { 482169689Skan int fd; 483169689Skan 484169689Skan setsid(); /* detach control tty */ 485169689Skan if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 486169689Skan (void)dup2(fd, STDIN_FILENO); 487169689Skan (void)dup2(fd, STDOUT_FILENO); 488169689Skan (void)dup2(fd, STDERR_FILENO); 489169689Skan if (fd > 2) 490169689Skan (void)close (fd); 491169689Skan } 492169689Skan } 493169689Skan } else { 494169689Skan TtyInit(); 495169689Skan TtyCommandMode(1); 496169689Skan } 497169689Skan LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 498169689Skan 499169689Skan 500169689Skan do 501169689Skan DoLoop(); 502169689Skan while (mode & MODE_DEDICATED); 503169689Skan 504169689Skan Cleanup(EX_DONE); 505169689Skan} 506169689Skan 507169689Skan/* 508169689Skan * Turn into packet mode, where we speak PPP. 509169689Skan */ 510169689Skanvoid 511169689SkanPacketMode() 512169689Skan{ 513169689Skan if (RawModem(modem) < 0) { 514169689Skan fprintf(stderr, "Not connected.\r\n"); 515169689Skan return; 516169689Skan } 517169689Skan 518169689Skan AsyncInit(); 519169689Skan VjInit(); 520169689Skan LcpInit(); 521169689Skan IpcpInit(); 522169689Skan CcpInit(); 523169689Skan LcpUp(); 524169689Skan 525169689Skan if (mode & (MODE_DIRECT|MODE_DEDICATED)) 526169689Skan LcpOpen(OPEN_ACTIVE); 527169689Skan else 528169689Skan LcpOpen(VarOpenMode); 529169689Skan if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 530169689Skan TtyCommandMode(1); 531169689Skan fprintf(stderr, "Packet mode.\r\n"); 532169689Skan aft_cmd = 1; 533169689Skan } 534169689Skan} 535169689Skan 536169689Skanstatic void 537169689SkanShowHelp() 538169689Skan{ 539169689Skan fprintf(stderr, "The following commands are available:\r\n"); 540169689Skan fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 541169689Skan fprintf(stderr, " ~-\tDecrease log level\r\n"); 542169689Skan fprintf(stderr, " ~+\tIncrease log level\r\n"); 543169689Skan fprintf(stderr, " ~.\tTerminate program\r\n"); 544169689Skan fprintf(stderr, " ~?\tThis help\r\n"); 545169689Skan} 546169689Skan 547169689Skanstatic void 548169689SkanReadTty() 549169689Skan{ 550169689Skan int n; 551169689Skan char ch; 552169689Skan static int ttystate; 553169689Skan#define MAXLINESIZE 200 554169689Skan char linebuff[MAXLINESIZE]; 555169689Skan 556169689Skan#ifdef DEBUG 557169689Skan logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 558169689Skan#endif 559169689Skan if (!TermMode) { 560169689Skan n = read(netfd, linebuff, sizeof(linebuff)-1); 561169689Skan aft_cmd = 1; 562169689Skan if (n > 0) { 563169689Skan DecodeCommand(linebuff, n, 1); 564169689Skan } else { 565169689Skan LogPrintf(LOG_PHASE_BIT, "client connection closed.\n"); 566169689Skan VarLocalAuth = LOCAL_NO_AUTH; 567169689Skan close(netfd); 568169689Skan close(1); 569169689Skan dup2(2, 1); /* Have to have something here or the modem will be 1 */ 570169689Skan netfd = -1; 571169689Skan mode &= ~MODE_INTER; 572169689Skan } 573169689Skan return; 574169689Skan } 575169689Skan 576169689Skan /* 577169689Skan * We are in terminal mode, decode special sequences 578169689Skan */ 579169689Skan n = read(0, &ch, 1); 580169689Skan#ifdef DEBUG 581169689Skan logprintf("got %d bytes\n", n); 582169689Skan#endif 583169689Skan 584169689Skan if (n > 0) { 585169689Skan switch (ttystate) { 586169689Skan case 0: 587169689Skan if (ch == '~') 588169689Skan ttystate++; 589169689Skan else 590169689Skan write(modem, &ch, n); 591169689Skan break; 592169689Skan case 1: 593169689Skan switch (ch) { 594169689Skan case '?': 595169689Skan ShowHelp(); 596169689Skan break; 597169689Skan case '-': 598169689Skan if (loglevel > 0) { 599169689Skan loglevel--; 600169689Skan fprintf(stderr, "New loglevel is %d\r\n", loglevel); 601169689Skan } 602169689Skan break; 603169689Skan case '+': 604169689Skan loglevel++; 605169689Skan fprintf(stderr, "New loglevel is %d\r\n", loglevel); 606169689Skan break; 607169689Skan#ifdef DEBUG 608169689Skan case 'm': 609169689Skan ShowMemMap(); 610169689Skan break; 611169689Skan#endif 612169689Skan case 'p': 613169689Skan /* 614169689Skan * XXX: Should check carrier. 615169689Skan */ 616169689Skan if (LcpFsm.state <= ST_CLOSED) { 617169689Skan VarOpenMode = OPEN_ACTIVE; 618169689Skan PacketMode(); 619169689Skan } 620169689Skan break; 621169689Skan#ifdef DEBUG 622169689Skan case 't': 623169689Skan ShowTimers(); 624169689Skan break; 625169689Skan#endif 626169689Skan case '.': 627169689Skan TermMode = 1; 628169689Skan TtyCommandMode(1); 629169689Skan break; 630169689Skan default: 631169689Skan if (write(modem, &ch, n) < 0) 632169689Skan fprintf(stderr, "err in write.\r\n"); 633169689Skan break; 634169689Skan } 635169689Skan ttystate = 0; 636169689Skan break; 637169689Skan } 638169689Skan } 639169689Skan} 640169689Skan 641169689Skan 642169689Skan/* 643169689Skan * Here, we'll try to detect HDLC frame 644169689Skan */ 645169689Skan 646169689Skanstatic char *FrameHeaders[] = { 647169689Skan "\176\377\003\300\041", 648169689Skan "\176\377\175\043\300\041", 649169689Skan "\176\177\175\043\100\041", 650169689Skan "\176\175\337\175\043\300\041", 651169689Skan "\176\175\137\175\043\100\041", 652169689Skan NULL, 653169689Skan}; 654169689Skan 655169689Skanu_char * 656169689SkanHdlcDetect(cp, n) 657169689Skanu_char *cp; 658169689Skanint n; 659169689Skan{ 660169689Skan char *ptr, *fp, **hp; 661169689Skan 662169689Skan cp[n] = '\0'; /* be sure to null terminated */ 663169689Skan ptr = NULL; 664169689Skan for (hp = FrameHeaders; *hp; hp++) { 665169689Skan fp = *hp; 666169689Skan if (DEV_IS_SYNC) 667169689Skan fp++; 668169689Skan ptr = strstr((char *)cp, fp); 669169689Skan if (ptr) 670169689Skan break; 671169689Skan } 672169689Skan return((u_char *)ptr); 673169689Skan} 674169689Skan 675169689Skanstatic struct pppTimer RedialTimer; 676169689Skan 677169689Skanstatic void 678169689SkanRedialTimeout() 679169689Skan{ 680169689Skan StopTimer(&RedialTimer); 681169689Skan LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 682169689Skan} 683169689Skan 684169689Skanstatic void 685169689SkanStartRedialTimer() 686169689Skan{ 687169689Skan StopTimer(&RedialTimer); 688169689Skan 689169689Skan if (VarRedialTimeout) { 690169689Skan LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n"); 691169689Skan RedialTimer.state = TIMER_STOPPED; 692169689Skan 693169689Skan if (VarRedialTimeout > 0) 694169689Skan RedialTimer.load = VarRedialTimeout * SECTICKS; 695169689Skan else 696169689Skan RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 697169689Skan 698169689Skan RedialTimer.func = RedialTimeout; 699169689Skan StartTimer(&RedialTimer); 700169689Skan } 701169689Skan} 702169689Skan 703169689Skan 704169689Skanstatic void 705169689SkanDoLoop() 706169689Skan{ 707169689Skan fd_set rfds, wfds, efds; 708169689Skan int pri, i, n, wfd, nfds; 709169689Skan struct sockaddr_in hisaddr; 710169689Skan struct timeval timeout, *tp; 711169689Skan int ssize = sizeof(hisaddr); 712169689Skan u_char *cp; 713169689Skan u_char rbuff[MAX_MRU]; 714169689Skan int dial_up; 715169689Skan int tries; 716169689Skan int qlen; 717169689Skan pid_t pgroup; 718169689Skan 719169689Skan pgroup = getpgrp(); 720169689Skan 721169689Skan if (mode & (MODE_DIRECT|MODE_BACKGROUND)) { 722169689Skan modem = OpenModem(mode); 723169689Skan LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 724169689Skan fflush(stderr); 725169689Skan PacketMode(); 726169689Skan } else if (mode & MODE_DEDICATED) { 727169689Skan if (modem < 0) 728169689Skan modem = OpenModem(mode); 729169689Skan } 730169689Skan 731169689Skan fflush(stdout); 732169689Skan 733169689Skan timeout.tv_sec = 0; 734169689Skan timeout.tv_usec = 0; 735169689Skan 736169689Skan if (mode & MODE_BACKGROUND) 737169689Skan dial_up = TRUE; /* Bring the line up */ 738169689Skan else 739169689Skan dial_up = FALSE; /* XXXX */ 740169689Skan tries = 0; 741169689Skan for (;;) { 742169689Skan nfds = 0; 743169689Skan FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 744169689Skan 745169689Skan /* 746169689Skan * If the link is down and we're in DDIAL mode, bring it back 747169689Skan * up. 748169689Skan */ 749169689Skan if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 750169689Skan dial_up = TRUE; 751169689Skan 752169689Skan /* 753169689Skan * If Ip packet for output is enqueued and require dial up, 754169689Skan * Just do it! 755169689Skan */ 756169689Skan if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */ 757169689Skan#ifdef DEBUG 758169689Skan logprintf("going to dial: modem = %d\n", modem); 759169689Skan#endif 760169689Skan modem = OpenModem(mode); 761169689Skan if (modem < 0) { 762169689Skan StartRedialTimer(); 763169689Skan } else { 764169689Skan tries++; /* Tries are per number, not per list of numbers. */ 765169689Skan if (VarDialTries) 766169689Skan LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries, 767169689Skan VarDialTries); 768169689Skan else 769169689Skan LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 770169689Skan if (DialModem()) { 771169689Skan sleep(1); /* little pause to allow peer starts */ 772169689Skan ModemTimeout(); 773169689Skan PacketMode(); 774169689Skan dial_up = FALSE; 775169689Skan tries = 0; 776169689Skan } else { 777169689Skan CloseModem(); 778169689Skan if (mode & MODE_BACKGROUND) { 779169689Skan if (VarNextPhone == NULL) 780169689Skan Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 781169689Skan else 782169689Skan sleep(1); /* Try all numbers in background mode */ 783169689Skan } else if (VarDialTries && tries >= VarDialTries) { 784169689Skan /* I give up ! Can't get through :( */ 785169689Skan StartRedialTimer(); 786169689Skan dial_up = FALSE; 787169689Skan tries = 0; 788169689Skan } else if (VarNextPhone == NULL) 789169689Skan /* Dial failed. Keep quite during redial wait period. */ 790169689Skan StartRedialTimer(); 791169689Skan else 792169689Skan /* 793169689Skan * Give the modem a chance to recover, then dial the next 794169689Skan * number in our list 795169689Skan */ 796169689Skan sleep(1); 797169689Skan } 798169689Skan } 799169689Skan } 800169689Skan qlen = ModemQlen(); 801169689Skan 802169689Skan if (qlen == 0) { 803169689Skan IpStartOutput(); 804169689Skan qlen = ModemQlen(); 805169689Skan } 806169689Skan 807169689Skan if (modem >= 0) { 808169689Skan if (modem + 1 > nfds) 809169689Skan nfds = modem + 1; 810169689Skan FD_SET(modem, &rfds); 811169689Skan FD_SET(modem, &efds); 812169689Skan if (qlen > 0) { 813169689Skan FD_SET(modem, &wfds); 814169689Skan } 815169689Skan } 816169689Skan if (server >= 0) { 817169689Skan if (server + 1 > nfds) 818169689Skan nfds = server + 1; 819169689Skan FD_SET(server, &rfds); 820169689Skan } 821169689Skan 822169689Skan /* *** IMPORTANT *** 823169689Skan * 824169689Skan * CPU is serviced every TICKUNIT micro seconds. 825169689Skan * This value must be chosen with great care. If this values is 826169689Skan * too big, it results loss of characters from modem and poor responce. 827169689Skan * If this values is too small, ppp process eats many CPU time. 828169689Skan */ 829169689Skan#ifndef SIGALRM 830169689Skan usleep(TICKUNIT); 831169689Skan TimerService(); 832169689Skan#else 833169689Skan handle_signals(); 834169689Skan#endif 835169689Skan 836169689Skan /* If there are aren't many packets queued, look for some more. */ 837169689Skan if (qlen < 20 && tun_in >= 0) { 838169689Skan if (tun_in + 1 > nfds) 839169689Skan nfds = tun_in + 1; 840169689Skan FD_SET(tun_in, &rfds); 841169689Skan } 842169689Skan 843169689Skan if (netfd >= 0) { 844169689Skan if (netfd + 1 > nfds) 845169689Skan nfds = netfd + 1; 846169689Skan FD_SET(netfd, &rfds); 847169689Skan FD_SET(netfd, &efds); 848169689Skan } 849169689Skan 850169689Skan#ifndef SIGALRM 851169689Skan /* 852169689Skan * Normally, select() will not block because modem is writable. 853169689Skan * In AUTO mode, select will block until we find packet from tun 854169689Skan */ 855169689Skan tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 856169689Skan i = select(nfds, &rfds, &wfds, &efds, tp); 857169689Skan#else 858169689Skan /* 859169689Skan * When SIGALRM timer is running, a select function will be 860169689Skan * return -1 and EINTR after a Time Service signal hundler 861169689Skan * is done. If the redial timer is not running and we are 862169689Skan * trying to dial, poll with a 0 value timer. 863169689Skan */ 864169689Skan tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 865169689Skan i = select(nfds, &rfds, &wfds, &efds, tp); 866169689Skan#endif 867169689Skan 868169689Skan if ( i == 0 ) { 869169689Skan continue; 870169689Skan } 871169689Skan 872169689Skan if ( i < 0 ) { 873169689Skan if ( errno == EINTR ) { 874169689Skan handle_signals(); 875169689Skan continue; 876169689Skan } 877169689Skan perror("select"); 878169689Skan break; 879169689Skan } 880169689Skan 881169689Skan if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 882169689Skan logprintf("Exception detected.\n"); 883169689Skan break; 884169689Skan } 885169689Skan 886169689Skan if (server >= 0 && FD_ISSET(server, &rfds)) { 887169689Skan LogPrintf(LOG_PHASE_BIT, "connected to client.\n"); 888169689Skan wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 889169689Skan if (wfd < 0) { 890169689Skan perror("accept"); 891169689Skan continue; 892169689Skan } 893169689Skan if (netfd >= 0) { 894169689Skan write(wfd, "already in use.\n", 16); 895169689Skan close(wfd); 896169689Skan continue; 897169689Skan } else 898169689Skan netfd = wfd; 899169689Skan if (dup2(netfd, 1) < 0) { 900169689Skan perror("dup2"); 901169689Skan close(netfd); 902169689Skan netfd = -1; 903169689Skan continue; 904169689Skan } 905169689Skan mode |= MODE_INTER; 906169689Skan Greetings(); 907169689Skan switch ( LocalAuthInit() ) { 908169689Skan case NOT_FOUND: 909169689Skan fprintf(stdout,LAUTH_M1); 910169689Skan fprintf(stdout,LAUTH_M2); 911169689Skan fflush(stdout); 912169689Skan /* Fall down */ 913169689Skan case VALID: 914169689Skan VarLocalAuth = LOCAL_AUTH; 915169689Skan break; 916169689Skan default: 917169689Skan break; 918169689Skan } 919169689Skan (void) IsInteractive(); 920169689Skan Prompt(0); 921169689Skan } 922169689Skan 923169689Skan if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 924169689Skan ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 925169689Skan /* something to read from tty */ 926169689Skan ReadTty(); 927169689Skan } 928169689Skan if (modem >= 0) { 929169689Skan if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 930169689Skan ModemStartOutput(modem); 931169689Skan } 932169689Skan if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 933169689Skan if (LcpFsm.state <= ST_CLOSED) 934169689Skan usleep(10000); 935169689Skan n = read(modem, rbuff, sizeof(rbuff)); 936169689Skan if ((mode & MODE_DIRECT) && n <= 0) { 937169689Skan DownConnection(); 938169689Skan } else 939169689Skan LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 940169689Skan 941169689Skan if (LcpFsm.state <= ST_CLOSED) { 942169689Skan /* 943169689Skan * In dedicated mode, we just discard input until LCP is started. 944169689Skan */ 945169689Skan if (!(mode & MODE_DEDICATED)) { 946169689Skan cp = HdlcDetect(rbuff, n); 947169689Skan if (cp) { 948169689Skan /* 949169689Skan * LCP packet is detected. Turn ourselves into packet mode. 950169689Skan */ 951169689Skan if (cp != rbuff) { 952169689Skan write(1, rbuff, cp - rbuff); 953169689Skan write(1, "\r\n", 2); 954169689Skan } 955169689Skan PacketMode(); 956169689Skan#ifdef notdef 957169689Skan AsyncInput(cp, n - (cp - rbuff)); 958169689Skan#endif 959169689Skan } else 960169689Skan write(1, rbuff, n); 961169689Skan } 962169689Skan } else { 963169689Skan if (n > 0) 964169689Skan AsyncInput(rbuff, n); 965169689Skan#ifdef notdef 966169689Skan continue; /* THIS LINE RESULT AS POOR PERFORMANCE */ 967169689Skan#endif 968169689Skan } 969169689Skan } 970169689Skan } 971169689Skan 972169689Skan if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 973169689Skan n = read(tun_in, rbuff, sizeof(rbuff)); 974169689Skan if (n < 0) { 975169689Skan perror("read from tun"); 976169689Skan continue; 977169689Skan } 978169689Skan /* 979169689Skan * Process on-demand dialup. Output packets are queued within tunnel 980169689Skan * device until IPCP is opened. 981169689Skan */ 982169689Skan if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 983169689Skan pri = PacketCheck(rbuff, n, FL_DIAL); 984169689Skan if (pri >= 0) { 985169689Skan if (mode & MODE_ALIAS) { 986169689Skan PacketAliasOut((struct ip *)rbuff); 987169689Skan n = ntohs(((struct ip *)rbuff)->ip_len); 988169689Skan } 989169689Skan IpEnqueue(pri, rbuff, n); 990169689Skan dial_up = TRUE; /* XXX */ 991169689Skan } 992169689Skan continue; 993169689Skan } 994169689Skan pri = PacketCheck(rbuff, n, FL_OUT); 995169689Skan if (pri >= 0) { 996169689Skan if (mode & MODE_ALIAS) { 997169689Skan PacketAliasOut((struct ip *)rbuff); 998169689Skan n = ntohs(((struct ip *)rbuff)->ip_len); 999169689Skan } 1000169689Skan IpEnqueue(pri, rbuff, n); 1001169689Skan } 1002169689Skan } 1003169689Skan } 1004169689Skan logprintf("job done.\n"); 1005169689Skan} 1006169689Skan