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