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