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