xref: /freebsd/usr.sbin/ppp/main.c (revision 4562be7470984e65380d2e03a64bb38a37bfd54e)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *			User Process PPP
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan, Inc.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
204562be74SBrian Somers  * $Id: main.c,v 1.97 1997/11/13 14:44:06 brian Exp $
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Add commands for traffic summary, version display, etc.
24af57ed9fSAtsushi Murai  *		o Add signal handler for misc controls.
25af57ed9fSAtsushi Murai  */
2675240ed1SBrian Somers #include <sys/param.h>
27af57ed9fSAtsushi Murai #include <sys/socket.h>
2875240ed1SBrian Somers #include <netinet/in.h>
29a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h>
30a9f484e5SJordan K. Hubbard #include <netinet/ip.h>
3175240ed1SBrian Somers #include <arpa/inet.h>
3275240ed1SBrian Somers #include <netdb.h>
3375240ed1SBrian Somers 
3475240ed1SBrian Somers #include <errno.h>
3575240ed1SBrian Somers #include <fcntl.h>
3675240ed1SBrian Somers #include <paths.h>
3775240ed1SBrian Somers #include <signal.h>
3875240ed1SBrian Somers #include <stdio.h>
3975240ed1SBrian Somers #include <stdlib.h>
4075240ed1SBrian Somers #include <string.h>
4175240ed1SBrian Somers #include <sys/time.h>
4275240ed1SBrian Somers #include <sys/wait.h>
43683cef3cSBrian Somers #include <sysexits.h>
4475240ed1SBrian Somers #include <termios.h>
4575240ed1SBrian Somers #include <unistd.h>
4675240ed1SBrian Somers 
4775240ed1SBrian Somers #include "mbuf.h"
4875240ed1SBrian Somers #include "log.h"
4975240ed1SBrian Somers #include "defs.h"
505106c671SBrian Somers #include "id.h"
5175240ed1SBrian Somers #include "timer.h"
5275240ed1SBrian Somers #include "fsm.h"
53af57ed9fSAtsushi Murai #include "modem.h"
54af57ed9fSAtsushi Murai #include "os.h"
55af57ed9fSAtsushi Murai #include "hdlc.h"
56ed6a16c1SPoul-Henning Kamp #include "ccp.h"
57af57ed9fSAtsushi Murai #include "lcp.h"
58af57ed9fSAtsushi Murai #include "ipcp.h"
596ed9fb2fSBrian Somers #include "loadalias.h"
6075240ed1SBrian Somers #include "command.h"
61af57ed9fSAtsushi Murai #include "vars.h"
6253c9f6c0SAtsushi Murai #include "auth.h"
6384b8a6ebSAtsushi Murai #include "filter.h"
64ed6a16c1SPoul-Henning Kamp #include "systems.h"
65ed6a16c1SPoul-Henning Kamp #include "ip.h"
66f5ff0f7cSBrian Somers #include "sig.h"
674ef16f24SBrian Somers #include "server.h"
68de451c68SBrian Somers #include "lcpproto.h"
6975240ed1SBrian Somers #include "main.h"
7075240ed1SBrian Somers #include "vjcomp.h"
7175240ed1SBrian Somers #include "async.h"
724562be74SBrian Somers #include "pathnames.h"
7353c9f6c0SAtsushi Murai 
7453c9f6c0SAtsushi Murai #ifndef O_NONBLOCK
7553c9f6c0SAtsushi Murai #ifdef O_NDELAY
7653c9f6c0SAtsushi Murai #define	O_NONBLOCK O_NDELAY
7753c9f6c0SAtsushi Murai #endif
7853c9f6c0SAtsushi Murai #endif
79af57ed9fSAtsushi Murai 
8075240ed1SBrian Somers int TermMode = 0;
8175240ed1SBrian Somers int tunno = 0;
82af57ed9fSAtsushi Murai 
83af57ed9fSAtsushi Murai static struct termios oldtio;	/* Original tty mode */
84af57ed9fSAtsushi Murai static struct termios comtio;	/* Command level tty mode */
856d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
8641c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
8776c5241dSBrian Somers static int dial_up;
88af57ed9fSAtsushi Murai 
8975240ed1SBrian Somers static void DoLoop(void);
9075240ed1SBrian Somers static void TerminalStop(int);
9175240ed1SBrian Somers static char *ex_desc(int);
9275240ed1SBrian Somers 
93af57ed9fSAtsushi Murai static void
94368aee2bSBrian Somers TtyInit(int DontWantInt)
95af57ed9fSAtsushi Murai {
96af57ed9fSAtsushi Murai   struct termios newtio;
97af57ed9fSAtsushi Murai   int stat;
98af57ed9fSAtsushi Murai 
99af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
100274e766cSBrian Somers   if (stat > 0) {
101af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
102274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
103274e766cSBrian Somers   }
104af57ed9fSAtsushi Murai   newtio = oldtio;
105af57ed9fSAtsushi Murai   newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
106af57ed9fSAtsushi Murai   newtio.c_iflag = 0;
107af57ed9fSAtsushi Murai   newtio.c_oflag &= ~OPOST;
108af57ed9fSAtsushi Murai   newtio.c_cc[VEOF] = _POSIX_VDISABLE;
109368aee2bSBrian Somers   if (DontWantInt)
110af57ed9fSAtsushi Murai     newtio.c_cc[VINTR] = _POSIX_VDISABLE;
111af57ed9fSAtsushi Murai   newtio.c_cc[VMIN] = 1;
112af57ed9fSAtsushi Murai   newtio.c_cc[VTIME] = 0;
113af57ed9fSAtsushi Murai   newtio.c_cflag |= CS8;
11453c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
115af57ed9fSAtsushi Murai   comtio = newtio;
116af57ed9fSAtsushi Murai }
117af57ed9fSAtsushi Murai 
118af57ed9fSAtsushi Murai /*
119af57ed9fSAtsushi Murai  *  Set tty into command mode. We allow canonical input and echo processing.
120af57ed9fSAtsushi Murai  */
121c3899f8dSAtsushi Murai void
122944f7098SBrian Somers TtyCommandMode(int prompt)
123af57ed9fSAtsushi Murai {
124af57ed9fSAtsushi Murai   struct termios newtio;
125af57ed9fSAtsushi Murai   int stat;
126af57ed9fSAtsushi Murai 
127af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER))
128af57ed9fSAtsushi Murai     return;
12953c9f6c0SAtsushi Murai   tcgetattr(0, &newtio);
130c3899f8dSAtsushi Murai   newtio.c_lflag |= (ECHO | ISIG | ICANON);
131af57ed9fSAtsushi Murai   newtio.c_iflag = oldtio.c_iflag;
132af57ed9fSAtsushi Murai   newtio.c_oflag |= OPOST;
13353c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
134af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
135274e766cSBrian Somers   if (stat > 0) {
136af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
137274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
138274e766cSBrian Somers   }
139af57ed9fSAtsushi Murai   TermMode = 0;
140944f7098SBrian Somers   if (prompt)
141944f7098SBrian Somers     Prompt();
142af57ed9fSAtsushi Murai }
143af57ed9fSAtsushi Murai 
144af57ed9fSAtsushi Murai /*
145af57ed9fSAtsushi Murai  * Set tty into terminal mode which is used while we invoke term command.
146af57ed9fSAtsushi Murai  */
147af57ed9fSAtsushi Murai void
148af57ed9fSAtsushi Murai TtyTermMode()
149af57ed9fSAtsushi Murai {
150af57ed9fSAtsushi Murai   int stat;
151af57ed9fSAtsushi Murai 
15253c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &comtio);
153af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
154274e766cSBrian Somers   if (stat > 0) {
155af57ed9fSAtsushi Murai     stat &= ~O_NONBLOCK;
156274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
157274e766cSBrian Somers   }
158af57ed9fSAtsushi Murai   TermMode = 1;
159af57ed9fSAtsushi Murai }
160af57ed9fSAtsushi Murai 
161af57ed9fSAtsushi Murai void
162c3899f8dSAtsushi Murai TtyOldMode()
163c3899f8dSAtsushi Murai {
164c3899f8dSAtsushi Murai   int stat;
165c3899f8dSAtsushi Murai 
166c3899f8dSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
167274e766cSBrian Somers   if (stat > 0) {
168c3899f8dSAtsushi Murai     stat &= ~O_NONBLOCK;
169274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
170274e766cSBrian Somers   }
171c3899f8dSAtsushi Murai   tcsetattr(0, TCSANOW, &oldtio);
172c3899f8dSAtsushi Murai }
173c3899f8dSAtsushi Murai 
174c3899f8dSAtsushi Murai void
175944f7098SBrian Somers Cleanup(int excode)
176af57ed9fSAtsushi Murai {
1778ea8442cSBrian Somers   ServerClose();
1780fe7ca31SBrian Somers   OsInterfaceDown(1);
1790fe7ca31SBrian Somers   HangupModem(1);
1809a571ec7SBrian Somers   nointr_sleep(1);
1816e4959f0SBrian Somers   DeleteIfRoutes(1);
1825106c671SBrian Somers   ID0unlink(pid_filename);
1836e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1846e4959f0SBrian Somers     char c = EX_ERRDEAD;
185944f7098SBrian Somers 
1866e4959f0SBrian Somers     if (write(BGFiledes[1], &c, 1) == 1)
187927145beSBrian Somers       LogPrintf(LogPHASE, "Parent notified of failure.\n");
1886e4959f0SBrian Somers     else
189927145beSBrian Somers       LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
1906e4959f0SBrian Somers     close(BGFiledes[1]);
1916e4959f0SBrian Somers   }
192927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
193c3899f8dSAtsushi Murai   TtyOldMode();
1945106c671SBrian Somers   LogClose();
195af57ed9fSAtsushi Murai 
196af57ed9fSAtsushi Murai   exit(excode);
197af57ed9fSAtsushi Murai }
198af57ed9fSAtsushi Murai 
199af57ed9fSAtsushi Murai static void
200944f7098SBrian Somers CloseConnection(int signo)
201af57ed9fSAtsushi Murai {
202368aee2bSBrian Somers   /* NOTE, these are manual, we've done a setsid() */
20312ef29a8SBrian Somers   pending_signal(SIGINT, SIG_IGN);
204873725ccSBrian Somers   LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
205944f7098SBrian Somers   reconnectState = RECON_FALSE;
206944f7098SBrian Somers   reconnectCount = 0;
207368aee2bSBrian Somers   DownConnection();
20875240ed1SBrian Somers   dial_up = 0;
20912ef29a8SBrian Somers   pending_signal(SIGINT, CloseConnection);
2106d14e2a8SJordan K. Hubbard }
211af57ed9fSAtsushi Murai 
212af57ed9fSAtsushi Murai static void
213944f7098SBrian Somers CloseSession(int signo)
214af57ed9fSAtsushi Murai {
2156d14e2a8SJordan K. Hubbard   if (BGPid) {
2166d14e2a8SJordan K. Hubbard     kill(BGPid, SIGINT);
2176d14e2a8SJordan K. Hubbard     exit(EX_TERM);
2186d14e2a8SJordan K. Hubbard   }
219927145beSBrian Somers   LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
22025aa96acSBrian Somers   reconnect(RECON_FALSE);
221af57ed9fSAtsushi Murai   LcpClose();
222af57ed9fSAtsushi Murai   Cleanup(EX_TERM);
223af57ed9fSAtsushi Murai }
224c3899f8dSAtsushi Murai 
225c3899f8dSAtsushi Murai static void
226c3899f8dSAtsushi Murai TerminalCont()
227c3899f8dSAtsushi Murai {
228f5ff0f7cSBrian Somers   pending_signal(SIGCONT, SIG_DFL);
229f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, TerminalStop);
230c3899f8dSAtsushi Murai   TtyCommandMode(getpgrp() == tcgetpgrp(0));
231c3899f8dSAtsushi Murai }
232c3899f8dSAtsushi Murai 
233c3899f8dSAtsushi Murai static void
234944f7098SBrian Somers TerminalStop(int signo)
235c3899f8dSAtsushi Murai {
236f5ff0f7cSBrian Somers   pending_signal(SIGCONT, TerminalCont);
237c3899f8dSAtsushi Murai   TtyOldMode();
238f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, SIG_DFL);
239c3899f8dSAtsushi Murai   kill(getpid(), signo);
240c3899f8dSAtsushi Murai }
241c3899f8dSAtsushi Murai 
2424ef16f24SBrian Somers static void
243944f7098SBrian Somers SetUpServer(int signo)
2444ef16f24SBrian Somers {
2454ef16f24SBrian Somers   int res;
246944f7098SBrian Somers 
2478ea8442cSBrian Somers   VarHaveLocalAuthKey = 0;
2488ea8442cSBrian Somers   LocalAuthInit();
2494ef16f24SBrian Somers   if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
250683cef3cSBrian Somers     LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
251683cef3cSBrian Somers 	      res, SERVER_PORT + tunno);
2524ef16f24SBrian Somers }
2534ef16f24SBrian Somers 
2548ea8442cSBrian Somers static void
2558ea8442cSBrian Somers BringDownServer(int signo)
2568ea8442cSBrian Somers {
2578ea8442cSBrian Somers   VarHaveLocalAuthKey = 0;
2588ea8442cSBrian Somers   LocalAuthInit();
2598ea8442cSBrian Somers   ServerClose();
2608ea8442cSBrian Somers }
2618ea8442cSBrian Somers 
2626efd9292SBrian Somers static char *
2636efd9292SBrian Somers ex_desc(int ex)
2646efd9292SBrian Somers {
2656efd9292SBrian Somers   static char num[12];
2666efd9292SBrian Somers   static char *desc[] = {"normal", "start", "sock",
2676efd9292SBrian Somers     "modem", "dial", "dead", "done", "reboot", "errdead",
2686efd9292SBrian Somers   "hangup", "term", "nodial", "nologin"};
2696efd9292SBrian Somers 
2706efd9292SBrian Somers   if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
2716efd9292SBrian Somers     return desc[ex];
2726efd9292SBrian Somers   snprintf(num, sizeof num, "%d", ex);
2736efd9292SBrian Somers   return num;
2746efd9292SBrian Somers }
275c3899f8dSAtsushi Murai 
27675240ed1SBrian Somers static void
277af57ed9fSAtsushi Murai Usage()
278af57ed9fSAtsushi Murai {
279680026d6SNate Williams   fprintf(stderr,
2806d14e2a8SJordan K. Hubbard 	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
281af57ed9fSAtsushi Murai   exit(EX_START);
282af57ed9fSAtsushi Murai }
283af57ed9fSAtsushi Murai 
28475240ed1SBrian Somers static void
285af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
286af57ed9fSAtsushi Murai {
287af57ed9fSAtsushi Murai   int optc;
288af57ed9fSAtsushi Murai   char *cp;
289af57ed9fSAtsushi Murai 
290af57ed9fSAtsushi Murai   optc = 0;
29112ef29a8SBrian Somers   mode = MODE_INTER;
292af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
293af57ed9fSAtsushi Murai     cp = *argv + 1;
29412ef29a8SBrian Somers     if (strcmp(cp, "auto") == 0) {
295af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
29612ef29a8SBrian Somers       mode &= ~MODE_INTER;
29712ef29a8SBrian Somers     } else if (strcmp(cp, "background") == 0) {
29812ef29a8SBrian Somers       mode |= MODE_BACKGROUND;
29912ef29a8SBrian Somers       mode &= ~MODE_INTER;
30012ef29a8SBrian Somers     } else if (strcmp(cp, "direct") == 0) {
301af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
30212ef29a8SBrian Somers       mode &= ~MODE_INTER;
30312ef29a8SBrian Somers     } else if (strcmp(cp, "dedicated") == 0) {
304af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
30512ef29a8SBrian Somers       mode &= ~MODE_INTER;
30612ef29a8SBrian Somers     } else if (strcmp(cp, "ddial") == 0) {
30712ef29a8SBrian Somers       mode |= MODE_DDIAL;
30812ef29a8SBrian Somers       mode &= ~MODE_INTER;
30912ef29a8SBrian Somers     } else if (strcmp(cp, "alias") == 0) {
3106ed9fb2fSBrian Somers       if (loadAliasHandlers(&VarAliasHandlers) == 0)
311a9f484e5SJordan K. Hubbard 	mode |= MODE_ALIAS;
3126ed9fb2fSBrian Somers       else
313927145beSBrian Somers 	LogPrintf(LogWARN, "Cannot load alias library\n");
314a9f484e5SJordan K. Hubbard       optc--;			/* this option isn't exclusive */
315944f7098SBrian Somers     } else
316af57ed9fSAtsushi Murai       Usage();
317af57ed9fSAtsushi Murai     optc++;
318944f7098SBrian Somers     argv++;
319944f7098SBrian Somers     argc--;
320af57ed9fSAtsushi Murai   }
321af57ed9fSAtsushi Murai   if (argc > 1) {
322af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
323af57ed9fSAtsushi Murai     exit(EX_START);
324af57ed9fSAtsushi Murai   }
325944f7098SBrian Somers   if (argc == 1)
32612ef29a8SBrian Somers     SetLabel(*argv);
327af57ed9fSAtsushi Murai 
328af57ed9fSAtsushi Murai   if (optc > 1) {
329af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
330af57ed9fSAtsushi Murai     exit(EX_START);
331af57ed9fSAtsushi Murai   }
332af57ed9fSAtsushi Murai }
333af57ed9fSAtsushi Murai 
334af57ed9fSAtsushi Murai static void
335af57ed9fSAtsushi Murai Greetings()
336af57ed9fSAtsushi Murai {
337927145beSBrian Somers   if (VarTerm) {
338927145beSBrian Somers     fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
339927145beSBrian Somers     fflush(VarTerm);
340927145beSBrian Somers   }
341af57ed9fSAtsushi Murai }
342af57ed9fSAtsushi Murai 
3434ef16f24SBrian Somers int
344944f7098SBrian Somers main(int argc, char **argv)
345af57ed9fSAtsushi Murai {
346aefd026aSBrian Somers   FILE *lockfile;
347927145beSBrian Somers   char *name;
348af57ed9fSAtsushi Murai 
3490706ff38SBrian Somers   VarTerm = 0;
35075240ed1SBrian Somers   name = strrchr(argv[0], '/');
351927145beSBrian Somers   LogOpen(name ? name + 1 : argv[0]);
352927145beSBrian Somers 
353944f7098SBrian Somers   argc--;
354944f7098SBrian Somers   argv++;
355af57ed9fSAtsushi Murai   ProcessArgs(argc, argv);
35612ef29a8SBrian Somers   if (!(mode & MODE_DIRECT))
3570706ff38SBrian Somers     VarTerm = stdout;
35812ef29a8SBrian Somers 
3595106c671SBrian Somers   ID0init();
3604562be74SBrian Somers   if (ID0realuid() != 0) {
3614562be74SBrian Somers     char conf[200], *ptr;
3624562be74SBrian Somers 
3634562be74SBrian Somers     snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
3644562be74SBrian Somers     do {
3654562be74SBrian Somers       if (!access(conf, W_OK)) {
3664562be74SBrian Somers         LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
3674562be74SBrian Somers         return -1;
3684562be74SBrian Somers       }
3694562be74SBrian Somers       ptr = conf + strlen(conf)-2;
3704562be74SBrian Somers       while (ptr > conf && *ptr != '/')
3714562be74SBrian Somers         *ptr-- = '\0';
3724562be74SBrian Somers     } while (ptr >= conf);
3734562be74SBrian Somers   }
3744562be74SBrian Somers 
37512ef29a8SBrian Somers   if (!ValidSystem(GetLabel())) {
37612ef29a8SBrian Somers     fprintf(stderr, "You may not use ppp in this mode with this label\n");
377815624cfSBrian Somers     if (mode & MODE_DIRECT) {
378815624cfSBrian Somers       const char *l;
379815624cfSBrian Somers       if ((l = GetLabel()) == NULL)
380815624cfSBrian Somers         l = "default";
381815624cfSBrian Somers       VarTerm = 0;
382815624cfSBrian Somers       LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
383815624cfSBrian Somers     }
384815624cfSBrian Somers     LogClose();
38512ef29a8SBrian Somers     return 1;
38612ef29a8SBrian Somers   }
38712ef29a8SBrian Somers 
388af57ed9fSAtsushi Murai   Greetings();
389af57ed9fSAtsushi Murai   IpcpDefAddress();
390683cef3cSBrian Somers   LocalAuthInit();
391af57ed9fSAtsushi Murai 
392927145beSBrian Somers   if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
393927145beSBrian Somers     fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
394af57ed9fSAtsushi Murai 
395af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
3964ef16f24SBrian Somers     LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
3974ef16f24SBrian Somers     return EX_START;
398af57ed9fSAtsushi Murai   }
399af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
400927145beSBrian Somers     fprintf(VarTerm, "Interactive mode\n");
401cc39a98fSBrian Somers     netfd = STDOUT_FILENO;
40212ef29a8SBrian Somers   } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
40312ef29a8SBrian Somers     if (GetLabel() == NULL) {
404927145beSBrian Somers       if (VarTerm)
405927145beSBrian Somers 	fprintf(VarTerm, "Destination system must be specified in"
4066efd9292SBrian Somers 		" auto, background or ddial mode.\n");
4074ef16f24SBrian Somers       return EX_START;
4086d14e2a8SJordan K. Hubbard     }
40912ef29a8SBrian Somers 
41053c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);	/* Save original tty mode */
411af57ed9fSAtsushi Murai 
412873725ccSBrian Somers   pending_signal(SIGHUP, CloseSession);
413f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
414873725ccSBrian Somers   pending_signal(SIGINT, CloseConnection);
415f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
41653c9f6c0SAtsushi Murai #ifdef SIGPIPE
417e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
41853c9f6c0SAtsushi Murai #endif
41953c9f6c0SAtsushi Murai #ifdef SIGALRM
420f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
42153c9f6c0SAtsushi Murai #endif
4224ef16f24SBrian Somers   if (mode & MODE_INTER) {
423c3899f8dSAtsushi Murai #ifdef SIGTSTP
424f5ff0f7cSBrian Somers     pending_signal(SIGTSTP, TerminalStop);
425c3899f8dSAtsushi Murai #endif
426c3899f8dSAtsushi Murai #ifdef SIGTTIN
427f5ff0f7cSBrian Somers     pending_signal(SIGTTIN, TerminalStop);
428c3899f8dSAtsushi Murai #endif
429c3899f8dSAtsushi Murai #ifdef SIGTTOU
430f5ff0f7cSBrian Somers     pending_signal(SIGTTOU, SIG_IGN);
431c3899f8dSAtsushi Murai #endif
432c3899f8dSAtsushi Murai   }
43312ef29a8SBrian Somers   if (!(mode & MODE_INTER)) {
4344ef16f24SBrian Somers #ifdef SIGUSR1
4354ef16f24SBrian Somers     pending_signal(SIGUSR1, SetUpServer);
4364ef16f24SBrian Somers #endif
4378ea8442cSBrian Somers #ifdef SIGUSR2
4388ea8442cSBrian Somers     pending_signal(SIGUSR2, BringDownServer);
4398ea8442cSBrian Somers #endif
44012ef29a8SBrian Somers   }
441af57ed9fSAtsushi Murai 
44212ef29a8SBrian Somers   if (GetLabel()) {
44312ef29a8SBrian Somers     if (SelectSystem(GetLabel(), CONFFILE) < 0) {
444e4450123SBrian Somers       LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
445e4450123SBrian Somers                 GetLabel());
446af57ed9fSAtsushi Murai       Cleanup(EX_START);
447af57ed9fSAtsushi Murai     }
44812ef29a8SBrian Somers     if (mode & MODE_OUTGOING_DAEMON &&
44912ef29a8SBrian Somers 	DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
450e4450123SBrian Somers       LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
451e4450123SBrian Somers 		" auto, background or ddial mode.\n", GetLabel());
452af57ed9fSAtsushi Murai       Cleanup(EX_START);
453af57ed9fSAtsushi Murai     }
454af57ed9fSAtsushi Murai   }
4556efd9292SBrian Somers 
45612ef29a8SBrian Somers   if (mode & MODE_DAEMON) {
4576d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4586d14e2a8SJordan K. Hubbard       if (pipe(BGFiledes)) {
459afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
4606d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4616d14e2a8SJordan K. Hubbard       }
4626d14e2a8SJordan K. Hubbard     }
463af57ed9fSAtsushi Murai 
464af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4656d14e2a8SJordan K. Hubbard       pid_t bgpid;
466a9c6b5dfSAtsushi Murai 
4676d14e2a8SJordan K. Hubbard       bgpid = fork();
4686d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
469afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
4706d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4716d14e2a8SJordan K. Hubbard       }
4726d14e2a8SJordan K. Hubbard       if (bgpid) {
4736d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
474a9c6b5dfSAtsushi Murai 
4756d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4766d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4776d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4786e4959f0SBrian Somers 	  close(BGFiledes[1]);
4796efd9292SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1) {
480927145beSBrian Somers 	    fprintf(VarTerm, "Child exit, no status.\n");
481927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
4826efd9292SBrian Somers 	  } else if (c == EX_NORMAL) {
483927145beSBrian Somers 	    fprintf(VarTerm, "PPP enabled.\n");
484927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
4856efd9292SBrian Somers 	  } else {
486927145beSBrian Somers 	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
487927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
48880e37c72SBrian Somers 		      ex_desc((int) c));
4896efd9292SBrian Somers 	  }
4906e4959f0SBrian Somers 	  close(BGFiledes[0]);
4916d14e2a8SJordan K. Hubbard 	}
4924ef16f24SBrian Somers 	return c;
4936e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
4946e4959f0SBrian Somers 	close(BGFiledes[0]);
495aefd026aSBrian Somers     }
496aefd026aSBrian Somers 
497d656a4c5SBrian Somers     VarTerm = 0;		/* We know it's currently stdout */
498fd2bc5ebSBrian Somers     close(1);
499d656a4c5SBrian Somers     close(2);
5000706ff38SBrian Somers 
501d656a4c5SBrian Somers     if (mode & MODE_DIRECT)
502368aee2bSBrian Somers       TtyInit(1);
50312ef29a8SBrian Somers     else if (mode & MODE_DAEMON) {
504d656a4c5SBrian Somers       setsid();
505fd2bc5ebSBrian Somers       close(0);
506d656a4c5SBrian Somers     }
507af57ed9fSAtsushi Murai   } else {
508368aee2bSBrian Somers     TtyInit(0);
509c3899f8dSAtsushi Murai     TtyCommandMode(1);
510af57ed9fSAtsushi Murai   }
51135495becSBrian Somers 
51235495becSBrian Somers   snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
51335495becSBrian Somers            _PATH_VARRUN, tunno);
5145106c671SBrian Somers   lockfile = ID0fopen(pid_filename, "w");
5155106c671SBrian Somers   if (lockfile != NULL) {
51635495becSBrian Somers     fprintf(lockfile, "%d\n", (int) getpid());
51735495becSBrian Somers     fclose(lockfile);
51835495becSBrian Somers   } else
51935495becSBrian Somers     LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
52035495becSBrian Somers               pid_filename, strerror(errno));
52135495becSBrian Somers 
522927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Started.\n");
523af57ed9fSAtsushi Murai 
524af57ed9fSAtsushi Murai 
525af57ed9fSAtsushi Murai   do
526af57ed9fSAtsushi Murai     DoLoop();
527af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
528af57ed9fSAtsushi Murai 
529af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
5304ef16f24SBrian Somers   return 0;
531af57ed9fSAtsushi Murai }
532af57ed9fSAtsushi Murai 
533af57ed9fSAtsushi Murai /*
5346d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
535af57ed9fSAtsushi Murai  */
536af57ed9fSAtsushi Murai void
537af57ed9fSAtsushi Murai PacketMode()
538af57ed9fSAtsushi Murai {
5399780ef31SBrian Somers   if (RawModem() < 0) {
540927145beSBrian Somers     LogPrintf(LogWARN, "PacketMode: Not connected.\n");
541af57ed9fSAtsushi Murai     return;
542af57ed9fSAtsushi Murai   }
543af57ed9fSAtsushi Murai   AsyncInit();
54403604f35SBrian Somers   VjInit(15);
545af57ed9fSAtsushi Murai   LcpInit();
546af57ed9fSAtsushi Murai   IpcpInit();
547af57ed9fSAtsushi Murai   CcpInit();
548af57ed9fSAtsushi Murai   LcpUp();
549af57ed9fSAtsushi Murai 
550af57ed9fSAtsushi Murai   LcpOpen(VarOpenMode);
55112ef29a8SBrian Somers   if (mode & MODE_INTER)
552c3899f8dSAtsushi Murai     TtyCommandMode(1);
553927145beSBrian Somers   if (VarTerm) {
554927145beSBrian Somers     fprintf(VarTerm, "Packet mode.\n");
555b0cdb3ceSJordan K. Hubbard     aft_cmd = 1;
556af57ed9fSAtsushi Murai   }
557af57ed9fSAtsushi Murai }
558af57ed9fSAtsushi Murai 
559af57ed9fSAtsushi Murai static void
560af57ed9fSAtsushi Murai ShowHelp()
561af57ed9fSAtsushi Murai {
562030d3ce6SBrian Somers   fprintf(stderr, "The following commands are available:\r\n");
563030d3ce6SBrian Somers   fprintf(stderr, " ~p\tEnter Packet mode\r\n");
564030d3ce6SBrian Somers   fprintf(stderr, " ~-\tDecrease log level\r\n");
565030d3ce6SBrian Somers   fprintf(stderr, " ~+\tIncrease log level\r\n");
566030d3ce6SBrian Somers   fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
567030d3ce6SBrian Somers   fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
568030d3ce6SBrian Somers   fprintf(stderr, " ~.\tTerminate program\r\n");
569030d3ce6SBrian Somers   fprintf(stderr, " ~?\tThis help\r\n");
570af57ed9fSAtsushi Murai }
571af57ed9fSAtsushi Murai 
572af57ed9fSAtsushi Murai static void
573af57ed9fSAtsushi Murai ReadTty()
574af57ed9fSAtsushi Murai {
575af57ed9fSAtsushi Murai   int n;
576af57ed9fSAtsushi Murai   char ch;
577af57ed9fSAtsushi Murai   static int ttystate;
578927145beSBrian Somers   FILE *oVarTerm;
57986e02934SBrian Somers   char linebuff[LINE_LEN];
580af57ed9fSAtsushi Murai 
581927145beSBrian Somers   LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
582927145beSBrian Somers 	    TermMode, netfd, mode);
583af57ed9fSAtsushi Murai   if (!TermMode) {
584af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff) - 1);
58553c9f6c0SAtsushi Murai     if (n > 0) {
586927145beSBrian Somers       aft_cmd = 1;
587a1e8f937SBrian Somers       if (linebuff[n-1] == '\n')
588a1e8f937SBrian Somers         linebuff[--n] = '\0';
589d9181b05SBrian Somers       if (n)
590d9181b05SBrian Somers         DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
591a1e8f937SBrian Somers       Prompt();
59253c9f6c0SAtsushi Murai     } else {
593927145beSBrian Somers       LogPrintf(LogPHASE, "client connection closed.\n");
594927145beSBrian Somers       oVarTerm = VarTerm;
595927145beSBrian Somers       VarTerm = 0;
596927145beSBrian Somers       if (oVarTerm && oVarTerm != stdout)
597927145beSBrian Somers 	fclose(oVarTerm);
598927145beSBrian Somers       close(netfd);
599927145beSBrian Somers       netfd = -1;
600af57ed9fSAtsushi Murai     }
601af57ed9fSAtsushi Murai     return;
602af57ed9fSAtsushi Murai   }
603af57ed9fSAtsushi Murai 
604af57ed9fSAtsushi Murai   /*
605af57ed9fSAtsushi Murai    * We are in terminal mode, decode special sequences
606af57ed9fSAtsushi Murai    */
607927145beSBrian Somers   n = read(fileno(VarTerm), &ch, 1);
608afc7fa2cSBrian Somers   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
609af57ed9fSAtsushi Murai 
610af57ed9fSAtsushi Murai   if (n > 0) {
611af57ed9fSAtsushi Murai     switch (ttystate) {
612af57ed9fSAtsushi Murai     case 0:
613af57ed9fSAtsushi Murai       if (ch == '~')
614af57ed9fSAtsushi Murai 	ttystate++;
615af57ed9fSAtsushi Murai       else
616af57ed9fSAtsushi Murai 	write(modem, &ch, n);
617af57ed9fSAtsushi Murai       break;
618af57ed9fSAtsushi Murai     case 1:
619af57ed9fSAtsushi Murai       switch (ch) {
620af57ed9fSAtsushi Murai       case '?':
621af57ed9fSAtsushi Murai 	ShowHelp();
622af57ed9fSAtsushi Murai 	break;
623af57ed9fSAtsushi Murai       case 'p':
624944f7098SBrian Somers 
625af57ed9fSAtsushi Murai 	/*
626af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
627af57ed9fSAtsushi Murai 	 */
628af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
629af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
630af57ed9fSAtsushi Murai 	  PacketMode();
631af57ed9fSAtsushi Murai 	}
632af57ed9fSAtsushi Murai 	break;
633af57ed9fSAtsushi Murai       case '.':
634af57ed9fSAtsushi Murai 	TermMode = 1;
635927145beSBrian Somers 	aft_cmd = 1;
636c3899f8dSAtsushi Murai 	TtyCommandMode(1);
637af57ed9fSAtsushi Murai 	break;
638927145beSBrian Somers       case 't':
639927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
640927145beSBrian Somers 	  ShowTimers();
641927145beSBrian Somers 	  break;
642927145beSBrian Somers 	}
643927145beSBrian Somers       case 'm':
644927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
645927145beSBrian Somers 	  ShowMemMap();
646927145beSBrian Somers 	  break;
647927145beSBrian Somers 	}
648af57ed9fSAtsushi Murai       default:
649af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
650927145beSBrian Somers 	  LogPrintf(LogERROR, "error writing to modem.\n");
651af57ed9fSAtsushi Murai 	break;
652af57ed9fSAtsushi Murai       }
653af57ed9fSAtsushi Murai       ttystate = 0;
654af57ed9fSAtsushi Murai       break;
655af57ed9fSAtsushi Murai     }
656af57ed9fSAtsushi Murai   }
657af57ed9fSAtsushi Murai }
658af57ed9fSAtsushi Murai 
659af57ed9fSAtsushi Murai 
660af57ed9fSAtsushi Murai /*
661af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
662af57ed9fSAtsushi Murai  */
663af57ed9fSAtsushi Murai 
664af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
66553c9f6c0SAtsushi Murai   "\176\377\003\300\041",
66653c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
66753c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
66853c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
66953c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
670af57ed9fSAtsushi Murai   NULL,
671af57ed9fSAtsushi Murai };
672af57ed9fSAtsushi Murai 
67375240ed1SBrian Somers static u_char *
674944f7098SBrian Somers HdlcDetect(u_char * cp, int n)
675af57ed9fSAtsushi Murai {
67653c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
677af57ed9fSAtsushi Murai 
678af57ed9fSAtsushi Murai   cp[n] = '\0';			/* be sure to null terminated */
679af57ed9fSAtsushi Murai   ptr = NULL;
680af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
68153c9f6c0SAtsushi Murai     fp = *hp;
68253c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
68353c9f6c0SAtsushi Murai       fp++;
684ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *) cp, fp);
685ed6a16c1SPoul-Henning Kamp     if (ptr)
686af57ed9fSAtsushi Murai       break;
687af57ed9fSAtsushi Murai   }
688af57ed9fSAtsushi Murai   return ((u_char *) ptr);
689af57ed9fSAtsushi Murai }
690af57ed9fSAtsushi Murai 
691af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
692af57ed9fSAtsushi Murai 
693af57ed9fSAtsushi Murai static void
694af57ed9fSAtsushi Murai RedialTimeout()
695af57ed9fSAtsushi Murai {
696af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
697927145beSBrian Somers   LogPrintf(LogPHASE, "Redialing timer expired.\n");
698af57ed9fSAtsushi Murai }
699af57ed9fSAtsushi Murai 
700af57ed9fSAtsushi Murai static void
701944f7098SBrian Somers StartRedialTimer(int Timeout)
702af57ed9fSAtsushi Murai {
703af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
704a9c6b5dfSAtsushi Murai 
70543ea9d19SBrian Somers   if (Timeout) {
706af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
707a9c6b5dfSAtsushi Murai 
70843ea9d19SBrian Somers     if (Timeout > 0)
70943ea9d19SBrian Somers       RedialTimer.load = Timeout * SECTICKS;
710a9c6b5dfSAtsushi Murai     else
711a9c6b5dfSAtsushi Murai       RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
712a9c6b5dfSAtsushi Murai 
713927145beSBrian Somers     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
71443ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
71543ea9d19SBrian Somers 
716af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
717af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
718af57ed9fSAtsushi Murai   }
719a9c6b5dfSAtsushi Murai }
720af57ed9fSAtsushi Murai 
721af57ed9fSAtsushi Murai 
722af57ed9fSAtsushi Murai static void
723af57ed9fSAtsushi Murai DoLoop()
724af57ed9fSAtsushi Murai {
725af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
726780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
727af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
728af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
729af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
730af57ed9fSAtsushi Murai   u_char *cp;
731af57ed9fSAtsushi Murai   u_char rbuff[MAX_MRU];
732a9c6b5dfSAtsushi Murai   int tries;
73360e218e4SAtsushi Murai   int qlen;
734368aee2bSBrian Somers   int res;
735c3899f8dSAtsushi Murai   pid_t pgroup;
736c3899f8dSAtsushi Murai 
737c3899f8dSAtsushi Murai   pgroup = getpgrp();
738af57ed9fSAtsushi Murai 
7396efd9292SBrian Somers   if (mode & MODE_DIRECT) {
7400706ff38SBrian Somers     LogPrintf(LogDEBUG, "Opening modem\n");
7419780ef31SBrian Somers     if (OpenModem() < 0)
742bc240299SBrian Somers       return;
743927145beSBrian Somers     LogPrintf(LogPHASE, "Packet mode enabled\n");
744af57ed9fSAtsushi Murai     PacketMode();
745af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
746780700e5SAndrey A. Chernov     if (modem < 0)
7479780ef31SBrian Somers       while (OpenModem() < 0)
7489a571ec7SBrian Somers 	nointr_sleep(VarReconnectTimer);
749af57ed9fSAtsushi Murai   }
750927145beSBrian Somers   fflush(VarTerm);
751af57ed9fSAtsushi Murai 
75284b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
753af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
75425aa96acSBrian Somers   reconnectState = RECON_UNKNOWN;
755af57ed9fSAtsushi Murai 
7566e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
75775240ed1SBrian Somers     dial_up = 1;		/* Bring the line up */
7586e4959f0SBrian Somers   else
75975240ed1SBrian Somers     dial_up = 0;		/* XXXX */
760a9c6b5dfSAtsushi Murai   tries = 0;
761af57ed9fSAtsushi Murai   for (;;) {
762780700e5SAndrey A. Chernov     nfds = 0;
763944f7098SBrian Somers     FD_ZERO(&rfds);
764944f7098SBrian Somers     FD_ZERO(&wfds);
765944f7098SBrian Somers     FD_ZERO(&efds);
76684b8a6ebSAtsushi Murai 
76784b8a6ebSAtsushi Murai     /*
768944f7098SBrian Somers      * If the link is down and we're in DDIAL mode, bring it back up.
769680026d6SNate Williams      */
770680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
77175240ed1SBrian Somers       dial_up = 1;
772680026d6SNate Williams 
773680026d6SNate Williams     /*
774944f7098SBrian Somers      * If we lost carrier and want to re-establish the connection due to the
775944f7098SBrian Somers      * "set reconnect" value, we'd better bring the line back up.
77607030d97SBrian Somers      */
7776efd9292SBrian Somers     if (LcpFsm.state <= ST_CLOSED) {
77875240ed1SBrian Somers       if (!dial_up && reconnectState == RECON_TRUE) {
7796efd9292SBrian Somers 	if (++reconnectCount <= VarReconnectTries) {
780927145beSBrian Somers 	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
7816efd9292SBrian Somers 		    reconnectCount, VarReconnectTries);
78207030d97SBrian Somers 	  StartRedialTimer(VarReconnectTimer);
78375240ed1SBrian Somers 	  dial_up = 1;
784298091daSBrian Somers 	} else {
7856efd9292SBrian Somers 	  if (VarReconnectTries)
786927145beSBrian Somers 	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
787298091daSBrian Somers 		      VarReconnectTries);
7886efd9292SBrian Somers 	  reconnectCount = 0;
7896efd9292SBrian Somers 	  if (mode & MODE_BACKGROUND)
7906efd9292SBrian Somers 	    Cleanup(EX_DEAD);
7916efd9292SBrian Somers 	}
79225aa96acSBrian Somers 	reconnectState = RECON_ENVOKED;
79312ef29a8SBrian Somers       } else if (mode & MODE_DEDICATED)
79412ef29a8SBrian Somers         if (VarOpenMode == OPEN_ACTIVE)
79512ef29a8SBrian Somers           PacketMode();
79607030d97SBrian Somers     }
79707030d97SBrian Somers 
79807030d97SBrian Somers     /*
799944f7098SBrian Somers      * If Ip packet for output is enqueued and require dial up, Just do it!
80084b8a6ebSAtsushi Murai      */
80107030d97SBrian Somers     if (dial_up && RedialTimer.state != TIMER_RUNNING) {
802927145beSBrian Somers       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
8039780ef31SBrian Somers       if (OpenModem() < 0) {
8040706ff38SBrian Somers 	tries++;
805712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
8060706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
8070706ff38SBrian Somers 		    tries, VarDialTries);
8080706ff38SBrian Somers 	else
8090706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
8100706ff38SBrian Somers 
811712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
8120706ff38SBrian Somers 	  if (mode & MODE_BACKGROUND)
8130706ff38SBrian Somers 	    Cleanup(EX_DIAL);	/* Can't get the modem */
81475240ed1SBrian Somers 	  dial_up = 0;
8150706ff38SBrian Somers 	  reconnectState = RECON_UNKNOWN;
8160706ff38SBrian Somers 	  reconnectCount = 0;
8170706ff38SBrian Somers 	  tries = 0;
8180706ff38SBrian Somers 	} else
81943ea9d19SBrian Somers 	  StartRedialTimer(VarRedialTimeout);
82084b8a6ebSAtsushi Murai       } else {
821944f7098SBrian Somers 	tries++;		/* Tries are per number, not per list of
822944f7098SBrian Somers 				 * numbers. */
823712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
824712ae387SBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
825c0139fb2SBrian Somers 	else
826927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
827712ae387SBrian Somers 
828368aee2bSBrian Somers 	if ((res = DialModem()) == EX_DONE) {
8299a571ec7SBrian Somers 	  nointr_sleep(1);		/* little pause to allow peer starts */
83084b8a6ebSAtsushi Murai 	  ModemTimeout();
83184b8a6ebSAtsushi Murai 	  PacketMode();
83275240ed1SBrian Somers 	  dial_up = 0;
83325aa96acSBrian Somers 	  reconnectState = RECON_UNKNOWN;
834a9c6b5dfSAtsushi Murai 	  tries = 0;
83584b8a6ebSAtsushi Murai 	} else {
8364ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
837368aee2bSBrian Somers 	    if (VarNextPhone == NULL || res == EX_SIG)
8384ed9958fSBrian Somers 	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
8394ed9958fSBrian Somers 	    else
84043ea9d19SBrian Somers 	      /* Try all numbers in background mode */
84143ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
842368aee2bSBrian Somers 	  } else if (!(mode & MODE_DDIAL) &&
843368aee2bSBrian Somers 		     ((VarDialTries && tries >= VarDialTries) ||
844368aee2bSBrian Somers 		      res == EX_SIG)) {
845c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
84643ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
84775240ed1SBrian Somers 	    dial_up = 0;
84825aa96acSBrian Somers 	    reconnectState = RECON_UNKNOWN;
84925aa96acSBrian Somers 	    reconnectCount = 0;
850a9c6b5dfSAtsushi Murai 	    tries = 0;
851c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
852c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
85343ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
854c0139fb2SBrian Somers 	  else
85543ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
85684b8a6ebSAtsushi Murai 	}
85784b8a6ebSAtsushi Murai       }
85884b8a6ebSAtsushi Murai     }
85960e218e4SAtsushi Murai     qlen = ModemQlen();
86076bd0c0aSDoug Rabson 
86176bd0c0aSDoug Rabson     if (qlen == 0) {
86276bd0c0aSDoug Rabson       IpStartOutput();
86376bd0c0aSDoug Rabson       qlen = ModemQlen();
86476bd0c0aSDoug Rabson     }
865780700e5SAndrey A. Chernov     if (modem >= 0) {
866780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
867780700e5SAndrey A. Chernov 	nfds = modem + 1;
86884b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
86984b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
87060e218e4SAtsushi Murai       if (qlen > 0) {
87184b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
87284b8a6ebSAtsushi Murai       }
87384b8a6ebSAtsushi Murai     }
874780700e5SAndrey A. Chernov     if (server >= 0) {
875780700e5SAndrey A. Chernov       if (server + 1 > nfds)
876780700e5SAndrey A. Chernov 	nfds = server + 1;
877780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
878780700e5SAndrey A. Chernov     }
879af57ed9fSAtsushi Murai 
880944f7098SBrian Somers     /*
881944f7098SBrian Somers      * *** IMPORTANT ***
882af57ed9fSAtsushi Murai      *
883944f7098SBrian Somers      * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
884944f7098SBrian Somers      * with great care. If this values is too big, it results loss of
885944f7098SBrian Somers      * characters from modem and poor responce. If this values is too small,
886944f7098SBrian Somers      * ppp process eats many CPU time.
887af57ed9fSAtsushi Murai      */
88853c9f6c0SAtsushi Murai #ifndef SIGALRM
8899a571ec7SBrian Somers     nointr_usleep(TICKUNIT);
890af57ed9fSAtsushi Murai     TimerService();
891f5ff0f7cSBrian Somers #else
892f5ff0f7cSBrian Somers     handle_signals();
89353c9f6c0SAtsushi Murai #endif
89468d2b4d6SBruce Evans 
89568d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
896780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
897780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
898780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
89984b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
900780700e5SAndrey A. Chernov     }
901780700e5SAndrey A. Chernov     if (netfd >= 0) {
902780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
903780700e5SAndrey A. Chernov 	nfds = netfd + 1;
904af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
905af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
906af57ed9fSAtsushi Murai     }
90753c9f6c0SAtsushi Murai #ifndef SIGALRM
908944f7098SBrian Somers 
909af57ed9fSAtsushi Murai     /*
910944f7098SBrian Somers      * Normally, select() will not block because modem is writable. In AUTO
911944f7098SBrian Somers      * mode, select will block until we find packet from tun
912af57ed9fSAtsushi Murai      */
913af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
914780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
91553c9f6c0SAtsushi Murai #else
916944f7098SBrian Somers 
91784b8a6ebSAtsushi Murai     /*
918944f7098SBrian Somers      * When SIGALRM timer is running, a select function will be return -1 and
919944f7098SBrian Somers      * EINTR after a Time Service signal hundler is done.  If the redial
920944f7098SBrian Somers      * timer is not running and we are trying to dial, poll with a 0 value
921944f7098SBrian Somers      * timer.
92284b8a6ebSAtsushi Murai      */
923a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
924780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
92553c9f6c0SAtsushi Murai #endif
9266b0b88d8SBrian Somers 
927af57ed9fSAtsushi Murai     if (i == 0) {
928af57ed9fSAtsushi Murai       continue;
929af57ed9fSAtsushi Murai     }
930534fe541SBrian Somers     if (i < 0) {
931534fe541SBrian Somers       if (errno == EINTR) {
932f5ff0f7cSBrian Somers 	handle_signals();
933f5ff0f7cSBrian Somers 	continue;
93484b8a6ebSAtsushi Murai       }
935afc7fa2cSBrian Somers       LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
936af57ed9fSAtsushi Murai       break;
937af57ed9fSAtsushi Murai     }
938780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
939927145beSBrian Somers       LogPrintf(LogALERT, "Exception detected.\n");
940af57ed9fSAtsushi Murai       break;
941af57ed9fSAtsushi Murai     }
942780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
943927145beSBrian Somers       LogPrintf(LogPHASE, "connected to client.\n");
944af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
945e0d3e233SAndrey A. Chernov       if (wfd < 0) {
946afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
947e0d3e233SAndrey A. Chernov 	continue;
948e0d3e233SAndrey A. Chernov       }
949780700e5SAndrey A. Chernov       if (netfd >= 0) {
950af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
951af57ed9fSAtsushi Murai 	close(wfd);
952af57ed9fSAtsushi Murai 	continue;
953af57ed9fSAtsushi Murai       } else
954af57ed9fSAtsushi Murai 	netfd = wfd;
955927145beSBrian Somers       VarTerm = fdopen(netfd, "a+");
9568ea8442cSBrian Somers       LocalAuthInit();
957af57ed9fSAtsushi Murai       Greetings();
958a1e8f937SBrian Somers       IsInteractive(1);
959274e766cSBrian Somers       Prompt();
960af57ed9fSAtsushi Murai     }
96112ef29a8SBrian Somers     if (netfd >= 0 && FD_ISSET(netfd, &rfds) &&
96212ef29a8SBrian Somers 	((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) {
963af57ed9fSAtsushi Murai       /* something to read from tty */
964af57ed9fSAtsushi Murai       ReadTty();
965af57ed9fSAtsushi Murai     }
966780700e5SAndrey A. Chernov     if (modem >= 0) {
967af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
968af57ed9fSAtsushi Murai 	ModemStartOutput(modem);
969af57ed9fSAtsushi Murai       }
970af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
97153c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
9729a571ec7SBrian Somers 	  nointr_usleep(10000);
973af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
974af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
975af57ed9fSAtsushi Murai 	  DownConnection();
976af57ed9fSAtsushi Murai 	} else
977927145beSBrian Somers 	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
978af57ed9fSAtsushi Murai 
979af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
980944f7098SBrian Somers 
981af57ed9fSAtsushi Murai 	  /*
982af57ed9fSAtsushi Murai 	   * In dedicated mode, we just discard input until LCP is started.
983af57ed9fSAtsushi Murai 	   */
984af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
985af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
986af57ed9fSAtsushi Murai 	    if (cp) {
987944f7098SBrian Somers 
988af57ed9fSAtsushi Murai 	      /*
989af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
990af57ed9fSAtsushi Murai 	       */
991af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
992927145beSBrian Somers 		write(modem, rbuff, cp - rbuff);
993927145beSBrian Somers 		write(modem, "\r\n", 2);
994af57ed9fSAtsushi Murai 	      }
995af57ed9fSAtsushi Murai 	      PacketMode();
996af57ed9fSAtsushi Murai 	    } else
997927145beSBrian Somers 	      write(fileno(VarTerm), rbuff, n);
998af57ed9fSAtsushi Murai 	  }
999af57ed9fSAtsushi Murai 	} else {
1000af57ed9fSAtsushi Murai 	  if (n > 0)
1001af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
1002af57ed9fSAtsushi Murai 	}
1003af57ed9fSAtsushi Murai       }
1004af57ed9fSAtsushi Murai     }
1005944f7098SBrian Somers     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
1006944f7098SBrian Somers 							 * from tun */
1007af57ed9fSAtsushi Murai       n = read(tun_in, rbuff, sizeof(rbuff));
1008af57ed9fSAtsushi Murai       if (n < 0) {
1009afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
1010af57ed9fSAtsushi Murai 	continue;
1011af57ed9fSAtsushi Murai       }
1012de451c68SBrian Somers       if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
1013de451c68SBrian Somers 	/* we've been asked to send something addressed *to* us :( */
1014de451c68SBrian Somers 	if (VarLoopback) {
1015de451c68SBrian Somers 	  pri = PacketCheck(rbuff, n, FL_IN);
1016de451c68SBrian Somers 	  if (pri >= 0) {
1017de451c68SBrian Somers 	    struct mbuf *bp;
1018944f7098SBrian Somers 
1019de451c68SBrian Somers 	    if (mode & MODE_ALIAS) {
1020de451c68SBrian Somers 	      VarPacketAliasIn(rbuff, sizeof rbuff);
1021de451c68SBrian Somers 	      n = ntohs(((struct ip *) rbuff)->ip_len);
1022de451c68SBrian Somers 	    }
1023de451c68SBrian Somers 	    bp = mballoc(n, MB_IPIN);
102475240ed1SBrian Somers 	    memcpy(MBUF_CTOP(bp), rbuff, n);
1025de451c68SBrian Somers 	    IpInput(bp);
1026de451c68SBrian Somers 	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
1027de451c68SBrian Somers 	  }
1028de451c68SBrian Somers 	  continue;
1029de451c68SBrian Somers 	} else
1030de451c68SBrian Somers 	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
1031de451c68SBrian Somers       }
1032de451c68SBrian Somers 
1033af57ed9fSAtsushi Murai       /*
1034af57ed9fSAtsushi Murai        * Process on-demand dialup. Output packets are queued within tunnel
1035af57ed9fSAtsushi Murai        * device until IPCP is opened.
1036af57ed9fSAtsushi Murai        */
1037af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
103884b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1039af57ed9fSAtsushi Murai 	if (pri >= 0) {
1040a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10416ed9fb2fSBrian Somers 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1042a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *) rbuff)->ip_len);
1043a9f484e5SJordan K. Hubbard 	  }
1044af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
104575240ed1SBrian Somers 	  dial_up = 1;	/* XXX */
1046af57ed9fSAtsushi Murai 	}
1047af57ed9fSAtsushi Murai 	continue;
1048af57ed9fSAtsushi Murai       }
104984b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1050a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1051a9f484e5SJordan K. Hubbard 	if (mode & MODE_ALIAS) {
10526ed9fb2fSBrian Somers 	  VarPacketAliasOut(rbuff, sizeof rbuff);
1053a9f484e5SJordan K. Hubbard 	  n = ntohs(((struct ip *) rbuff)->ip_len);
1054a9f484e5SJordan K. Hubbard 	}
1055af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1056af57ed9fSAtsushi Murai       }
1057af57ed9fSAtsushi Murai     }
1058a9f484e5SJordan K. Hubbard   }
1059927145beSBrian Somers   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1060af57ed9fSAtsushi Murai }
1061