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