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