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