main.c revision 25910
1145522Sdarrenr/* 2145522Sdarrenr * User Process PPP 353642Sguido * 4255332Scy * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 553642Sguido * 680482Sdarrenr * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 753642Sguido * 853642Sguido * Redistribution and use in source and binary forms are permitted 957126Sguido * provided that the above copyright notice and this paragraph are 10172776Sdarrenr * duplicated in all such forms and that any documentation, 1153642Sguido * advertising materials, and other materials related to such 1253642Sguido * distribution and use acknowledge that the software was developed 1353642Sguido * by the Internet Initiative Japan, Inc. The name of the 1453642Sguido * IIJ may not be used to endorse or promote products derived 15153876Sguido * from this software without specific prior written permission. 16145522Sdarrenr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1760854Sdarrenr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18145522Sdarrenr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1960854Sdarrenr * 2060854Sdarrenr * $Id: main.c,v 1.52 1997/05/19 02:00:06 brian Exp $ 21145522Sdarrenr * 22145522Sdarrenr * TODO: 2380482Sdarrenr * o Add commands for traffic summary, version display, etc. 2480482Sdarrenr * o Add signal handler for misc controls. 2580482Sdarrenr */ 2680482Sdarrenr#include "fsm.h" 2780482Sdarrenr#include <fcntl.h> 2880482Sdarrenr#include <paths.h> 2953642Sguido#include <sys/time.h> 30255332Scy#include <termios.h> 31255332Scy#include <signal.h> 32255332Scy#include <sys/wait.h> 33255332Scy#include <errno.h> 3453642Sguido#include <netdb.h> 3553642Sguido#include <unistd.h> 3653642Sguido#include <sys/socket.h> 37145522Sdarrenr#include <arpa/inet.h> 3853642Sguido#include <netinet/in_systm.h> 3960854Sdarrenr#include <netinet/ip.h> 4060854Sdarrenr#include "modem.h" 4160854Sdarrenr#include "os.h" 4292685Sdarrenr#include "hdlc.h" 43145522Sdarrenr#include "ccp.h" 44145522Sdarrenr#include "lcp.h" 4595418Sdarrenr#include "ipcp.h" 46145522Sdarrenr#include "vars.h" 47145522Sdarrenr#include "auth.h" 48145522Sdarrenr#include "filter.h" 49145522Sdarrenr#include "systems.h" 50145522Sdarrenr#include "ip.h" 51145522Sdarrenr#include "alias.h" 52145522Sdarrenr#include "sig.h" 53145522Sdarrenr 54145522Sdarrenr#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 55145522Sdarrenr#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n" 56145522Sdarrenr 57145522Sdarrenr#ifndef O_NONBLOCK 5895418Sdarrenr#ifdef O_NDELAY 5953642Sguido#define O_NONBLOCK O_NDELAY 60145522Sdarrenr#endif 61255332Scy#endif 62145522Sdarrenr 63145522Sdarrenrextern void VjInit(), AsyncInit(); 64153876Sguidoextern void AsyncInput(); 65153876Sguidoextern int SelectSystem(); 6653642Sguido 6753642Sguidoextern void DecodeCommand(), Prompt(); 6853642Sguidoextern int aft_cmd; 6953642Sguidoextern int IsInteractive(); 7053642Sguidostatic void DoLoop(void); 71145522Sdarrenrstatic void TerminalStop(); 72145522Sdarrenrstatic char *ex_desc(); 73145522Sdarrenr 74145522Sdarrenrstatic struct termios oldtio; /* Original tty mode */ 7553642Sguidostatic struct termios comtio; /* Command level tty mode */ 76145522Sdarrenrint TermMode; 77145522Sdarrenrstatic int server; 78145522Sdarrenrstatic pid_t BGPid = 0; 79145522Sdarrenrstruct sockaddr_in ifsin; 80145522Sdarrenrstatic char pid_filename[MAXPATHLEN]; 81255332Scystatic char if_filename[MAXPATHLEN]; 82255332Scyint tunno; 83145522Sdarrenr 84145522Sdarrenrstatic void 85145522SdarrenrTtyInit() 8653642Sguido{ 8753642Sguido struct termios newtio; 88145522Sdarrenr int stat; 89145522Sdarrenr 90145522Sdarrenr stat = fcntl(0, F_GETFL, 0); 9160854Sdarrenr if (stat > 0) { 9260854Sdarrenr stat |= O_NONBLOCK; 9360854Sdarrenr (void)fcntl(0, F_SETFL, stat); 94145522Sdarrenr } 9560854Sdarrenr newtio = oldtio; 9660854Sdarrenr newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 9760854Sdarrenr newtio.c_iflag = 0; 9860854Sdarrenr newtio.c_oflag &= ~OPOST; 9953642Sguido newtio.c_cc[VEOF] = _POSIX_VDISABLE; 10053642Sguido newtio.c_cc[VINTR] = _POSIX_VDISABLE; 10153642Sguido newtio.c_cc[VMIN] = 1; 10253642Sguido newtio.c_cc[VTIME] = 0; 103145522Sdarrenr newtio.c_cflag |= CS8; 104145522Sdarrenr tcsetattr(0, TCSADRAIN, &newtio); 105145522Sdarrenr comtio = newtio; 106145522Sdarrenr} 10753642Sguido 10853642Sguido/* 10960854Sdarrenr * Set tty into command mode. We allow canonical input and echo processing. 11092685Sdarrenr */ 111145522Sdarrenrvoid 112145522SdarrenrTtyCommandMode(prompt) 11353642Sguidoint prompt; 114145522Sdarrenr{ 115145522Sdarrenr struct termios newtio; 116145522Sdarrenr int stat; 117145522Sdarrenr 118145522Sdarrenr if (!(mode & MODE_INTER)) 119145522Sdarrenr return; 120145522Sdarrenr tcgetattr(0, &newtio); 121145522Sdarrenr newtio.c_lflag |= (ECHO|ISIG|ICANON); 122145522Sdarrenr newtio.c_iflag = oldtio.c_iflag; 123145522Sdarrenr newtio.c_oflag |= OPOST; 124145522Sdarrenr tcsetattr(0, TCSADRAIN, &newtio); 125145522Sdarrenr stat = fcntl(0, F_GETFL, 0); 126255332Scy if (stat > 0) { 127145522Sdarrenr stat |= O_NONBLOCK; 128145522Sdarrenr (void)fcntl(0, F_SETFL, stat); 129145522Sdarrenr } 130145522Sdarrenr TermMode = 0; 131145522Sdarrenr if(prompt) Prompt(); 132145522Sdarrenr} 133145522Sdarrenr 134145522Sdarrenr/* 135145522Sdarrenr * Set tty into terminal mode which is used while we invoke term command. 136145522Sdarrenr */ 137145522Sdarrenrvoid 138255332ScyTtyTermMode() 139145522Sdarrenr{ 140145522Sdarrenr int stat; 141145522Sdarrenr 14253642Sguido tcsetattr(0, TCSADRAIN, &comtio); 14353642Sguido stat = fcntl(0, F_GETFL, 0); 14453642Sguido if (stat > 0) { 14553642Sguido stat &= ~O_NONBLOCK; 14653642Sguido (void)fcntl(0, F_SETFL, stat); 14753642Sguido } 14853642Sguido TermMode = 1; 14953642Sguido} 150145522Sdarrenr 151145522Sdarrenrvoid 15253642SguidoTtyOldMode() 15353642Sguido{ 15460854Sdarrenr int stat; 15560854Sdarrenr 15660854Sdarrenr stat = fcntl(0, F_GETFL, 0); 15760854Sdarrenr if (stat > 0) { 15860854Sdarrenr stat &= ~O_NONBLOCK; 15953642Sguido (void)fcntl(0, F_SETFL, stat); 16060854Sdarrenr } 16160854Sdarrenr tcsetattr(0, TCSANOW, &oldtio); 16260854Sdarrenr} 16353642Sguido 164145522Sdarrenrvoid 165145522SdarrenrCleanup(excode) 166145522Sdarrenrint excode; 167145522Sdarrenr{ 168145522Sdarrenr 16953642Sguido OsLinkdown(); 17053642Sguido OsCloseLink(1); 17153642Sguido sleep(1); 17253642Sguido if (mode & MODE_AUTO) 17353642Sguido DeleteIfRoutes(1); 17453642Sguido (void)unlink(pid_filename); 17560854Sdarrenr (void)unlink(if_filename); 17660854Sdarrenr OsInterfaceDown(1); 17760854Sdarrenr if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 17860854Sdarrenr char c = EX_ERRDEAD; 179102520Sdarrenr if (write(BGFiledes[1],&c,1) == 1) 180145522Sdarrenr LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n"); 18153642Sguido else 18253642Sguido LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n"); 18353642Sguido close(BGFiledes[1]); 18453642Sguido } 18553642Sguido LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode)); 18653642Sguido LogClose(); 187145522Sdarrenr if (server >= 0) { 188145522Sdarrenr close(server); 189255332Scy server = -1; 190145522Sdarrenr } 191145522Sdarrenr 192145522Sdarrenr TtyOldMode(); 193145522Sdarrenr 194145522Sdarrenr exit(excode); 195145522Sdarrenr} 196170268Sdarrenr 19753642Sguidostatic void 19853642SguidoHangup(signo) 19953642Sguidoint signo; 200255332Scy{ 201255332Scy if (signo == SIGSEGV) { 202255332Scy LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 203255332Scy LogClose(); 204255332Scy abort(); 205255332Scy } 206255332Scy if (BGPid) { 207255332Scy kill (BGPid, SIGTERM); 208255332Scy exit (EX_HANGUP); 209255332Scy } 210255332Scy else { 211255332Scy LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 212255332Scy Cleanup(EX_HANGUP); 213255332Scy } 214255332Scy} 215255332Scy 216255332Scystatic void 217255332ScyCloseSession(signo) 218255332Scyint signo; 219255332Scy{ 22053642Sguido if (BGPid) { 221255332Scy kill (BGPid, SIGINT); 222255332Scy exit (EX_TERM); 223255332Scy } 224255332Scy else { 225255332Scy LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 226255332Scy LcpClose(); 227255332Scy reconnectCount = 0; 228255332Scy Cleanup(EX_TERM); 229255332Scy } 230255332Scy} 231255332Scy 232255332Scystatic void 233255332ScyTerminalCont() 234255332Scy{ 235255332Scy pending_signal(SIGCONT, SIG_DFL); 236255332Scy pending_signal(SIGTSTP, TerminalStop); 237255332Scy TtyCommandMode(getpgrp() == tcgetpgrp(0)); 238255332Scy} 239255332Scy 240255332Scystatic void 24153642SguidoTerminalStop(signo) 242255332Scyint signo; 243255332Scy{ 244255332Scy pending_signal(SIGCONT, TerminalCont); 24553642Sguido TtyOldMode(); 246255332Scy pending_signal(SIGTSTP, SIG_DFL); 247255332Scy kill(getpid(), signo); 248255332Scy} 249255332Scy 250255332Scystatic char * 251255332Scyex_desc(int ex) 252255332Scy{ 25353642Sguido static char num[12]; 254255332Scy static char *desc[] = { "normal", "start", "sock", 255255332Scy "modem", "dial", "dead", "done", "reboot", "errdead", 256255332Scy "hangup", "term", "nodial", "nologin" }; 257255332Scy 258255332Scy if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 259255332Scy return desc[ex]; 260255332Scy snprintf(num, sizeof num, "%d", ex); 261170268Sdarrenr return num; 262255332Scy} 263255332Scy 264255332Scyvoid 265255332ScyUsage() 26653642Sguido{ 26753642Sguido fprintf(stderr, 26853642Sguido "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 269255332Scy exit(EX_START); 270255332Scy} 271255332Scy 272255332Scyvoid 273255332ScyProcessArgs(int argc, char **argv) 274255332Scy{ 275255332Scy int optc; 276255332Scy char *cp; 277255332Scy 278255332Scy optc = 0; 279255332Scy while (argc > 0 && **argv == '-') { 280255332Scy cp = *argv + 1; 281255332Scy if (strcmp(cp, "auto") == 0) 282255332Scy mode |= MODE_AUTO; 283255332Scy else if (strcmp(cp, "background") == 0) 284255332Scy mode |= MODE_BACKGROUND|MODE_AUTO; 285255332Scy else if (strcmp(cp, "direct") == 0) 286255332Scy mode |= MODE_DIRECT; 287255332Scy else if (strcmp(cp, "dedicated") == 0) 288255332Scy mode |= MODE_DEDICATED; 289255332Scy else if (strcmp(cp, "ddial") == 0) 290255332Scy mode |= MODE_DDIAL|MODE_AUTO; 291255332Scy else if (strcmp(cp, "alias") == 0) { 292255332Scy mode |= MODE_ALIAS; 293255332Scy optc--; /* this option isn't exclusive */ 294255332Scy } 295255332Scy else 296255332Scy Usage(); 297145522Sdarrenr optc++; 298255332Scy argv++; argc--; 299255332Scy } 300255332Scy if (argc > 1) { 301255332Scy fprintf(stderr, "specify only one system label.\n"); 302255332Scy exit(EX_START); 303255332Scy } 304255332Scy if (argc == 1) dstsystem = *argv; 305145522Sdarrenr 30653642Sguido if (optc > 1) { 307255332Scy fprintf(stderr, "specify only one mode.\n"); 308255332Scy exit(EX_START); 309255332Scy } 310255332Scy} 311255332Scy 312255332Scystatic void 313255332ScyGreetings() 314255332Scy{ 315255332Scy printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 316255332Scy fflush(stdout); 317255332Scy} 318255332Scy 319255332Scyvoid 320255332Scymain(argc, argv) 321255332Scyint argc; 322255332Scychar **argv; 323255332Scy{ 324255332Scy FILE *lockfile; 325255332Scy argc--; argv++; 326255332Scy 327255332Scy mode = MODE_INTER; /* default operation is interactive mode */ 328255332Scy netfd = server = modem = tun_in = -1; 329255332Scy ProcessArgs(argc, argv); 330255332Scy Greetings(); 331255332Scy GetUid(); 332255332Scy IpcpDefAddress(); 333255332Scy InitAlias(); 334255332Scy 335255332Scy if (SelectSystem("default", CONFFILE) < 0) { 336255332Scy fprintf(stderr, "Warning: No default entry is given in config file.\n"); 33753642Sguido } 338 339 switch ( LocalAuthInit() ) { 340 case NOT_FOUND: 341 fprintf(stderr,LAUTH_M1); 342 fprintf(stderr,LAUTH_M2); 343 fflush (stderr); 344 /* Fall down */ 345 case VALID: 346 VarLocalAuth = LOCAL_AUTH; 347 break; 348 default: 349 break; 350 } 351 352 if (OpenTunnel(&tunno) < 0) { 353 perror("open_tun"); 354 exit(EX_START); 355 } 356 357 if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 358 mode &= ~MODE_INTER; 359 if (mode & MODE_INTER) { 360 printf("Interactive mode\n"); 361 netfd = STDIN_FILENO; 362 } else if (mode & MODE_AUTO) { 363 printf("Automatic Dialer mode\n"); 364 if (dstsystem == NULL) { 365 fprintf(stderr, "Destination system must be specified in" 366 " auto, background or ddial mode.\n"); 367 exit(EX_START); 368 } 369 } 370 371 tcgetattr(0, &oldtio); /* Save original tty mode */ 372 373 pending_signal(SIGHUP, LogReOpen); 374 pending_signal(SIGTERM, CloseSession); 375 pending_signal(SIGINT, CloseSession); 376 pending_signal(SIGQUIT, CloseSession); 377#ifdef SIGSEGV 378 signal(SIGSEGV, Hangup); 379#endif 380#ifdef SIGPIPE 381 signal(SIGPIPE, SIG_IGN); 382#endif 383#ifdef SIGALRM 384 pending_signal(SIGALRM, SIG_IGN); 385#endif 386 if(mode & MODE_INTER) 387 { 388#ifdef SIGTSTP 389 pending_signal(SIGTSTP, TerminalStop); 390#endif 391#ifdef SIGTTIN 392 pending_signal(SIGTTIN, TerminalStop); 393#endif 394#ifdef SIGTTOU 395 pending_signal(SIGTTOU, SIG_IGN); 396#endif 397 } 398 399 if (dstsystem) { 400 if (SelectSystem(dstsystem, CONFFILE) < 0) { 401 fprintf(stderr, "Destination system not found in conf file.\n"); 402 Cleanup(EX_START); 403 } 404 if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 405 fprintf(stderr, "Must specify dstaddr with" 406 " auto, background or ddial mode.\n"); 407 Cleanup(EX_START); 408 } 409 } 410 if (mode & MODE_DIRECT) 411 printf("Packet mode enabled.\n"); 412 413 if (!(mode & MODE_INTER)) { 414 int port = SERVER_PORT + tunno; 415 416 if (mode & MODE_BACKGROUND) { 417 if (pipe (BGFiledes)) { 418 perror("pipe"); 419 Cleanup(EX_SOCK); 420 } 421 } 422 423 /* Create server socket and listen at there. */ 424 server = socket(PF_INET, SOCK_STREAM, 0); 425 if (server < 0) { 426 perror("socket"); 427 Cleanup(EX_SOCK); 428 } 429 ifsin.sin_family = AF_INET; 430 ifsin.sin_addr.s_addr = INADDR_ANY; 431 ifsin.sin_port = htons(port); 432 if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 433 perror("bind"); 434 if (errno == EADDRINUSE) 435 fprintf(stderr, "Wait for a while, then try again.\n"); 436 Cleanup(EX_SOCK); 437 } 438 if (listen(server, 5) != 0) { 439 fprintf(stderr, "Unable to listen to socket - OS overload?\n"); 440 } 441 442 DupLog(); 443 if (!(mode & MODE_DIRECT)) { 444 pid_t bgpid; 445 446 bgpid = fork (); 447 if (bgpid == -1) { 448 perror ("fork"); 449 Cleanup (EX_SOCK); 450 } 451 if (bgpid) { 452 char c = EX_NORMAL; 453 454 if (mode & MODE_BACKGROUND) { 455 /* Wait for our child to close its pipe before we exit. */ 456 BGPid = bgpid; 457 close (BGFiledes[1]); 458 if (read(BGFiledes[0], &c, 1) != 1) { 459 printf("Child exit, no status.\n"); 460 LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n"); 461 } else if (c == EX_NORMAL) { 462 printf("PPP enabled.\n"); 463 LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n"); 464 } else { 465 printf("Child failed (%s).\n",ex_desc((int)c)); 466 LogPrintf(LOG_PHASE_BIT, "Parent: Child failed (%s).\n", 467 ex_desc((int)c)); 468 } 469 close (BGFiledes[0]); 470 } 471 exit(c); 472 } else if (mode & MODE_BACKGROUND) 473 close(BGFiledes[0]); 474 } 475 476 snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 477 _PATH_VARRUN, tunno); 478 (void)unlink(pid_filename); 479 480 if ((lockfile = fopen(pid_filename, "w")) != NULL) { 481 fprintf(lockfile, "%d\n", (int)getpid()); 482 fclose(lockfile); 483 } else 484 logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno)); 485 486 snprintf(if_filename, sizeof if_filename, "%s%s.if", 487 _PATH_VARRUN, VarBaseDevice); 488 (void)unlink(if_filename); 489 490 if ((lockfile = fopen(if_filename, "w")) != NULL) { 491 fprintf(lockfile, "tun%d\n", tunno); 492 fclose(lockfile); 493 } else 494 logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno)); 495 496 if (server >= 0) 497 LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 498#ifdef DOTTYINIT 499 if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 500#else 501 if (mode & MODE_DIRECT) { 502#endif 503 TtyInit(); 504 } else { 505 int fd; 506 507 setsid(); /* detach control tty */ 508 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 509 (void)dup2(fd, STDIN_FILENO); 510 (void)dup2(fd, STDOUT_FILENO); 511 (void)dup2(fd, STDERR_FILENO); 512 if (fd > 2) 513 (void)close (fd); 514 } 515 } 516 } else { 517 TtyInit(); 518 TtyCommandMode(1); 519 } 520 LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 521 522 523 do 524 DoLoop(); 525 while (mode & MODE_DEDICATED); 526 527 Cleanup(EX_DONE); 528} 529 530/* 531 * Turn into packet mode, where we speak PPP. 532 */ 533void 534PacketMode() 535{ 536 if (RawModem(modem) < 0) { 537 fprintf(stderr, "Not connected.\r\n"); 538 return; 539 } 540 541 AsyncInit(); 542 VjInit(); 543 LcpInit(); 544 IpcpInit(); 545 CcpInit(); 546 LcpUp(); 547 548 LcpOpen(VarOpenMode); 549 if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 550 TtyCommandMode(1); 551 fprintf(stderr, "Packet mode.\r\n"); 552 aft_cmd = 1; 553 } 554} 555 556static void 557ShowHelp() 558{ 559 fprintf(stderr, "The following commands are available:\r\n"); 560 fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 561 fprintf(stderr, " ~-\tDecrease log level\r\n"); 562 fprintf(stderr, " ~+\tIncrease log level\r\n"); 563 fprintf(stderr, " ~.\tTerminate program\r\n"); 564 fprintf(stderr, " ~?\tThis help\r\n"); 565} 566 567static void 568ReadTty() 569{ 570 int n; 571 char ch; 572 static int ttystate; 573#define MAXLINESIZE 200 574 char linebuff[MAXLINESIZE]; 575 576#ifdef DEBUG 577 logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 578#endif 579 if (!TermMode) { 580 n = read(netfd, linebuff, sizeof(linebuff)-1); 581 aft_cmd = 1; 582 if (n > 0) { 583 DecodeCommand(linebuff, n, 1); 584 } else { 585 LogPrintf(LOG_PHASE_BIT, "client connection closed.\n"); 586 VarLocalAuth = LOCAL_NO_AUTH; 587 close(netfd); 588 close(1); 589 dup2(2, 1); /* Have to have something here or the modem will be 1 */ 590 netfd = -1; 591 mode &= ~MODE_INTER; 592 } 593 return; 594 } 595 596 /* 597 * We are in terminal mode, decode special sequences 598 */ 599 n = read(0, &ch, 1); 600#ifdef DEBUG 601 logprintf("got %d bytes\n", n); 602#endif 603 604 if (n > 0) { 605 switch (ttystate) { 606 case 0: 607 if (ch == '~') 608 ttystate++; 609 else 610 write(modem, &ch, n); 611 break; 612 case 1: 613 switch (ch) { 614 case '?': 615 ShowHelp(); 616 break; 617 case '-': 618 if (loglevel > 0) { 619 loglevel--; 620 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 621 } 622 break; 623 case '+': 624 loglevel++; 625 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 626 break; 627#ifdef DEBUG 628 case 'm': 629 ShowMemMap(); 630 break; 631#endif 632 case 'p': 633 /* 634 * XXX: Should check carrier. 635 */ 636 if (LcpFsm.state <= ST_CLOSED) { 637 VarOpenMode = OPEN_ACTIVE; 638 PacketMode(); 639 } 640 break; 641#ifdef DEBUG 642 case 't': 643 ShowTimers(); 644 break; 645#endif 646 case '.': 647 TermMode = 1; 648 TtyCommandMode(1); 649 break; 650 default: 651 if (write(modem, &ch, n) < 0) 652 fprintf(stderr, "err in write.\r\n"); 653 break; 654 } 655 ttystate = 0; 656 break; 657 } 658 } 659} 660 661 662/* 663 * Here, we'll try to detect HDLC frame 664 */ 665 666static char *FrameHeaders[] = { 667 "\176\377\003\300\041", 668 "\176\377\175\043\300\041", 669 "\176\177\175\043\100\041", 670 "\176\175\337\175\043\300\041", 671 "\176\175\137\175\043\100\041", 672 NULL, 673}; 674 675u_char * 676HdlcDetect(cp, n) 677u_char *cp; 678int n; 679{ 680 char *ptr, *fp, **hp; 681 682 cp[n] = '\0'; /* be sure to null terminated */ 683 ptr = NULL; 684 for (hp = FrameHeaders; *hp; hp++) { 685 fp = *hp; 686 if (DEV_IS_SYNC) 687 fp++; 688 ptr = strstr((char *)cp, fp); 689 if (ptr) 690 break; 691 } 692 return((u_char *)ptr); 693} 694 695static struct pppTimer RedialTimer; 696 697static void 698RedialTimeout() 699{ 700 StopTimer(&RedialTimer); 701 LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 702} 703 704static void 705StartRedialTimer(Timeout) 706 int Timeout; 707{ 708 StopTimer(&RedialTimer); 709 710 if (Timeout) { 711 RedialTimer.state = TIMER_STOPPED; 712 713 if (Timeout > 0) 714 RedialTimer.load = Timeout * SECTICKS; 715 else 716 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 717 718 LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n", 719 RedialTimer.load / SECTICKS); 720 721 RedialTimer.func = RedialTimeout; 722 StartTimer(&RedialTimer); 723 } 724} 725 726 727static void 728DoLoop() 729{ 730 fd_set rfds, wfds, efds; 731 int pri, i, n, wfd, nfds; 732 struct sockaddr_in hisaddr; 733 struct timeval timeout, *tp; 734 int ssize = sizeof(hisaddr); 735 u_char *cp; 736 u_char rbuff[MAX_MRU]; 737 int dial_up; 738 int tries; 739 int qlen; 740 pid_t pgroup; 741 742 pgroup = getpgrp(); 743 744 if (mode & MODE_DIRECT) { 745 modem = OpenModem(mode); 746 LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 747 fflush(stderr); 748 PacketMode(); 749 } else if (mode & MODE_DEDICATED) { 750 if (modem < 0) 751 modem = OpenModem(mode); 752 } 753 754 fflush(stdout); 755 756 timeout.tv_sec = 0; 757 timeout.tv_usec = 0; 758 reconnectRequired = 0; 759 760 if (mode & MODE_BACKGROUND) 761 dial_up = TRUE; /* Bring the line up */ 762 else 763 dial_up = FALSE; /* XXXX */ 764 tries = 0; 765 for (;;) { 766 nfds = 0; 767 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 768 769 /* 770 * If the link is down and we're in DDIAL mode, bring it back 771 * up. 772 */ 773 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 774 dial_up = TRUE; 775 776 /* 777 * If we lost carrier and want to re-establish the connection 778 * due to the "set reconnect" value, we'd better bring the line 779 * back up. 780 */ 781 if (LcpFsm.state <= ST_CLOSED) { 782 if (dial_up != TRUE && reconnectRequired) { 783 if (++reconnectCount <= VarReconnectTries) { 784 LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n", 785 reconnectCount, VarReconnectTries); 786 StartRedialTimer(VarReconnectTimer); 787 dial_up = TRUE; 788 } else { 789 if (VarReconnectTries) 790 LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n", 791 VarReconnectTries); 792 reconnectCount = 0; 793 if (mode & MODE_BACKGROUND) 794 Cleanup(EX_DEAD); 795 } 796 } 797 reconnectRequired = 0; 798 } 799 800 /* 801 * If Ip packet for output is enqueued and require dial up, 802 * Just do it! 803 */ 804 if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 805#ifdef DEBUG 806 logprintf("going to dial: modem = %d\n", modem); 807#endif 808 modem = OpenModem(mode); 809 if (modem < 0) { 810 StartRedialTimer(VarRedialTimeout); 811 } else { 812 tries++; /* Tries are per number, not per list of numbers. */ 813 if (VarDialTries) 814 LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries, 815 VarDialTries); 816 else 817 LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 818 if (DialModem()) { 819 sleep(1); /* little pause to allow peer starts */ 820 ModemTimeout(); 821 PacketMode(); 822 dial_up = FALSE; 823 tries = 0; 824 } else { 825 CloseModem(); 826 if (mode & MODE_BACKGROUND) { 827 if (VarNextPhone == NULL) 828 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 829 else 830 /* Try all numbers in background mode */ 831 StartRedialTimer(VarRedialNextTimeout); 832 } else if (VarDialTries && tries >= VarDialTries) { 833 /* I give up ! Can't get through :( */ 834 StartRedialTimer(VarRedialTimeout); 835 dial_up = FALSE; 836 tries = 0; 837 } else if (VarNextPhone == NULL) 838 /* Dial failed. Keep quite during redial wait period. */ 839 StartRedialTimer(VarRedialTimeout); 840 else 841 StartRedialTimer(VarRedialNextTimeout); 842 } 843 } 844 } 845 qlen = ModemQlen(); 846 847 if (qlen == 0) { 848 IpStartOutput(); 849 qlen = ModemQlen(); 850 } 851 852 if (modem >= 0) { 853 if (modem + 1 > nfds) 854 nfds = modem + 1; 855 FD_SET(modem, &rfds); 856 FD_SET(modem, &efds); 857 if (qlen > 0) { 858 FD_SET(modem, &wfds); 859 } 860 } 861 if (server >= 0) { 862 if (server + 1 > nfds) 863 nfds = server + 1; 864 FD_SET(server, &rfds); 865 } 866 867 /* *** IMPORTANT *** 868 * 869 * CPU is serviced every TICKUNIT micro seconds. 870 * This value must be chosen with great care. If this values is 871 * too big, it results loss of characters from modem and poor responce. 872 * If this values is too small, ppp process eats many CPU time. 873 */ 874#ifndef SIGALRM 875 usleep(TICKUNIT); 876 TimerService(); 877#else 878 handle_signals(); 879#endif 880 881 /* If there are aren't many packets queued, look for some more. */ 882 if (qlen < 20 && tun_in >= 0) { 883 if (tun_in + 1 > nfds) 884 nfds = tun_in + 1; 885 FD_SET(tun_in, &rfds); 886 } 887 888 if (netfd >= 0) { 889 if (netfd + 1 > nfds) 890 nfds = netfd + 1; 891 FD_SET(netfd, &rfds); 892 FD_SET(netfd, &efds); 893 } 894 895#ifndef SIGALRM 896 /* 897 * Normally, select() will not block because modem is writable. 898 * In AUTO mode, select will block until we find packet from tun 899 */ 900 tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 901 i = select(nfds, &rfds, &wfds, &efds, tp); 902#else 903 /* 904 * When SIGALRM timer is running, a select function will be 905 * return -1 and EINTR after a Time Service signal hundler 906 * is done. If the redial timer is not running and we are 907 * trying to dial, poll with a 0 value timer. 908 */ 909 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 910 i = select(nfds, &rfds, &wfds, &efds, tp); 911#endif 912 913 if ( i == 0 ) { 914 continue; 915 } 916 917 if ( i < 0 ) { 918 if ( errno == EINTR ) { 919 handle_signals(); 920 continue; 921 } 922 perror("select"); 923 break; 924 } 925 926 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 927 logprintf("Exception detected.\n"); 928 break; 929 } 930 931 if (server >= 0 && FD_ISSET(server, &rfds)) { 932 LogPrintf(LOG_PHASE_BIT, "connected to client.\n"); 933 wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 934 if (wfd < 0) { 935 perror("accept"); 936 continue; 937 } 938 if (netfd >= 0) { 939 write(wfd, "already in use.\n", 16); 940 close(wfd); 941 continue; 942 } else 943 netfd = wfd; 944 if (dup2(netfd, 1) < 0) { 945 perror("dup2"); 946 close(netfd); 947 netfd = -1; 948 continue; 949 } 950 mode |= MODE_INTER; 951 Greetings(); 952 switch ( LocalAuthInit() ) { 953 case NOT_FOUND: 954 fprintf(stdout,LAUTH_M1); 955 fprintf(stdout,LAUTH_M2); 956 fflush(stdout); 957 /* Fall down */ 958 case VALID: 959 VarLocalAuth = LOCAL_AUTH; 960 break; 961 default: 962 break; 963 } 964 (void) IsInteractive(); 965 Prompt(); 966 } 967 968 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 969 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 970 /* something to read from tty */ 971 ReadTty(); 972 } 973 if (modem >= 0) { 974 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 975 ModemStartOutput(modem); 976 } 977 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 978 if (LcpFsm.state <= ST_CLOSED) 979 usleep(10000); 980 n = read(modem, rbuff, sizeof(rbuff)); 981 if ((mode & MODE_DIRECT) && n <= 0) { 982 DownConnection(); 983 } else 984 LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 985 986 if (LcpFsm.state <= ST_CLOSED) { 987 /* 988 * In dedicated mode, we just discard input until LCP is started. 989 */ 990 if (!(mode & MODE_DEDICATED)) { 991 cp = HdlcDetect(rbuff, n); 992 if (cp) { 993 /* 994 * LCP packet is detected. Turn ourselves into packet mode. 995 */ 996 if (cp != rbuff) { 997 write(1, rbuff, cp - rbuff); 998 write(1, "\r\n", 2); 999 } 1000 PacketMode(); 1001 } else 1002 write(1, rbuff, n); 1003 } 1004 } else { 1005 if (n > 0) 1006 AsyncInput(rbuff, n); 1007 } 1008 } 1009 } 1010 1011 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 1012 n = read(tun_in, rbuff, sizeof(rbuff)); 1013 if (n < 0) { 1014 perror("read from tun"); 1015 continue; 1016 } 1017 /* 1018 * Process on-demand dialup. Output packets are queued within tunnel 1019 * device until IPCP is opened. 1020 */ 1021 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1022 pri = PacketCheck(rbuff, n, FL_DIAL); 1023 if (pri >= 0) { 1024 if (mode & MODE_ALIAS) { 1025 PacketAliasOut((struct ip *)rbuff); 1026 n = ntohs(((struct ip *)rbuff)->ip_len); 1027 } 1028 IpEnqueue(pri, rbuff, n); 1029 dial_up = TRUE; /* XXX */ 1030 } 1031 continue; 1032 } 1033 pri = PacketCheck(rbuff, n, FL_OUT); 1034 if (pri >= 0) { 1035 if (mode & MODE_ALIAS) { 1036 PacketAliasOut((struct ip *)rbuff); 1037 n = ntohs(((struct ip *)rbuff)->ip_len); 1038 } 1039 IpEnqueue(pri, rbuff, n); 1040 } 1041 } 1042 } 1043 logprintf("job done.\n"); 1044} 1045