main.c revision 25908
190792Sgshapiro/* 2147078Sgshapiro * User Process PPP 390792Sgshapiro * 490792Sgshapiro * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 590792Sgshapiro * 690792Sgshapiro * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 790792Sgshapiro * 890792Sgshapiro * Redistribution and use in source and binary forms are permitted 990792Sgshapiro * provided that the above copyright notice and this paragraph are 1090792Sgshapiro * duplicated in all such forms and that any documentation, 11147078Sgshapiro * advertising materials, and other materials related to such 1290792Sgshapiro * distribution and use acknowledge that the software was developed 1390792Sgshapiro * by the Internet Initiative Japan, Inc. The name of the 1490792Sgshapiro * IIJ may not be used to endorse or promote products derived 1590792Sgshapiro * from this software without specific prior written permission. 1690792Sgshapiro * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1790792Sgshapiro * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1890792Sgshapiro * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19120256Sgshapiro * 2090792Sgshapiro * $Id: main.c,v 1.51 1997/05/17 16:08:46 brian Exp $ 2190792Sgshapiro * 2290792Sgshapiro * TODO: 2390792Sgshapiro * o Add commands for traffic summary, version display, etc. 2490792Sgshapiro * o Add signal handler for misc controls. 2590792Sgshapiro */ 2690792Sgshapiro#include "fsm.h" 2790792Sgshapiro#include <fcntl.h> 2890792Sgshapiro#include <paths.h> 2990792Sgshapiro#include <sys/time.h> 3090792Sgshapiro#include <termios.h> 3190792Sgshapiro#include <signal.h> 3290792Sgshapiro#include <sys/wait.h> 3390792Sgshapiro#include <errno.h> 3490792Sgshapiro#include <netdb.h> 3590792Sgshapiro#include <unistd.h> 3690792Sgshapiro#include <sys/socket.h> 3790792Sgshapiro#include <arpa/inet.h> 3890792Sgshapiro#include <netinet/in_systm.h> 3990792Sgshapiro#include <netinet/ip.h> 4090792Sgshapiro#include "modem.h" 4190792Sgshapiro#include "os.h" 4290792Sgshapiro#include "hdlc.h" 4390792Sgshapiro#include "ccp.h" 4490792Sgshapiro#include "lcp.h" 4590792Sgshapiro#include "ipcp.h" 4690792Sgshapiro#include "vars.h" 4790792Sgshapiro#include "auth.h" 4890792Sgshapiro#include "filter.h" 4990792Sgshapiro#include "systems.h" 5090792Sgshapiro#include "ip.h" 5190792Sgshapiro#include "alias.h" 5290792Sgshapiro#include "sig.h" 5390792Sgshapiro 5490792Sgshapiro#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 5590792Sgshapiro#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n" 5690792Sgshapiro 5790792Sgshapiro#ifndef O_NONBLOCK 5890792Sgshapiro#ifdef O_NDELAY 5990792Sgshapiro#define O_NONBLOCK O_NDELAY 6090792Sgshapiro#endif 6190792Sgshapiro#endif 6290792Sgshapiro 6390792Sgshapiroextern void VjInit(), AsyncInit(); 6490792Sgshapiroextern void AsyncInput(); 6590792Sgshapiroextern int SelectSystem(); 6690792Sgshapiro 6790792Sgshapiroextern void DecodeCommand(), Prompt(); 6890792Sgshapiroextern int aft_cmd; 6990792Sgshapiroextern int IsInteractive(); 7090792Sgshapirostatic void DoLoop(void); 7190792Sgshapirostatic void TerminalStop(); 7290792Sgshapirostatic char *ex_desc(); 73120256Sgshapiro 7490792Sgshapirostatic struct termios oldtio; /* Original tty mode */ 7590792Sgshapirostatic struct termios comtio; /* Command level tty mode */ 7690792Sgshapiroint TermMode; 7790792Sgshapirostatic int server; 7890792Sgshapirostatic pid_t BGPid = 0; 7990792Sgshapirostruct sockaddr_in ifsin; 8090792Sgshapirostatic char pid_filename[MAXPATHLEN]; 8190792Sgshapirostatic char if_filename[MAXPATHLEN]; 8290792Sgshapiroint tunno; 8390792Sgshapiro 8490792Sgshapirostatic void 8590792SgshapiroTtyInit() 8690792Sgshapiro{ 8790792Sgshapiro struct termios newtio; 8890792Sgshapiro int stat; 8990792Sgshapiro 90120256Sgshapiro stat = fcntl(0, F_GETFL, 0); 9190792Sgshapiro if (stat > 0) { 9290792Sgshapiro stat |= O_NONBLOCK; 9390792Sgshapiro (void)fcntl(0, F_SETFL, stat); 9490792Sgshapiro } 9590792Sgshapiro newtio = oldtio; 9690792Sgshapiro newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 9790792Sgshapiro newtio.c_iflag = 0; 9890792Sgshapiro newtio.c_oflag &= ~OPOST; 9990792Sgshapiro newtio.c_cc[VEOF] = _POSIX_VDISABLE; 10090792Sgshapiro newtio.c_cc[VINTR] = _POSIX_VDISABLE; 10190792Sgshapiro newtio.c_cc[VMIN] = 1; 10290792Sgshapiro newtio.c_cc[VTIME] = 0; 10390792Sgshapiro newtio.c_cflag |= CS8; 10490792Sgshapiro tcsetattr(0, TCSADRAIN, &newtio); 105120256Sgshapiro comtio = newtio; 106120256Sgshapiro} 107147078Sgshapiro 108147078Sgshapiro/* 109147078Sgshapiro * Set tty into command mode. We allow canonical input and echo processing. 110147078Sgshapiro */ 111147078Sgshapirovoid 112147078SgshapiroTtyCommandMode(prompt) 113147078Sgshapiroint prompt; 114147078Sgshapiro{ 115147078Sgshapiro struct termios newtio; 116147078Sgshapiro int stat; 117147078Sgshapiro 118147078Sgshapiro if (!(mode & MODE_INTER)) 119147078Sgshapiro return; 120147078Sgshapiro tcgetattr(0, &newtio); 121147078Sgshapiro newtio.c_lflag |= (ECHO|ISIG|ICANON); 122147078Sgshapiro newtio.c_iflag = oldtio.c_iflag; 123147078Sgshapiro newtio.c_oflag |= OPOST; 124147078Sgshapiro tcsetattr(0, TCSADRAIN, &newtio); 125147078Sgshapiro stat = fcntl(0, F_GETFL, 0); 126147078Sgshapiro if (stat > 0) { 127147078Sgshapiro stat |= O_NONBLOCK; 128147078Sgshapiro (void)fcntl(0, F_SETFL, stat); 129147078Sgshapiro } 130147078Sgshapiro TermMode = 0; 131147078Sgshapiro if(prompt) Prompt(); 132147078Sgshapiro} 133147078Sgshapiro 134147078Sgshapiro/* 135147078Sgshapiro * Set tty into terminal mode which is used while we invoke term command. 136147078Sgshapiro */ 137147078Sgshapirovoid 138147078SgshapiroTtyTermMode() 139147078Sgshapiro{ 140147078Sgshapiro int stat; 14190792Sgshapiro 142 tcsetattr(0, TCSADRAIN, &comtio); 143 stat = fcntl(0, F_GETFL, 0); 144 if (stat > 0) { 145 stat &= ~O_NONBLOCK; 146 (void)fcntl(0, F_SETFL, stat); 147 } 148 TermMode = 1; 149} 150 151void 152TtyOldMode() 153{ 154 int stat; 155 156 stat = fcntl(0, F_GETFL, 0); 157 if (stat > 0) { 158 stat &= ~O_NONBLOCK; 159 (void)fcntl(0, F_SETFL, stat); 160 } 161 tcsetattr(0, TCSANOW, &oldtio); 162} 163 164void 165Cleanup(excode) 166int excode; 167{ 168 169 OsLinkdown(); 170 OsCloseLink(1); 171 sleep(1); 172 if (mode & MODE_AUTO) 173 DeleteIfRoutes(1); 174 (void)unlink(pid_filename); 175 (void)unlink(if_filename); 176 OsInterfaceDown(1); 177 if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 178 char c = EX_ERRDEAD; 179 if (write(BGFiledes[1],&c,1) == 1) 180 LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n"); 181 else 182 LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n"); 183 close(BGFiledes[1]); 184 } 185 LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode)); 186 LogClose(); 187 if (server >= 0) { 188 close(server); 189 server = -1; 190 } 191 192 TtyOldMode(); 193 194 exit(excode); 195} 196 197static void 198Hangup(signo) 199int signo; 200{ 201 if (signo == SIGSEGV) { 202 LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 203 LogClose(); 204 abort(); 205 } 206 if (BGPid) { 207 kill (BGPid, SIGTERM); 208 exit (EX_HANGUP); 209 } 210 else { 211 LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 212 Cleanup(EX_HANGUP); 213 } 214} 215 216static void 217CloseSession(signo) 218int signo; 219{ 220 if (BGPid) { 221 kill (BGPid, SIGINT); 222 exit (EX_TERM); 223 } 224 else { 225 LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 226 LcpClose(); 227 reconnectCount = 0; 228 Cleanup(EX_TERM); 229 } 230} 231 232static void 233TerminalCont() 234{ 235 pending_signal(SIGCONT, SIG_DFL); 236 pending_signal(SIGTSTP, TerminalStop); 237 TtyCommandMode(getpgrp() == tcgetpgrp(0)); 238} 239 240static void 241TerminalStop(signo) 242int signo; 243{ 244 pending_signal(SIGCONT, TerminalCont); 245 TtyOldMode(); 246 pending_signal(SIGTSTP, SIG_DFL); 247 kill(getpid(), signo); 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 264void 265Usage() 266{ 267 fprintf(stderr, 268 "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 269 exit(EX_START); 270} 271 272void 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 mode |= MODE_ALIAS; 293 optc--; /* this option isn't exclusive */ 294 } 295 else 296 Usage(); 297 optc++; 298 argv++; argc--; 299 } 300 if (argc > 1) { 301 fprintf(stderr, "specify only one system label.\n"); 302 exit(EX_START); 303 } 304 if (argc == 1) dstsystem = *argv; 305 306 if (optc > 1) { 307 fprintf(stderr, "specify only one mode.\n"); 308 exit(EX_START); 309 } 310} 311 312static void 313Greetings() 314{ 315 printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 316 fflush(stdout); 317} 318 319void 320main(argc, argv) 321int argc; 322char **argv; 323{ 324 FILE *lockfile; 325 argc--; argv++; 326 327 mode = MODE_INTER; /* default operation is interactive mode */ 328 netfd = server = modem = tun_in = -1; 329 ProcessArgs(argc, argv); 330 Greetings(); 331 GetUid(); 332 IpcpDefAddress(); 333 InitAlias(); 334 335 if (SelectSystem("default", CONFFILE) < 0) { 336 fprintf(stderr, "Warning: No default entry is given in config file.\n"); 337 } 338 339 switch ( LocalAuthInit() ) { 340 case NOT_FOUND: 341 fprintf(stderr,LAUTH_M1); 342 fprintf(stderr,LAUTH_M2); 343 fflush (stderr); 344 /* Fall down */ 345 case VALID: 346 VarLocalAuth = LOCAL_AUTH; 347 break; 348 default: 349 break; 350 } 351 352 if (OpenTunnel(&tunno) < 0) { 353 perror("open_tun"); 354 exit(EX_START); 355 } 356 357 if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 358 mode &= ~MODE_INTER; 359 if (mode & MODE_INTER) { 360 printf("Interactive mode\n"); 361 netfd = STDIN_FILENO; 362 } else if (mode & MODE_AUTO) { 363 printf("Automatic Dialer mode\n"); 364 if (dstsystem == NULL) { 365 fprintf(stderr, "Destination system must be specified in" 366 " auto, background or ddial mode.\n"); 367 exit(EX_START); 368 } 369 } 370 371 tcgetattr(0, &oldtio); /* Save original tty mode */ 372 373 pending_signal(SIGHUP, LogReOpen); 374 pending_signal(SIGTERM, CloseSession); 375 pending_signal(SIGINT, CloseSession); 376 pending_signal(SIGQUIT, CloseSession); 377#ifdef SIGSEGV 378 signal(SIGSEGV, Hangup); 379#endif 380#ifdef SIGPIPE 381 signal(SIGPIPE, SIG_IGN); 382#endif 383#ifdef SIGALRM 384 pending_signal(SIGALRM, SIG_IGN); 385#endif 386 if(mode & MODE_INTER) 387 { 388#ifdef SIGTSTP 389 pending_signal(SIGTSTP, TerminalStop); 390#endif 391#ifdef SIGTTIN 392 pending_signal(SIGTTIN, TerminalStop); 393#endif 394#ifdef SIGTTOU 395 pending_signal(SIGTTOU, SIG_IGN); 396#endif 397 } 398 399 if (dstsystem) { 400 if (SelectSystem(dstsystem, CONFFILE) < 0) { 401 fprintf(stderr, "Destination system not found in conf file.\n"); 402 Cleanup(EX_START); 403 } 404 if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 405 fprintf(stderr, "Must specify dstaddr with" 406 " auto, background or ddial mode.\n"); 407 Cleanup(EX_START); 408 } 409 } 410 if (mode & MODE_DIRECT) 411 printf("Packet mode enabled.\n"); 412 413 if (!(mode & MODE_INTER)) { 414 int port = SERVER_PORT + tunno; 415 416 if (mode & MODE_BACKGROUND) { 417 if (pipe (BGFiledes)) { 418 perror("pipe"); 419 Cleanup(EX_SOCK); 420 } 421 } 422 423 /* Create server socket and listen at there. */ 424 server = socket(PF_INET, SOCK_STREAM, 0); 425 if (server < 0) { 426 perror("socket"); 427 Cleanup(EX_SOCK); 428 } 429 ifsin.sin_family = AF_INET; 430 ifsin.sin_addr.s_addr = INADDR_ANY; 431 ifsin.sin_port = htons(port); 432 if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 433 perror("bind"); 434 if (errno == EADDRINUSE) 435 fprintf(stderr, "Wait for a while, then try again.\n"); 436 Cleanup(EX_SOCK); 437 } 438 if (listen(server, 5) != 0) { 439 fprintf(stderr, "Unable to listen to socket - OS overload?\n"); 440 } 441 442 DupLog(); 443 if (!(mode & MODE_DIRECT)) { 444 pid_t bgpid; 445 446 bgpid = fork (); 447 if (bgpid == -1) { 448 perror ("fork"); 449 Cleanup (EX_SOCK); 450 } 451 if (bgpid) { 452 char c = EX_NORMAL; 453 454 if (mode & MODE_BACKGROUND) { 455 /* Wait for our child to close its pipe before we exit. */ 456 BGPid = bgpid; 457 close (BGFiledes[1]); 458 if (read(BGFiledes[0], &c, 1) != 1) { 459 printf("Child exit, no status.\n"); 460 LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n"); 461 } else if (c == EX_NORMAL) { 462 printf("PPP enabled.\n"); 463 LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n"); 464 } else { 465 printf("Child failed %d.\n",(int)c); 466 LogPrintf (LOG_PHASE_BIT, "Parent: Child failed %d.\n",(int)c); 467 } 468 close (BGFiledes[0]); 469 } 470 exit(c); 471 } else if (mode & MODE_BACKGROUND) 472 close(BGFiledes[0]); 473 } 474 475 snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 476 _PATH_VARRUN, tunno); 477 (void)unlink(pid_filename); 478 479 if ((lockfile = fopen(pid_filename, "w")) != NULL) { 480 fprintf(lockfile, "%d\n", (int)getpid()); 481 fclose(lockfile); 482 } else 483 logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno)); 484 485 snprintf(if_filename, sizeof if_filename, "%s%s.if", 486 _PATH_VARRUN, VarBaseDevice); 487 (void)unlink(if_filename); 488 489 if ((lockfile = fopen(if_filename, "w")) != NULL) { 490 fprintf(lockfile, "tun%d\n", tunno); 491 fclose(lockfile); 492 } else 493 logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno)); 494 495 if (server >= 0) 496 LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 497#ifdef DOTTYINIT 498 if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 499#else 500 if (mode & MODE_DIRECT) { 501#endif 502 TtyInit(); 503 } else { 504 int fd; 505 506 setsid(); /* detach control tty */ 507 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 508 (void)dup2(fd, STDIN_FILENO); 509 (void)dup2(fd, STDOUT_FILENO); 510 (void)dup2(fd, STDERR_FILENO); 511 if (fd > 2) 512 (void)close (fd); 513 } 514 } 515 } else { 516 TtyInit(); 517 TtyCommandMode(1); 518 } 519 LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 520 521 522 do 523 DoLoop(); 524 while (mode & MODE_DEDICATED); 525 526 Cleanup(EX_DONE); 527} 528 529/* 530 * Turn into packet mode, where we speak PPP. 531 */ 532void 533PacketMode() 534{ 535 if (RawModem(modem) < 0) { 536 fprintf(stderr, "Not connected.\r\n"); 537 return; 538 } 539 540 AsyncInit(); 541 VjInit(); 542 LcpInit(); 543 IpcpInit(); 544 CcpInit(); 545 LcpUp(); 546 547 LcpOpen(VarOpenMode); 548 if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 549 TtyCommandMode(1); 550 fprintf(stderr, "Packet mode.\r\n"); 551 aft_cmd = 1; 552 } 553} 554 555static void 556ShowHelp() 557{ 558 fprintf(stderr, "The following commands are available:\r\n"); 559 fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 560 fprintf(stderr, " ~-\tDecrease log level\r\n"); 561 fprintf(stderr, " ~+\tIncrease log level\r\n"); 562 fprintf(stderr, " ~.\tTerminate program\r\n"); 563 fprintf(stderr, " ~?\tThis help\r\n"); 564} 565 566static void 567ReadTty() 568{ 569 int n; 570 char ch; 571 static int ttystate; 572#define MAXLINESIZE 200 573 char linebuff[MAXLINESIZE]; 574 575#ifdef DEBUG 576 logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 577#endif 578 if (!TermMode) { 579 n = read(netfd, linebuff, sizeof(linebuff)-1); 580 aft_cmd = 1; 581 if (n > 0) { 582 DecodeCommand(linebuff, n, 1); 583 } else { 584 LogPrintf(LOG_PHASE_BIT, "client connection closed.\n"); 585 VarLocalAuth = LOCAL_NO_AUTH; 586 close(netfd); 587 close(1); 588 dup2(2, 1); /* Have to have something here or the modem will be 1 */ 589 netfd = -1; 590 mode &= ~MODE_INTER; 591 } 592 return; 593 } 594 595 /* 596 * We are in terminal mode, decode special sequences 597 */ 598 n = read(0, &ch, 1); 599#ifdef DEBUG 600 logprintf("got %d bytes\n", n); 601#endif 602 603 if (n > 0) { 604 switch (ttystate) { 605 case 0: 606 if (ch == '~') 607 ttystate++; 608 else 609 write(modem, &ch, n); 610 break; 611 case 1: 612 switch (ch) { 613 case '?': 614 ShowHelp(); 615 break; 616 case '-': 617 if (loglevel > 0) { 618 loglevel--; 619 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 620 } 621 break; 622 case '+': 623 loglevel++; 624 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 625 break; 626#ifdef DEBUG 627 case 'm': 628 ShowMemMap(); 629 break; 630#endif 631 case 'p': 632 /* 633 * XXX: Should check carrier. 634 */ 635 if (LcpFsm.state <= ST_CLOSED) { 636 VarOpenMode = OPEN_ACTIVE; 637 PacketMode(); 638 } 639 break; 640#ifdef DEBUG 641 case 't': 642 ShowTimers(); 643 break; 644#endif 645 case '.': 646 TermMode = 1; 647 TtyCommandMode(1); 648 break; 649 default: 650 if (write(modem, &ch, n) < 0) 651 fprintf(stderr, "err in write.\r\n"); 652 break; 653 } 654 ttystate = 0; 655 break; 656 } 657 } 658} 659 660 661/* 662 * Here, we'll try to detect HDLC frame 663 */ 664 665static char *FrameHeaders[] = { 666 "\176\377\003\300\041", 667 "\176\377\175\043\300\041", 668 "\176\177\175\043\100\041", 669 "\176\175\337\175\043\300\041", 670 "\176\175\137\175\043\100\041", 671 NULL, 672}; 673 674u_char * 675HdlcDetect(cp, n) 676u_char *cp; 677int n; 678{ 679 char *ptr, *fp, **hp; 680 681 cp[n] = '\0'; /* be sure to null terminated */ 682 ptr = NULL; 683 for (hp = FrameHeaders; *hp; hp++) { 684 fp = *hp; 685 if (DEV_IS_SYNC) 686 fp++; 687 ptr = strstr((char *)cp, fp); 688 if (ptr) 689 break; 690 } 691 return((u_char *)ptr); 692} 693 694static struct pppTimer RedialTimer; 695 696static void 697RedialTimeout() 698{ 699 StopTimer(&RedialTimer); 700 LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 701} 702 703static void 704StartRedialTimer(Timeout) 705 int Timeout; 706{ 707 StopTimer(&RedialTimer); 708 709 if (Timeout) { 710 RedialTimer.state = TIMER_STOPPED; 711 712 if (Timeout > 0) 713 RedialTimer.load = Timeout * SECTICKS; 714 else 715 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 716 717 LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n", 718 RedialTimer.load / SECTICKS); 719 720 RedialTimer.func = RedialTimeout; 721 StartTimer(&RedialTimer); 722 } 723} 724 725 726static void 727DoLoop() 728{ 729 fd_set rfds, wfds, efds; 730 int pri, i, n, wfd, nfds; 731 struct sockaddr_in hisaddr; 732 struct timeval timeout, *tp; 733 int ssize = sizeof(hisaddr); 734 u_char *cp; 735 u_char rbuff[MAX_MRU]; 736 int dial_up; 737 int tries; 738 int qlen; 739 pid_t pgroup; 740 741 pgroup = getpgrp(); 742 743 if (mode & MODE_DIRECT) { 744 modem = OpenModem(mode); 745 LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 746 fflush(stderr); 747 PacketMode(); 748 } else if (mode & MODE_DEDICATED) { 749 if (modem < 0) 750 modem = OpenModem(mode); 751 } 752 753 fflush(stdout); 754 755 timeout.tv_sec = 0; 756 timeout.tv_usec = 0; 757 reconnectRequired = 0; 758 759 if (mode & MODE_BACKGROUND) 760 dial_up = TRUE; /* Bring the line up */ 761 else 762 dial_up = FALSE; /* XXXX */ 763 tries = 0; 764 for (;;) { 765 nfds = 0; 766 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 767 768 /* 769 * If the link is down and we're in DDIAL mode, bring it back 770 * up. 771 */ 772 if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 773 dial_up = TRUE; 774 775 /* 776 * If we lost carrier and want to re-establish the connection 777 * due to the "set reconnect" value, we'd better bring the line 778 * back up. 779 */ 780 if (LcpFsm.state <= ST_CLOSED) { 781 if (dial_up != TRUE && reconnectRequired) { 782 if (++reconnectCount <= VarReconnectTries) { 783 LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n", 784 reconnectCount, VarReconnectTries); 785 StartRedialTimer(VarReconnectTimer); 786 dial_up = TRUE; 787 } else { 788 if (VarReconnectTries) 789 LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n", 790 VarReconnectTries); 791 reconnectCount = 0; 792 if (mode & MODE_BACKGROUND) 793 Cleanup(EX_DEAD); 794 } 795 } 796 reconnectRequired = 0; 797 } 798 799 /* 800 * If Ip packet for output is enqueued and require dial up, 801 * Just do it! 802 */ 803 if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 804#ifdef DEBUG 805 logprintf("going to dial: modem = %d\n", modem); 806#endif 807 modem = OpenModem(mode); 808 if (modem < 0) { 809 StartRedialTimer(VarRedialTimeout); 810 } else { 811 tries++; /* Tries are per number, not per list of numbers. */ 812 if (VarDialTries) 813 LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries, 814 VarDialTries); 815 else 816 LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 817 if (DialModem()) { 818 sleep(1); /* little pause to allow peer starts */ 819 ModemTimeout(); 820 PacketMode(); 821 dial_up = FALSE; 822 tries = 0; 823 } else { 824 CloseModem(); 825 if (mode & MODE_BACKGROUND) { 826 if (VarNextPhone == NULL) 827 Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 828 else 829 /* Try all numbers in background mode */ 830 StartRedialTimer(VarRedialNextTimeout); 831 } else if (VarDialTries && tries >= VarDialTries) { 832 /* I give up ! Can't get through :( */ 833 StartRedialTimer(VarRedialTimeout); 834 dial_up = FALSE; 835 tries = 0; 836 } else if (VarNextPhone == NULL) 837 /* Dial failed. Keep quite during redial wait period. */ 838 StartRedialTimer(VarRedialTimeout); 839 else 840 StartRedialTimer(VarRedialNextTimeout); 841 } 842 } 843 } 844 qlen = ModemQlen(); 845 846 if (qlen == 0) { 847 IpStartOutput(); 848 qlen = ModemQlen(); 849 } 850 851 if (modem >= 0) { 852 if (modem + 1 > nfds) 853 nfds = modem + 1; 854 FD_SET(modem, &rfds); 855 FD_SET(modem, &efds); 856 if (qlen > 0) { 857 FD_SET(modem, &wfds); 858 } 859 } 860 if (server >= 0) { 861 if (server + 1 > nfds) 862 nfds = server + 1; 863 FD_SET(server, &rfds); 864 } 865 866 /* *** IMPORTANT *** 867 * 868 * CPU is serviced every TICKUNIT micro seconds. 869 * This value must be chosen with great care. If this values is 870 * too big, it results loss of characters from modem and poor responce. 871 * If this values is too small, ppp process eats many CPU time. 872 */ 873#ifndef SIGALRM 874 usleep(TICKUNIT); 875 TimerService(); 876#else 877 handle_signals(); 878#endif 879 880 /* If there are aren't many packets queued, look for some more. */ 881 if (qlen < 20 && tun_in >= 0) { 882 if (tun_in + 1 > nfds) 883 nfds = tun_in + 1; 884 FD_SET(tun_in, &rfds); 885 } 886 887 if (netfd >= 0) { 888 if (netfd + 1 > nfds) 889 nfds = netfd + 1; 890 FD_SET(netfd, &rfds); 891 FD_SET(netfd, &efds); 892 } 893 894#ifndef SIGALRM 895 /* 896 * Normally, select() will not block because modem is writable. 897 * In AUTO mode, select will block until we find packet from tun 898 */ 899 tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 900 i = select(nfds, &rfds, &wfds, &efds, tp); 901#else 902 /* 903 * When SIGALRM timer is running, a select function will be 904 * return -1 and EINTR after a Time Service signal hundler 905 * is done. If the redial timer is not running and we are 906 * trying to dial, poll with a 0 value timer. 907 */ 908 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 909 i = select(nfds, &rfds, &wfds, &efds, tp); 910#endif 911 912 if ( i == 0 ) { 913 continue; 914 } 915 916 if ( i < 0 ) { 917 if ( errno == EINTR ) { 918 handle_signals(); 919 continue; 920 } 921 perror("select"); 922 break; 923 } 924 925 if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 926 logprintf("Exception detected.\n"); 927 break; 928 } 929 930 if (server >= 0 && FD_ISSET(server, &rfds)) { 931 LogPrintf(LOG_PHASE_BIT, "connected to client.\n"); 932 wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 933 if (wfd < 0) { 934 perror("accept"); 935 continue; 936 } 937 if (netfd >= 0) { 938 write(wfd, "already in use.\n", 16); 939 close(wfd); 940 continue; 941 } else 942 netfd = wfd; 943 if (dup2(netfd, 1) < 0) { 944 perror("dup2"); 945 close(netfd); 946 netfd = -1; 947 continue; 948 } 949 mode |= MODE_INTER; 950 Greetings(); 951 switch ( LocalAuthInit() ) { 952 case NOT_FOUND: 953 fprintf(stdout,LAUTH_M1); 954 fprintf(stdout,LAUTH_M2); 955 fflush(stdout); 956 /* Fall down */ 957 case VALID: 958 VarLocalAuth = LOCAL_AUTH; 959 break; 960 default: 961 break; 962 } 963 (void) IsInteractive(); 964 Prompt(); 965 } 966 967 if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 968 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 969 /* something to read from tty */ 970 ReadTty(); 971 } 972 if (modem >= 0) { 973 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 974 ModemStartOutput(modem); 975 } 976 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 977 if (LcpFsm.state <= ST_CLOSED) 978 usleep(10000); 979 n = read(modem, rbuff, sizeof(rbuff)); 980 if ((mode & MODE_DIRECT) && n <= 0) { 981 DownConnection(); 982 } else 983 LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 984 985 if (LcpFsm.state <= ST_CLOSED) { 986 /* 987 * In dedicated mode, we just discard input until LCP is started. 988 */ 989 if (!(mode & MODE_DEDICATED)) { 990 cp = HdlcDetect(rbuff, n); 991 if (cp) { 992 /* 993 * LCP packet is detected. Turn ourselves into packet mode. 994 */ 995 if (cp != rbuff) { 996 write(1, rbuff, cp - rbuff); 997 write(1, "\r\n", 2); 998 } 999 PacketMode(); 1000 } else 1001 write(1, rbuff, n); 1002 } 1003 } else { 1004 if (n > 0) 1005 AsyncInput(rbuff, n); 1006 } 1007 } 1008 } 1009 1010 if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 1011 n = read(tun_in, rbuff, sizeof(rbuff)); 1012 if (n < 0) { 1013 perror("read from tun"); 1014 continue; 1015 } 1016 /* 1017 * Process on-demand dialup. Output packets are queued within tunnel 1018 * device until IPCP is opened. 1019 */ 1020 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 1021 pri = PacketCheck(rbuff, n, FL_DIAL); 1022 if (pri >= 0) { 1023 if (mode & MODE_ALIAS) { 1024 PacketAliasOut((struct ip *)rbuff); 1025 n = ntohs(((struct ip *)rbuff)->ip_len); 1026 } 1027 IpEnqueue(pri, rbuff, n); 1028 dial_up = TRUE; /* XXX */ 1029 } 1030 continue; 1031 } 1032 pri = PacketCheck(rbuff, n, FL_OUT); 1033 if (pri >= 0) { 1034 if (mode & MODE_ALIAS) { 1035 PacketAliasOut((struct ip *)rbuff); 1036 n = ntohs(((struct ip *)rbuff)->ip_len); 1037 } 1038 IpEnqueue(pri, rbuff, n); 1039 } 1040 } 1041 } 1042 logprintf("job done.\n"); 1043} 1044