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