xref: /freebsd/usr.sbin/ppp/main.c (revision 5106c67149438f0d50a1915bbcb75be1db7aae30)
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  *
205106c671SBrian Somers  * $Id: main.c,v 1.88 1997/11/08 00:28:09 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"
7253c9f6c0SAtsushi Murai 
7353c9f6c0SAtsushi Murai #ifndef O_NONBLOCK
7453c9f6c0SAtsushi Murai #ifdef O_NDELAY
7553c9f6c0SAtsushi Murai #define	O_NONBLOCK O_NDELAY
7653c9f6c0SAtsushi Murai #endif
7753c9f6c0SAtsushi Murai #endif
78af57ed9fSAtsushi Murai 
7975240ed1SBrian Somers int TermMode = 0;
8075240ed1SBrian Somers int tunno = 0;
81af57ed9fSAtsushi Murai 
82af57ed9fSAtsushi Murai static struct termios oldtio;	/* Original tty mode */
83af57ed9fSAtsushi Murai static struct termios comtio;	/* Command level tty mode */
846d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
8541c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
8676c5241dSBrian Somers static int dial_up;
87af57ed9fSAtsushi Murai 
8875240ed1SBrian Somers static void DoLoop(void);
8975240ed1SBrian Somers static void TerminalStop(int);
9075240ed1SBrian Somers static char *ex_desc(int);
9175240ed1SBrian Somers 
92af57ed9fSAtsushi Murai static void
93368aee2bSBrian Somers TtyInit(int DontWantInt)
94af57ed9fSAtsushi Murai {
95af57ed9fSAtsushi Murai   struct termios newtio;
96af57ed9fSAtsushi Murai   int stat;
97af57ed9fSAtsushi Murai 
98af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
99274e766cSBrian Somers   if (stat > 0) {
100af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
101274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
102274e766cSBrian Somers   }
103af57ed9fSAtsushi Murai   newtio = oldtio;
104af57ed9fSAtsushi Murai   newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
105af57ed9fSAtsushi Murai   newtio.c_iflag = 0;
106af57ed9fSAtsushi Murai   newtio.c_oflag &= ~OPOST;
107af57ed9fSAtsushi Murai   newtio.c_cc[VEOF] = _POSIX_VDISABLE;
108368aee2bSBrian Somers   if (DontWantInt)
109af57ed9fSAtsushi Murai     newtio.c_cc[VINTR] = _POSIX_VDISABLE;
110af57ed9fSAtsushi Murai   newtio.c_cc[VMIN] = 1;
111af57ed9fSAtsushi Murai   newtio.c_cc[VTIME] = 0;
112af57ed9fSAtsushi Murai   newtio.c_cflag |= CS8;
11353c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
114af57ed9fSAtsushi Murai   comtio = newtio;
115af57ed9fSAtsushi Murai }
116af57ed9fSAtsushi Murai 
117af57ed9fSAtsushi Murai /*
118af57ed9fSAtsushi Murai  *  Set tty into command mode. We allow canonical input and echo processing.
119af57ed9fSAtsushi Murai  */
120c3899f8dSAtsushi Murai void
121944f7098SBrian Somers TtyCommandMode(int prompt)
122af57ed9fSAtsushi Murai {
123af57ed9fSAtsushi Murai   struct termios newtio;
124af57ed9fSAtsushi Murai   int stat;
125af57ed9fSAtsushi Murai 
126af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER))
127af57ed9fSAtsushi Murai     return;
12853c9f6c0SAtsushi Murai   tcgetattr(0, &newtio);
129c3899f8dSAtsushi Murai   newtio.c_lflag |= (ECHO | ISIG | ICANON);
130af57ed9fSAtsushi Murai   newtio.c_iflag = oldtio.c_iflag;
131af57ed9fSAtsushi Murai   newtio.c_oflag |= OPOST;
13253c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
133af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
134274e766cSBrian Somers   if (stat > 0) {
135af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
136274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
137274e766cSBrian Somers   }
138af57ed9fSAtsushi Murai   TermMode = 0;
139944f7098SBrian Somers   if (prompt)
140944f7098SBrian Somers     Prompt();
141af57ed9fSAtsushi Murai }
142af57ed9fSAtsushi Murai 
143af57ed9fSAtsushi Murai /*
144af57ed9fSAtsushi Murai  * Set tty into terminal mode which is used while we invoke term command.
145af57ed9fSAtsushi Murai  */
146af57ed9fSAtsushi Murai void
147af57ed9fSAtsushi Murai TtyTermMode()
148af57ed9fSAtsushi Murai {
149af57ed9fSAtsushi Murai   int stat;
150af57ed9fSAtsushi Murai 
15153c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &comtio);
152af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
153274e766cSBrian Somers   if (stat > 0) {
154af57ed9fSAtsushi Murai     stat &= ~O_NONBLOCK;
155274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
156274e766cSBrian Somers   }
157af57ed9fSAtsushi Murai   TermMode = 1;
158af57ed9fSAtsushi Murai }
159af57ed9fSAtsushi Murai 
160af57ed9fSAtsushi Murai void
161c3899f8dSAtsushi Murai TtyOldMode()
162c3899f8dSAtsushi Murai {
163c3899f8dSAtsushi Murai   int stat;
164c3899f8dSAtsushi Murai 
165c3899f8dSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
166274e766cSBrian Somers   if (stat > 0) {
167c3899f8dSAtsushi Murai     stat &= ~O_NONBLOCK;
168274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
169274e766cSBrian Somers   }
170c3899f8dSAtsushi Murai   tcsetattr(0, TCSANOW, &oldtio);
171c3899f8dSAtsushi Murai }
172c3899f8dSAtsushi Murai 
173c3899f8dSAtsushi Murai void
174944f7098SBrian Somers Cleanup(int excode)
175af57ed9fSAtsushi Murai {
1760fe7ca31SBrian Somers   OsInterfaceDown(1);
1770fe7ca31SBrian Somers   HangupModem(1);
1789a571ec7SBrian Somers   nointr_sleep(1);
1796efd9292SBrian Somers   if (mode & MODE_AUTO)
1806e4959f0SBrian Somers     DeleteIfRoutes(1);
1815106c671SBrian Somers   ID0unlink(pid_filename);
1826e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1836e4959f0SBrian Somers     char c = EX_ERRDEAD;
184944f7098SBrian Somers 
1856e4959f0SBrian Somers     if (write(BGFiledes[1], &c, 1) == 1)
186927145beSBrian Somers       LogPrintf(LogPHASE, "Parent notified of failure.\n");
1876e4959f0SBrian Somers     else
188927145beSBrian Somers       LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
1896e4959f0SBrian Somers     close(BGFiledes[1]);
1906e4959f0SBrian Somers   }
191927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
1924ef16f24SBrian Somers   ServerClose();
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() */
203873725ccSBrian Somers   LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
204944f7098SBrian Somers   reconnectState = RECON_FALSE;
205944f7098SBrian Somers   reconnectCount = 0;
206368aee2bSBrian Somers   DownConnection();
20775240ed1SBrian Somers   dial_up = 0;
2086d14e2a8SJordan K. Hubbard }
209af57ed9fSAtsushi Murai 
210af57ed9fSAtsushi Murai static void
211944f7098SBrian Somers CloseSession(int signo)
212af57ed9fSAtsushi Murai {
2136d14e2a8SJordan K. Hubbard   if (BGPid) {
2146d14e2a8SJordan K. Hubbard     kill(BGPid, SIGINT);
2156d14e2a8SJordan K. Hubbard     exit(EX_TERM);
2166d14e2a8SJordan K. Hubbard   }
217927145beSBrian Somers   LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
21825aa96acSBrian Somers   reconnect(RECON_FALSE);
219af57ed9fSAtsushi Murai   LcpClose();
220af57ed9fSAtsushi Murai   Cleanup(EX_TERM);
221af57ed9fSAtsushi Murai }
222c3899f8dSAtsushi Murai 
223c3899f8dSAtsushi Murai static void
224c3899f8dSAtsushi Murai TerminalCont()
225c3899f8dSAtsushi Murai {
226f5ff0f7cSBrian Somers   pending_signal(SIGCONT, SIG_DFL);
227f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, TerminalStop);
228c3899f8dSAtsushi Murai   TtyCommandMode(getpgrp() == tcgetpgrp(0));
229c3899f8dSAtsushi Murai }
230c3899f8dSAtsushi Murai 
231c3899f8dSAtsushi Murai static void
232944f7098SBrian Somers TerminalStop(int signo)
233c3899f8dSAtsushi Murai {
234f5ff0f7cSBrian Somers   pending_signal(SIGCONT, TerminalCont);
235c3899f8dSAtsushi Murai   TtyOldMode();
236f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, SIG_DFL);
237c3899f8dSAtsushi Murai   kill(getpid(), signo);
238c3899f8dSAtsushi Murai }
239c3899f8dSAtsushi Murai 
2404ef16f24SBrian Somers static void
241944f7098SBrian Somers SetUpServer(int signo)
2424ef16f24SBrian Somers {
2434ef16f24SBrian Somers   int res;
244944f7098SBrian Somers 
2454ef16f24SBrian Somers   if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
246683cef3cSBrian Somers     LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
247683cef3cSBrian Somers 	      res, SERVER_PORT + tunno);
2484ef16f24SBrian Somers }
2494ef16f24SBrian Somers 
2506efd9292SBrian Somers static char *
2516efd9292SBrian Somers ex_desc(int ex)
2526efd9292SBrian Somers {
2536efd9292SBrian Somers   static char num[12];
2546efd9292SBrian Somers   static char *desc[] = {"normal", "start", "sock",
2556efd9292SBrian Somers     "modem", "dial", "dead", "done", "reboot", "errdead",
2566efd9292SBrian Somers   "hangup", "term", "nodial", "nologin"};
2576efd9292SBrian Somers 
2586efd9292SBrian Somers   if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
2596efd9292SBrian Somers     return desc[ex];
2606efd9292SBrian Somers   snprintf(num, sizeof num, "%d", ex);
2616efd9292SBrian Somers   return num;
2626efd9292SBrian Somers }
263c3899f8dSAtsushi Murai 
26475240ed1SBrian Somers static void
265af57ed9fSAtsushi Murai Usage()
266af57ed9fSAtsushi Murai {
267680026d6SNate Williams   fprintf(stderr,
2686d14e2a8SJordan K. Hubbard 	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
269af57ed9fSAtsushi Murai   exit(EX_START);
270af57ed9fSAtsushi Murai }
271af57ed9fSAtsushi Murai 
27275240ed1SBrian Somers static void
273af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
274af57ed9fSAtsushi Murai {
275af57ed9fSAtsushi Murai   int optc;
276af57ed9fSAtsushi Murai   char *cp;
277af57ed9fSAtsushi Murai 
278af57ed9fSAtsushi Murai   optc = 0;
279af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
280af57ed9fSAtsushi Murai     cp = *argv + 1;
281af57ed9fSAtsushi Murai     if (strcmp(cp, "auto") == 0)
282af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
2836d14e2a8SJordan K. Hubbard     else if (strcmp(cp, "background") == 0)
2846efd9292SBrian Somers       mode |= MODE_BACKGROUND | MODE_AUTO;
285af57ed9fSAtsushi Murai     else if (strcmp(cp, "direct") == 0)
286af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
287af57ed9fSAtsushi Murai     else if (strcmp(cp, "dedicated") == 0)
288af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
289680026d6SNate Williams     else if (strcmp(cp, "ddial") == 0)
290680026d6SNate Williams       mode |= MODE_DDIAL | MODE_AUTO;
291a9f484e5SJordan K. Hubbard     else if (strcmp(cp, "alias") == 0) {
2926ed9fb2fSBrian Somers       if (loadAliasHandlers(&VarAliasHandlers) == 0)
293a9f484e5SJordan K. Hubbard 	mode |= MODE_ALIAS;
2946ed9fb2fSBrian Somers       else
295927145beSBrian Somers 	LogPrintf(LogWARN, "Cannot load alias library\n");
296a9f484e5SJordan K. Hubbard       optc--;			/* this option isn't exclusive */
297944f7098SBrian Somers     } else
298af57ed9fSAtsushi Murai       Usage();
299af57ed9fSAtsushi Murai     optc++;
300944f7098SBrian Somers     argv++;
301944f7098SBrian Somers     argc--;
302af57ed9fSAtsushi Murai   }
303af57ed9fSAtsushi Murai   if (argc > 1) {
304af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
305af57ed9fSAtsushi Murai     exit(EX_START);
306af57ed9fSAtsushi Murai   }
307944f7098SBrian Somers   if (argc == 1)
308944f7098SBrian Somers     dstsystem = *argv;
309af57ed9fSAtsushi Murai 
310af57ed9fSAtsushi Murai   if (optc > 1) {
311af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
312af57ed9fSAtsushi Murai     exit(EX_START);
313af57ed9fSAtsushi Murai   }
314af57ed9fSAtsushi Murai }
315af57ed9fSAtsushi Murai 
316af57ed9fSAtsushi Murai static void
317af57ed9fSAtsushi Murai Greetings()
318af57ed9fSAtsushi Murai {
319927145beSBrian Somers   if (VarTerm) {
320927145beSBrian Somers     fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
321927145beSBrian Somers     fflush(VarTerm);
322927145beSBrian Somers   }
323af57ed9fSAtsushi Murai }
324af57ed9fSAtsushi Murai 
3254ef16f24SBrian Somers int
326944f7098SBrian Somers main(int argc, char **argv)
327af57ed9fSAtsushi Murai {
328aefd026aSBrian Somers   FILE *lockfile;
329927145beSBrian Somers   char *name;
330af57ed9fSAtsushi Murai 
3310706ff38SBrian Somers   VarTerm = 0;
33275240ed1SBrian Somers   name = strrchr(argv[0], '/');
333927145beSBrian Somers   LogOpen(name ? name + 1 : argv[0]);
334927145beSBrian Somers 
335944f7098SBrian Somers   argc--;
336944f7098SBrian Somers   argv++;
337af57ed9fSAtsushi Murai   ProcessArgs(argc, argv);
338683cef3cSBrian Somers   if (!(mode & MODE_DIRECT)) {
339683cef3cSBrian Somers     if (getuid() != 0) {
340683cef3cSBrian Somers       fprintf(stderr, "You may only run ppp in client mode as user id 0\n");
341683cef3cSBrian Somers       LogClose();
342683cef3cSBrian Somers       return EX_NOPERM;
343683cef3cSBrian Somers     }
3440706ff38SBrian Somers     VarTerm = stdout;
345683cef3cSBrian Somers   }
3465106c671SBrian Somers   ID0init();
347af57ed9fSAtsushi Murai   Greetings();
348af57ed9fSAtsushi Murai   IpcpDefAddress();
349683cef3cSBrian Somers   LocalAuthInit();
350af57ed9fSAtsushi Murai 
351927145beSBrian Somers   if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
352927145beSBrian Somers     fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
353af57ed9fSAtsushi Murai 
354af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
3554ef16f24SBrian Somers     LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
3564ef16f24SBrian Somers     return EX_START;
357af57ed9fSAtsushi Murai   }
3586efd9292SBrian Somers   if (mode & (MODE_AUTO | MODE_DIRECT | MODE_DEDICATED))
359af57ed9fSAtsushi Murai     mode &= ~MODE_INTER;
360af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
361927145beSBrian Somers     fprintf(VarTerm, "Interactive mode\n");
362cc39a98fSBrian Somers     netfd = STDOUT_FILENO;
363af57ed9fSAtsushi Murai   } else if (mode & MODE_AUTO) {
364927145beSBrian Somers     fprintf(VarTerm, "Automatic Dialer mode\n");
365af57ed9fSAtsushi Murai     if (dstsystem == NULL) {
366927145beSBrian Somers       if (VarTerm)
367927145beSBrian Somers 	fprintf(VarTerm, "Destination system must be specified in"
3686efd9292SBrian Somers 		" auto, background or ddial mode.\n");
3694ef16f24SBrian Somers       return EX_START;
3706d14e2a8SJordan K. Hubbard     }
371af57ed9fSAtsushi Murai   }
37253c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);	/* Save original tty mode */
373af57ed9fSAtsushi Murai 
374873725ccSBrian Somers   pending_signal(SIGHUP, CloseSession);
375f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
376873725ccSBrian Somers   pending_signal(SIGINT, CloseConnection);
377f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
37853c9f6c0SAtsushi Murai #ifdef SIGPIPE
379e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
38053c9f6c0SAtsushi Murai #endif
38153c9f6c0SAtsushi Murai #ifdef SIGALRM
382f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
38353c9f6c0SAtsushi Murai #endif
3844ef16f24SBrian Somers   if (mode & MODE_INTER) {
385c3899f8dSAtsushi Murai #ifdef SIGTSTP
386f5ff0f7cSBrian Somers     pending_signal(SIGTSTP, TerminalStop);
387c3899f8dSAtsushi Murai #endif
388c3899f8dSAtsushi Murai #ifdef SIGTTIN
389f5ff0f7cSBrian Somers     pending_signal(SIGTTIN, TerminalStop);
390c3899f8dSAtsushi Murai #endif
391c3899f8dSAtsushi Murai #ifdef SIGTTOU
392f5ff0f7cSBrian Somers     pending_signal(SIGTTOU, SIG_IGN);
393c3899f8dSAtsushi Murai #endif
394c3899f8dSAtsushi Murai   }
3954ef16f24SBrian Somers #ifdef SIGUSR1
3964ef16f24SBrian Somers   if (mode != MODE_INTER)
3974ef16f24SBrian Somers     pending_signal(SIGUSR1, SetUpServer);
3984ef16f24SBrian Somers #endif
399af57ed9fSAtsushi Murai 
400af57ed9fSAtsushi Murai   if (dstsystem) {
401af57ed9fSAtsushi Murai     if (SelectSystem(dstsystem, CONFFILE) < 0) {
4020706ff38SBrian Somers       LogPrintf(LogWARN, "Destination system not found in conf file.\n");
403af57ed9fSAtsushi Murai       Cleanup(EX_START);
404af57ed9fSAtsushi Murai     }
405af57ed9fSAtsushi Murai     if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
4060706ff38SBrian Somers       LogPrintf(LogWARN, "Must specify dstaddr with"
4076efd9292SBrian Somers 		" auto, background or ddial mode.\n");
408af57ed9fSAtsushi Murai       Cleanup(EX_START);
409af57ed9fSAtsushi Murai     }
410af57ed9fSAtsushi Murai   }
4116efd9292SBrian Somers 
4124ef16f24SBrian Somers   if (!(mode & MODE_INTER)) {
4136d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4146d14e2a8SJordan K. Hubbard       if (pipe(BGFiledes)) {
415afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
4166d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4176d14e2a8SJordan K. Hubbard       }
4186d14e2a8SJordan K. Hubbard     }
41975240ed1SBrian Somers     /* Create server socket and listen (initial value is -2) */
420683cef3cSBrian Somers     if (server == -2)
421683cef3cSBrian Somers       ServerTcpOpen(SERVER_PORT + tunno);
422af57ed9fSAtsushi Murai 
423af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4246d14e2a8SJordan K. Hubbard       pid_t bgpid;
425a9c6b5dfSAtsushi Murai 
4266d14e2a8SJordan K. Hubbard       bgpid = fork();
4276d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
428afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
4296d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4306d14e2a8SJordan K. Hubbard       }
4316d14e2a8SJordan K. Hubbard       if (bgpid) {
4326d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
433a9c6b5dfSAtsushi Murai 
4346d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4356d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4366d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4376e4959f0SBrian Somers 	  close(BGFiledes[1]);
4386efd9292SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1) {
439927145beSBrian Somers 	    fprintf(VarTerm, "Child exit, no status.\n");
440927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
4416efd9292SBrian Somers 	  } else if (c == EX_NORMAL) {
442927145beSBrian Somers 	    fprintf(VarTerm, "PPP enabled.\n");
443927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
4446efd9292SBrian Somers 	  } else {
445927145beSBrian Somers 	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
446927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
44780e37c72SBrian Somers 		      ex_desc((int) c));
4486efd9292SBrian Somers 	  }
4496e4959f0SBrian Somers 	  close(BGFiledes[0]);
4506d14e2a8SJordan K. Hubbard 	}
4514ef16f24SBrian Somers 	return c;
4526e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
4536e4959f0SBrian Somers 	close(BGFiledes[0]);
454aefd026aSBrian Somers     }
455aefd026aSBrian Somers 
456d656a4c5SBrian Somers     VarTerm = 0;		/* We know it's currently stdout */
457fd2bc5ebSBrian Somers     close(1);
458d656a4c5SBrian Somers     close(2);
4590706ff38SBrian Somers 
460af57ed9fSAtsushi Murai #ifdef DOTTYINIT
461d656a4c5SBrian Somers     if (mode & (MODE_DIRECT | MODE_DEDICATED))
462af57ed9fSAtsushi Murai #else
463d656a4c5SBrian Somers     if (mode & MODE_DIRECT)
464af57ed9fSAtsushi Murai #endif
465368aee2bSBrian Somers       TtyInit(1);
466d656a4c5SBrian Somers     else {
467d656a4c5SBrian Somers       setsid();
468fd2bc5ebSBrian Somers       close(0);
469d656a4c5SBrian Somers     }
470af57ed9fSAtsushi Murai   } else {
471368aee2bSBrian Somers     TtyInit(0);
472c3899f8dSAtsushi Murai     TtyCommandMode(1);
473af57ed9fSAtsushi Murai   }
47435495becSBrian Somers 
47535495becSBrian Somers   snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
47635495becSBrian Somers            _PATH_VARRUN, tunno);
4775106c671SBrian Somers   lockfile = ID0fopen(pid_filename, "w");
4785106c671SBrian Somers   if (lockfile != NULL) {
47935495becSBrian Somers     fprintf(lockfile, "%d\n", (int) getpid());
48035495becSBrian Somers     fclose(lockfile);
48135495becSBrian Somers   } else
48235495becSBrian Somers     LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
48335495becSBrian Somers               pid_filename, strerror(errno));
48435495becSBrian Somers 
485927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Started.\n");
486af57ed9fSAtsushi Murai 
487af57ed9fSAtsushi Murai 
488af57ed9fSAtsushi Murai   do
489af57ed9fSAtsushi Murai     DoLoop();
490af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
491af57ed9fSAtsushi Murai 
492af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
4934ef16f24SBrian Somers   return 0;
494af57ed9fSAtsushi Murai }
495af57ed9fSAtsushi Murai 
496af57ed9fSAtsushi Murai /*
4976d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
498af57ed9fSAtsushi Murai  */
499af57ed9fSAtsushi Murai void
500af57ed9fSAtsushi Murai PacketMode()
501af57ed9fSAtsushi Murai {
5029780ef31SBrian Somers   if (RawModem() < 0) {
503927145beSBrian Somers     LogPrintf(LogWARN, "PacketMode: Not connected.\n");
504af57ed9fSAtsushi Murai     return;
505af57ed9fSAtsushi Murai   }
506af57ed9fSAtsushi Murai   AsyncInit();
50703604f35SBrian Somers   VjInit(15);
508af57ed9fSAtsushi Murai   LcpInit();
509af57ed9fSAtsushi Murai   IpcpInit();
510af57ed9fSAtsushi Murai   CcpInit();
511af57ed9fSAtsushi Murai   LcpUp();
512af57ed9fSAtsushi Murai 
513af57ed9fSAtsushi Murai   LcpOpen(VarOpenMode);
514af57ed9fSAtsushi Murai   if ((mode & (MODE_INTER | MODE_AUTO)) == MODE_INTER) {
515c3899f8dSAtsushi Murai     TtyCommandMode(1);
516927145beSBrian Somers     if (VarTerm) {
517927145beSBrian Somers       fprintf(VarTerm, "Packet mode.\n");
518b0cdb3ceSJordan K. Hubbard       aft_cmd = 1;
519af57ed9fSAtsushi Murai     }
520af57ed9fSAtsushi Murai   }
521927145beSBrian Somers }
522af57ed9fSAtsushi Murai 
523af57ed9fSAtsushi Murai static void
524af57ed9fSAtsushi Murai ShowHelp()
525af57ed9fSAtsushi Murai {
526030d3ce6SBrian Somers   fprintf(stderr, "The following commands are available:\r\n");
527030d3ce6SBrian Somers   fprintf(stderr, " ~p\tEnter Packet mode\r\n");
528030d3ce6SBrian Somers   fprintf(stderr, " ~-\tDecrease log level\r\n");
529030d3ce6SBrian Somers   fprintf(stderr, " ~+\tIncrease log level\r\n");
530030d3ce6SBrian Somers   fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
531030d3ce6SBrian Somers   fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
532030d3ce6SBrian Somers   fprintf(stderr, " ~.\tTerminate program\r\n");
533030d3ce6SBrian Somers   fprintf(stderr, " ~?\tThis help\r\n");
534af57ed9fSAtsushi Murai }
535af57ed9fSAtsushi Murai 
536af57ed9fSAtsushi Murai static void
537af57ed9fSAtsushi Murai ReadTty()
538af57ed9fSAtsushi Murai {
539af57ed9fSAtsushi Murai   int n;
540af57ed9fSAtsushi Murai   char ch;
541af57ed9fSAtsushi Murai   static int ttystate;
542927145beSBrian Somers   FILE *oVarTerm;
543944f7098SBrian Somers 
544af57ed9fSAtsushi Murai #define MAXLINESIZE 200
545af57ed9fSAtsushi Murai   char linebuff[MAXLINESIZE];
546af57ed9fSAtsushi Murai 
547927145beSBrian Somers   LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
548927145beSBrian Somers 	    TermMode, netfd, mode);
549af57ed9fSAtsushi Murai   if (!TermMode) {
550af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff) - 1);
55153c9f6c0SAtsushi Murai     if (n > 0) {
552927145beSBrian Somers       aft_cmd = 1;
553a1e8f937SBrian Somers       if (linebuff[n-1] == '\n')
554a1e8f937SBrian Somers         linebuff[--n] = '\0';
555a1e8f937SBrian Somers       if (n) {
556a1e8f937SBrian Somers         if (IsInteractive(0))
557a1e8f937SBrian Somers           LogPrintf(LogCOMMAND, "%s\n", linebuff);
558a1e8f937SBrian Somers         else
559331953abSBrian Somers           LogPrintf(LogCOMMAND, "Client: %s\n", linebuff);
560af57ed9fSAtsushi Murai         DecodeCommand(linebuff, n, 1);
561a1e8f937SBrian Somers       } else
562a1e8f937SBrian Somers         Prompt();
56353c9f6c0SAtsushi Murai     } else {
564927145beSBrian Somers       LogPrintf(LogPHASE, "client connection closed.\n");
565e0d3e233SAndrey A. Chernov       VarLocalAuth = LOCAL_NO_AUTH;
566af57ed9fSAtsushi Murai       mode &= ~MODE_INTER;
567927145beSBrian Somers       oVarTerm = VarTerm;
568927145beSBrian Somers       VarTerm = 0;
569927145beSBrian Somers       if (oVarTerm && oVarTerm != stdout)
570927145beSBrian Somers 	fclose(oVarTerm);
571927145beSBrian Somers       close(netfd);
572927145beSBrian Somers       netfd = -1;
573af57ed9fSAtsushi Murai     }
574af57ed9fSAtsushi Murai     return;
575af57ed9fSAtsushi Murai   }
576af57ed9fSAtsushi Murai 
577af57ed9fSAtsushi Murai   /*
578af57ed9fSAtsushi Murai    * We are in terminal mode, decode special sequences
579af57ed9fSAtsushi Murai    */
580927145beSBrian Somers   n = read(fileno(VarTerm), &ch, 1);
581afc7fa2cSBrian Somers   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
582af57ed9fSAtsushi Murai 
583af57ed9fSAtsushi Murai   if (n > 0) {
584af57ed9fSAtsushi Murai     switch (ttystate) {
585af57ed9fSAtsushi Murai     case 0:
586af57ed9fSAtsushi Murai       if (ch == '~')
587af57ed9fSAtsushi Murai 	ttystate++;
588af57ed9fSAtsushi Murai       else
589af57ed9fSAtsushi Murai 	write(modem, &ch, n);
590af57ed9fSAtsushi Murai       break;
591af57ed9fSAtsushi Murai     case 1:
592af57ed9fSAtsushi Murai       switch (ch) {
593af57ed9fSAtsushi Murai       case '?':
594af57ed9fSAtsushi Murai 	ShowHelp();
595af57ed9fSAtsushi Murai 	break;
596af57ed9fSAtsushi Murai       case 'p':
597944f7098SBrian Somers 
598af57ed9fSAtsushi Murai 	/*
599af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
600af57ed9fSAtsushi Murai 	 */
601af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
602af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
603af57ed9fSAtsushi Murai 	  PacketMode();
604af57ed9fSAtsushi Murai 	}
605af57ed9fSAtsushi Murai 	break;
606af57ed9fSAtsushi Murai       case '.':
607af57ed9fSAtsushi Murai 	TermMode = 1;
608927145beSBrian Somers 	aft_cmd = 1;
609c3899f8dSAtsushi Murai 	TtyCommandMode(1);
610af57ed9fSAtsushi Murai 	break;
611927145beSBrian Somers       case 't':
612927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
613927145beSBrian Somers 	  ShowTimers();
614927145beSBrian Somers 	  break;
615927145beSBrian Somers 	}
616927145beSBrian Somers       case 'm':
617927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
618927145beSBrian Somers 	  ShowMemMap();
619927145beSBrian Somers 	  break;
620927145beSBrian Somers 	}
621af57ed9fSAtsushi Murai       default:
622af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
623927145beSBrian Somers 	  LogPrintf(LogERROR, "error writing to modem.\n");
624af57ed9fSAtsushi Murai 	break;
625af57ed9fSAtsushi Murai       }
626af57ed9fSAtsushi Murai       ttystate = 0;
627af57ed9fSAtsushi Murai       break;
628af57ed9fSAtsushi Murai     }
629af57ed9fSAtsushi Murai   }
630af57ed9fSAtsushi Murai }
631af57ed9fSAtsushi Murai 
632af57ed9fSAtsushi Murai 
633af57ed9fSAtsushi Murai /*
634af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
635af57ed9fSAtsushi Murai  */
636af57ed9fSAtsushi Murai 
637af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
63853c9f6c0SAtsushi Murai   "\176\377\003\300\041",
63953c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
64053c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
64153c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
64253c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
643af57ed9fSAtsushi Murai   NULL,
644af57ed9fSAtsushi Murai };
645af57ed9fSAtsushi Murai 
64675240ed1SBrian Somers static u_char *
647944f7098SBrian Somers HdlcDetect(u_char * cp, int n)
648af57ed9fSAtsushi Murai {
64953c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
650af57ed9fSAtsushi Murai 
651af57ed9fSAtsushi Murai   cp[n] = '\0';			/* be sure to null terminated */
652af57ed9fSAtsushi Murai   ptr = NULL;
653af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
65453c9f6c0SAtsushi Murai     fp = *hp;
65553c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
65653c9f6c0SAtsushi Murai       fp++;
657ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *) cp, fp);
658ed6a16c1SPoul-Henning Kamp     if (ptr)
659af57ed9fSAtsushi Murai       break;
660af57ed9fSAtsushi Murai   }
661af57ed9fSAtsushi Murai   return ((u_char *) ptr);
662af57ed9fSAtsushi Murai }
663af57ed9fSAtsushi Murai 
664af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
665af57ed9fSAtsushi Murai 
666af57ed9fSAtsushi Murai static void
667af57ed9fSAtsushi Murai RedialTimeout()
668af57ed9fSAtsushi Murai {
669af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
670927145beSBrian Somers   LogPrintf(LogPHASE, "Redialing timer expired.\n");
671af57ed9fSAtsushi Murai }
672af57ed9fSAtsushi Murai 
673af57ed9fSAtsushi Murai static void
674944f7098SBrian Somers StartRedialTimer(int Timeout)
675af57ed9fSAtsushi Murai {
676af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
677a9c6b5dfSAtsushi Murai 
67843ea9d19SBrian Somers   if (Timeout) {
679af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
680a9c6b5dfSAtsushi Murai 
68143ea9d19SBrian Somers     if (Timeout > 0)
68243ea9d19SBrian Somers       RedialTimer.load = Timeout * SECTICKS;
683a9c6b5dfSAtsushi Murai     else
684a9c6b5dfSAtsushi Murai       RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
685a9c6b5dfSAtsushi Murai 
686927145beSBrian Somers     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
68743ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
68843ea9d19SBrian Somers 
689af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
690af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
691af57ed9fSAtsushi Murai   }
692a9c6b5dfSAtsushi Murai }
693af57ed9fSAtsushi Murai 
694af57ed9fSAtsushi Murai 
695af57ed9fSAtsushi Murai static void
696af57ed9fSAtsushi Murai DoLoop()
697af57ed9fSAtsushi Murai {
698af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
699780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
700af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
701af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
702af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
703af57ed9fSAtsushi Murai   u_char *cp;
704af57ed9fSAtsushi Murai   u_char rbuff[MAX_MRU];
705a9c6b5dfSAtsushi Murai   int tries;
70660e218e4SAtsushi Murai   int qlen;
707368aee2bSBrian Somers   int res;
708c3899f8dSAtsushi Murai   pid_t pgroup;
709c3899f8dSAtsushi Murai 
710c3899f8dSAtsushi Murai   pgroup = getpgrp();
711af57ed9fSAtsushi Murai 
7126efd9292SBrian Somers   if (mode & MODE_DIRECT) {
7130706ff38SBrian Somers     LogPrintf(LogDEBUG, "Opening modem\n");
7149780ef31SBrian Somers     if (OpenModem() < 0)
715bc240299SBrian Somers       return;
716927145beSBrian Somers     LogPrintf(LogPHASE, "Packet mode enabled\n");
717af57ed9fSAtsushi Murai     PacketMode();
718af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
719780700e5SAndrey A. Chernov     if (modem < 0)
7209780ef31SBrian Somers       while (OpenModem() < 0)
7219a571ec7SBrian Somers 	nointr_sleep(VarReconnectTimer);
722af57ed9fSAtsushi Murai   }
723927145beSBrian Somers   fflush(VarTerm);
724af57ed9fSAtsushi Murai 
72584b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
726af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
72725aa96acSBrian Somers   reconnectState = RECON_UNKNOWN;
728af57ed9fSAtsushi Murai 
7296e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
73075240ed1SBrian Somers     dial_up = 1;		/* Bring the line up */
7316e4959f0SBrian Somers   else
73275240ed1SBrian Somers     dial_up = 0;		/* XXXX */
733a9c6b5dfSAtsushi Murai   tries = 0;
734af57ed9fSAtsushi Murai   for (;;) {
735780700e5SAndrey A. Chernov     nfds = 0;
736944f7098SBrian Somers     FD_ZERO(&rfds);
737944f7098SBrian Somers     FD_ZERO(&wfds);
738944f7098SBrian Somers     FD_ZERO(&efds);
73984b8a6ebSAtsushi Murai 
74084b8a6ebSAtsushi Murai     /*
741944f7098SBrian Somers      * If the link is down and we're in DDIAL mode, bring it back up.
742680026d6SNate Williams      */
743680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
74475240ed1SBrian Somers       dial_up = 1;
745680026d6SNate Williams 
746680026d6SNate Williams     /*
747944f7098SBrian Somers      * If we lost carrier and want to re-establish the connection due to the
748944f7098SBrian Somers      * "set reconnect" value, we'd better bring the line back up.
74907030d97SBrian Somers      */
7506efd9292SBrian Somers     if (LcpFsm.state <= ST_CLOSED) {
75175240ed1SBrian Somers       if (!dial_up && reconnectState == RECON_TRUE) {
7526efd9292SBrian Somers 	if (++reconnectCount <= VarReconnectTries) {
753927145beSBrian Somers 	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
7546efd9292SBrian Somers 		    reconnectCount, VarReconnectTries);
75507030d97SBrian Somers 	  StartRedialTimer(VarReconnectTimer);
75675240ed1SBrian Somers 	  dial_up = 1;
757298091daSBrian Somers 	} else {
7586efd9292SBrian Somers 	  if (VarReconnectTries)
759927145beSBrian Somers 	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
760298091daSBrian Somers 		      VarReconnectTries);
7616efd9292SBrian Somers 	  reconnectCount = 0;
7626efd9292SBrian Somers 	  if (mode & MODE_BACKGROUND)
7636efd9292SBrian Somers 	    Cleanup(EX_DEAD);
7646efd9292SBrian Somers 	}
76525aa96acSBrian Somers 	reconnectState = RECON_ENVOKED;
7666efd9292SBrian Somers       }
76707030d97SBrian Somers     }
76807030d97SBrian Somers 
76907030d97SBrian Somers     /*
770944f7098SBrian Somers      * If Ip packet for output is enqueued and require dial up, Just do it!
77184b8a6ebSAtsushi Murai      */
77207030d97SBrian Somers     if (dial_up && RedialTimer.state != TIMER_RUNNING) {
773927145beSBrian Somers       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
7749780ef31SBrian Somers       if (OpenModem() < 0) {
7750706ff38SBrian Somers 	tries++;
776712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
7770706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
7780706ff38SBrian Somers 		    tries, VarDialTries);
7790706ff38SBrian Somers 	else
7800706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
7810706ff38SBrian Somers 
782712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
7830706ff38SBrian Somers 	  if (mode & MODE_BACKGROUND)
7840706ff38SBrian Somers 	    Cleanup(EX_DIAL);	/* Can't get the modem */
78575240ed1SBrian Somers 	  dial_up = 0;
7860706ff38SBrian Somers 	  reconnectState = RECON_UNKNOWN;
7870706ff38SBrian Somers 	  reconnectCount = 0;
7880706ff38SBrian Somers 	  tries = 0;
7890706ff38SBrian Somers 	} else
79043ea9d19SBrian Somers 	  StartRedialTimer(VarRedialTimeout);
79184b8a6ebSAtsushi Murai       } else {
792944f7098SBrian Somers 	tries++;		/* Tries are per number, not per list of
793944f7098SBrian Somers 				 * numbers. */
794712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
795712ae387SBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
796c0139fb2SBrian Somers 	else
797927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
798712ae387SBrian Somers 
799368aee2bSBrian Somers 	if ((res = DialModem()) == EX_DONE) {
8009a571ec7SBrian Somers 	  nointr_sleep(1);		/* little pause to allow peer starts */
80184b8a6ebSAtsushi Murai 	  ModemTimeout();
80284b8a6ebSAtsushi Murai 	  PacketMode();
80375240ed1SBrian Somers 	  dial_up = 0;
80425aa96acSBrian Somers 	  reconnectState = RECON_UNKNOWN;
805a9c6b5dfSAtsushi Murai 	  tries = 0;
80684b8a6ebSAtsushi Murai 	} else {
8074ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
808368aee2bSBrian Somers 	    if (VarNextPhone == NULL || res == EX_SIG)
8094ed9958fSBrian Somers 	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
8104ed9958fSBrian Somers 	    else
81143ea9d19SBrian Somers 	      /* Try all numbers in background mode */
81243ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
813368aee2bSBrian Somers 	  } else if (!(mode & MODE_DDIAL) &&
814368aee2bSBrian Somers 		     ((VarDialTries && tries >= VarDialTries) ||
815368aee2bSBrian Somers 		      res == EX_SIG)) {
816c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
81743ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
81875240ed1SBrian Somers 	    dial_up = 0;
81925aa96acSBrian Somers 	    reconnectState = RECON_UNKNOWN;
82025aa96acSBrian Somers 	    reconnectCount = 0;
821a9c6b5dfSAtsushi Murai 	    tries = 0;
822c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
823c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
82443ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
825c0139fb2SBrian Somers 	  else
82643ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
82784b8a6ebSAtsushi Murai 	}
82884b8a6ebSAtsushi Murai       }
82984b8a6ebSAtsushi Murai     }
83060e218e4SAtsushi Murai     qlen = ModemQlen();
83176bd0c0aSDoug Rabson 
83276bd0c0aSDoug Rabson     if (qlen == 0) {
83376bd0c0aSDoug Rabson       IpStartOutput();
83476bd0c0aSDoug Rabson       qlen = ModemQlen();
83576bd0c0aSDoug Rabson     }
836780700e5SAndrey A. Chernov     if (modem >= 0) {
837780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
838780700e5SAndrey A. Chernov 	nfds = modem + 1;
83984b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
84084b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
84160e218e4SAtsushi Murai       if (qlen > 0) {
84284b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
84384b8a6ebSAtsushi Murai       }
84484b8a6ebSAtsushi Murai     }
845780700e5SAndrey A. Chernov     if (server >= 0) {
846780700e5SAndrey A. Chernov       if (server + 1 > nfds)
847780700e5SAndrey A. Chernov 	nfds = server + 1;
848780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
849780700e5SAndrey A. Chernov     }
850af57ed9fSAtsushi Murai 
851944f7098SBrian Somers     /*
852944f7098SBrian Somers      * *** IMPORTANT ***
853af57ed9fSAtsushi Murai      *
854944f7098SBrian Somers      * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
855944f7098SBrian Somers      * with great care. If this values is too big, it results loss of
856944f7098SBrian Somers      * characters from modem and poor responce. If this values is too small,
857944f7098SBrian Somers      * ppp process eats many CPU time.
858af57ed9fSAtsushi Murai      */
85953c9f6c0SAtsushi Murai #ifndef SIGALRM
8609a571ec7SBrian Somers     nointr_usleep(TICKUNIT);
861af57ed9fSAtsushi Murai     TimerService();
862f5ff0f7cSBrian Somers #else
863f5ff0f7cSBrian Somers     handle_signals();
86453c9f6c0SAtsushi Murai #endif
86568d2b4d6SBruce Evans 
86668d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
867780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
868780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
869780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
87084b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
871780700e5SAndrey A. Chernov     }
872780700e5SAndrey A. Chernov     if (netfd >= 0) {
873780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
874780700e5SAndrey A. Chernov 	nfds = netfd + 1;
875af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
876af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
877af57ed9fSAtsushi Murai     }
87853c9f6c0SAtsushi Murai #ifndef SIGALRM
879944f7098SBrian Somers 
880af57ed9fSAtsushi Murai     /*
881944f7098SBrian Somers      * Normally, select() will not block because modem is writable. In AUTO
882944f7098SBrian Somers      * mode, select will block until we find packet from tun
883af57ed9fSAtsushi Murai      */
884af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
885780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
88653c9f6c0SAtsushi Murai #else
887944f7098SBrian Somers 
88884b8a6ebSAtsushi Murai     /*
889944f7098SBrian Somers      * When SIGALRM timer is running, a select function will be return -1 and
890944f7098SBrian Somers      * EINTR after a Time Service signal hundler is done.  If the redial
891944f7098SBrian Somers      * timer is not running and we are trying to dial, poll with a 0 value
892944f7098SBrian Somers      * timer.
89384b8a6ebSAtsushi Murai      */
894a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
895780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
89653c9f6c0SAtsushi Murai #endif
8976b0b88d8SBrian Somers 
898af57ed9fSAtsushi Murai     if (i == 0) {
899af57ed9fSAtsushi Murai       continue;
900af57ed9fSAtsushi Murai     }
901534fe541SBrian Somers     if (i < 0) {
902534fe541SBrian Somers       if (errno == EINTR) {
903f5ff0f7cSBrian Somers 	handle_signals();
904f5ff0f7cSBrian Somers 	continue;
90584b8a6ebSAtsushi Murai       }
906afc7fa2cSBrian Somers       LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
907af57ed9fSAtsushi Murai       break;
908af57ed9fSAtsushi Murai     }
909780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
910927145beSBrian Somers       LogPrintf(LogALERT, "Exception detected.\n");
911af57ed9fSAtsushi Murai       break;
912af57ed9fSAtsushi Murai     }
913780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
914927145beSBrian Somers       LogPrintf(LogPHASE, "connected to client.\n");
915af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
916e0d3e233SAndrey A. Chernov       if (wfd < 0) {
917afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
918e0d3e233SAndrey A. Chernov 	continue;
919e0d3e233SAndrey A. Chernov       }
920780700e5SAndrey A. Chernov       if (netfd >= 0) {
921af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
922af57ed9fSAtsushi Murai 	close(wfd);
923af57ed9fSAtsushi Murai 	continue;
924af57ed9fSAtsushi Murai       } else
925af57ed9fSAtsushi Murai 	netfd = wfd;
926927145beSBrian Somers       VarTerm = fdopen(netfd, "a+");
927af57ed9fSAtsushi Murai       mode |= MODE_INTER;
928af57ed9fSAtsushi Murai       Greetings();
929a1e8f937SBrian Somers       IsInteractive(1);
930274e766cSBrian Somers       Prompt();
931af57ed9fSAtsushi Murai     }
932780700e5SAndrey A. Chernov     if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
933f1884650SAtsushi Murai 	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
934af57ed9fSAtsushi Murai       /* something to read from tty */
935af57ed9fSAtsushi Murai       ReadTty();
936af57ed9fSAtsushi Murai     }
937780700e5SAndrey A. Chernov     if (modem >= 0) {
938af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
939af57ed9fSAtsushi Murai 	ModemStartOutput(modem);
940af57ed9fSAtsushi Murai       }
941af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
94253c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
9439a571ec7SBrian Somers 	  nointr_usleep(10000);
944af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
945af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
946af57ed9fSAtsushi Murai 	  DownConnection();
947af57ed9fSAtsushi Murai 	} else
948927145beSBrian Somers 	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
949af57ed9fSAtsushi Murai 
950af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
951944f7098SBrian Somers 
952af57ed9fSAtsushi Murai 	  /*
953af57ed9fSAtsushi Murai 	   * In dedicated mode, we just discard input until LCP is started.
954af57ed9fSAtsushi Murai 	   */
955af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
956af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
957af57ed9fSAtsushi Murai 	    if (cp) {
958944f7098SBrian Somers 
959af57ed9fSAtsushi Murai 	      /*
960af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
961af57ed9fSAtsushi Murai 	       */
962af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
963927145beSBrian Somers 		write(modem, rbuff, cp - rbuff);
964927145beSBrian Somers 		write(modem, "\r\n", 2);
965af57ed9fSAtsushi Murai 	      }
966af57ed9fSAtsushi Murai 	      PacketMode();
967af57ed9fSAtsushi Murai 	    } else
968927145beSBrian Somers 	      write(fileno(VarTerm), rbuff, n);
969af57ed9fSAtsushi Murai 	  }
970af57ed9fSAtsushi Murai 	} else {
971af57ed9fSAtsushi Murai 	  if (n > 0)
972af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
973af57ed9fSAtsushi Murai 	}
974af57ed9fSAtsushi Murai       }
975af57ed9fSAtsushi Murai     }
976944f7098SBrian Somers     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
977944f7098SBrian Somers 							 * from tun */
978af57ed9fSAtsushi Murai       n = read(tun_in, rbuff, sizeof(rbuff));
979af57ed9fSAtsushi Murai       if (n < 0) {
980afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
981af57ed9fSAtsushi Murai 	continue;
982af57ed9fSAtsushi Murai       }
983de451c68SBrian Somers       if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
984de451c68SBrian Somers 	/* we've been asked to send something addressed *to* us :( */
985de451c68SBrian Somers 	if (VarLoopback) {
986de451c68SBrian Somers 	  pri = PacketCheck(rbuff, n, FL_IN);
987de451c68SBrian Somers 	  if (pri >= 0) {
988de451c68SBrian Somers 	    struct mbuf *bp;
989944f7098SBrian Somers 
990de451c68SBrian Somers 	    if (mode & MODE_ALIAS) {
991de451c68SBrian Somers 	      VarPacketAliasIn(rbuff, sizeof rbuff);
992de451c68SBrian Somers 	      n = ntohs(((struct ip *) rbuff)->ip_len);
993de451c68SBrian Somers 	    }
994de451c68SBrian Somers 	    bp = mballoc(n, MB_IPIN);
99575240ed1SBrian Somers 	    memcpy(MBUF_CTOP(bp), rbuff, n);
996de451c68SBrian Somers 	    IpInput(bp);
997de451c68SBrian Somers 	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
998de451c68SBrian Somers 	  }
999de451c68SBrian Somers 	  continue;
1000de451c68SBrian Somers 	} else
1001de451c68SBrian Somers 	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
1002de451c68SBrian Somers       }
1003de451c68SBrian Somers 
1004af57ed9fSAtsushi Murai       /*
1005af57ed9fSAtsushi Murai        * Process on-demand dialup. Output packets are queued within tunnel
1006af57ed9fSAtsushi Murai        * device until IPCP is opened.
1007af57ed9fSAtsushi Murai        */
1008af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
100984b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1010af57ed9fSAtsushi Murai 	if (pri >= 0) {
1011a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10126ed9fb2fSBrian Somers 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1013a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *) rbuff)->ip_len);
1014a9f484e5SJordan K. Hubbard 	  }
1015af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
101675240ed1SBrian Somers 	  dial_up = 1;	/* XXX */
1017af57ed9fSAtsushi Murai 	}
1018af57ed9fSAtsushi Murai 	continue;
1019af57ed9fSAtsushi Murai       }
102084b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1021a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1022a9f484e5SJordan K. Hubbard 	if (mode & MODE_ALIAS) {
10236ed9fb2fSBrian Somers 	  VarPacketAliasOut(rbuff, sizeof rbuff);
1024a9f484e5SJordan K. Hubbard 	  n = ntohs(((struct ip *) rbuff)->ip_len);
1025a9f484e5SJordan K. Hubbard 	}
1026af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1027af57ed9fSAtsushi Murai       }
1028af57ed9fSAtsushi Murai     }
1029a9f484e5SJordan K. Hubbard   }
1030927145beSBrian Somers   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1031af57ed9fSAtsushi Murai }
1032