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.21 1996/10/07 04:21:00 jkh 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 "fsm.h" 27 #include <fcntl.h> 28 #include <paths.h> 29 #include <sys/time.h> 30 #include <termios.h> 31 #include <signal.h> 32 #include <sys/wait.h> 33 #include <errno.h> 34 #include <netdb.h> 35 #include <unistd.h> 36 #include <sys/socket.h> 37 #include <arpa/inet.h> 38 #include "modem.h" 39 #include "os.h" 40 #include "hdlc.h" 41 #include "ccp.h" 42 #include "lcp.h" 43 #include "ipcp.h" 44 #include "vars.h" 45 #include "auth.h" 46 #include "filter.h" 47 #include "systems.h" 48 #include "ip.h" 49 50 #define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 51 #define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n" 52 53 #ifndef O_NONBLOCK 54 #ifdef O_NDELAY 55 #define O_NONBLOCK O_NDELAY 56 #endif 57 #endif 58 59 extern void VjInit(), AsyncInit(); 60 extern void AsyncInput(), IpOutput(); 61 extern int SelectSystem(); 62 63 extern void DecodeCommand(), Prompt(); 64 extern int aft_cmd; 65 extern int IsInteractive(); 66 extern struct in_addr ifnetmask; 67 static void DoLoop(void); 68 static void TerminalStop(); 69 70 static struct termios oldtio; /* Original tty mode */ 71 static struct termios comtio; /* Command level tty mode */ 72 int TermMode; 73 static int server; 74 struct sockaddr_in ifsin; 75 char pid_filename[128]; 76 77 static void 78 TtyInit() 79 { 80 struct termios newtio; 81 int stat; 82 83 stat = fcntl(0, F_GETFL, 0); 84 stat |= O_NONBLOCK; 85 fcntl(0, F_SETFL, stat); 86 newtio = oldtio; 87 newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 88 newtio.c_iflag = 0; 89 newtio.c_oflag &= ~OPOST; 90 newtio.c_cc[VEOF] = _POSIX_VDISABLE; 91 newtio.c_cc[VINTR] = _POSIX_VDISABLE; 92 newtio.c_cc[VMIN] = 1; 93 newtio.c_cc[VTIME] = 0; 94 newtio.c_cflag |= CS8; 95 tcsetattr(0, TCSADRAIN, &newtio); 96 comtio = newtio; 97 } 98 99 /* 100 * Set tty into command mode. We allow canonical input and echo processing. 101 */ 102 void 103 TtyCommandMode(prompt) 104 int prompt; 105 { 106 struct termios newtio; 107 int stat; 108 109 if (!(mode & MODE_INTER)) 110 return; 111 tcgetattr(0, &newtio); 112 newtio.c_lflag |= (ECHO|ISIG|ICANON); 113 newtio.c_iflag = oldtio.c_iflag; 114 newtio.c_oflag |= OPOST; 115 tcsetattr(0, TCSADRAIN, &newtio); 116 stat = fcntl(0, F_GETFL, 0); 117 stat |= O_NONBLOCK; 118 fcntl(0, F_SETFL, stat); 119 TermMode = 0; 120 if(prompt) Prompt(0); 121 } 122 123 /* 124 * Set tty into terminal mode which is used while we invoke term command. 125 */ 126 void 127 TtyTermMode() 128 { 129 int stat; 130 131 tcsetattr(0, TCSADRAIN, &comtio); 132 stat = fcntl(0, F_GETFL, 0); 133 stat &= ~O_NONBLOCK; 134 fcntl(0, F_SETFL, stat); 135 TermMode = 1; 136 } 137 138 void 139 TtyOldMode() 140 { 141 int stat; 142 143 stat = fcntl(0, F_GETFL, 0); 144 stat &= ~O_NONBLOCK; 145 fcntl(0, F_SETFL, stat); 146 tcsetattr(0, TCSANOW, &oldtio); 147 } 148 149 void 150 Cleanup(excode) 151 int excode; 152 { 153 154 OsLinkdown(); 155 OsCloseLink(1); 156 sleep(1); 157 if (mode & MODE_AUTO) { 158 DeleteIfRoutes(1); 159 unlink(pid_filename); 160 } 161 OsInterfaceDown(1); 162 LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n"); 163 LogClose(); 164 if (server > 0) 165 close(server); 166 TtyOldMode(); 167 168 exit(excode); 169 } 170 171 static void 172 Hangup(signo) 173 int signo; 174 { 175 if (signo == SIGSEGV) { 176 LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo); 177 LogClose(); 178 abort(); 179 } 180 LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo); 181 Cleanup(EX_HANGUP); 182 } 183 184 static void 185 CloseSession(signo) 186 int signo; 187 { 188 LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo); 189 LcpClose(); 190 Cleanup(EX_TERM); 191 } 192 193 194 static void 195 TerminalCont() 196 { 197 (void)signal(SIGCONT, SIG_DFL); 198 (void)signal(SIGTSTP, TerminalStop); 199 TtyCommandMode(getpgrp() == tcgetpgrp(0)); 200 } 201 202 static void 203 TerminalStop(signo) 204 int signo; 205 { 206 (void)signal(SIGCONT, TerminalCont); 207 TtyOldMode(); 208 signal(SIGTSTP, SIG_DFL); 209 kill(getpid(), signo); 210 } 211 212 213 void 214 Usage() 215 { 216 fprintf(stderr, "Usage: ppp [-auto | -direct | -dedicated] [system]\n"); 217 exit(EX_START); 218 } 219 220 void 221 ProcessArgs(int argc, char **argv) 222 { 223 int optc; 224 char *cp; 225 226 optc = 0; 227 while (argc > 0 && **argv == '-') { 228 cp = *argv + 1; 229 if (strcmp(cp, "auto") == 0) 230 mode |= MODE_AUTO; 231 else if (strcmp(cp, "direct") == 0) 232 mode |= MODE_DIRECT; 233 else if (strcmp(cp, "dedicated") == 0) 234 mode |= MODE_DEDICATED; 235 else 236 Usage(); 237 optc++; 238 argv++; argc--; 239 } 240 if (argc > 1) { 241 fprintf(stderr, "specify only one system label.\n"); 242 exit(EX_START); 243 } 244 if (argc == 1) dstsystem = *argv; 245 246 if (optc > 1) { 247 fprintf(stderr, "specify only one mode.\n"); 248 exit(EX_START); 249 } 250 } 251 252 static void 253 Greetings() 254 { 255 printf("User Process PPP. Written by Toshiharu OHNO.\r\n"); 256 fflush(stdout); 257 } 258 259 void 260 main(argc, argv) 261 int argc; 262 char **argv; 263 { 264 int tunno; 265 266 argc--; argv++; 267 268 mode = MODE_INTER; /* default operation is interactive mode */ 269 netfd = -1; 270 ProcessArgs(argc, argv); 271 Greetings(); 272 GetUid(); 273 IpcpDefAddress(); 274 275 if (SelectSystem("default", CONFFILE) < 0) { 276 fprintf(stderr, "Warning: No default entry is given in config file.\n"); 277 } 278 279 if (LogOpen()) 280 exit(EX_START); 281 282 switch ( LocalAuthInit() ) { 283 case NOT_FOUND: 284 fprintf(stderr,LAUTH_M1); 285 fprintf(stderr,LAUTH_M2); 286 fflush (stderr); 287 /* Fall down */ 288 case VALID: 289 VarLocalAuth = LOCAL_AUTH; 290 break; 291 default: 292 break; 293 } 294 295 if (OpenTunnel(&tunno) < 0) { 296 perror("open_tun"); 297 exit(EX_START); 298 } 299 300 if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 301 mode &= ~MODE_INTER; 302 if (mode & MODE_INTER) { 303 printf("Interactive mode\n"); 304 netfd = 0; 305 } else if (mode & MODE_AUTO) { 306 printf("Automatic mode\n"); 307 if (dstsystem == NULL) { 308 fprintf(stderr, "Destination system must be specified in auto mode.\n"); 309 exit(EX_START); 310 } 311 } 312 313 tcgetattr(0, &oldtio); /* Save original tty mode */ 314 315 signal(SIGHUP, Hangup); 316 signal(SIGTERM, CloseSession); 317 signal(SIGINT, CloseSession); 318 signal(SIGQUIT, CloseSession); 319 #ifdef SIGSEGV 320 signal(SIGSEGV, Hangup); 321 #endif 322 #ifdef SIGPIPE 323 signal(SIGPIPE, Hangup); 324 #endif 325 #ifdef SIGALRM 326 signal(SIGALRM, SIG_IGN); 327 #endif 328 if(mode & MODE_INTER) 329 { 330 #ifdef SIGTSTP 331 signal(SIGTSTP, TerminalStop); 332 #endif 333 #ifdef SIGTTIN 334 signal(SIGTTIN, TerminalStop); 335 #endif 336 #ifdef SIGTTOU 337 signal(SIGTTOU, SIG_IGN); 338 #endif 339 } 340 341 if (dstsystem) { 342 if (SelectSystem(dstsystem, CONFFILE) < 0) { 343 fprintf(stderr, "Destination system not found in conf file.\n"); 344 Cleanup(EX_START); 345 } 346 if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 347 fprintf(stderr, "Must specify dstaddr with auto mode.\n"); 348 Cleanup(EX_START); 349 } 350 } 351 if (mode & MODE_DIRECT) 352 printf("Packet mode enabled.\n"); 353 354 #ifdef notdef 355 if (mode & MODE_AUTO) { 356 OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask); 357 } 358 #endif 359 360 if (!(mode & MODE_INTER)) { 361 int port = SERVER_PORT + tunno; 362 /* 363 * Create server socket and listen at there. 364 */ 365 server = socket(PF_INET, SOCK_STREAM, 0); 366 if (server < 0) { 367 perror("socket"); 368 Cleanup(EX_SOCK); 369 } 370 ifsin.sin_family = AF_INET; 371 ifsin.sin_addr.s_addr = INADDR_ANY; 372 ifsin.sin_port = htons(port); 373 if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 374 perror("bind"); 375 if (errno == EADDRINUSE) 376 fprintf(stderr, "Wait for a while, then try again.\n"); 377 Cleanup(EX_SOCK); 378 } 379 listen(server, 5); 380 381 DupLog(); 382 if (!(mode & MODE_DIRECT)) { 383 int fd; 384 char pid[32]; 385 386 if (fork()) 387 exit(0); 388 389 snprintf(pid_filename, sizeof (pid_filename), "%s/PPP.%s", 390 _PATH_VARRUN, dstsystem); 391 unlink(pid_filename); 392 sprintf(pid, "%d\n", getpid()); 393 394 if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1) 395 { 396 write(fd, pid, strlen(pid)); 397 close(fd); 398 } 399 } 400 LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port); 401 #ifdef DOTTYINIT 402 if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 403 #else 404 if (mode & MODE_DIRECT) { 405 #endif 406 TtyInit(); 407 } else { 408 int fd; 409 410 setsid(); /* detach control tty */ 411 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 412 (void)dup2(fd, STDIN_FILENO); 413 (void)dup2(fd, STDOUT_FILENO); 414 (void)dup2(fd, STDERR_FILENO); 415 if (fd > 2) 416 (void)close (fd); 417 } 418 } 419 } else { 420 server = -1; 421 TtyInit(); 422 TtyCommandMode(1); 423 } 424 LogPrintf(LOG_PHASE_BIT, "PPP Started.\n"); 425 426 427 do 428 DoLoop(); 429 while (mode & MODE_DEDICATED); 430 431 Cleanup(EX_DONE); 432 } 433 434 /* 435 * Turn into packet mode, where we speek PPP. 436 */ 437 void 438 PacketMode() 439 { 440 if (RawModem(modem) < 0) { 441 fprintf(stderr, "Not connected.\r\n"); 442 return; 443 } 444 445 AsyncInit(); 446 VjInit(); 447 LcpInit(); 448 IpcpInit(); 449 CcpInit(); 450 LcpUp(); 451 452 if (mode & (MODE_DIRECT|MODE_DEDICATED)) 453 LcpOpen(OPEN_ACTIVE); 454 else 455 LcpOpen(VarOpenMode); 456 if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 457 TtyCommandMode(1); 458 fprintf(stderr, "Packet mode.\r\n"); 459 aft_cmd = 1; 460 } 461 } 462 463 static void 464 ShowHelp() 465 { 466 fprintf(stderr, "The following commands are available:\r\n"); 467 fprintf(stderr, " ~p\tEnter to Packet mode\r\n"); 468 fprintf(stderr, " ~-\tDecrease log level\r\n"); 469 fprintf(stderr, " ~+\tIncrease log level\r\n"); 470 fprintf(stderr, " ~.\tTerminate program\r\n"); 471 fprintf(stderr, " ~?\tThis help\r\n"); 472 } 473 474 static void 475 ReadTty() 476 { 477 int n; 478 char ch; 479 static int ttystate; 480 #define MAXLINESIZE 200 481 char linebuff[MAXLINESIZE]; 482 483 #ifdef DEBUG 484 logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode); 485 #endif 486 if (!TermMode) { 487 n = read(netfd, linebuff, sizeof(linebuff)-1); 488 aft_cmd = 1; 489 if (n > 0) { 490 DecodeCommand(linebuff, n, 1); 491 } else { 492 #ifdef DEBUG 493 logprintf("connection closed.\n"); 494 #endif 495 close(netfd); 496 netfd = -1; 497 mode &= ~MODE_INTER; 498 } 499 return; 500 } 501 502 /* 503 * We are in terminal mode, decode special sequences 504 */ 505 n = read(0, &ch, 1); 506 #ifdef DEBUG 507 logprintf("got %d bytes\n", n); 508 #endif 509 510 if (n > 0) { 511 switch (ttystate) { 512 case 0: 513 if (ch == '~') 514 ttystate++; 515 else 516 write(modem, &ch, n); 517 break; 518 case 1: 519 switch (ch) { 520 case '?': 521 ShowHelp(); 522 break; 523 case '-': 524 if (loglevel > 0) { 525 loglevel--; 526 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 527 } 528 break; 529 case '+': 530 loglevel++; 531 fprintf(stderr, "New loglevel is %d\r\n", loglevel); 532 break; 533 #ifdef DEBUG 534 case 'm': 535 ShowMemMap(); 536 break; 537 #endif 538 case 'p': 539 /* 540 * XXX: Should check carrier. 541 */ 542 if (LcpFsm.state <= ST_CLOSED) { 543 VarOpenMode = OPEN_ACTIVE; 544 PacketMode(); 545 } 546 break; 547 #ifdef DEBUG 548 case 't': 549 ShowTimers(); 550 break; 551 #endif 552 case '.': 553 TermMode = 1; 554 TtyCommandMode(1); 555 break; 556 default: 557 if (write(modem, &ch, n) < 0) 558 fprintf(stderr, "err in write.\r\n"); 559 break; 560 } 561 ttystate = 0; 562 break; 563 } 564 } 565 } 566 567 568 /* 569 * Here, we'll try to detect HDLC frame 570 */ 571 572 static char *FrameHeaders[] = { 573 "\176\377\003\300\041", 574 "\176\377\175\043\300\041", 575 "\176\177\175\043\100\041", 576 "\176\175\337\175\043\300\041", 577 "\176\175\137\175\043\100\041", 578 NULL, 579 }; 580 581 u_char * 582 HdlcDetect(cp, n) 583 u_char *cp; 584 int n; 585 { 586 char *ptr, *fp, **hp; 587 588 cp[n] = '\0'; /* be sure to null terminated */ 589 ptr = NULL; 590 for (hp = FrameHeaders; *hp; hp++) { 591 fp = *hp; 592 if (DEV_IS_SYNC) 593 fp++; 594 ptr = strstr((char *)cp, fp); 595 if (ptr) 596 break; 597 } 598 return((u_char *)ptr); 599 } 600 601 static struct pppTimer RedialTimer; 602 603 static void 604 RedialTimeout() 605 { 606 StopTimer(&RedialTimer); 607 LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n"); 608 } 609 610 static void 611 StartRedialTimer() 612 { 613 StopTimer(&RedialTimer); 614 615 if (VarRedialTimeout) { 616 LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n"); 617 RedialTimer.state = TIMER_STOPPED; 618 619 if (VarRedialTimeout > 0) 620 RedialTimer.load = VarRedialTimeout * SECTICKS; 621 else 622 RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 623 624 RedialTimer.func = RedialTimeout; 625 StartTimer(&RedialTimer); 626 } 627 } 628 629 630 static void 631 DoLoop() 632 { 633 fd_set rfds, wfds, efds; 634 int pri, i, n, wfd; 635 struct sockaddr_in hisaddr; 636 struct timeval timeout, *tp; 637 int ssize = sizeof(hisaddr); 638 u_char *cp; 639 u_char rbuff[MAX_MRU]; 640 int dial_up; 641 int tries; 642 int qlen; 643 pid_t pgroup; 644 645 pgroup = getpgrp(); 646 647 if (mode & MODE_DIRECT) { 648 modem = OpenModem(mode); 649 LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n"); 650 fflush(stderr); 651 PacketMode(); 652 } else if (mode & MODE_DEDICATED) { 653 if (!modem) 654 modem = OpenModem(mode); 655 } 656 657 fflush(stdout); 658 659 timeout.tv_sec = 0; 660 timeout.tv_usec = 0; 661 662 dial_up = FALSE; /* XXXX */ 663 tries = 0; 664 for (;;) { 665 FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 666 667 /* 668 * If Ip packet for output is enqueued and require dial up, 669 * Just do it! 670 */ 671 if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */ 672 #ifdef DEBUG 673 logprintf("going to dial: modem = %d\n", modem); 674 #endif 675 modem = OpenModem(mode); 676 if (modem < 0) { 677 modem = 0; /* Set intial value for next OpenModem */ 678 StartRedialTimer(); 679 } else { 680 tries++; 681 LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries); 682 if (DialModem()) { 683 sleep(1); /* little pause to allow peer starts */ 684 ModemTimeout(); 685 PacketMode(); 686 dial_up = FALSE; 687 tries = 0; 688 } else { 689 CloseModem(); 690 /* Dial failed. Keep quite during redial wait period. */ 691 StartRedialTimer(); 692 693 if (VarDialTries && tries >= VarDialTries) { 694 dial_up = FALSE; 695 tries = 0; 696 } 697 } 698 } 699 } 700 qlen = ModemQlen(); 701 702 if (qlen == 0) { 703 IpStartOutput(); 704 qlen = ModemQlen(); 705 } 706 707 if (modem) { 708 FD_SET(modem, &rfds); 709 FD_SET(modem, &efds); 710 if (qlen > 0) { 711 FD_SET(modem, &wfds); 712 } 713 } 714 if (server > 0) FD_SET(server, &rfds); 715 716 /* *** IMPORTANT *** 717 * 718 * CPU is serviced every TICKUNIT micro seconds. 719 * This value must be chosen with great care. If this values is 720 * too big, it results loss of characters from modem and poor responce. 721 * If this values is too small, ppp process eats many CPU time. 722 */ 723 #ifndef SIGALRM 724 usleep(TICKUNIT); 725 TimerService(); 726 #endif 727 728 /* If there are aren't many packets queued, look for some more. */ 729 if (qlen < 20) 730 FD_SET(tun_in, &rfds); 731 732 if (netfd > -1) { 733 FD_SET(netfd, &rfds); 734 FD_SET(netfd, &efds); 735 } 736 737 #ifndef SIGALRM 738 /* 739 * Normally, select() will not block because modem is writable. 740 * In AUTO mode, select will block until we find packet from tun 741 */ 742 tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 743 i = select(tun_in+10, &rfds, &wfds, &efds, tp); 744 #else 745 /* 746 * When SIGALRM timer is running, a select function will be 747 * return -1 and EINTR after a Time Service signal hundler 748 * is done. If the redial timer is not running and we are 749 * trying to dial, poll with a 0 value timer. 750 */ 751 tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 752 i = select(tun_in+10, &rfds, &wfds, &efds, tp); 753 #endif 754 if ( i == 0 ) { 755 continue; 756 } 757 758 if ( i < 0 ) { 759 if ( errno == EINTR ) { 760 continue; /* Got SIGALRM, Do check a queue for dialing */ 761 } 762 perror("select"); 763 break; 764 } 765 766 if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) { 767 logprintf("Exception detected.\n"); 768 break; 769 } 770 771 if (server > 0 && FD_ISSET(server, &rfds)) { 772 #ifdef DEBUG 773 logprintf("connected to client.\n"); 774 #endif 775 wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 776 if (netfd > 0) { 777 write(wfd, "already in use.\n", 16); 778 close(wfd); 779 continue; 780 } else 781 netfd = wfd; 782 if (dup2(netfd, 1) < 0) 783 perror("dup2"); 784 mode |= MODE_INTER; 785 Greetings(); 786 switch ( LocalAuthInit() ) { 787 case NOT_FOUND: 788 fprintf(stdout,LAUTH_M1); 789 fprintf(stdout,LAUTH_M2); 790 fflush(stdout); 791 /* Fall down */ 792 case VALID: 793 VarLocalAuth = LOCAL_AUTH; 794 break; 795 default: 796 break; 797 } 798 (void) IsInteractive(); 799 Prompt(0); 800 } 801 802 if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) && 803 ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 804 /* something to read from tty */ 805 ReadTty(); 806 } 807 if (modem) { 808 if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 809 ModemStartOutput(modem); 810 } 811 if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 812 if (LcpFsm.state <= ST_CLOSED) 813 usleep(10000); 814 n = read(modem, rbuff, sizeof(rbuff)); 815 if ((mode & MODE_DIRECT) && n <= 0) { 816 DownConnection(); 817 } else 818 LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n); 819 820 if (LcpFsm.state <= ST_CLOSED) { 821 /* 822 * In dedicated mode, we just discard input until LCP is started. 823 */ 824 if (!(mode & MODE_DEDICATED)) { 825 cp = HdlcDetect(rbuff, n); 826 if (cp) { 827 /* 828 * LCP packet is detected. Turn ourselves into packet mode. 829 */ 830 if (cp != rbuff) { 831 write(1, rbuff, cp - rbuff); 832 write(1, "\r\n", 2); 833 } 834 PacketMode(); 835 #ifdef notdef 836 AsyncInput(cp, n - (cp - rbuff)); 837 #endif 838 } else 839 write(1, rbuff, n); 840 } 841 } else { 842 if (n > 0) 843 AsyncInput(rbuff, n); 844 #ifdef notdef 845 continue; /* THIS LINE RESULT AS POOR PERFORMANCE */ 846 #endif 847 } 848 } 849 } 850 851 if (FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 852 n = read(tun_in, rbuff, sizeof(rbuff)); 853 if (n < 0) { 854 perror("read from tun"); 855 continue; 856 } 857 /* 858 * Process on-demand dialup. Output packets are queued within tunnel 859 * device until IPCP is opened. 860 */ 861 if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 862 pri = PacketCheck(rbuff, n, FL_DIAL); 863 if (pri >= 0) { 864 IpEnqueue(pri, rbuff, n); 865 dial_up = TRUE; /* XXX */ 866 } 867 continue; 868 } 869 pri = PacketCheck(rbuff, n, FL_OUT); 870 if (pri >= 0) 871 IpEnqueue(pri, rbuff, n); 872 } 873 } 874 logprintf("job done.\n"); 875 } 876