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 $
|
20 * $Id: main.c,v 1.89 1997/11/09 06:22:43 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 char linebuff[LINE_LEN]; |
544
|
544#define MAXLINESIZE 200
545 char linebuff[MAXLINESIZE];
546
|
545 LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 546 TermMode, netfd, mode); 547 if (!TermMode) { 548 n = read(netfd, linebuff, sizeof(linebuff) - 1); 549 if (n > 0) { 550 aft_cmd = 1; 551 if (linebuff[n-1] == '\n') 552 linebuff[--n] = '\0'; 553 if (n) { 554 if (IsInteractive(0)) 555 LogPrintf(LogCOMMAND, "%s\n", linebuff); 556 else 557 LogPrintf(LogCOMMAND, "Client: %s\n", linebuff); 558 DecodeCommand(linebuff, n, 1); 559 } else 560 Prompt(); 561 } else { 562 LogPrintf(LogPHASE, "client connection closed.\n"); 563 VarLocalAuth = LOCAL_NO_AUTH; 564 mode &= ~MODE_INTER; 565 oVarTerm = VarTerm; 566 VarTerm = 0; 567 if (oVarTerm && oVarTerm != stdout) 568 fclose(oVarTerm); 569 close(netfd); 570 netfd = -1; 571 } 572 return; 573 } 574 575 /* 576 * We are in terminal mode, decode special sequences 577 */ 578 n = read(fileno(VarTerm), &ch, 1); 579 LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 580 581 if (n > 0) { 582 switch (ttystate) { 583 case 0: 584 if (ch == '~') 585 ttystate++; 586 else 587 write(modem, &ch, n); 588 break; 589 case 1: 590 switch (ch) { 591 case '?': 592 ShowHelp(); 593 break; 594 case 'p': 595 596 /* 597 * XXX: Should check carrier. 598 */ 599 if (LcpFsm.state <= ST_CLOSED) { 600 VarOpenMode = OPEN_ACTIVE; 601 PacketMode(); 602 } 603 break; 604 case '.': 605 TermMode = 1; 606 aft_cmd = 1; 607 TtyCommandMode(1); 608 break; 609 case 't': 610 if (LogIsKept(LogDEBUG)) { 611 ShowTimers(); 612 break; 613 } 614 case 'm': 615 if (LogIsKept(LogDEBUG)) { 616 ShowMemMap(); 617 break; 618 } 619 default: 620 if (write(modem, &ch, n) < 0) 621 LogPrintf(LogERROR, "error writing to modem.\n"); 622 break; 623 } 624 ttystate = 0; 625 break; 626 } 627 } 628} 629 630 631/* 632 * Here, we'll try to detect HDLC frame 633 */ 634 635static char *FrameHeaders[] = { 636 "\176\377\003\300\041", 637 "\176\377\175\043\300\041", 638 "\176\177\175\043\100\041", 639 "\176\175\337\175\043\300\041", 640 "\176\175\137\175\043\100\041", 641 NULL, 642}; 643 644static u_char * 645HdlcDetect(u_char * cp, int n) 646{ 647 char *ptr, *fp, **hp; 648 649 cp[n] = '\0'; /* be sure to null terminated */ 650 ptr = NULL; 651 for (hp = FrameHeaders; *hp; hp++) { 652 fp = *hp; 653 if (DEV_IS_SYNC) 654 fp++; 655 ptr = strstr((char *) cp, fp); 656 if (ptr) 657 break; 658 } 659 return ((u_char *) ptr); 660} 661 662static struct pppTimer RedialTimer; 663 664static void 665RedialTimeout() 666{ 667 StopTimer(&RedialTimer); 668 LogPrintf(LogPHASE, "Redialing timer expired.\n"); 669} 670 671static void 672StartRedialTimer(int Timeout) 673{ 674 StopTimer(&RedialTimer); 675 676 if (Timeout) { 677 RedialTimer.state = TIMER_STOPPED; 678 679 if (Timeout > 0) 680 RedialTimer.load = Timeout * SECTICKS; 681 else 682 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 683 684 LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 685 RedialTimer.load / SECTICKS); 686 687 RedialTimer.func = RedialTimeout; 688 StartTimer(&RedialTimer); 689 } 690} 691 692 693static void 694DoLoop() 695{ 696 fd_set rfds, wfds, efds; 697 int pri, i, n, wfd, nfds; 698 struct sockaddr_in hisaddr; 699 struct timeval timeout, *tp; 700 int ssize = sizeof(hisaddr); 701 u_char *cp; 702 u_char rbuff[MAX_MRU]; 703 int tries; 704 int qlen; 705 int res; 706 pid_t pgroup; 707 708 pgroup = getpgrp(); 709 710 if (mode & MODE_DIRECT) { 711 LogPrintf(LogDEBUG, "Opening modem\n"); 712 if (OpenModem() < 0) 713 return; 714 LogPrintf(LogPHASE, "Packet mode enabled\n"); 715 PacketMode(); 716 } else if (mode & MODE_DEDICATED) { 717 if (modem < 0) 718 while (OpenModem() < 0) 719 nointr_sleep(VarReconnectTimer); 720 } 721 fflush(VarTerm); 722 723 timeout.tv_sec = 0; 724 timeout.tv_usec = 0; 725 reconnectState = RECON_UNKNOWN; 726 727 if (mode & MODE_BACKGROUND) 728 dial_up = 1; /* Bring the line up */ 729 else 730 dial_up = 0; /* XXXX */ 731 tries = 0; 732 for (;;) { 733 nfds = 0; 734 FD_ZERO(&rfds); 735 FD_ZERO(&wfds); 736 FD_ZERO(&efds); 737 738 /* 739 * If the link is down and we're in DDIAL mode, bring it back up. 740 */ 741 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 742 dial_up = 1; 743 744 /* 745 * If we lost carrier and want to re-establish the connection due to the 746 * "set reconnect" value, we'd better bring the line back up. 747 */ 748 if (LcpFsm.state <= ST_CLOSED) { 749 if (!dial_up && reconnectState == RECON_TRUE) { 750 if (++reconnectCount <= VarReconnectTries) { 751 LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 752 reconnectCount, VarReconnectTries); 753 StartRedialTimer(VarReconnectTimer); 754 dial_up = 1; 755 } else { 756 if (VarReconnectTries) 757 LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 758 VarReconnectTries); 759 reconnectCount = 0; 760 if (mode & MODE_BACKGROUND) 761 Cleanup(EX_DEAD); 762 } 763 reconnectState = RECON_ENVOKED; 764 } 765 } 766 767 /* 768 * If Ip packet for output is enqueued and require dial up, Just do it! 769 */ 770 if (dial_up && RedialTimer.state != TIMER_RUNNING) { 771 LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 772 if (OpenModem() < 0) { 773 tries++; 774 if (!(mode & MODE_DDIAL) && VarDialTries) 775 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 776 tries, VarDialTries); 777 else 778 LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 779 780 if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 781 if (mode & MODE_BACKGROUND) 782 Cleanup(EX_DIAL); /* Can't get the modem */ 783 dial_up = 0; 784 reconnectState = RECON_UNKNOWN; 785 reconnectCount = 0; 786 tries = 0; 787 } else 788 StartRedialTimer(VarRedialTimeout); 789 } else { 790 tries++; /* Tries are per number, not per list of 791 * numbers. */ 792 if (!(mode & MODE_DDIAL) && VarDialTries) 793 LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 794 else 795 LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 796 797 if ((res = DialModem()) == EX_DONE) { 798 nointr_sleep(1); /* little pause to allow peer starts */ 799 ModemTimeout(); 800 PacketMode(); 801 dial_up = 0; 802 reconnectState = RECON_UNKNOWN; 803 tries = 0; 804 } else { 805 if (mode & MODE_BACKGROUND) { 806 if (VarNextPhone == NULL || res == EX_SIG) 807 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 808 else 809 /* Try all numbers in background mode */ 810 StartRedialTimer(VarRedialNextTimeout); 811 } else if (!(mode & MODE_DDIAL) && 812 ((VarDialTries && tries >= VarDialTries) || 813 res == EX_SIG)) { 814 /* I give up ! Can't get through :( */ 815 StartRedialTimer(VarRedialTimeout); 816 dial_up = 0; 817 reconnectState = RECON_UNKNOWN; 818 reconnectCount = 0; 819 tries = 0; 820 } else if (VarNextPhone == NULL) 821 /* Dial failed. Keep quite during redial wait period. */ 822 StartRedialTimer(VarRedialTimeout); 823 else 824 StartRedialTimer(VarRedialNextTimeout); 825 } 826 } 827 } 828 qlen = ModemQlen(); 829 830 if (qlen == 0) { 831 IpStartOutput(); 832 qlen = ModemQlen(); 833 } 834 if (modem >= 0) { 835 if (modem + 1 > nfds) 836 nfds = modem + 1; 837 FD_SET(modem, &rfds); 838 FD_SET(modem, &efds); 839 if (qlen > 0) { 840 FD_SET(modem, &wfds); 841 } 842 } 843 if (server >= 0) { 844 if (server + 1 > nfds) 845 nfds = server + 1; 846 FD_SET(server, &rfds); 847 } 848 849 /* 850 * *** IMPORTANT *** 851 * 852 * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 853 * with great care. If this values is too big, it results loss of 854 * characters from modem and poor responce. If this values is too small, 855 * ppp process eats many CPU time. 856 */ 857#ifndef SIGALRM 858 nointr_usleep(TICKUNIT); 859 TimerService(); 860#else 861 handle_signals(); 862#endif 863 864 /* If there are aren't many packets queued, look for some more. */ 865 if (qlen < 20 && tun_in >= 0) { 866 if (tun_in + 1 > nfds) 867 nfds = tun_in + 1; 868 FD_SET(tun_in, &rfds); 869 } 870 if (netfd >= 0) { 871 if (netfd + 1 > nfds) 872 nfds = netfd + 1; 873 FD_SET(netfd, &rfds); 874 FD_SET(netfd, &efds); 875 } 876#ifndef SIGALRM 877 878 /* 879 * Normally, select() will not block because modem is writable. In AUTO 880 * mode, select will block until we find packet from tun 881 */ 882 tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 883 i = select(nfds, &rfds, &wfds, &efds, tp); 884#else 885 886 /* 887 * When SIGALRM timer is running, a select function will be return -1 and 888 * EINTR after a Time Service signal hundler is done. If the redial 889 * timer is not running and we are trying to dial, poll with a 0 value 890 * timer. 891 */ 892 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 893 i = select(nfds, &rfds, &wfds, &efds, tp); 894#endif 895 896 if (i == 0) { 897 continue; 898 } 899 if (i < 0) { 900 if (errno == EINTR) { 901 handle_signals(); 902 continue; 903 } 904 LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 905 break; 906 } 907 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 908 LogPrintf(LogALERT, "Exception detected.\n"); 909 break; 910 } 911 if (server >= 0 && FD_ISSET(server, &rfds)) { 912 LogPrintf(LogPHASE, "connected to client.\n"); 913 wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 914 if (wfd < 0) { 915 LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 916 continue; 917 } 918 if (netfd >= 0) { 919 write(wfd, "already in use.\n", 16); 920 close(wfd); 921 continue; 922 } else 923 netfd = wfd; 924 VarTerm = fdopen(netfd, "a+"); 925 mode |= MODE_INTER; 926 Greetings(); 927 IsInteractive(1); 928 Prompt(); 929 } 930 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 931 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 932 /* something to read from tty */ 933 ReadTty(); 934 } 935 if (modem >= 0) { 936 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 937 ModemStartOutput(modem); 938 } 939 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 940 if (LcpFsm.state <= ST_CLOSED) 941 nointr_usleep(10000); 942 n = read(modem, rbuff, sizeof(rbuff)); 943 if ((mode & MODE_DIRECT) && n <= 0) { 944 DownConnection(); 945 } else 946 LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 947 948 if (LcpFsm.state <= ST_CLOSED) { 949 950 /* 951 * In dedicated mode, we just discard input until LCP is started. 952 */ 953 if (!(mode & MODE_DEDICATED)) { 954 cp = HdlcDetect(rbuff, n); 955 if (cp) { 956 957 /* 958 * LCP packet is detected. Turn ourselves into packet mode. 959 */ 960 if (cp != rbuff) { 961 write(modem, rbuff, cp - rbuff); 962 write(modem, "\r\n", 2); 963 } 964 PacketMode(); 965 } else 966 write(fileno(VarTerm), rbuff, n); 967 } 968 } else { 969 if (n > 0) 970 AsyncInput(rbuff, n); 971 } 972 } 973 } 974 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 975 * from tun */ 976 n = read(tun_in, rbuff, sizeof(rbuff)); 977 if (n < 0) { 978 LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 979 continue; 980 } 981 if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 982 /* we've been asked to send something addressed *to* us :( */ 983 if (VarLoopback) { 984 pri = PacketCheck(rbuff, n, FL_IN); 985 if (pri >= 0) { 986 struct mbuf *bp; 987 988 if (mode & MODE_ALIAS) { 989 VarPacketAliasIn(rbuff, sizeof rbuff); 990 n = ntohs(((struct ip *) rbuff)->ip_len); 991 } 992 bp = mballoc(n, MB_IPIN); 993 memcpy(MBUF_CTOP(bp), rbuff, n); 994 IpInput(bp); 995 LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 996 } 997 continue; 998 } else 999 LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 1000 } 1001 1002 /* 1003 * Process on-demand dialup. Output packets are queued within tunnel 1004 * device until IPCP is opened. 1005 */ 1006 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1007 pri = PacketCheck(rbuff, n, FL_DIAL); 1008 if (pri >= 0) { 1009 if (mode & MODE_ALIAS) { 1010 VarPacketAliasOut(rbuff, sizeof rbuff); 1011 n = ntohs(((struct ip *) rbuff)->ip_len); 1012 } 1013 IpEnqueue(pri, rbuff, n); 1014 dial_up = 1; /* XXX */ 1015 } 1016 continue; 1017 } 1018 pri = PacketCheck(rbuff, n, FL_OUT); 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 } 1026 } 1027 } 1028 LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1029}
|