main.c revision 26551
1/* 2 * User Process PPP 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: main.c,v 1.60 1997/06/09 03:27:28 brian Exp $ 21 * 22 * TODO: 23 * o Add commands for traffic summary, version display, etc. 24 * o Add signal handler for misc controls. 25 */ 26#include "fsm.h" 27#include <fcntl.h> 28#include <paths.h> 29#include <sys/time.h> 30#include <termios.h> 31#include <signal.h> 32#include <sys/wait.h> 33#include <errno.h> 34#include <netdb.h> 35#include <unistd.h> 36#include <sys/socket.h> 37#include <arpa/inet.h> 38#include <netinet/in_systm.h> 39#include <netinet/ip.h> 40#include "modem.h" 41#include "os.h" 42#include "hdlc.h" 43#include "ccp.h" 44#include "lcp.h" 45#include "ipcp.h" 46#include "loadalias.h" 47#include "vars.h" 48#include "auth.h" 49#include "filter.h" 50#include "systems.h" 51#include "ip.h" 52#include "sig.h" 53 54#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 55#define LAUTH_M2 "Warning: Manipulation is allowed by anyone\n" 56 57#ifndef O_NONBLOCK 58#ifdef O_NDELAY 59#define O_NONBLOCK O_NDELAY 60#endif 61#endif 62 63extern void VjInit(), AsyncInit(); 64extern void AsyncInput(); 65extern int SelectSystem(); 66 67extern void DecodeCommand(), Prompt(); 68extern int aft_cmd; 69extern int IsInteractive(); 70static void DoLoop(void); 71static void TerminalStop(); 72static char *ex_desc(); 73 74static struct termios oldtio; /* Original tty mode */ 75static struct termios comtio; /* Command level tty mode */ 76int TermMode; 77static int server; 78static pid_t BGPid = 0; 79struct sockaddr_in ifsin; 80static char pid_filename[MAXPATHLEN]; 81static char if_filename[MAXPATHLEN]; 82int tunno; 83 84static void 85TtyInit() 86{ 87 struct termios newtio; 88 int stat; 89 90 stat = fcntl(0, F_GETFL, 0); 91 if (stat > 0) { 92 stat |= O_NONBLOCK; 93 (void)fcntl(0, F_SETFL, stat); 94 } 95 newtio = oldtio; 96 newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 97 newtio.c_iflag = 0; 98 newtio.c_oflag &= ~OPOST; 99 newtio.c_cc[VEOF] = _POSIX_VDISABLE; 100 newtio.c_cc[VINTR] = _POSIX_VDISABLE; 101 newtio.c_cc[VMIN] = 1; 102 newtio.c_cc[VTIME] = 0; 103 newtio.c_cflag |= CS8; 104 tcsetattr(0, TCSADRAIN, &newtio); 105 comtio = newtio; 106} 107 108/* 109 * Set tty into command mode. We allow canonical input and echo processing. 110 */ 111void 112TtyCommandMode(prompt) 113int prompt; 114{ 115 struct termios newtio; 116 int stat; 117 118 if (!(mode & MODE_INTER)) 119 return; 120 tcgetattr(0, &newtio); 121 newtio.c_lflag |= (ECHO|ISIG|ICANON); 122 newtio.c_iflag = oldtio.c_iflag; 123 newtio.c_oflag |= OPOST; 124 tcsetattr(0, TCSADRAIN, &newtio); 125 stat = fcntl(0, F_GETFL, 0); 126 if (stat > 0) { 127 stat |= O_NONBLOCK; 128 (void)fcntl(0, F_SETFL, stat); 129 } 130 TermMode = 0; 131 if(prompt) Prompt(); 132} 133 134/* 135 * Set tty into terminal mode which is used while we invoke term command. 136 */ 137void 138TtyTermMode() 139{ 140 int stat; 141 142 tcsetattr(0, TCSADRAIN, &comtio); 143 stat = fcntl(0, F_GETFL, 0); 144 if (stat > 0) { 145 stat &= ~O_NONBLOCK; 146 (void)fcntl(0, F_SETFL, stat); 147 } 148 TermMode = 1; 149} 150 151void 152TtyOldMode() 153{ 154 int stat; 155 156 stat = fcntl(0, F_GETFL, 0); 157 if (stat > 0) { 158 stat &= ~O_NONBLOCK; 159 (void)fcntl(0, F_SETFL, stat); 160 } 161 tcsetattr(0, TCSANOW, &oldtio); 162} 163 164void 165Cleanup(excode) 166int excode; 167{ 168 169 OsLinkdown(); 170 OsCloseLink(1); 171 sleep(1); 172 if (mode & MODE_AUTO) 173 DeleteIfRoutes(1); 174 (void)unlink(pid_filename); 175 (void)unlink(if_filename); 176 OsInterfaceDown(1); 177 if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 178 char c = EX_ERRDEAD; 179 if (write(BGFiledes[1],&c,1) == 1) 180 LogPrintf(LogPHASE,"Parent notified of failure.\n"); 181 else 182 LogPrintf(LogPHASE,"Failed to notify parent of failure.\n"); 183 close(BGFiledes[1]); 184 } 185 LogPrintf(LogPHASE, "PPP Terminated (%s).\n",ex_desc(excode)); 186 LogClose(); 187 if (server >= 0) { 188 close(server); 189 server = -1; 190 } 191 192 TtyOldMode(); 193 194 exit(excode); 195} 196 197static void 198Hangup(signo) 199int signo; 200{ 201#ifdef TRAPSEGV 202 if (signo == SIGSEGV) { 203 LogPrintf(LogPHASE, "Signal %d, core dump.\n", signo); 204 LogClose(); 205 abort(); 206 } 207#endif 208 if (BGPid) { 209 kill (BGPid, SIGTERM); 210 exit (EX_HANGUP); 211 } 212 else { 213 LogPrintf(LogPHASE, "Signal %d, hangup.\n", signo); 214 Cleanup(EX_HANGUP); 215 } 216} 217 218static void 219CloseSession(signo) 220int signo; 221{ 222 if (BGPid) { 223 kill (BGPid, SIGINT); 224 exit (EX_TERM); 225 } 226 LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 227 reconnect(RECON_FALSE); 228 LcpClose(); 229 Cleanup(EX_TERM); 230} 231 232static void 233TerminalCont() 234{ 235 pending_signal(SIGCONT, SIG_DFL); 236 pending_signal(SIGTSTP, TerminalStop); 237 TtyCommandMode(getpgrp() == tcgetpgrp(0)); 238} 239 240static void 241TerminalStop(signo) 242int signo; 243{ 244 pending_signal(SIGCONT, TerminalCont); 245 TtyOldMode(); 246 pending_signal(SIGTSTP, SIG_DFL); 247 kill(getpid(), signo); 248} 249 250static char * 251ex_desc(int ex) 252{ 253 static char num[12]; 254 static char *desc[] = { "normal", "start", "sock", 255 "modem", "dial", "dead", "done", "reboot", "errdead", 256 "hangup", "term", "nodial", "nologin" }; 257 258 if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 259 return desc[ex]; 260 snprintf(num, sizeof num, "%d", ex); 261 return num; 262} 263 264void 265Usage() 266{ 267 fprintf(stderr, 268 "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 269 exit(EX_START); 270} 271 272void 273ProcessArgs(int argc, char **argv) 274{ 275 int optc; 276 char *cp; 277 278 optc = 0; 279 while (argc > 0 && **argv == '-') { 280 cp = *argv + 1; 281 if (strcmp(cp, "auto") == 0) 282 mode |= MODE_AUTO; 283 else if (strcmp(cp, "background") == 0) 284 mode |= MODE_BACKGROUND|MODE_AUTO; 285 else if (strcmp(cp, "direct") == 0) 286 mode |= MODE_DIRECT; 287 else if (strcmp(cp, "dedicated") == 0) 288 mode |= MODE_DEDICATED; 289 else if (strcmp(cp, "ddial") == 0) 290 mode |= MODE_DDIAL|MODE_AUTO; 291 else if (strcmp(cp, "alias") == 0) { 292 if (loadAliasHandlers(&VarAliasHandlers) == 0) 293 mode |= MODE_ALIAS; 294 else 295 LogPrintf(LogWARN, "Cannot load alias library\n"); 296 optc--; /* this option isn't exclusive */ 297 } 298 else 299 Usage(); 300 optc++; 301 argv++; argc--; 302 } 303 if (argc > 1) { 304 fprintf(stderr, "specify only one system label.\n"); 305 exit(EX_START); 306 } 307 if (argc == 1) dstsystem = *argv; 308 309 if (optc > 1) { 310 fprintf(stderr, "specify only one mode.\n"); 311 exit(EX_START); 312 } 313} 314 315static void 316Greetings() 317{ 318 if (VarTerm) { 319 fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 320 fflush(VarTerm); 321 } 322} 323 324void 325main(argc, argv) 326int argc; 327char **argv; 328{ 329 FILE *lockfile; 330 char *name; 331 332 VarTerm = 0; 333 name = rindex(argv[0], '/'); 334 LogOpen(name ? name+1 : argv[0]); 335 336 argc--; argv++; 337 mode = MODE_INTER; /* default operation is interactive mode */ 338 netfd = server = modem = tun_in = -1; 339 ProcessArgs(argc, argv); 340 if (!(mode & MODE_DIRECT)) 341 VarTerm = stdout; 342 Greetings(); 343 GetUid(); 344 IpcpDefAddress(); 345 346 if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 347 fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 348 349 switch ( LocalAuthInit() ) { 350 case NOT_FOUND: 351 if (VarTerm) { 352 fprintf(VarTerm,LAUTH_M1); 353 fprintf(VarTerm,LAUTH_M2); 354 fflush(VarTerm); 355 } 356 /* Fall down */ 357 case VALID: 358 VarLocalAuth = LOCAL_AUTH; 359 break; 360 default: 361 break; 362 } 363 364 if (OpenTunnel(&tunno) < 0) { 365 LogPrintf(LogWARN, "open_tun: %s", strerror(errno)); 366 exit(EX_START); 367 } 368 369 if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 370 mode &= ~MODE_INTER; 371 if (mode & MODE_INTER) { 372 fprintf(VarTerm, "Interactive mode\n"); 373 netfd = STDIN_FILENO; 374 } else if (mode & MODE_AUTO) { 375 fprintf(VarTerm, "Automatic Dialer mode\n"); 376 if (dstsystem == NULL) { 377 if (VarTerm) 378 fprintf(VarTerm, "Destination system must be specified in" 379 " auto, background or ddial mode.\n"); 380 exit(EX_START); 381 } 382 } 383 384 tcgetattr(0, &oldtio); /* Save original tty mode */ 385 386 pending_signal(SIGHUP, Hangup); 387 pending_signal(SIGTERM, CloseSession); 388 pending_signal(SIGINT, CloseSession); 389 pending_signal(SIGQUIT, CloseSession); 390#ifdef TRAPSEGV 391 signal(SIGSEGV, Hangup); 392#endif 393#ifdef SIGPIPE 394 signal(SIGPIPE, SIG_IGN); 395#endif 396#ifdef SIGALRM 397 pending_signal(SIGALRM, SIG_IGN); 398#endif 399 if(mode & MODE_INTER) 400 { 401#ifdef SIGTSTP 402 pending_signal(SIGTSTP, TerminalStop); 403#endif 404#ifdef SIGTTIN 405 pending_signal(SIGTTIN, TerminalStop); 406#endif 407#ifdef SIGTTOU 408 pending_signal(SIGTTOU, SIG_IGN); 409#endif 410 } 411 412 if (dstsystem) { 413 if (SelectSystem(dstsystem, CONFFILE) < 0) { 414 LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 415 Cleanup(EX_START); 416 } 417 if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 418 LogPrintf(LogWARN, "Must specify dstaddr with" 419 " auto, background or ddial mode.\n"); 420 Cleanup(EX_START); 421 } 422 } 423 424 if (!(mode & MODE_INTER)) { 425 int port = SERVER_PORT + tunno; 426 427 if (mode & MODE_BACKGROUND) { 428 if (pipe (BGFiledes)) { 429 LogPrintf(LogERROR, "pipe: %s", strerror(errno)); 430 Cleanup(EX_SOCK); 431 } 432 } 433 434 /* Create server socket and listen at there. */ 435 server = socket(PF_INET, SOCK_STREAM, 0); 436 if (server < 0) { 437 LogPrintf(LogERROR, "socket: %s", strerror(errno)); 438 Cleanup(EX_SOCK); 439 } 440 ifsin.sin_family = AF_INET; 441 ifsin.sin_addr.s_addr = INADDR_ANY; 442 ifsin.sin_port = htons(port); 443 setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server); 444 if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 445 LogPrintf(LogERROR, "bind: %s", strerror(errno)); 446 if (errno == EADDRINUSE && VarTerm) 447 fprintf(VarTerm, "Wait for a while, then try again.\n"); 448 Cleanup(EX_SOCK); 449 } 450 if (listen(server, 5) != 0) { 451 LogPrintf(LogERROR, "Unable to listen to socket - OS overload?\n"); 452 Cleanup(EX_SOCK); 453 } 454 455 if (!(mode & MODE_DIRECT)) { 456 pid_t bgpid; 457 458 bgpid = fork (); 459 if (bgpid == -1) { 460 LogPrintf(LogERROR, "fork: %s", strerror(errno)); 461 Cleanup (EX_SOCK); 462 } 463 if (bgpid) { 464 char c = EX_NORMAL; 465 466 if (mode & MODE_BACKGROUND) { 467 /* Wait for our child to close its pipe before we exit. */ 468 BGPid = bgpid; 469 close(BGFiledes[1]); 470 if (read(BGFiledes[0], &c, 1) != 1) { 471 fprintf(VarTerm, "Child exit, no status.\n"); 472 LogPrintf (LogPHASE, "Parent: Child exit, no status.\n"); 473 } else if (c == EX_NORMAL) { 474 fprintf(VarTerm, "PPP enabled.\n"); 475 LogPrintf (LogPHASE, "Parent: PPP enabled.\n"); 476 } else { 477 fprintf(VarTerm, "Child failed (%s).\n",ex_desc((int)c)); 478 LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 479 ex_desc((int)c)); 480 } 481 close(BGFiledes[0]); 482 } 483 exit(c); 484 } else if (mode & MODE_BACKGROUND) 485 close(BGFiledes[0]); 486 } 487 488 snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 489 _PATH_VARRUN, tunno); 490 (void)unlink(pid_filename); 491 492 if ((lockfile = fopen(pid_filename, "w")) != NULL) { 493 fprintf(lockfile, "%d\n", (int)getpid()); 494 fclose(lockfile); 495 } else 496 LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 497 pid_filename, strerror(errno)); 498 499 snprintf(if_filename, sizeof if_filename, "%s%s.if", 500 _PATH_VARRUN, VarBaseDevice); 501 (void)unlink(if_filename); 502 503 if ((lockfile = fopen(if_filename, "w")) != NULL) { 504 fprintf(lockfile, "tun%d\n", tunno); 505 fclose(lockfile); 506 } else 507 LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 508 if_filename, strerror(errno)); 509 510 if (server >= 0) 511 LogPrintf(LogPHASE, "Listening at %d.\n", port); 512 513 VarTerm = 0; /* We know it's currently stdin */ 514 515#ifdef DOTTYINIT 516 if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 517#else 518 if (mode & MODE_DIRECT) { 519#endif 520 chdir("/"); /* Be consistent with daemon() */ 521 TtyInit(); 522 } else 523 daemon(0,0); 524 } else { 525 TtyInit(); 526 TtyCommandMode(1); 527 } 528 LogPrintf(LogPHASE, "PPP Started.\n"); 529 530 531 do 532 DoLoop(); 533 while (mode & MODE_DEDICATED); 534 535 Cleanup(EX_DONE); 536} 537 538/* 539 * Turn into packet mode, where we speak PPP. 540 */ 541void 542PacketMode() 543{ 544 if (RawModem(modem) < 0) { 545 LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 546 return; 547 } 548 549 AsyncInit(); 550 VjInit(); 551 LcpInit(); 552 IpcpInit(); 553 CcpInit(); 554 LcpUp(); 555 556 LcpOpen(VarOpenMode); 557 if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 558 TtyCommandMode(1); 559 if (VarTerm) { 560 fprintf(VarTerm, "Packet mode.\n"); 561 aft_cmd = 1; 562 } 563 } 564} 565 566static void 567ShowHelp() 568{ 569 fprintf(stderr, "The following commands are available:\n"); 570 fprintf(stderr, " ~p\tEnter Packet mode\n"); 571 fprintf(stderr, " ~-\tDecrease log level\n"); 572 fprintf(stderr, " ~+\tIncrease log level\n"); 573 fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\n"); 574 fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\n"); 575 fprintf(stderr, " ~.\tTerminate program\n"); 576 fprintf(stderr, " ~?\tThis help\n"); 577} 578 579static void 580ReadTty() 581{ 582 int n; 583 char ch; 584 static int ttystate; 585 FILE *oVarTerm; 586#define MAXLINESIZE 200 587 char linebuff[MAXLINESIZE]; 588 589 LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 590 TermMode, netfd, mode); 591 if (!TermMode) { 592 n = read(netfd, linebuff, sizeof(linebuff)-1); 593 if (n > 0) { 594 aft_cmd = 1; 595 DecodeCommand(linebuff, n, 1); 596 } else { 597 LogPrintf(LogPHASE, "client connection closed.\n"); 598 VarLocalAuth = LOCAL_NO_AUTH; 599 mode &= ~MODE_INTER; 600 oVarTerm = VarTerm; 601 VarTerm = 0; 602 if (oVarTerm && oVarTerm != stdout) 603 fclose(oVarTerm); 604 close(netfd); 605 netfd = -1; 606 } 607 return; 608 } 609 610 /* 611 * We are in terminal mode, decode special sequences 612 */ 613 n = read(fileno(VarTerm), &ch, 1); 614 LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)", n); 615 616 if (n > 0) { 617 switch (ttystate) { 618 case 0: 619 if (ch == '~') 620 ttystate++; 621 else 622 write(modem, &ch, n); 623 break; 624 case 1: 625 switch (ch) { 626 case '?': 627 ShowHelp(); 628 break; 629 case 'p': 630 /* 631 * XXX: Should check carrier. 632 */ 633 if (LcpFsm.state <= ST_CLOSED) { 634 VarOpenMode = OPEN_ACTIVE; 635 PacketMode(); 636 } 637 break; 638 case '.': 639 TermMode = 1; 640 aft_cmd = 1; 641 TtyCommandMode(1); 642 break; 643 case 't': 644 if (LogIsKept(LogDEBUG)) { 645 ShowTimers(); 646 break; 647 } 648 case 'm': 649 if (LogIsKept(LogDEBUG)) { 650 ShowMemMap(); 651 break; 652 } 653 default: 654 if (write(modem, &ch, n) < 0) 655 LogPrintf(LogERROR, "error writing to modem.\n"); 656 break; 657 } 658 ttystate = 0; 659 break; 660 } 661 } 662} 663 664 665/* 666 * Here, we'll try to detect HDLC frame 667 */ 668 669static char *FrameHeaders[] = { 670 "\176\377\003\300\041", 671 "\176\377\175\043\300\041", 672 "\176\177\175\043\100\041", 673 "\176\175\337\175\043\300\041", 674 "\176\175\137\175\043\100\041", 675 NULL, 676}; 677 678u_char * 679HdlcDetect(cp, n) 680u_char *cp; 681int n; 682{ 683 char *ptr, *fp, **hp; 684 685 cp[n] = '\0'; /* be sure to null terminated */ 686 ptr = NULL; 687 for (hp = FrameHeaders; *hp; hp++) { 688 fp = *hp; 689 if (DEV_IS_SYNC) 690 fp++; 691 ptr = strstr((char *)cp, fp); 692 if (ptr) 693 break; 694 } 695 return((u_char *)ptr); 696} 697 698static struct pppTimer RedialTimer; 699 700static void 701RedialTimeout() 702{ 703 StopTimer(&RedialTimer); 704 LogPrintf(LogPHASE, "Redialing timer expired.\n"); 705} 706 707static void 708StartRedialTimer(Timeout) 709 int Timeout; 710{ 711 StopTimer(&RedialTimer); 712 713 if (Timeout) { 714 RedialTimer.state = TIMER_STOPPED; 715 716 if (Timeout > 0) 717 RedialTimer.load = Timeout * SECTICKS; 718 else 719 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 720 721 LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 722 RedialTimer.load / SECTICKS); 723 724 RedialTimer.func = RedialTimeout; 725 StartTimer(&RedialTimer); 726 } 727} 728 729 730static void 731DoLoop() 732{ 733 fd_set rfds, wfds, efds; 734 int pri, i, n, wfd, nfds; 735 struct sockaddr_in hisaddr; 736 struct timeval timeout, *tp; 737 int ssize = sizeof(hisaddr); 738 u_char *cp; 739 u_char rbuff[MAX_MRU]; 740 int dial_up; 741 int tries; 742 int qlen; 743 pid_t pgroup; 744 745 pgroup = getpgrp(); 746 747 if (mode & MODE_DIRECT) { 748 LogPrintf(LogDEBUG, "Opening modem\n"); 749 modem = OpenModem(mode); 750 LogPrintf(LogPHASE, "Packet mode enabled\n"); 751 PacketMode(); 752 } else if (mode & MODE_DEDICATED) { 753 if (modem < 0) 754 modem = OpenModem(mode); 755 } 756 757 fflush(VarTerm); 758 759 timeout.tv_sec = 0; 760 timeout.tv_usec = 0; 761 reconnectState = RECON_UNKNOWN; 762 763 if (mode & MODE_BACKGROUND) 764 dial_up = TRUE; /* Bring the line up */ 765 else 766 dial_up = FALSE; /* XXXX */ 767 tries = 0; 768 for (;;) { 769 nfds = 0; 770 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 771 772 /* 773 * If the link is down and we're in DDIAL mode, bring it back 774 * up. 775 */ 776 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 777 dial_up = TRUE; 778 779 /* 780 * If we lost carrier and want to re-establish the connection 781 * due to the "set reconnect" value, we'd better bring the line 782 * back up. 783 */ 784 if (LcpFsm.state <= ST_CLOSED) { 785 if (dial_up != TRUE && reconnectState == RECON_TRUE) { 786 if (++reconnectCount <= VarReconnectTries) { 787 LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 788 reconnectCount, VarReconnectTries); 789 StartRedialTimer(VarReconnectTimer); 790 dial_up = TRUE; 791 } else { 792 if (VarReconnectTries) 793 LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 794 VarReconnectTries); 795 reconnectCount = 0; 796 if (mode & MODE_BACKGROUND) 797 Cleanup(EX_DEAD); 798 } 799 reconnectState = RECON_ENVOKED; 800 } 801 } 802 803 /* 804 * If Ip packet for output is enqueued and require dial up, 805 * Just do it! 806 */ 807 if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 808 LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 809 modem = OpenModem(mode); 810 if (modem < 0) { 811 tries++; 812 if (VarDialTries) 813 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 814 tries, VarDialTries); 815 else 816 LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 817 818 if (VarDialTries && tries >= VarDialTries) { 819 if (mode & MODE_BACKGROUND) 820 Cleanup(EX_DIAL); /* Can't get the modem */ 821 dial_up = FALSE; 822 reconnectState = RECON_UNKNOWN; 823 reconnectCount = 0; 824 tries = 0; 825 } else 826 StartRedialTimer(VarRedialTimeout); 827 } else { 828 tries++; /* Tries are per number, not per list of numbers. */ 829 if (VarDialTries) 830 LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, 831 VarDialTries); 832 else 833 LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 834 if (DialModem() == EX_DONE) { 835 sleep(1); /* little pause to allow peer starts */ 836 ModemTimeout(); 837 PacketMode(); 838 dial_up = FALSE; 839 reconnectState = RECON_UNKNOWN; 840 tries = 0; 841 } else { 842 CloseModem(); 843 if (mode & MODE_BACKGROUND) { 844 if (VarNextPhone == NULL) 845 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 846 else 847 /* Try all numbers in background mode */ 848 StartRedialTimer(VarRedialNextTimeout); 849 } else if (VarDialTries && tries >= VarDialTries) { 850 /* I give up ! Can't get through :( */ 851 StartRedialTimer(VarRedialTimeout); 852 dial_up = FALSE; 853 reconnectState = RECON_UNKNOWN; 854 reconnectCount = 0; 855 tries = 0; 856 } else if (VarNextPhone == NULL) 857 /* Dial failed. Keep quite during redial wait period. */ 858 StartRedialTimer(VarRedialTimeout); 859 else 860 StartRedialTimer(VarRedialNextTimeout); 861 } 862 } 863 } 864 qlen = ModemQlen(); 865 866 if (qlen == 0) { 867 IpStartOutput(); 868 qlen = ModemQlen(); 869 } 870 871 if (modem >= 0) { 872 if (modem + 1 > nfds) 873 nfds = modem + 1; 874 FD_SET(modem, &rfds); 875 FD_SET(modem, &efds); 876 if (qlen > 0) { 877 FD_SET(modem, &wfds); 878 } 879 } 880 if (server >= 0) { 881 if (server + 1 > nfds) 882 nfds = server + 1; 883 FD_SET(server, &rfds); 884 } 885 886 /* *** IMPORTANT *** 887 * 888 * CPU is serviced every TICKUNIT micro seconds. 889 * This value must be chosen with great care. If this values is 890 * too big, it results loss of characters from modem and poor responce. 891 * If this values is too small, ppp process eats many CPU time. 892 */ 893#ifndef SIGALRM 894 usleep(TICKUNIT); 895 TimerService(); 896#else 897 handle_signals(); 898#endif 899 900 /* If there are aren't many packets queued, look for some more. */ 901 if (qlen < 20 && tun_in >= 0) { 902 if (tun_in + 1 > nfds) 903 nfds = tun_in + 1; 904 FD_SET(tun_in, &rfds); 905 } 906 907 if (netfd >= 0) { 908 if (netfd + 1 > nfds) 909 nfds = netfd + 1; 910 FD_SET(netfd, &rfds); 911 FD_SET(netfd, &efds); 912 } 913 914#ifndef SIGALRM 915 /* 916 * Normally, select() will not block because modem is writable. 917 * In AUTO mode, select will block until we find packet from tun 918 */ 919 tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 920 i = select(nfds, &rfds, &wfds, &efds, tp); 921#else 922 /* 923 * When SIGALRM timer is running, a select function will be 924 * return -1 and EINTR after a Time Service signal hundler 925 * is done. If the redial timer is not running and we are 926 * trying to dial, poll with a 0 value timer. 927 */ 928 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 929 i = select(nfds, &rfds, &wfds, &efds, tp); 930#endif 931 932 if ( i == 0 ) { 933 continue; 934 } 935 936 if ( i < 0 ) { 937 if ( errno == EINTR ) { 938 handle_signals(); 939 continue; 940 } 941 LogPrintf(LogERROR, "select: %s", strerror(errno)); 942 break; 943 } 944 945 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 946 LogPrintf(LogALERT, "Exception detected.\n"); 947 break; 948 } 949 950 if (server >= 0 && FD_ISSET(server, &rfds)) { 951 LogPrintf(LogPHASE, "connected to client.\n"); 952 wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 953 if (wfd < 0) { 954 LogPrintf(LogERROR, "accept: %s", strerror(errno)); 955 continue; 956 } 957 if (netfd >= 0) { 958 write(wfd, "already in use.\n", 16); 959 close(wfd); 960 continue; 961 } else 962 netfd = wfd; 963 VarTerm = fdopen(netfd, "a+"); 964 mode |= MODE_INTER; 965 Greetings(); 966 switch ( LocalAuthInit() ) { 967 case NOT_FOUND: 968 if (VarTerm) { 969 fprintf(VarTerm,LAUTH_M1); 970 fprintf(VarTerm,LAUTH_M2); 971 fflush(VarTerm); 972 } 973 /* Fall down */ 974 case VALID: 975 VarLocalAuth = LOCAL_AUTH; 976 break; 977 default: 978 break; 979 } 980 (void) IsInteractive(); 981 Prompt(); 982 } 983 984 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 985 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 986 /* something to read from tty */ 987 ReadTty(); 988 } 989 if (modem >= 0) { 990 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 991 ModemStartOutput(modem); 992 } 993 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 994 if (LcpFsm.state <= ST_CLOSED) 995 usleep(10000); 996 n = read(modem, rbuff, sizeof(rbuff)); 997 if ((mode & MODE_DIRECT) && n <= 0) { 998 DownConnection(); 999 } else 1000 LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 1001 1002 if (LcpFsm.state <= ST_CLOSED) { 1003 /* 1004 * In dedicated mode, we just discard input until LCP is started. 1005 */ 1006 if (!(mode & MODE_DEDICATED)) { 1007 cp = HdlcDetect(rbuff, n); 1008 if (cp) { 1009 /* 1010 * LCP packet is detected. Turn ourselves into packet mode. 1011 */ 1012 if (cp != rbuff) { 1013 write(modem, rbuff, cp - rbuff); 1014 write(modem, "\r\n", 2); 1015 } 1016 PacketMode(); 1017 } else 1018 write(fileno(VarTerm), rbuff, n); 1019 } 1020 } else { 1021 if (n > 0) 1022 AsyncInput(rbuff, n); 1023 } 1024 } 1025 } 1026 1027 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 1028 n = read(tun_in, rbuff, sizeof(rbuff)); 1029 if (n < 0) { 1030 LogPrintf(LogERROR, "read from tun: %s", strerror(errno)); 1031 continue; 1032 } 1033 /* 1034 * Process on-demand dialup. Output packets are queued within tunnel 1035 * device until IPCP is opened. 1036 */ 1037 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1038 pri = PacketCheck(rbuff, n, FL_DIAL); 1039 if (pri >= 0) { 1040 if (mode & MODE_ALIAS) { 1041 VarPacketAliasOut(rbuff, sizeof rbuff); 1042 n = ntohs(((struct ip *)rbuff)->ip_len); 1043 } 1044 IpEnqueue(pri, rbuff, n); 1045 dial_up = TRUE; /* XXX */ 1046 } 1047 continue; 1048 } 1049 pri = PacketCheck(rbuff, n, FL_OUT); 1050 if (pri >= 0) { 1051 if (mode & MODE_ALIAS) { 1052 VarPacketAliasOut(rbuff, sizeof rbuff); 1053 n = ntohs(((struct ip *)rbuff)->ip_len); 1054 } 1055 IpEnqueue(pri, rbuff, n); 1056 } 1057 } 1058 } 1059 LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1060} 1061