Deleted Added
full compact
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}