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