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.80 1997/09/21 20:26:46 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(), 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(); 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 DecodeCommand(linebuff, n, 1); 551 } else { 552 LogPrintf(LogPHASE, "client connection closed.\n"); 553 VarLocalAuth = LOCAL_NO_AUTH; 554 mode &= ~MODE_INTER; 555 oVarTerm = VarTerm; 556 VarTerm = 0; 557 if (oVarTerm && oVarTerm != stdout) 558 fclose(oVarTerm); 559 close(netfd); 560 netfd = -1; 561 } 562 return; 563 } 564 565 /* 566 * We are in terminal mode, decode special sequences 567 */ 568 n = read(fileno(VarTerm), &ch, 1); 569 LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 570 571 if (n > 0) { 572 switch (ttystate) { 573 case 0: 574 if (ch == '~') 575 ttystate++; 576 else 577 write(modem, &ch, n); 578 break; 579 case 1: 580 switch (ch) { 581 case '?': 582 ShowHelp(); 583 break; 584 case 'p': 585 586 /* 587 * XXX: Should check carrier. 588 */ 589 if (LcpFsm.state <= ST_CLOSED) { 590 VarOpenMode = OPEN_ACTIVE; 591 PacketMode(); 592 } 593 break; 594 case '.': 595 TermMode = 1; 596 aft_cmd = 1; 597 TtyCommandMode(1); 598 break; 599 case 't': 600 if (LogIsKept(LogDEBUG)) { 601 ShowTimers(); 602 break; 603 } 604 case 'm': 605 if (LogIsKept(LogDEBUG)) { 606 ShowMemMap(); 607 break; 608 } 609 default: 610 if (write(modem, &ch, n) < 0) 611 LogPrintf(LogERROR, "error writing to modem.\n"); 612 break; 613 } 614 ttystate = 0; 615 break; 616 } 617 } 618 } 619 620 621 /* 622 * Here, we'll try to detect HDLC frame 623 */ 624 625 static char *FrameHeaders[] = { 626 "\176\377\003\300\041", 627 "\176\377\175\043\300\041", 628 "\176\177\175\043\100\041", 629 "\176\175\337\175\043\300\041", 630 "\176\175\137\175\043\100\041", 631 NULL, 632 }; 633 634 u_char * 635 HdlcDetect(u_char * cp, int n) 636 { 637 char *ptr, *fp, **hp; 638 639 cp[n] = '\0'; /* be sure to null terminated */ 640 ptr = NULL; 641 for (hp = FrameHeaders; *hp; hp++) { 642 fp = *hp; 643 if (DEV_IS_SYNC) 644 fp++; 645 ptr = strstr((char *) cp, fp); 646 if (ptr) 647 break; 648 } 649 return ((u_char *) ptr); 650 } 651 652 static struct pppTimer RedialTimer; 653 654 static void 655 RedialTimeout() 656 { 657 StopTimer(&RedialTimer); 658 LogPrintf(LogPHASE, "Redialing timer expired.\n"); 659 } 660 661 static void 662 StartRedialTimer(int Timeout) 663 { 664 StopTimer(&RedialTimer); 665 666 if (Timeout) { 667 RedialTimer.state = TIMER_STOPPED; 668 669 if (Timeout > 0) 670 RedialTimer.load = Timeout * SECTICKS; 671 else 672 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 673 674 LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 675 RedialTimer.load / SECTICKS); 676 677 RedialTimer.func = RedialTimeout; 678 StartTimer(&RedialTimer); 679 } 680 } 681 682 683 static void 684 DoLoop() 685 { 686 fd_set rfds, wfds, efds; 687 int pri, i, n, wfd, nfds; 688 struct sockaddr_in hisaddr; 689 struct timeval timeout, *tp; 690 int ssize = sizeof(hisaddr); 691 u_char *cp; 692 u_char rbuff[MAX_MRU]; 693 int tries; 694 int qlen; 695 int res; 696 pid_t pgroup; 697 698 pgroup = getpgrp(); 699 700 if (mode & MODE_DIRECT) { 701 LogPrintf(LogDEBUG, "Opening modem\n"); 702 if (OpenModem(mode) < 0) 703 return; 704 LogPrintf(LogPHASE, "Packet mode enabled\n"); 705 PacketMode(); 706 } else if (mode & MODE_DEDICATED) { 707 if (modem < 0) 708 while (OpenModem(mode) < 0) 709 sleep(VarReconnectTimer); 710 } 711 fflush(VarTerm); 712 713 timeout.tv_sec = 0; 714 timeout.tv_usec = 0; 715 reconnectState = RECON_UNKNOWN; 716 717 if (mode & MODE_BACKGROUND) 718 dial_up = TRUE; /* Bring the line up */ 719 else 720 dial_up = FALSE; /* XXXX */ 721 tries = 0; 722 for (;;) { 723 nfds = 0; 724 FD_ZERO(&rfds); 725 FD_ZERO(&wfds); 726 FD_ZERO(&efds); 727 728 /* 729 * If the link is down and we're in DDIAL mode, bring it back up. 730 */ 731 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 732 dial_up = TRUE; 733 734 /* 735 * If we lost carrier and want to re-establish the connection due to the 736 * "set reconnect" value, we'd better bring the line back up. 737 */ 738 if (LcpFsm.state <= ST_CLOSED) { 739 if (dial_up != TRUE && reconnectState == RECON_TRUE) { 740 if (++reconnectCount <= VarReconnectTries) { 741 LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 742 reconnectCount, VarReconnectTries); 743 StartRedialTimer(VarReconnectTimer); 744 dial_up = TRUE; 745 } else { 746 if (VarReconnectTries) 747 LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 748 VarReconnectTries); 749 reconnectCount = 0; 750 if (mode & MODE_BACKGROUND) 751 Cleanup(EX_DEAD); 752 } 753 reconnectState = RECON_ENVOKED; 754 } 755 } 756 757 /* 758 * If Ip packet for output is enqueued and require dial up, Just do it! 759 */ 760 if (dial_up && RedialTimer.state != TIMER_RUNNING) { 761 LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 762 if (OpenModem(mode) < 0) { 763 tries++; 764 if (!(mode & MODE_DDIAL) && VarDialTries) 765 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 766 tries, VarDialTries); 767 else 768 LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 769 770 if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 771 if (mode & MODE_BACKGROUND) 772 Cleanup(EX_DIAL); /* Can't get the modem */ 773 dial_up = FALSE; 774 reconnectState = RECON_UNKNOWN; 775 reconnectCount = 0; 776 tries = 0; 777 } else 778 StartRedialTimer(VarRedialTimeout); 779 } else { 780 tries++; /* Tries are per number, not per list of 781 * numbers. */ 782 if (!(mode & MODE_DDIAL) && VarDialTries) 783 LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 784 else 785 LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 786 787 if ((res = DialModem()) == EX_DONE) { 788 sleep(1); /* little pause to allow peer starts */ 789 ModemTimeout(); 790 PacketMode(); 791 dial_up = FALSE; 792 reconnectState = RECON_UNKNOWN; 793 tries = 0; 794 } else { 795 CloseModem(); 796 if (mode & MODE_BACKGROUND) { 797 if (VarNextPhone == NULL || res == EX_SIG) 798 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 799 else 800 /* Try all numbers in background mode */ 801 StartRedialTimer(VarRedialNextTimeout); 802 } else if (!(mode & MODE_DDIAL) && 803 ((VarDialTries && tries >= VarDialTries) || 804 res == EX_SIG)) { 805 /* I give up ! Can't get through :( */ 806 StartRedialTimer(VarRedialTimeout); 807 dial_up = FALSE; 808 reconnectState = RECON_UNKNOWN; 809 reconnectCount = 0; 810 tries = 0; 811 } else if (VarNextPhone == NULL) 812 /* Dial failed. Keep quite during redial wait period. */ 813 StartRedialTimer(VarRedialTimeout); 814 else 815 StartRedialTimer(VarRedialNextTimeout); 816 } 817 } 818 } 819 qlen = ModemQlen(); 820 821 if (qlen == 0) { 822 IpStartOutput(); 823 qlen = ModemQlen(); 824 } 825 if (modem >= 0) { 826 if (modem + 1 > nfds) 827 nfds = modem + 1; 828 FD_SET(modem, &rfds); 829 FD_SET(modem, &efds); 830 if (qlen > 0) { 831 FD_SET(modem, &wfds); 832 } 833 } 834 if (server >= 0) { 835 if (server + 1 > nfds) 836 nfds = server + 1; 837 FD_SET(server, &rfds); 838 } 839 840 /* 841 * *** IMPORTANT *** 842 * 843 * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 844 * with great care. If this values is too big, it results loss of 845 * characters from modem and poor responce. If this values is too small, 846 * ppp process eats many CPU time. 847 */ 848 #ifndef SIGALRM 849 usleep(TICKUNIT); 850 TimerService(); 851 #else 852 handle_signals(); 853 #endif 854 855 /* If there are aren't many packets queued, look for some more. */ 856 if (qlen < 20 && tun_in >= 0) { 857 if (tun_in + 1 > nfds) 858 nfds = tun_in + 1; 859 FD_SET(tun_in, &rfds); 860 } 861 if (netfd >= 0) { 862 if (netfd + 1 > nfds) 863 nfds = netfd + 1; 864 FD_SET(netfd, &rfds); 865 FD_SET(netfd, &efds); 866 } 867 #ifndef SIGALRM 868 869 /* 870 * Normally, select() will not block because modem is writable. In AUTO 871 * mode, select will block until we find packet from tun 872 */ 873 tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 874 i = select(nfds, &rfds, &wfds, &efds, tp); 875 #else 876 877 /* 878 * When SIGALRM timer is running, a select function will be return -1 and 879 * EINTR after a Time Service signal hundler is done. If the redial 880 * timer is not running and we are trying to dial, poll with a 0 value 881 * timer. 882 */ 883 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 884 i = select(nfds, &rfds, &wfds, &efds, tp); 885 #endif 886 887 if (i == 0) { 888 continue; 889 } 890 if (i < 0) { 891 if (errno == EINTR) { 892 handle_signals(); 893 continue; 894 } 895 LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 896 break; 897 } 898 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 899 LogPrintf(LogALERT, "Exception detected.\n"); 900 break; 901 } 902 if (server >= 0 && FD_ISSET(server, &rfds)) { 903 LogPrintf(LogPHASE, "connected to client.\n"); 904 wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 905 if (wfd < 0) { 906 LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 907 continue; 908 } 909 if (netfd >= 0) { 910 write(wfd, "already in use.\n", 16); 911 close(wfd); 912 continue; 913 } else 914 netfd = wfd; 915 VarTerm = fdopen(netfd, "a+"); 916 mode |= MODE_INTER; 917 Greetings(); 918 (void) IsInteractive(); 919 Prompt(); 920 } 921 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 922 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 923 /* something to read from tty */ 924 ReadTty(); 925 } 926 if (modem >= 0) { 927 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 928 ModemStartOutput(modem); 929 } 930 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 931 if (LcpFsm.state <= ST_CLOSED) 932 usleep(10000); 933 n = read(modem, rbuff, sizeof(rbuff)); 934 if ((mode & MODE_DIRECT) && n <= 0) { 935 DownConnection(); 936 } else 937 LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 938 939 if (LcpFsm.state <= ST_CLOSED) { 940 941 /* 942 * In dedicated mode, we just discard input until LCP is started. 943 */ 944 if (!(mode & MODE_DEDICATED)) { 945 cp = HdlcDetect(rbuff, n); 946 if (cp) { 947 948 /* 949 * LCP packet is detected. Turn ourselves into packet mode. 950 */ 951 if (cp != rbuff) { 952 write(modem, rbuff, cp - rbuff); 953 write(modem, "\r\n", 2); 954 } 955 PacketMode(); 956 } else 957 write(fileno(VarTerm), rbuff, n); 958 } 959 } else { 960 if (n > 0) 961 AsyncInput(rbuff, n); 962 } 963 } 964 } 965 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 966 * from tun */ 967 n = read(tun_in, rbuff, sizeof(rbuff)); 968 if (n < 0) { 969 LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 970 continue; 971 } 972 if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 973 /* we've been asked to send something addressed *to* us :( */ 974 if (VarLoopback) { 975 pri = PacketCheck(rbuff, n, FL_IN); 976 if (pri >= 0) { 977 struct mbuf *bp; 978 979 if (mode & MODE_ALIAS) { 980 VarPacketAliasIn(rbuff, sizeof rbuff); 981 n = ntohs(((struct ip *) rbuff)->ip_len); 982 } 983 bp = mballoc(n, MB_IPIN); 984 bcopy(rbuff, MBUF_CTOP(bp), n); 985 IpInput(bp); 986 LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 987 } 988 continue; 989 } else 990 LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 991 } 992 993 /* 994 * Process on-demand dialup. Output packets are queued within tunnel 995 * device until IPCP is opened. 996 */ 997 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 998 pri = PacketCheck(rbuff, n, FL_DIAL); 999 if (pri >= 0) { 1000 if (mode & MODE_ALIAS) { 1001 VarPacketAliasOut(rbuff, sizeof rbuff); 1002 n = ntohs(((struct ip *) rbuff)->ip_len); 1003 } 1004 IpEnqueue(pri, rbuff, n); 1005 dial_up = TRUE; /* XXX */ 1006 } 1007 continue; 1008 } 1009 pri = PacketCheck(rbuff, n, FL_OUT); 1010 if (pri >= 0) { 1011 if (mode & MODE_ALIAS) { 1012 VarPacketAliasOut(rbuff, sizeof rbuff); 1013 n = ntohs(((struct ip *) rbuff)->ip_len); 1014 } 1015 IpEnqueue(pri, rbuff, n); 1016 } 1017 } 1018 } 1019 LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1020 } 1021