main.c revision 29551
1230557Sjimharris/* 2230557Sjimharris * User Process PPP 3230557Sjimharris * 4230557Sjimharris * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5230557Sjimharris * 6230557Sjimharris * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7230557Sjimharris * 8230557Sjimharris * Redistribution and use in source and binary forms are permitted 9230557Sjimharris * provided that the above copyright notice and this paragraph are 10230557Sjimharris * duplicated in all such forms and that any documentation, 11230557Sjimharris * advertising materials, and other materials related to such 12230557Sjimharris * distribution and use acknowledge that the software was developed 13230557Sjimharris * by the Internet Initiative Japan, Inc. The name of the 14230557Sjimharris * IIJ may not be used to endorse or promote products derived 15230557Sjimharris * from this software without specific prior written permission. 16230557Sjimharris * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17230557Sjimharris * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18230557Sjimharris * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19230557Sjimharris * 20230557Sjimharris * $Id: main.c,v 1.78 1997/09/16 23:15:13 brian Exp $ 21230557Sjimharris * 22230557Sjimharris * TODO: 23230557Sjimharris * o Add commands for traffic summary, version display, etc. 24230557Sjimharris * o Add signal handler for misc controls. 25230557Sjimharris */ 26230557Sjimharris#include "fsm.h" 27230557Sjimharris#include <fcntl.h> 28230557Sjimharris#include <paths.h> 29230557Sjimharris#include <sys/time.h> 30230557Sjimharris#include <termios.h> 31230557Sjimharris#include <signal.h> 32230557Sjimharris#include <sys/wait.h> 33230557Sjimharris#include <errno.h> 34230557Sjimharris#include <netdb.h> 35230557Sjimharris#include <unistd.h> 36230557Sjimharris#include <sys/socket.h> 37230557Sjimharris#include <arpa/inet.h> 38230557Sjimharris#include <netinet/in_systm.h> 39230557Sjimharris#include <netinet/ip.h> 40230557Sjimharris#include <sysexits.h> 41230557Sjimharris#include "modem.h" 42230557Sjimharris#include "os.h" 43230557Sjimharris#include "hdlc.h" 44230557Sjimharris#include "ccp.h" 45230557Sjimharris#include "lcp.h" 46230557Sjimharris#include "ipcp.h" 47230557Sjimharris#include "loadalias.h" 48230557Sjimharris#include "vars.h" 49230557Sjimharris#include "auth.h" 50230557Sjimharris#include "filter.h" 51230557Sjimharris#include "systems.h" 52230557Sjimharris#include "ip.h" 53230557Sjimharris#include "sig.h" 54230557Sjimharris#include "server.h" 55230557Sjimharris#include "lcpproto.h" 56230557Sjimharris 57230557Sjimharris#ifndef O_NONBLOCK 58230557Sjimharris#ifdef O_NDELAY 59230557Sjimharris#define O_NONBLOCK O_NDELAY 60230557Sjimharris#endif 61230557Sjimharris#endif 62230557Sjimharris 63230557Sjimharrisextern void VjInit(), AsyncInit(); 64230557Sjimharrisextern void AsyncInput(); 65230557Sjimharrisextern int SelectSystem(); 66230557Sjimharris 67230557Sjimharrisextern void DecodeCommand(), Prompt(); 68230557Sjimharrisextern int aft_cmd; 69230557Sjimharrisextern int IsInteractive(); 70230557Sjimharrisstatic void DoLoop(void); 71230557Sjimharrisstatic void TerminalStop(); 72230557Sjimharrisstatic char *ex_desc(); 73230557Sjimharris 74230557Sjimharrisstatic struct termios oldtio; /* Original tty mode */ 75230557Sjimharrisstatic struct termios comtio; /* Command level tty mode */ 76230557Sjimharrisint TermMode; 77230557Sjimharrisstatic pid_t BGPid = 0; 78230557Sjimharrisstatic char pid_filename[MAXPATHLEN]; 79230557Sjimharrisstatic char if_filename[MAXPATHLEN]; 80230557Sjimharrisint tunno; 81230557Sjimharrisstatic int dial_up; 82230557Sjimharris 83230557Sjimharrisstatic void 84230557SjimharrisTtyInit(int DontWantInt) 85230557Sjimharris{ 86230557Sjimharris struct termios newtio; 87230557Sjimharris int stat; 88230557Sjimharris 89230557Sjimharris stat = fcntl(0, F_GETFL, 0); 90230557Sjimharris if (stat > 0) { 91230557Sjimharris stat |= O_NONBLOCK; 92230557Sjimharris (void) fcntl(0, F_SETFL, stat); 93230557Sjimharris } 94230557Sjimharris newtio = oldtio; 95230557Sjimharris newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 96230557Sjimharris newtio.c_iflag = 0; 97230557Sjimharris newtio.c_oflag &= ~OPOST; 98230557Sjimharris newtio.c_cc[VEOF] = _POSIX_VDISABLE; 99230557Sjimharris if (DontWantInt) 100230557Sjimharris newtio.c_cc[VINTR] = _POSIX_VDISABLE; 101230557Sjimharris newtio.c_cc[VMIN] = 1; 102230557Sjimharris newtio.c_cc[VTIME] = 0; 103230557Sjimharris newtio.c_cflag |= CS8; 104230557Sjimharris tcsetattr(0, TCSADRAIN, &newtio); 105230557Sjimharris comtio = newtio; 106230557Sjimharris} 107230557Sjimharris 108230557Sjimharris/* 109230557Sjimharris * Set tty into command mode. We allow canonical input and echo processing. 110230557Sjimharris */ 111230557Sjimharrisvoid 112230557SjimharrisTtyCommandMode(int prompt) 113230557Sjimharris{ 114230557Sjimharris struct termios newtio; 115230557Sjimharris int stat; 116230557Sjimharris 117230557Sjimharris if (!(mode & MODE_INTER)) 118230557Sjimharris return; 119230557Sjimharris tcgetattr(0, &newtio); 120230557Sjimharris newtio.c_lflag |= (ECHO | ISIG | ICANON); 121230557Sjimharris newtio.c_iflag = oldtio.c_iflag; 122230557Sjimharris newtio.c_oflag |= OPOST; 123230557Sjimharris tcsetattr(0, TCSADRAIN, &newtio); 124230557Sjimharris stat = fcntl(0, F_GETFL, 0); 125230557Sjimharris if (stat > 0) { 126230557Sjimharris stat |= O_NONBLOCK; 127230557Sjimharris (void) fcntl(0, F_SETFL, stat); 128230557Sjimharris } 129230557Sjimharris TermMode = 0; 130230557Sjimharris if (prompt) 131230557Sjimharris Prompt(); 132230557Sjimharris} 133230557Sjimharris 134230557Sjimharris/* 135230557Sjimharris * Set tty into terminal mode which is used while we invoke term command. 136230557Sjimharris */ 137230557Sjimharrisvoid 138230557SjimharrisTtyTermMode() 139230557Sjimharris{ 140230557Sjimharris int stat; 141230557Sjimharris 142230557Sjimharris tcsetattr(0, TCSADRAIN, &comtio); 143230557Sjimharris stat = fcntl(0, F_GETFL, 0); 144230557Sjimharris if (stat > 0) { 145230557Sjimharris stat &= ~O_NONBLOCK; 146230557Sjimharris (void) fcntl(0, F_SETFL, stat); 147230557Sjimharris } 148230557Sjimharris TermMode = 1; 149230557Sjimharris} 150230557Sjimharris 151230557Sjimharrisvoid 152230557SjimharrisTtyOldMode() 153230557Sjimharris{ 154230557Sjimharris int stat; 155230557Sjimharris 156230557Sjimharris stat = fcntl(0, F_GETFL, 0); 157230557Sjimharris if (stat > 0) { 158230557Sjimharris stat &= ~O_NONBLOCK; 159230557Sjimharris (void) fcntl(0, F_SETFL, stat); 160230557Sjimharris } 161230557Sjimharris tcsetattr(0, TCSANOW, &oldtio); 162230557Sjimharris} 163230557Sjimharris 164230557Sjimharrisvoid 165230557SjimharrisCleanup(int excode) 166230557Sjimharris{ 167230557Sjimharris OsLinkdown(); 168230557Sjimharris OsCloseLink(1); 169230557Sjimharris sleep(1); 170230557Sjimharris if (mode & MODE_AUTO) 171230557Sjimharris DeleteIfRoutes(1); 172230557Sjimharris (void) unlink(pid_filename); 173230557Sjimharris (void) unlink(if_filename); 174230557Sjimharris OsInterfaceDown(1); 175230557Sjimharris if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 176230557Sjimharris char c = EX_ERRDEAD; 177230557Sjimharris 178230557Sjimharris if (write(BGFiledes[1], &c, 1) == 1) 179230557Sjimharris LogPrintf(LogPHASE, "Parent notified of failure.\n"); 180230557Sjimharris else 181230557Sjimharris LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); 182230557Sjimharris close(BGFiledes[1]); 183230557Sjimharris } 184230557Sjimharris LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 185230557Sjimharris LogClose(); 186230557Sjimharris ServerClose(); 187230557Sjimharris TtyOldMode(); 188230557Sjimharris 189230557Sjimharris exit(excode); 190230557Sjimharris} 191230557Sjimharris 192230557Sjimharrisstatic void 193230557SjimharrisCloseConnection(int signo) 194230557Sjimharris{ 195230557Sjimharris /* NOTE, these are manual, we've done a setsid() */ 196230557Sjimharris LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 197230557Sjimharris reconnectState = RECON_FALSE; 198230557Sjimharris reconnectCount = 0; 199230557Sjimharris DownConnection(); 200230557Sjimharris dial_up = FALSE; 201230557Sjimharris} 202230557Sjimharris 203230557Sjimharrisstatic void 204230557SjimharrisCloseSession(int signo) 205230557Sjimharris{ 206230557Sjimharris if (BGPid) { 207230557Sjimharris kill(BGPid, SIGINT); 208230557Sjimharris exit(EX_TERM); 209230557Sjimharris } 210230557Sjimharris LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 211230557Sjimharris reconnect(RECON_FALSE); 212230557Sjimharris LcpClose(); 213230557Sjimharris Cleanup(EX_TERM); 214230557Sjimharris} 215230557Sjimharris 216230557Sjimharrisstatic void 217230557SjimharrisTerminalCont() 218230557Sjimharris{ 219230557Sjimharris pending_signal(SIGCONT, SIG_DFL); 220230557Sjimharris pending_signal(SIGTSTP, TerminalStop); 221230557Sjimharris TtyCommandMode(getpgrp() == tcgetpgrp(0)); 222230557Sjimharris} 223230557Sjimharris 224230557Sjimharrisstatic void 225230557SjimharrisTerminalStop(int signo) 226230557Sjimharris{ 227230557Sjimharris pending_signal(SIGCONT, TerminalCont); 228230557Sjimharris TtyOldMode(); 229230557Sjimharris pending_signal(SIGTSTP, SIG_DFL); 230230557Sjimharris kill(getpid(), signo); 231230557Sjimharris} 232230557Sjimharris 233230557Sjimharrisstatic void 234230557SjimharrisSetUpServer(int signo) 235230557Sjimharris{ 236230557Sjimharris int res; 237230557Sjimharris 238230557Sjimharris if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) 239230557Sjimharris LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 240230557Sjimharris res, SERVER_PORT + tunno); 241230557Sjimharris} 242230557Sjimharris 243230557Sjimharrisstatic char * 244230557Sjimharrisex_desc(int ex) 245230557Sjimharris{ 246230557Sjimharris static char num[12]; 247230557Sjimharris static char *desc[] = {"normal", "start", "sock", 248230557Sjimharris "modem", "dial", "dead", "done", "reboot", "errdead", 249230557Sjimharris "hangup", "term", "nodial", "nologin"}; 250230557Sjimharris 251230557Sjimharris if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc)) 252230557Sjimharris return desc[ex]; 253230557Sjimharris snprintf(num, sizeof num, "%d", ex); 254230557Sjimharris return num; 255230557Sjimharris} 256230557Sjimharris 257230557Sjimharrisvoid 258230557SjimharrisUsage() 259230557Sjimharris{ 260230557Sjimharris fprintf(stderr, 261230557Sjimharris "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 262230557Sjimharris exit(EX_START); 263230557Sjimharris} 264230557Sjimharris 265230557Sjimharrisvoid 266230557SjimharrisProcessArgs(int argc, char **argv) 267230557Sjimharris{ 268230557Sjimharris int optc; 269230557Sjimharris char *cp; 270230557Sjimharris 271230557Sjimharris optc = 0; 272230557Sjimharris while (argc > 0 && **argv == '-') { 273230557Sjimharris cp = *argv + 1; 274230557Sjimharris if (strcmp(cp, "auto") == 0) 275230557Sjimharris mode |= MODE_AUTO; 276230557Sjimharris else if (strcmp(cp, "background") == 0) 277230557Sjimharris mode |= MODE_BACKGROUND | MODE_AUTO; 278230557Sjimharris else if (strcmp(cp, "direct") == 0) 279230557Sjimharris mode |= MODE_DIRECT; 280230557Sjimharris else if (strcmp(cp, "dedicated") == 0) 281230557Sjimharris mode |= MODE_DEDICATED; 282230557Sjimharris else if (strcmp(cp, "ddial") == 0) 283230557Sjimharris mode |= MODE_DDIAL | MODE_AUTO; 284230557Sjimharris else if (strcmp(cp, "alias") == 0) { 285230557Sjimharris if (loadAliasHandlers(&VarAliasHandlers) == 0) 286230557Sjimharris mode |= MODE_ALIAS; 287230557Sjimharris else 288230557Sjimharris LogPrintf(LogWARN, "Cannot load alias library\n"); 289230557Sjimharris optc--; /* this option isn't exclusive */ 290230557Sjimharris } else 291230557Sjimharris Usage(); 292230557Sjimharris optc++; 293230557Sjimharris argv++; 294230557Sjimharris argc--; 295230557Sjimharris } 296230557Sjimharris if (argc > 1) { 297230557Sjimharris fprintf(stderr, "specify only one system label.\n"); 298230557Sjimharris exit(EX_START); 299230557Sjimharris } 300230557Sjimharris if (argc == 1) 301230557Sjimharris dstsystem = *argv; 302230557Sjimharris 303230557Sjimharris if (optc > 1) { 304230557Sjimharris fprintf(stderr, "specify only one mode.\n"); 305230557Sjimharris exit(EX_START); 306230557Sjimharris } 307230557Sjimharris} 308230557Sjimharris 309230557Sjimharrisstatic void 310230557SjimharrisGreetings() 311230557Sjimharris{ 312230557Sjimharris if (VarTerm) { 313230557Sjimharris fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 314230557Sjimharris fflush(VarTerm); 315230557Sjimharris } 316230557Sjimharris} 317230557Sjimharris 318230557Sjimharrisint 319230557Sjimharrismain(int argc, char **argv) 320230557Sjimharris{ 321230557Sjimharris FILE *lockfile; 322230557Sjimharris char *name; 323230557Sjimharris 324230557Sjimharris VarTerm = 0; 325230557Sjimharris name = rindex(argv[0], '/'); 326230557Sjimharris LogOpen(name ? name + 1 : argv[0]); 327230557Sjimharris 328230557Sjimharris argc--; 329230557Sjimharris argv++; 330230557Sjimharris mode = MODE_INTER; /* default operation is interactive mode */ 331230557Sjimharris netfd = modem = tun_in = -1; 332230557Sjimharris server = -2; 333230557Sjimharris ProcessArgs(argc, argv); 334230557Sjimharris if (!(mode & MODE_DIRECT)) { 335230557Sjimharris if (getuid() != 0) { 336230557Sjimharris fprintf(stderr, "You may only run ppp in client mode as user id 0\n"); 337230557Sjimharris LogClose(); 338230557Sjimharris return EX_NOPERM; 339230557Sjimharris } 340230557Sjimharris VarTerm = stdout; 341230557Sjimharris } 342230557Sjimharris Greetings(); 343230557Sjimharris GetUid(); 344230557Sjimharris IpcpDefAddress(); 345230557Sjimharris LocalAuthInit(); 346230557Sjimharris 347230557Sjimharris if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 348230557Sjimharris fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 349230557Sjimharris 350230557Sjimharris if (OpenTunnel(&tunno) < 0) { 351230557Sjimharris LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno)); 352230557Sjimharris return EX_START; 353230557Sjimharris } 354230557Sjimharris if (mode & (MODE_AUTO | MODE_DIRECT | MODE_DEDICATED)) 355230557Sjimharris mode &= ~MODE_INTER; 356230557Sjimharris if (mode & MODE_INTER) { 357230557Sjimharris fprintf(VarTerm, "Interactive mode\n"); 358230557Sjimharris netfd = STDOUT_FILENO; 359230557Sjimharris } else if (mode & MODE_AUTO) { 360230557Sjimharris fprintf(VarTerm, "Automatic Dialer mode\n"); 361230557Sjimharris if (dstsystem == NULL) { 362230557Sjimharris if (VarTerm) 363230557Sjimharris fprintf(VarTerm, "Destination system must be specified in" 364230557Sjimharris " auto, background or ddial mode.\n"); 365230557Sjimharris return EX_START; 366230557Sjimharris } 367230557Sjimharris } 368230557Sjimharris tcgetattr(0, &oldtio); /* Save original tty mode */ 369230557Sjimharris 370230557Sjimharris pending_signal(SIGHUP, CloseSession); 371230557Sjimharris pending_signal(SIGTERM, CloseSession); 372230557Sjimharris pending_signal(SIGINT, CloseConnection); 373230557Sjimharris pending_signal(SIGQUIT, CloseSession); 374230557Sjimharris#ifdef SIGPIPE 375230557Sjimharris signal(SIGPIPE, SIG_IGN); 376230557Sjimharris#endif 377230557Sjimharris#ifdef SIGALRM 378230557Sjimharris pending_signal(SIGALRM, SIG_IGN); 379230557Sjimharris#endif 380230557Sjimharris if (mode & MODE_INTER) { 381230557Sjimharris#ifdef SIGTSTP 382230557Sjimharris pending_signal(SIGTSTP, TerminalStop); 383230557Sjimharris#endif 384230557Sjimharris#ifdef SIGTTIN 385230557Sjimharris pending_signal(SIGTTIN, TerminalStop); 386230557Sjimharris#endif 387230557Sjimharris#ifdef SIGTTOU 388230557Sjimharris pending_signal(SIGTTOU, SIG_IGN); 389230557Sjimharris#endif 390230557Sjimharris } 391230557Sjimharris#ifdef SIGUSR1 392230557Sjimharris if (mode != MODE_INTER) 393230557Sjimharris pending_signal(SIGUSR1, SetUpServer); 394230557Sjimharris#endif 395230557Sjimharris 396230557Sjimharris if (dstsystem) { 397230557Sjimharris if (SelectSystem(dstsystem, CONFFILE) < 0) { 398230557Sjimharris LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 399230557Sjimharris Cleanup(EX_START); 400230557Sjimharris } 401230557Sjimharris if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 402230557Sjimharris LogPrintf(LogWARN, "Must specify dstaddr with" 403230557Sjimharris " auto, background or ddial mode.\n"); 404230557Sjimharris Cleanup(EX_START); 405230557Sjimharris } 406230557Sjimharris } 407230557Sjimharris 408230557Sjimharris if (!(mode & MODE_INTER)) { 409230557Sjimharris if (mode & MODE_BACKGROUND) { 410230557Sjimharris if (pipe(BGFiledes)) { 411230557Sjimharris LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 412230557Sjimharris Cleanup(EX_SOCK); 413230557Sjimharris } 414230557Sjimharris } 415230557Sjimharris /* Create server socket and listen. */ 416230557Sjimharris if (server == -2) 417230557Sjimharris ServerTcpOpen(SERVER_PORT + tunno); 418230557Sjimharris 419 if (!(mode & MODE_DIRECT)) { 420 pid_t bgpid; 421 422 bgpid = fork(); 423 if (bgpid == -1) { 424 LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 425 Cleanup(EX_SOCK); 426 } 427 if (bgpid) { 428 char c = EX_NORMAL; 429 430 if (mode & MODE_BACKGROUND) { 431 /* Wait for our child to close its pipe before we exit. */ 432 BGPid = bgpid; 433 close(BGFiledes[1]); 434 if (read(BGFiledes[0], &c, 1) != 1) { 435 fprintf(VarTerm, "Child exit, no status.\n"); 436 LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 437 } else if (c == EX_NORMAL) { 438 fprintf(VarTerm, "PPP enabled.\n"); 439 LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 440 } else { 441 fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 442 LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 443 ex_desc((int) c)); 444 } 445 close(BGFiledes[0]); 446 } 447 return c; 448 } else if (mode & MODE_BACKGROUND) 449 close(BGFiledes[0]); 450 } 451 snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid", 452 _PATH_VARRUN, tunno); 453 (void) unlink(pid_filename); 454 455 if ((lockfile = fopen(pid_filename, "w")) != NULL) { 456 fprintf(lockfile, "%d\n", (int) getpid()); 457 fclose(lockfile); 458 } else 459 LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 460 pid_filename, strerror(errno)); 461 462 snprintf(if_filename, sizeof if_filename, "%s%s.if", 463 _PATH_VARRUN, VarBaseDevice); 464 (void) unlink(if_filename); 465 466 if ((lockfile = fopen(if_filename, "w")) != NULL) { 467 fprintf(lockfile, "tun%d\n", tunno); 468 fclose(lockfile); 469 } else 470 LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 471 if_filename, strerror(errno)); 472 473 VarTerm = 0; /* We know it's currently stdout */ 474 close(1); 475 close(2); 476 477#ifdef DOTTYINIT 478 if (mode & (MODE_DIRECT | MODE_DEDICATED)) 479#else 480 if (mode & MODE_DIRECT) 481#endif 482 TtyInit(1); 483 else { 484 setsid(); 485 close(0); 486 } 487 } else { 488 TtyInit(0); 489 TtyCommandMode(1); 490 } 491 LogPrintf(LogPHASE, "PPP Started.\n"); 492 493 494 do 495 DoLoop(); 496 while (mode & MODE_DEDICATED); 497 498 Cleanup(EX_DONE); 499 return 0; 500} 501 502/* 503 * Turn into packet mode, where we speak PPP. 504 */ 505void 506PacketMode() 507{ 508 if (RawModem(modem) < 0) { 509 LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 510 return; 511 } 512 AsyncInit(); 513 VjInit(); 514 LcpInit(); 515 IpcpInit(); 516 CcpInit(); 517 LcpUp(); 518 519 LcpOpen(VarOpenMode); 520 if ((mode & (MODE_INTER | MODE_AUTO)) == MODE_INTER) { 521 TtyCommandMode(1); 522 if (VarTerm) { 523 fprintf(VarTerm, "Packet mode.\n"); 524 aft_cmd = 1; 525 } 526 } 527} 528 529static void 530ShowHelp() 531{ 532 fprintf(stderr, "The following commands are available:\r\n"); 533 fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 534 fprintf(stderr, " ~-\tDecrease log level\r\n"); 535 fprintf(stderr, " ~+\tIncrease log level\r\n"); 536 fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 537 fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 538 fprintf(stderr, " ~.\tTerminate program\r\n"); 539 fprintf(stderr, " ~?\tThis help\r\n"); 540} 541 542static void 543ReadTty() 544{ 545 int n; 546 char ch; 547 static int ttystate; 548 FILE *oVarTerm; 549 550#define MAXLINESIZE 200 551 char linebuff[MAXLINESIZE]; 552 553 LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 554 TermMode, netfd, mode); 555 if (!TermMode) { 556 n = read(netfd, linebuff, sizeof(linebuff) - 1); 557 if (n > 0) { 558 aft_cmd = 1; 559 DecodeCommand(linebuff, n, 1); 560 } else { 561 LogPrintf(LogPHASE, "client connection closed.\n"); 562 VarLocalAuth = LOCAL_NO_AUTH; 563 mode &= ~MODE_INTER; 564 oVarTerm = VarTerm; 565 VarTerm = 0; 566 if (oVarTerm && oVarTerm != stdout) 567 fclose(oVarTerm); 568 close(netfd); 569 netfd = -1; 570 } 571 return; 572 } 573 574 /* 575 * We are in terminal mode, decode special sequences 576 */ 577 n = read(fileno(VarTerm), &ch, 1); 578 LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 579 580 if (n > 0) { 581 switch (ttystate) { 582 case 0: 583 if (ch == '~') 584 ttystate++; 585 else 586 write(modem, &ch, n); 587 break; 588 case 1: 589 switch (ch) { 590 case '?': 591 ShowHelp(); 592 break; 593 case 'p': 594 595 /* 596 * XXX: Should check carrier. 597 */ 598 if (LcpFsm.state <= ST_CLOSED) { 599 VarOpenMode = OPEN_ACTIVE; 600 PacketMode(); 601 } 602 break; 603 case '.': 604 TermMode = 1; 605 aft_cmd = 1; 606 TtyCommandMode(1); 607 break; 608 case 't': 609 if (LogIsKept(LogDEBUG)) { 610 ShowTimers(); 611 break; 612 } 613 case 'm': 614 if (LogIsKept(LogDEBUG)) { 615 ShowMemMap(); 616 break; 617 } 618 default: 619 if (write(modem, &ch, n) < 0) 620 LogPrintf(LogERROR, "error writing to modem.\n"); 621 break; 622 } 623 ttystate = 0; 624 break; 625 } 626 } 627} 628 629 630/* 631 * Here, we'll try to detect HDLC frame 632 */ 633 634static char *FrameHeaders[] = { 635 "\176\377\003\300\041", 636 "\176\377\175\043\300\041", 637 "\176\177\175\043\100\041", 638 "\176\175\337\175\043\300\041", 639 "\176\175\137\175\043\100\041", 640 NULL, 641}; 642 643u_char * 644HdlcDetect(u_char * cp, int n) 645{ 646 char *ptr, *fp, **hp; 647 648 cp[n] = '\0'; /* be sure to null terminated */ 649 ptr = NULL; 650 for (hp = FrameHeaders; *hp; hp++) { 651 fp = *hp; 652 if (DEV_IS_SYNC) 653 fp++; 654 ptr = strstr((char *) cp, fp); 655 if (ptr) 656 break; 657 } 658 return ((u_char *) ptr); 659} 660 661static struct pppTimer RedialTimer; 662 663static void 664RedialTimeout() 665{ 666 StopTimer(&RedialTimer); 667 LogPrintf(LogPHASE, "Redialing timer expired.\n"); 668} 669 670static void 671StartRedialTimer(int Timeout) 672{ 673 StopTimer(&RedialTimer); 674 675 if (Timeout) { 676 RedialTimer.state = TIMER_STOPPED; 677 678 if (Timeout > 0) 679 RedialTimer.load = Timeout * SECTICKS; 680 else 681 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 682 683 LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 684 RedialTimer.load / SECTICKS); 685 686 RedialTimer.func = RedialTimeout; 687 StartTimer(&RedialTimer); 688 } 689} 690 691 692static void 693DoLoop() 694{ 695 fd_set rfds, wfds, efds; 696 int pri, i, n, wfd, nfds; 697 struct sockaddr_in hisaddr; 698 struct timeval timeout, *tp; 699 int ssize = sizeof(hisaddr); 700 u_char *cp; 701 u_char rbuff[MAX_MRU]; 702 int tries; 703 int qlen; 704 int res; 705 pid_t pgroup; 706 707 pgroup = getpgrp(); 708 709 if (mode & MODE_DIRECT) { 710 LogPrintf(LogDEBUG, "Opening modem\n"); 711 if (OpenModem(mode) < 0) 712 return; 713 LogPrintf(LogPHASE, "Packet mode enabled\n"); 714 close(0); 715 PacketMode(); 716 } else if (mode & MODE_DEDICATED) { 717 if (modem < 0) 718 while (OpenModem(mode) < 0) 719 sleep(VarReconnectTimer); 720 } 721 fflush(VarTerm); 722 723 timeout.tv_sec = 0; 724 timeout.tv_usec = 0; 725 reconnectState = RECON_UNKNOWN; 726 727 if (mode & MODE_BACKGROUND) 728 dial_up = TRUE; /* Bring the line up */ 729 else 730 dial_up = FALSE; /* XXXX */ 731 tries = 0; 732 for (;;) { 733 nfds = 0; 734 FD_ZERO(&rfds); 735 FD_ZERO(&wfds); 736 FD_ZERO(&efds); 737 738 /* 739 * If the link is down and we're in DDIAL mode, bring it back up. 740 */ 741 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 742 dial_up = TRUE; 743 744 /* 745 * If we lost carrier and want to re-establish the connection due to the 746 * "set reconnect" value, we'd better bring the line back up. 747 */ 748 if (LcpFsm.state <= ST_CLOSED) { 749 if (dial_up != TRUE && reconnectState == RECON_TRUE) { 750 if (++reconnectCount <= VarReconnectTries) { 751 LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 752 reconnectCount, VarReconnectTries); 753 StartRedialTimer(VarReconnectTimer); 754 dial_up = TRUE; 755 } else { 756 if (VarReconnectTries) 757 LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 758 VarReconnectTries); 759 reconnectCount = 0; 760 if (mode & MODE_BACKGROUND) 761 Cleanup(EX_DEAD); 762 } 763 reconnectState = RECON_ENVOKED; 764 } 765 } 766 767 /* 768 * If Ip packet for output is enqueued and require dial up, Just do it! 769 */ 770 if (dial_up && RedialTimer.state != TIMER_RUNNING) { 771 LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 772 if (OpenModem(mode) < 0) { 773 tries++; 774 if (!(mode & MODE_DDIAL) && VarDialTries) 775 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 776 tries, VarDialTries); 777 else 778 LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 779 780 if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 781 if (mode & MODE_BACKGROUND) 782 Cleanup(EX_DIAL); /* Can't get the modem */ 783 dial_up = FALSE; 784 reconnectState = RECON_UNKNOWN; 785 reconnectCount = 0; 786 tries = 0; 787 } else 788 StartRedialTimer(VarRedialTimeout); 789 } else { 790 tries++; /* Tries are per number, not per list of 791 * numbers. */ 792 if (!(mode & MODE_DDIAL) && VarDialTries) 793 LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 794 else 795 LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 796 797 if ((res = DialModem()) == EX_DONE) { 798 sleep(1); /* little pause to allow peer starts */ 799 ModemTimeout(); 800 PacketMode(); 801 dial_up = FALSE; 802 reconnectState = RECON_UNKNOWN; 803 tries = 0; 804 } else { 805 CloseModem(); 806 if (mode & MODE_BACKGROUND) { 807 if (VarNextPhone == NULL || res == EX_SIG) 808 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 809 else 810 /* Try all numbers in background mode */ 811 StartRedialTimer(VarRedialNextTimeout); 812 } else if (!(mode & MODE_DDIAL) && 813 ((VarDialTries && tries >= VarDialTries) || 814 res == EX_SIG)) { 815 /* I give up ! Can't get through :( */ 816 StartRedialTimer(VarRedialTimeout); 817 dial_up = FALSE; 818 reconnectState = RECON_UNKNOWN; 819 reconnectCount = 0; 820 tries = 0; 821 } else if (VarNextPhone == NULL) 822 /* Dial failed. Keep quite during redial wait period. */ 823 StartRedialTimer(VarRedialTimeout); 824 else 825 StartRedialTimer(VarRedialNextTimeout); 826 } 827 } 828 } 829 qlen = ModemQlen(); 830 831 if (qlen == 0) { 832 IpStartOutput(); 833 qlen = ModemQlen(); 834 } 835 if (modem >= 0) { 836 if (modem + 1 > nfds) 837 nfds = modem + 1; 838 FD_SET(modem, &rfds); 839 FD_SET(modem, &efds); 840 if (qlen > 0) { 841 FD_SET(modem, &wfds); 842 } 843 } 844 if (server >= 0) { 845 if (server + 1 > nfds) 846 nfds = server + 1; 847 FD_SET(server, &rfds); 848 } 849 850 /* 851 * *** IMPORTANT *** 852 * 853 * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 854 * with great care. If this values is too big, it results loss of 855 * characters from modem and poor responce. If this values is too small, 856 * ppp process eats many CPU time. 857 */ 858#ifndef SIGALRM 859 usleep(TICKUNIT); 860 TimerService(); 861#else 862 handle_signals(); 863#endif 864 865 /* If there are aren't many packets queued, look for some more. */ 866 if (qlen < 20 && tun_in >= 0) { 867 if (tun_in + 1 > nfds) 868 nfds = tun_in + 1; 869 FD_SET(tun_in, &rfds); 870 } 871 if (netfd >= 0) { 872 if (netfd + 1 > nfds) 873 nfds = netfd + 1; 874 FD_SET(netfd, &rfds); 875 FD_SET(netfd, &efds); 876 } 877#ifndef SIGALRM 878 879 /* 880 * Normally, select() will not block because modem is writable. In AUTO 881 * mode, select will block until we find packet from tun 882 */ 883 tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 884 i = select(nfds, &rfds, &wfds, &efds, tp); 885#else 886 887 /* 888 * When SIGALRM timer is running, a select function will be return -1 and 889 * EINTR after a Time Service signal hundler is done. If the redial 890 * timer is not running and we are trying to dial, poll with a 0 value 891 * timer. 892 */ 893 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 894 i = select(nfds, &rfds, &wfds, &efds, tp); 895#endif 896 897 if (i == 0) { 898 continue; 899 } 900 if (i < 0) { 901 if (errno == EINTR) { 902 handle_signals(); 903 continue; 904 } 905 LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 906 break; 907 } 908 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 909 LogPrintf(LogALERT, "Exception detected.\n"); 910 break; 911 } 912 if (server >= 0 && FD_ISSET(server, &rfds)) { 913 LogPrintf(LogPHASE, "connected to client.\n"); 914 wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 915 if (wfd < 0) { 916 LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 917 continue; 918 } 919 if (netfd >= 0) { 920 write(wfd, "already in use.\n", 16); 921 close(wfd); 922 continue; 923 } else 924 netfd = wfd; 925 VarTerm = fdopen(netfd, "a+"); 926 mode |= MODE_INTER; 927 Greetings(); 928 (void) IsInteractive(); 929 Prompt(); 930 } 931 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 932 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 933 /* something to read from tty */ 934 ReadTty(); 935 } 936 if (modem >= 0) { 937 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 938 ModemStartOutput(modem); 939 } 940 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 941 if (LcpFsm.state <= ST_CLOSED) 942 usleep(10000); 943 n = read(modem, rbuff, sizeof(rbuff)); 944 if ((mode & MODE_DIRECT) && n <= 0) { 945 DownConnection(); 946 } else 947 LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 948 949 if (LcpFsm.state <= ST_CLOSED) { 950 951 /* 952 * In dedicated mode, we just discard input until LCP is started. 953 */ 954 if (!(mode & MODE_DEDICATED)) { 955 cp = HdlcDetect(rbuff, n); 956 if (cp) { 957 958 /* 959 * LCP packet is detected. Turn ourselves into packet mode. 960 */ 961 if (cp != rbuff) { 962 write(modem, rbuff, cp - rbuff); 963 write(modem, "\r\n", 2); 964 } 965 PacketMode(); 966 } else 967 write(fileno(VarTerm), rbuff, n); 968 } 969 } else { 970 if (n > 0) 971 AsyncInput(rbuff, n); 972 } 973 } 974 } 975 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 976 * from tun */ 977 n = read(tun_in, rbuff, sizeof(rbuff)); 978 if (n < 0) { 979 LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 980 continue; 981 } 982 if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 983 /* we've been asked to send something addressed *to* us :( */ 984 if (VarLoopback) { 985 pri = PacketCheck(rbuff, n, FL_IN); 986 if (pri >= 0) { 987 struct mbuf *bp; 988 989 if (mode & MODE_ALIAS) { 990 VarPacketAliasIn(rbuff, sizeof rbuff); 991 n = ntohs(((struct ip *) rbuff)->ip_len); 992 } 993 bp = mballoc(n, MB_IPIN); 994 bcopy(rbuff, MBUF_CTOP(bp), n); 995 IpInput(bp); 996 LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 997 } 998 continue; 999 } else 1000 LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 1001 } 1002 1003 /* 1004 * Process on-demand dialup. Output packets are queued within tunnel 1005 * device until IPCP is opened. 1006 */ 1007 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1008 pri = PacketCheck(rbuff, n, FL_DIAL); 1009 if (pri >= 0) { 1010 if (mode & MODE_ALIAS) { 1011 VarPacketAliasOut(rbuff, sizeof rbuff); 1012 n = ntohs(((struct ip *) rbuff)->ip_len); 1013 } 1014 IpEnqueue(pri, rbuff, n); 1015 dial_up = TRUE; /* XXX */ 1016 } 1017 continue; 1018 } 1019 pri = PacketCheck(rbuff, n, FL_OUT); 1020 if (pri >= 0) { 1021 if (mode & MODE_ALIAS) { 1022 VarPacketAliasOut(rbuff, sizeof rbuff); 1023 n = ntohs(((struct ip *) rbuff)->ip_len); 1024 } 1025 IpEnqueue(pri, rbuff, n); 1026 } 1027 } 1028 } 1029 LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1030} 1031