main.c revision 31823
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.107 1997/12/13 02:37:27 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 int nfds; 366 367 nfds = getdtablesize(); 368 if (nfds >= FD_SETSIZE) 369 /* 370 * If we've got loads of file descriptors, make sure they're all 371 * closed. If they aren't, we may end up with a seg fault when our 372 * `fd_set's get too big when select()ing ! 373 */ 374 while (--nfds > 2) 375 close(nfds); 376 377 VarTerm = 0; 378 name = strrchr(argv[0], '/'); 379 LogOpen(name ? name + 1 : argv[0]); 380 381 argc--; 382 argv++; 383 label = ProcessArgs(argc, argv); 384 if (!(mode & MODE_DIRECT)) 385 VarTerm = stdout; 386 387 ID0init(); 388 if (ID0realuid() != 0) { 389 char conf[200], *ptr; 390 391 snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 392 do { 393 if (!access(conf, W_OK)) { 394 LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); 395 return -1; 396 } 397 ptr = conf + strlen(conf)-2; 398 while (ptr > conf && *ptr != '/') 399 *ptr-- = '\0'; 400 } while (ptr >= conf); 401 } 402 403 if (!ValidSystem(label)) { 404 fprintf(stderr, "You may not use ppp in this mode with this label\n"); 405 if (mode & MODE_DIRECT) { 406 const char *l; 407 l = label ? label : "default"; 408 VarTerm = 0; 409 LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); 410 } 411 LogClose(); 412 return 1; 413 } 414 415 if (!GetShortHost()) 416 return 1; 417 Greetings(); 418 IpcpDefAddress(); 419 420 if (mode & MODE_INTER) 421 VarLocalAuth = LOCAL_AUTH; 422 423 if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 424 fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 425 426 if (OpenTunnel(&tunno) < 0) { 427 LogPrintf(LogWARN, "OpenTunnel: %s\n", strerror(errno)); 428 return EX_START; 429 } 430 if (mode & MODE_INTER) { 431 fprintf(VarTerm, "Interactive mode\n"); 432 netfd = STDOUT_FILENO; 433 } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED)) 434 if (label == NULL) { 435 if (VarTerm) 436 fprintf(VarTerm, "Destination system must be specified in" 437 " auto, background or ddial mode.\n"); 438 return EX_START; 439 } 440 441 tcgetattr(0, &oldtio); /* Save original tty mode */ 442 443 pending_signal(SIGHUP, CloseSession); 444 pending_signal(SIGTERM, CloseSession); 445 pending_signal(SIGINT, CloseConnection); 446 pending_signal(SIGQUIT, CloseSession); 447#ifdef SIGPIPE 448 signal(SIGPIPE, SIG_IGN); 449#endif 450#ifdef SIGALRM 451 pending_signal(SIGALRM, SIG_IGN); 452#endif 453 if (mode & MODE_INTER) { 454#ifdef SIGTSTP 455 pending_signal(SIGTSTP, TerminalStop); 456#endif 457#ifdef SIGTTIN 458 pending_signal(SIGTTIN, TerminalStop); 459#endif 460#ifdef SIGTTOU 461 pending_signal(SIGTTOU, SIG_IGN); 462#endif 463 } 464 if (!(mode & MODE_INTER)) { 465#ifdef SIGUSR1 466 pending_signal(SIGUSR1, SetUpServer); 467#endif 468#ifdef SIGUSR2 469 pending_signal(SIGUSR2, BringDownServer); 470#endif 471 } 472 473 if (label) { 474 if (SelectSystem(label, CONFFILE) < 0) { 475 LogPrintf(LogWARN, "Destination system %s not found in conf file.\n", 476 GetLabel()); 477 Cleanup(EX_START); 478 } 479 /* 480 * We don't SetLabel() 'till now in case SelectSystem() has an 481 * embeded load "otherlabel" command. 482 */ 483 SetLabel(label); 484 if (mode & MODE_OUTGOING_DAEMON && 485 DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 486 LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for" 487 " auto, background or ddial mode.\n", label); 488 Cleanup(EX_START); 489 } 490 } 491 492 if (mode & MODE_DAEMON) { 493 if (mode & MODE_BACKGROUND) { 494 if (pipe(BGFiledes)) { 495 LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 496 Cleanup(EX_SOCK); 497 } 498 } 499 500 if (!(mode & MODE_DIRECT)) { 501 pid_t bgpid; 502 503 bgpid = fork(); 504 if (bgpid == -1) { 505 LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 506 Cleanup(EX_SOCK); 507 } 508 if (bgpid) { 509 char c = EX_NORMAL; 510 511 if (mode & MODE_BACKGROUND) { 512 /* Wait for our child to close its pipe before we exit. */ 513 BGPid = bgpid; 514 close(BGFiledes[1]); 515 if (read(BGFiledes[0], &c, 1) != 1) { 516 fprintf(VarTerm, "Child exit, no status.\n"); 517 LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 518 } else if (c == EX_NORMAL) { 519 fprintf(VarTerm, "PPP enabled.\n"); 520 LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 521 } else { 522 fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 523 LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 524 ex_desc((int) c)); 525 } 526 close(BGFiledes[0]); 527 } 528 return c; 529 } else if (mode & MODE_BACKGROUND) 530 close(BGFiledes[0]); 531 } 532 533 VarTerm = 0; /* We know it's currently stdout */ 534 close(1); 535 close(2); 536 537 if (mode & MODE_DIRECT) 538 TtyInit(1); 539 else if (mode & MODE_DAEMON) { 540 setsid(); 541 close(0); 542 } 543 } else { 544 TtyInit(0); 545 TtyCommandMode(1); 546 } 547 548 snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid", 549 _PATH_VARRUN, tunno); 550 lockfile = ID0fopen(pid_filename, "w"); 551 if (lockfile != NULL) { 552 fprintf(lockfile, "%d\n", (int) getpid()); 553 fclose(lockfile); 554 } else 555 LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 556 pid_filename, strerror(errno)); 557 558 LogPrintf(LogPHASE, "PPP Started.\n"); 559 560 561 do 562 DoLoop(); 563 while (mode & MODE_DEDICATED); 564 565 Cleanup(EX_DONE); 566 return 0; 567} 568 569/* 570 * Turn into packet mode, where we speak PPP. 571 */ 572void 573PacketMode() 574{ 575 if (RawModem() < 0) { 576 LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 577 return; 578 } 579 AsyncInit(); 580 VjInit(15); 581 LcpInit(); 582 IpcpInit(); 583 CcpInit(); 584 LcpUp(); 585 586 LcpOpen(VarOpenMode); 587 if (mode & MODE_INTER) 588 TtyCommandMode(1); 589 if (VarTerm) { 590 fprintf(VarTerm, "Packet mode.\n"); 591 aft_cmd = 1; 592 } 593} 594 595static void 596ShowHelp(void) 597{ 598 fprintf(stderr, "The following commands are available:\r\n"); 599 fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 600 fprintf(stderr, " ~-\tDecrease log level\r\n"); 601 fprintf(stderr, " ~+\tIncrease log level\r\n"); 602 fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 603 fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 604 fprintf(stderr, " ~.\tTerminate program\r\n"); 605 fprintf(stderr, " ~?\tThis help\r\n"); 606} 607 608static void 609ReadTty(void) 610{ 611 int n; 612 char ch; 613 static int ttystate; 614 char linebuff[LINE_LEN]; 615 616 LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 617 TermMode, netfd, mode); 618 if (!TermMode) { 619 n = read(netfd, linebuff, sizeof(linebuff) - 1); 620 if (n > 0) { 621 aft_cmd = 1; 622 if (linebuff[n-1] == '\n') 623 linebuff[--n] = '\0'; 624 if (n) 625 DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client"); 626 Prompt(); 627 } else if (n <= 0) 628 DropClient(); 629 return; 630 } 631 632 /* 633 * We are in terminal mode, decode special sequences 634 */ 635 n = read(fileno(VarTerm), &ch, 1); 636 LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 637 638 if (n > 0) { 639 switch (ttystate) { 640 case 0: 641 if (ch == '~') 642 ttystate++; 643 else 644 write(modem, &ch, n); 645 break; 646 case 1: 647 switch (ch) { 648 case '?': 649 ShowHelp(); 650 break; 651 case 'p': 652 653 /* 654 * XXX: Should check carrier. 655 */ 656 if (LcpFsm.state <= ST_CLOSED) { 657 VarOpenMode = OPEN_ACTIVE; 658 PacketMode(); 659 } 660 break; 661 case '.': 662 TermMode = 1; 663 aft_cmd = 1; 664 TtyCommandMode(1); 665 break; 666 case 't': 667 if (LogIsKept(LogDEBUG)) { 668 ShowTimers(); 669 break; 670 } 671 case 'm': 672 if (LogIsKept(LogDEBUG)) { 673 ShowMemMap(NULL); 674 break; 675 } 676 default: 677 if (write(modem, &ch, n) < 0) 678 LogPrintf(LogERROR, "error writing to modem.\n"); 679 break; 680 } 681 ttystate = 0; 682 break; 683 } 684 } 685} 686 687 688/* 689 * Here, we'll try to detect HDLC frame 690 */ 691 692static const char *FrameHeaders[] = { 693 "\176\377\003\300\041", 694 "\176\377\175\043\300\041", 695 "\176\177\175\043\100\041", 696 "\176\175\337\175\043\300\041", 697 "\176\175\137\175\043\100\041", 698 NULL, 699}; 700 701static const u_char * 702HdlcDetect(u_char * cp, int n) 703{ 704 const char *ptr, *fp, **hp; 705 706 cp[n] = '\0'; /* be sure to null terminated */ 707 ptr = NULL; 708 for (hp = FrameHeaders; *hp; hp++) { 709 fp = *hp; 710 if (DEV_IS_SYNC) 711 fp++; 712 ptr = strstr((char *) cp, fp); 713 if (ptr) 714 break; 715 } 716 return ((const u_char *) ptr); 717} 718 719static struct pppTimer RedialTimer; 720 721static void 722RedialTimeout(void *v) 723{ 724 StopTimer(&RedialTimer); 725 LogPrintf(LogPHASE, "Redialing timer expired.\n"); 726} 727 728static void 729StartRedialTimer(int Timeout) 730{ 731 StopTimer(&RedialTimer); 732 733 if (Timeout) { 734 RedialTimer.state = TIMER_STOPPED; 735 736 if (Timeout > 0) 737 RedialTimer.load = Timeout * SECTICKS; 738 else 739 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 740 741 LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 742 RedialTimer.load / SECTICKS); 743 744 RedialTimer.func = RedialTimeout; 745 StartTimer(&RedialTimer); 746 } 747} 748 749 750static void 751DoLoop(void) 752{ 753 fd_set rfds, wfds, efds; 754 int pri, i, n, wfd, nfds; 755 struct sockaddr_in hisaddr; 756 struct timeval timeout, *tp; 757 int ssize = sizeof(hisaddr); 758 const u_char *cp; 759 int tries; 760 int qlen; 761 int res; 762 struct tun_data tun; 763#define rbuff tun.data 764 765 if (mode & MODE_DIRECT) { 766 LogPrintf(LogDEBUG, "Opening modem\n"); 767 if (OpenModem() < 0) 768 return; 769 LogPrintf(LogPHASE, "Packet mode enabled\n"); 770 PacketMode(); 771 } else if (mode & MODE_DEDICATED) { 772 if (modem < 0) 773 while (OpenModem() < 0) 774 nointr_sleep(VarReconnectTimer); 775 } 776 fflush(VarTerm); 777 778 timeout.tv_sec = 0; 779 timeout.tv_usec = 0; 780 reconnectState = RECON_UNKNOWN; 781 782 if (mode & MODE_BACKGROUND) 783 dial_up = 1; /* Bring the line up */ 784 else 785 dial_up = 0; /* XXXX */ 786 tries = 0; 787 for (;;) { 788 nfds = 0; 789 FD_ZERO(&rfds); 790 FD_ZERO(&wfds); 791 FD_ZERO(&efds); 792 793 /* 794 * If the link is down and we're in DDIAL mode, bring it back up. 795 */ 796 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 797 dial_up = 1; 798 799 /* 800 * If we lost carrier and want to re-establish the connection due to the 801 * "set reconnect" value, we'd better bring the line back up. 802 */ 803 if (LcpFsm.state <= ST_CLOSED) { 804 if (!dial_up && reconnectState == RECON_TRUE) { 805 if (++reconnectCount <= VarReconnectTries) { 806 LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 807 reconnectCount, VarReconnectTries); 808 StartRedialTimer(VarReconnectTimer); 809 dial_up = 1; 810 } else { 811 if (VarReconnectTries) 812 LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 813 VarReconnectTries); 814 reconnectCount = 0; 815 if (mode & MODE_BACKGROUND) 816 Cleanup(EX_DEAD); 817 } 818 reconnectState = RECON_ENVOKED; 819 } else if (mode & MODE_DEDICATED) 820 if (VarOpenMode == OPEN_ACTIVE) 821 PacketMode(); 822 } 823 824 /* 825 * If Ip packet for output is enqueued and require dial up, Just do it! 826 */ 827 if (dial_up && RedialTimer.state != TIMER_RUNNING) { 828 LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 829 if (OpenModem() < 0) { 830 tries++; 831 if (!(mode & MODE_DDIAL) && VarDialTries) 832 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 833 tries, VarDialTries); 834 else 835 LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 836 837 if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 838 if (mode & MODE_BACKGROUND) 839 Cleanup(EX_DIAL); /* Can't get the modem */ 840 dial_up = 0; 841 reconnectState = RECON_UNKNOWN; 842 reconnectCount = 0; 843 tries = 0; 844 } else 845 StartRedialTimer(VarRedialTimeout); 846 } else { 847 tries++; /* Tries are per number, not per list of 848 * numbers. */ 849 if (!(mode & MODE_DDIAL) && VarDialTries) 850 LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 851 else 852 LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 853 854 if ((res = DialModem()) == EX_DONE) { 855 nointr_sleep(1); /* little pause to allow peer starts */ 856 ModemTimeout(NULL); 857 PacketMode(); 858 dial_up = 0; 859 reconnectState = RECON_UNKNOWN; 860 tries = 0; 861 } else { 862 if (mode & MODE_BACKGROUND) { 863 if (VarNextPhone == NULL || res == EX_SIG) 864 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 865 else 866 /* Try all numbers in background mode */ 867 StartRedialTimer(VarRedialNextTimeout); 868 } else if (!(mode & MODE_DDIAL) && 869 ((VarDialTries && tries >= VarDialTries) || 870 res == EX_SIG)) { 871 /* I give up ! Can't get through :( */ 872 StartRedialTimer(VarRedialTimeout); 873 dial_up = 0; 874 reconnectState = RECON_UNKNOWN; 875 reconnectCount = 0; 876 tries = 0; 877 } else if (VarNextPhone == NULL) 878 /* Dial failed. Keep quite during redial wait period. */ 879 StartRedialTimer(VarRedialTimeout); 880 else 881 StartRedialTimer(VarRedialNextTimeout); 882 } 883 } 884 } 885 qlen = ModemQlen(); 886 887 if (qlen == 0) { 888 IpStartOutput(); 889 qlen = ModemQlen(); 890 } 891 if (modem >= 0) { 892 if (modem + 1 > nfds) 893 nfds = modem + 1; 894 FD_SET(modem, &rfds); 895 FD_SET(modem, &efds); 896 if (qlen > 0) { 897 FD_SET(modem, &wfds); 898 } 899 } 900 if (server >= 0) { 901 if (server + 1 > nfds) 902 nfds = server + 1; 903 FD_SET(server, &rfds); 904 } 905 906 /* 907 * *** IMPORTANT *** 908 * 909 * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 910 * with great care. If this values is too big, it results loss of 911 * characters from modem and poor responce. If this values is too small, 912 * ppp process eats many CPU time. 913 */ 914#ifndef SIGALRM 915 nointr_usleep(TICKUNIT); 916 TimerService(); 917#else 918 handle_signals(); 919#endif 920 921 /* If there are aren't many packets queued, look for some more. */ 922 if (qlen < 20 && tun_in >= 0) { 923 if (tun_in + 1 > nfds) 924 nfds = tun_in + 1; 925 FD_SET(tun_in, &rfds); 926 } 927 if (netfd >= 0) { 928 if (netfd + 1 > nfds) 929 nfds = netfd + 1; 930 FD_SET(netfd, &rfds); 931 FD_SET(netfd, &efds); 932 } 933#ifndef SIGALRM 934 935 /* 936 * Normally, select() will not block because modem is writable. In AUTO 937 * mode, select will block until we find packet from tun 938 */ 939 tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 940 i = select(nfds, &rfds, &wfds, &efds, tp); 941#else 942 943 /* 944 * When SIGALRM timer is running, a select function will be return -1 and 945 * EINTR after a Time Service signal hundler is done. If the redial 946 * timer is not running and we are trying to dial, poll with a 0 value 947 * timer. 948 */ 949 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 950 i = select(nfds, &rfds, &wfds, &efds, tp); 951#endif 952 953 if (i == 0) { 954 continue; 955 } 956 if (i < 0) { 957 if (errno == EINTR) { 958 handle_signals(); 959 continue; 960 } 961 LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 962 break; 963 } 964 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 965 LogPrintf(LogALERT, "Exception detected.\n"); 966 break; 967 } 968 if (server >= 0 && FD_ISSET(server, &rfds)) { 969 LogPrintf(LogPHASE, "connected to client.\n"); 970 wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 971 if (wfd < 0) { 972 LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 973 continue; 974 } 975 if (netfd >= 0) { 976 write(wfd, "already in use.\n", 16); 977 close(wfd); 978 continue; 979 } else 980 netfd = wfd; 981 VarTerm = fdopen(netfd, "a+"); 982 LocalAuthInit(); 983 Greetings(); 984 IsInteractive(1); 985 Prompt(); 986 } 987 if (netfd >= 0 && FD_ISSET(netfd, &rfds)) 988 /* something to read from tty */ 989 ReadTty(); 990 if (modem >= 0 && FD_ISSET(modem, &wfds)) { 991 /* ready to write into modem */ 992 ModemStartOutput(modem); 993 if (modem < 0) 994 dial_up = 1; 995 } 996 if (modem >= 0 && FD_ISSET(modem, &rfds)) { 997 /* something to read from modem */ 998 if (LcpFsm.state <= ST_CLOSED) 999 nointr_usleep(10000); 1000 n = read(modem, rbuff, sizeof(rbuff)); 1001 if ((mode & MODE_DIRECT) && n <= 0) { 1002 DownConnection(); 1003 } else 1004 LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 1005 1006 if (LcpFsm.state <= ST_CLOSED) { 1007 /* 1008 * In dedicated mode, we just discard input until LCP is started. 1009 */ 1010 if (!(mode & MODE_DEDICATED)) { 1011 cp = HdlcDetect(rbuff, n); 1012 if (cp) { 1013 /* 1014 * LCP packet is detected. Turn ourselves into packet mode. 1015 */ 1016 if (cp != rbuff) { 1017 write(modem, rbuff, cp - rbuff); 1018 write(modem, "\r\n", 2); 1019 } 1020 PacketMode(); 1021 } else 1022 write(fileno(VarTerm), rbuff, n); 1023 } 1024 } else { 1025 if (n > 0) 1026 AsyncInput(rbuff, n); 1027 } 1028 } 1029 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 1030 * from tun */ 1031 n = read(tun_in, &tun, sizeof(tun)); 1032 if (n < 0) { 1033 LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 1034 continue; 1035 } 1036 n -= sizeof(tun)-sizeof(tun.data); 1037 if (n <= 0) { 1038 LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n); 1039 continue; 1040 } 1041 if (!tun_check_header(tun, AF_INET)) 1042 continue; 1043 if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 1044 /* we've been asked to send something addressed *to* us :( */ 1045 if (VarLoopback) { 1046 pri = PacketCheck(rbuff, n, FL_IN); 1047 if (pri >= 0) { 1048 struct mbuf *bp; 1049 1050#ifndef NOALIAS 1051 if (mode & MODE_ALIAS) { 1052 VarPacketAliasIn(rbuff, sizeof rbuff); 1053 n = ntohs(((struct ip *) rbuff)->ip_len); 1054 } 1055#endif 1056 bp = mballoc(n, MB_IPIN); 1057 memcpy(MBUF_CTOP(bp), rbuff, n); 1058 IpInput(bp); 1059 LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 1060 } 1061 continue; 1062 } else 1063 LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 1064 } 1065 1066 /* 1067 * Process on-demand dialup. Output packets are queued within tunnel 1068 * device until IPCP is opened. 1069 */ 1070 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1071 pri = PacketCheck(rbuff, n, FL_DIAL); 1072 if (pri >= 0) { 1073#ifndef NOALIAS 1074 if (mode & MODE_ALIAS) { 1075 VarPacketAliasOut(rbuff, sizeof rbuff); 1076 n = ntohs(((struct ip *) rbuff)->ip_len); 1077 } 1078#endif 1079 IpEnqueue(pri, rbuff, n); 1080 dial_up = 1; /* XXX */ 1081 } 1082 continue; 1083 } 1084 pri = PacketCheck(rbuff, n, FL_OUT); 1085 if (pri >= 0) { 1086#ifndef NOALIAS 1087 if (mode & MODE_ALIAS) { 1088 VarPacketAliasOut(rbuff, sizeof rbuff); 1089 n = ntohs(((struct ip *) rbuff)->ip_len); 1090 } 1091#endif 1092 IpEnqueue(pri, rbuff, n); 1093 } 1094 } 1095 } 1096 LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1097} 1098