xref: /freebsd/usr.sbin/ppp/main.c (revision 75240ed1789e0754da5b1024dcb80dcfc5dae0c3)
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  *
2075240ed1SBrian Somers  * $Id: main.c,v 1.84 1997/10/24 22:36:30 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"
5075240ed1SBrian Somers #include "timer.h"
5175240ed1SBrian Somers #include "fsm.h"
52af57ed9fSAtsushi Murai #include "modem.h"
53af57ed9fSAtsushi Murai #include "os.h"
54af57ed9fSAtsushi Murai #include "hdlc.h"
55ed6a16c1SPoul-Henning Kamp #include "ccp.h"
56af57ed9fSAtsushi Murai #include "lcp.h"
57af57ed9fSAtsushi Murai #include "ipcp.h"
586ed9fb2fSBrian Somers #include "loadalias.h"
5975240ed1SBrian Somers #include "command.h"
60af57ed9fSAtsushi Murai #include "vars.h"
6153c9f6c0SAtsushi Murai #include "auth.h"
6284b8a6ebSAtsushi Murai #include "filter.h"
63ed6a16c1SPoul-Henning Kamp #include "systems.h"
64ed6a16c1SPoul-Henning Kamp #include "ip.h"
65f5ff0f7cSBrian Somers #include "sig.h"
664ef16f24SBrian Somers #include "server.h"
67de451c68SBrian Somers #include "lcpproto.h"
6875240ed1SBrian Somers #include "main.h"
6975240ed1SBrian Somers #include "vjcomp.h"
7075240ed1SBrian Somers #include "async.h"
7153c9f6c0SAtsushi Murai 
7253c9f6c0SAtsushi Murai #ifndef O_NONBLOCK
7353c9f6c0SAtsushi Murai #ifdef O_NDELAY
7453c9f6c0SAtsushi Murai #define	O_NONBLOCK O_NDELAY
7553c9f6c0SAtsushi Murai #endif
7653c9f6c0SAtsushi Murai #endif
77af57ed9fSAtsushi Murai 
7875240ed1SBrian Somers int TermMode = 0;
7975240ed1SBrian Somers int tunno = 0;
80af57ed9fSAtsushi Murai 
81af57ed9fSAtsushi Murai static struct termios oldtio;	/* Original tty mode */
82af57ed9fSAtsushi Murai static struct termios comtio;	/* Command level tty mode */
836d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
8441c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
8541c6c543SBrian Somers static char if_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 {
176af57ed9fSAtsushi Murai   OsLinkdown();
177af57ed9fSAtsushi Murai   OsCloseLink(1);
1789a571ec7SBrian Somers   nointr_sleep(1);
1796efd9292SBrian Somers   if (mode & MODE_AUTO)
1806e4959f0SBrian Somers     DeleteIfRoutes(1);
181aefd026aSBrian Somers   (void) unlink(pid_filename);
182aefd026aSBrian Somers   (void) unlink(if_filename);
183af57ed9fSAtsushi Murai   OsInterfaceDown(1);
1846e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1856e4959f0SBrian Somers     char c = EX_ERRDEAD;
186944f7098SBrian Somers 
1876e4959f0SBrian Somers     if (write(BGFiledes[1], &c, 1) == 1)
188927145beSBrian Somers       LogPrintf(LogPHASE, "Parent notified of failure.\n");
1896e4959f0SBrian Somers     else
190927145beSBrian Somers       LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
1916e4959f0SBrian Somers     close(BGFiledes[1]);
1926e4959f0SBrian Somers   }
193927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
194af57ed9fSAtsushi Murai   LogClose();
1954ef16f24SBrian Somers   ServerClose();
196c3899f8dSAtsushi Murai   TtyOldMode();
197af57ed9fSAtsushi Murai 
198af57ed9fSAtsushi Murai   exit(excode);
199af57ed9fSAtsushi Murai }
200af57ed9fSAtsushi Murai 
201af57ed9fSAtsushi Murai static void
202944f7098SBrian Somers CloseConnection(int signo)
203af57ed9fSAtsushi Murai {
204368aee2bSBrian Somers   /* NOTE, these are manual, we've done a setsid() */
205873725ccSBrian Somers   LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
206944f7098SBrian Somers   reconnectState = RECON_FALSE;
207944f7098SBrian Somers   reconnectCount = 0;
208368aee2bSBrian Somers   DownConnection();
20975240ed1SBrian Somers   dial_up = 0;
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 
2474ef16f24SBrian Somers   if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
248683cef3cSBrian Somers     LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
249683cef3cSBrian Somers 	      res, SERVER_PORT + tunno);
2504ef16f24SBrian Somers }
2514ef16f24SBrian Somers 
2526efd9292SBrian Somers static char *
2536efd9292SBrian Somers ex_desc(int ex)
2546efd9292SBrian Somers {
2556efd9292SBrian Somers   static char num[12];
2566efd9292SBrian Somers   static char *desc[] = {"normal", "start", "sock",
2576efd9292SBrian Somers     "modem", "dial", "dead", "done", "reboot", "errdead",
2586efd9292SBrian Somers   "hangup", "term", "nodial", "nologin"};
2596efd9292SBrian Somers 
2606efd9292SBrian Somers   if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
2616efd9292SBrian Somers     return desc[ex];
2626efd9292SBrian Somers   snprintf(num, sizeof num, "%d", ex);
2636efd9292SBrian Somers   return num;
2646efd9292SBrian Somers }
265c3899f8dSAtsushi Murai 
26675240ed1SBrian Somers static void
267af57ed9fSAtsushi Murai Usage()
268af57ed9fSAtsushi Murai {
269680026d6SNate Williams   fprintf(stderr,
2706d14e2a8SJordan K. Hubbard 	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
271af57ed9fSAtsushi Murai   exit(EX_START);
272af57ed9fSAtsushi Murai }
273af57ed9fSAtsushi Murai 
27475240ed1SBrian Somers static void
275af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
276af57ed9fSAtsushi Murai {
277af57ed9fSAtsushi Murai   int optc;
278af57ed9fSAtsushi Murai   char *cp;
279af57ed9fSAtsushi Murai 
280af57ed9fSAtsushi Murai   optc = 0;
281af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
282af57ed9fSAtsushi Murai     cp = *argv + 1;
283af57ed9fSAtsushi Murai     if (strcmp(cp, "auto") == 0)
284af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
2856d14e2a8SJordan K. Hubbard     else if (strcmp(cp, "background") == 0)
2866efd9292SBrian Somers       mode |= MODE_BACKGROUND | MODE_AUTO;
287af57ed9fSAtsushi Murai     else if (strcmp(cp, "direct") == 0)
288af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
289af57ed9fSAtsushi Murai     else if (strcmp(cp, "dedicated") == 0)
290af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
291680026d6SNate Williams     else if (strcmp(cp, "ddial") == 0)
292680026d6SNate Williams       mode |= MODE_DDIAL | MODE_AUTO;
293a9f484e5SJordan K. Hubbard     else if (strcmp(cp, "alias") == 0) {
2946ed9fb2fSBrian Somers       if (loadAliasHandlers(&VarAliasHandlers) == 0)
295a9f484e5SJordan K. Hubbard 	mode |= MODE_ALIAS;
2966ed9fb2fSBrian Somers       else
297927145beSBrian Somers 	LogPrintf(LogWARN, "Cannot load alias library\n");
298a9f484e5SJordan K. Hubbard       optc--;			/* this option isn't exclusive */
299944f7098SBrian Somers     } else
300af57ed9fSAtsushi Murai       Usage();
301af57ed9fSAtsushi Murai     optc++;
302944f7098SBrian Somers     argv++;
303944f7098SBrian Somers     argc--;
304af57ed9fSAtsushi Murai   }
305af57ed9fSAtsushi Murai   if (argc > 1) {
306af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
307af57ed9fSAtsushi Murai     exit(EX_START);
308af57ed9fSAtsushi Murai   }
309944f7098SBrian Somers   if (argc == 1)
310944f7098SBrian Somers     dstsystem = *argv;
311af57ed9fSAtsushi Murai 
312af57ed9fSAtsushi Murai   if (optc > 1) {
313af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
314af57ed9fSAtsushi Murai     exit(EX_START);
315af57ed9fSAtsushi Murai   }
316af57ed9fSAtsushi Murai }
317af57ed9fSAtsushi Murai 
318af57ed9fSAtsushi Murai static void
319af57ed9fSAtsushi Murai Greetings()
320af57ed9fSAtsushi Murai {
321927145beSBrian Somers   if (VarTerm) {
322927145beSBrian Somers     fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
323927145beSBrian Somers     fflush(VarTerm);
324927145beSBrian Somers   }
325af57ed9fSAtsushi Murai }
326af57ed9fSAtsushi Murai 
3274ef16f24SBrian Somers int
328944f7098SBrian Somers main(int argc, char **argv)
329af57ed9fSAtsushi Murai {
330aefd026aSBrian Somers   FILE *lockfile;
331927145beSBrian Somers   char *name;
332af57ed9fSAtsushi Murai 
3330706ff38SBrian Somers   VarTerm = 0;
33475240ed1SBrian Somers   name = strrchr(argv[0], '/');
335927145beSBrian Somers   LogOpen(name ? name + 1 : argv[0]);
336927145beSBrian Somers 
337944f7098SBrian Somers   argc--;
338944f7098SBrian Somers   argv++;
339af57ed9fSAtsushi Murai   ProcessArgs(argc, argv);
340683cef3cSBrian Somers   if (!(mode & MODE_DIRECT)) {
341683cef3cSBrian Somers     if (getuid() != 0) {
342683cef3cSBrian Somers       fprintf(stderr, "You may only run ppp in client mode as user id 0\n");
343683cef3cSBrian Somers       LogClose();
344683cef3cSBrian Somers       return EX_NOPERM;
345683cef3cSBrian Somers     }
3460706ff38SBrian Somers     VarTerm = stdout;
347683cef3cSBrian Somers   }
348af57ed9fSAtsushi Murai   Greetings();
349af57ed9fSAtsushi Murai   GetUid();
350af57ed9fSAtsushi Murai   IpcpDefAddress();
351683cef3cSBrian Somers   LocalAuthInit();
352af57ed9fSAtsushi Murai 
353927145beSBrian Somers   if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
354927145beSBrian Somers     fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
355af57ed9fSAtsushi Murai 
356af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
3574ef16f24SBrian Somers     LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
3584ef16f24SBrian Somers     return EX_START;
359af57ed9fSAtsushi Murai   }
3606efd9292SBrian Somers   if (mode & (MODE_AUTO | MODE_DIRECT | MODE_DEDICATED))
361af57ed9fSAtsushi Murai     mode &= ~MODE_INTER;
362af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
363927145beSBrian Somers     fprintf(VarTerm, "Interactive mode\n");
364cc39a98fSBrian Somers     netfd = STDOUT_FILENO;
365af57ed9fSAtsushi Murai   } else if (mode & MODE_AUTO) {
366927145beSBrian Somers     fprintf(VarTerm, "Automatic Dialer mode\n");
367af57ed9fSAtsushi Murai     if (dstsystem == NULL) {
368927145beSBrian Somers       if (VarTerm)
369927145beSBrian Somers 	fprintf(VarTerm, "Destination system must be specified in"
3706efd9292SBrian Somers 		" auto, background or ddial mode.\n");
3714ef16f24SBrian Somers       return EX_START;
3726d14e2a8SJordan K. Hubbard     }
373af57ed9fSAtsushi Murai   }
37453c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);	/* Save original tty mode */
375af57ed9fSAtsushi Murai 
376873725ccSBrian Somers   pending_signal(SIGHUP, CloseSession);
377f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
378873725ccSBrian Somers   pending_signal(SIGINT, CloseConnection);
379f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
38053c9f6c0SAtsushi Murai #ifdef SIGPIPE
381e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
38253c9f6c0SAtsushi Murai #endif
38353c9f6c0SAtsushi Murai #ifdef SIGALRM
384f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
38553c9f6c0SAtsushi Murai #endif
3864ef16f24SBrian Somers   if (mode & MODE_INTER) {
387c3899f8dSAtsushi Murai #ifdef SIGTSTP
388f5ff0f7cSBrian Somers     pending_signal(SIGTSTP, TerminalStop);
389c3899f8dSAtsushi Murai #endif
390c3899f8dSAtsushi Murai #ifdef SIGTTIN
391f5ff0f7cSBrian Somers     pending_signal(SIGTTIN, TerminalStop);
392c3899f8dSAtsushi Murai #endif
393c3899f8dSAtsushi Murai #ifdef SIGTTOU
394f5ff0f7cSBrian Somers     pending_signal(SIGTTOU, SIG_IGN);
395c3899f8dSAtsushi Murai #endif
396c3899f8dSAtsushi Murai   }
3974ef16f24SBrian Somers #ifdef SIGUSR1
3984ef16f24SBrian Somers   if (mode != MODE_INTER)
3994ef16f24SBrian Somers     pending_signal(SIGUSR1, SetUpServer);
4004ef16f24SBrian Somers #endif
401af57ed9fSAtsushi Murai 
402af57ed9fSAtsushi Murai   if (dstsystem) {
403af57ed9fSAtsushi Murai     if (SelectSystem(dstsystem, CONFFILE) < 0) {
4040706ff38SBrian Somers       LogPrintf(LogWARN, "Destination system not found in conf file.\n");
405af57ed9fSAtsushi Murai       Cleanup(EX_START);
406af57ed9fSAtsushi Murai     }
407af57ed9fSAtsushi Murai     if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
4080706ff38SBrian Somers       LogPrintf(LogWARN, "Must specify dstaddr with"
4096efd9292SBrian Somers 		" auto, background or ddial mode.\n");
410af57ed9fSAtsushi Murai       Cleanup(EX_START);
411af57ed9fSAtsushi Murai     }
412af57ed9fSAtsushi Murai   }
4136efd9292SBrian Somers 
4144ef16f24SBrian Somers   if (!(mode & MODE_INTER)) {
4156d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4166d14e2a8SJordan K. Hubbard       if (pipe(BGFiledes)) {
417afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
4186d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4196d14e2a8SJordan K. Hubbard       }
4206d14e2a8SJordan K. Hubbard     }
42175240ed1SBrian Somers     /* Create server socket and listen (initial value is -2) */
422683cef3cSBrian Somers     if (server == -2)
423683cef3cSBrian Somers       ServerTcpOpen(SERVER_PORT + tunno);
424af57ed9fSAtsushi Murai 
425af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4266d14e2a8SJordan K. Hubbard       pid_t bgpid;
427a9c6b5dfSAtsushi Murai 
4286d14e2a8SJordan K. Hubbard       bgpid = fork();
4296d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
430afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
4316d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4326d14e2a8SJordan K. Hubbard       }
4336d14e2a8SJordan K. Hubbard       if (bgpid) {
4346d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
435a9c6b5dfSAtsushi Murai 
4366d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4376d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4386d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4396e4959f0SBrian Somers 	  close(BGFiledes[1]);
4406efd9292SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1) {
441927145beSBrian Somers 	    fprintf(VarTerm, "Child exit, no status.\n");
442927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
4436efd9292SBrian Somers 	  } else if (c == EX_NORMAL) {
444927145beSBrian Somers 	    fprintf(VarTerm, "PPP enabled.\n");
445927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
4466efd9292SBrian Somers 	  } else {
447927145beSBrian Somers 	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
448927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
44980e37c72SBrian Somers 		      ex_desc((int) c));
4506efd9292SBrian Somers 	  }
4516e4959f0SBrian Somers 	  close(BGFiledes[0]);
4526d14e2a8SJordan K. Hubbard 	}
4534ef16f24SBrian Somers 	return c;
4546e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
4556e4959f0SBrian Somers 	close(BGFiledes[0]);
456aefd026aSBrian Somers     }
457aefd026aSBrian Somers 
458d656a4c5SBrian Somers     VarTerm = 0;		/* We know it's currently stdout */
459fd2bc5ebSBrian Somers     close(1);
460d656a4c5SBrian Somers     close(2);
4610706ff38SBrian Somers 
462af57ed9fSAtsushi Murai #ifdef DOTTYINIT
463d656a4c5SBrian Somers     if (mode & (MODE_DIRECT | MODE_DEDICATED))
464af57ed9fSAtsushi Murai #else
465d656a4c5SBrian Somers     if (mode & MODE_DIRECT)
466af57ed9fSAtsushi Murai #endif
467368aee2bSBrian Somers       TtyInit(1);
468d656a4c5SBrian Somers     else {
469d656a4c5SBrian Somers       setsid();
470fd2bc5ebSBrian Somers       close(0);
471d656a4c5SBrian Somers     }
472af57ed9fSAtsushi Murai   } else {
473368aee2bSBrian Somers     TtyInit(0);
474c3899f8dSAtsushi Murai     TtyCommandMode(1);
475af57ed9fSAtsushi Murai   }
47635495becSBrian Somers 
47735495becSBrian Somers   snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
47835495becSBrian Somers            _PATH_VARRUN, tunno);
47935495becSBrian Somers   (void) unlink(pid_filename);
48035495becSBrian Somers 
48135495becSBrian Somers   if ((lockfile = fopen(pid_filename, "w")) != NULL) {
48235495becSBrian Somers     fprintf(lockfile, "%d\n", (int) getpid());
48335495becSBrian Somers     fclose(lockfile);
48435495becSBrian Somers   } else
48535495becSBrian Somers     LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
48635495becSBrian Somers               pid_filename, strerror(errno));
48735495becSBrian Somers 
488927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Started.\n");
489af57ed9fSAtsushi Murai 
490af57ed9fSAtsushi Murai 
491af57ed9fSAtsushi Murai   do
492af57ed9fSAtsushi Murai     DoLoop();
493af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
494af57ed9fSAtsushi Murai 
495af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
4964ef16f24SBrian Somers   return 0;
497af57ed9fSAtsushi Murai }
498af57ed9fSAtsushi Murai 
499af57ed9fSAtsushi Murai /*
5006d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
501af57ed9fSAtsushi Murai  */
502af57ed9fSAtsushi Murai void
503af57ed9fSAtsushi Murai PacketMode()
504af57ed9fSAtsushi Murai {
505af57ed9fSAtsushi Murai   if (RawModem(modem) < 0) {
506927145beSBrian Somers     LogPrintf(LogWARN, "PacketMode: Not connected.\n");
507af57ed9fSAtsushi Murai     return;
508af57ed9fSAtsushi Murai   }
509af57ed9fSAtsushi Murai   AsyncInit();
51003604f35SBrian Somers   VjInit(15);
511af57ed9fSAtsushi Murai   LcpInit();
512af57ed9fSAtsushi Murai   IpcpInit();
513af57ed9fSAtsushi Murai   CcpInit();
514af57ed9fSAtsushi Murai   LcpUp();
515af57ed9fSAtsushi Murai 
516af57ed9fSAtsushi Murai   LcpOpen(VarOpenMode);
517af57ed9fSAtsushi Murai   if ((mode & (MODE_INTER | MODE_AUTO)) == MODE_INTER) {
518c3899f8dSAtsushi Murai     TtyCommandMode(1);
519927145beSBrian Somers     if (VarTerm) {
520927145beSBrian Somers       fprintf(VarTerm, "Packet mode.\n");
521b0cdb3ceSJordan K. Hubbard       aft_cmd = 1;
522af57ed9fSAtsushi Murai     }
523af57ed9fSAtsushi Murai   }
524927145beSBrian Somers }
525af57ed9fSAtsushi Murai 
526af57ed9fSAtsushi Murai static void
527af57ed9fSAtsushi Murai ShowHelp()
528af57ed9fSAtsushi Murai {
529030d3ce6SBrian Somers   fprintf(stderr, "The following commands are available:\r\n");
530030d3ce6SBrian Somers   fprintf(stderr, " ~p\tEnter Packet mode\r\n");
531030d3ce6SBrian Somers   fprintf(stderr, " ~-\tDecrease log level\r\n");
532030d3ce6SBrian Somers   fprintf(stderr, " ~+\tIncrease log level\r\n");
533030d3ce6SBrian Somers   fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
534030d3ce6SBrian Somers   fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
535030d3ce6SBrian Somers   fprintf(stderr, " ~.\tTerminate program\r\n");
536030d3ce6SBrian Somers   fprintf(stderr, " ~?\tThis help\r\n");
537af57ed9fSAtsushi Murai }
538af57ed9fSAtsushi Murai 
539af57ed9fSAtsushi Murai static void
540af57ed9fSAtsushi Murai ReadTty()
541af57ed9fSAtsushi Murai {
542af57ed9fSAtsushi Murai   int n;
543af57ed9fSAtsushi Murai   char ch;
544af57ed9fSAtsushi Murai   static int ttystate;
545927145beSBrian Somers   FILE *oVarTerm;
546944f7098SBrian Somers 
547af57ed9fSAtsushi Murai #define MAXLINESIZE 200
548af57ed9fSAtsushi Murai   char linebuff[MAXLINESIZE];
549af57ed9fSAtsushi Murai 
550927145beSBrian Somers   LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
551927145beSBrian Somers 	    TermMode, netfd, mode);
552af57ed9fSAtsushi Murai   if (!TermMode) {
553af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff) - 1);
55453c9f6c0SAtsushi Murai     if (n > 0) {
555927145beSBrian Somers       aft_cmd = 1;
556331953abSBrian Somers       linebuff[n] = '\0';
557331953abSBrian Somers       LogPrintf(LogCOMMAND, "Client: %s\n", linebuff);
558af57ed9fSAtsushi Murai       DecodeCommand(linebuff, n, 1);
55953c9f6c0SAtsushi Murai     } else {
560927145beSBrian Somers       LogPrintf(LogPHASE, "client connection closed.\n");
561e0d3e233SAndrey A. Chernov       VarLocalAuth = LOCAL_NO_AUTH;
562af57ed9fSAtsushi Murai       mode &= ~MODE_INTER;
563927145beSBrian Somers       oVarTerm = VarTerm;
564927145beSBrian Somers       VarTerm = 0;
565927145beSBrian Somers       if (oVarTerm && oVarTerm != stdout)
566927145beSBrian Somers 	fclose(oVarTerm);
567927145beSBrian Somers       close(netfd);
568927145beSBrian Somers       netfd = -1;
569af57ed9fSAtsushi Murai     }
570af57ed9fSAtsushi Murai     return;
571af57ed9fSAtsushi Murai   }
572af57ed9fSAtsushi Murai 
573af57ed9fSAtsushi Murai   /*
574af57ed9fSAtsushi Murai    * We are in terminal mode, decode special sequences
575af57ed9fSAtsushi Murai    */
576927145beSBrian Somers   n = read(fileno(VarTerm), &ch, 1);
577afc7fa2cSBrian Somers   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
578af57ed9fSAtsushi Murai 
579af57ed9fSAtsushi Murai   if (n > 0) {
580af57ed9fSAtsushi Murai     switch (ttystate) {
581af57ed9fSAtsushi Murai     case 0:
582af57ed9fSAtsushi Murai       if (ch == '~')
583af57ed9fSAtsushi Murai 	ttystate++;
584af57ed9fSAtsushi Murai       else
585af57ed9fSAtsushi Murai 	write(modem, &ch, n);
586af57ed9fSAtsushi Murai       break;
587af57ed9fSAtsushi Murai     case 1:
588af57ed9fSAtsushi Murai       switch (ch) {
589af57ed9fSAtsushi Murai       case '?':
590af57ed9fSAtsushi Murai 	ShowHelp();
591af57ed9fSAtsushi Murai 	break;
592af57ed9fSAtsushi Murai       case 'p':
593944f7098SBrian Somers 
594af57ed9fSAtsushi Murai 	/*
595af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
596af57ed9fSAtsushi Murai 	 */
597af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
598af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
599af57ed9fSAtsushi Murai 	  PacketMode();
600af57ed9fSAtsushi Murai 	}
601af57ed9fSAtsushi Murai 	break;
602af57ed9fSAtsushi Murai       case '.':
603af57ed9fSAtsushi Murai 	TermMode = 1;
604927145beSBrian Somers 	aft_cmd = 1;
605c3899f8dSAtsushi Murai 	TtyCommandMode(1);
606af57ed9fSAtsushi Murai 	break;
607927145beSBrian Somers       case 't':
608927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
609927145beSBrian Somers 	  ShowTimers();
610927145beSBrian Somers 	  break;
611927145beSBrian Somers 	}
612927145beSBrian Somers       case 'm':
613927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
614927145beSBrian Somers 	  ShowMemMap();
615927145beSBrian Somers 	  break;
616927145beSBrian Somers 	}
617af57ed9fSAtsushi Murai       default:
618af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
619927145beSBrian Somers 	  LogPrintf(LogERROR, "error writing to modem.\n");
620af57ed9fSAtsushi Murai 	break;
621af57ed9fSAtsushi Murai       }
622af57ed9fSAtsushi Murai       ttystate = 0;
623af57ed9fSAtsushi Murai       break;
624af57ed9fSAtsushi Murai     }
625af57ed9fSAtsushi Murai   }
626af57ed9fSAtsushi Murai }
627af57ed9fSAtsushi Murai 
628af57ed9fSAtsushi Murai 
629af57ed9fSAtsushi Murai /*
630af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
631af57ed9fSAtsushi Murai  */
632af57ed9fSAtsushi Murai 
633af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
63453c9f6c0SAtsushi Murai   "\176\377\003\300\041",
63553c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
63653c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
63753c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
63853c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
639af57ed9fSAtsushi Murai   NULL,
640af57ed9fSAtsushi Murai };
641af57ed9fSAtsushi Murai 
64275240ed1SBrian Somers static u_char *
643944f7098SBrian Somers HdlcDetect(u_char * cp, int n)
644af57ed9fSAtsushi Murai {
64553c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
646af57ed9fSAtsushi Murai 
647af57ed9fSAtsushi Murai   cp[n] = '\0';			/* be sure to null terminated */
648af57ed9fSAtsushi Murai   ptr = NULL;
649af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
65053c9f6c0SAtsushi Murai     fp = *hp;
65153c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
65253c9f6c0SAtsushi Murai       fp++;
653ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *) cp, fp);
654ed6a16c1SPoul-Henning Kamp     if (ptr)
655af57ed9fSAtsushi Murai       break;
656af57ed9fSAtsushi Murai   }
657af57ed9fSAtsushi Murai   return ((u_char *) ptr);
658af57ed9fSAtsushi Murai }
659af57ed9fSAtsushi Murai 
660af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
661af57ed9fSAtsushi Murai 
662af57ed9fSAtsushi Murai static void
663af57ed9fSAtsushi Murai RedialTimeout()
664af57ed9fSAtsushi Murai {
665af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
666927145beSBrian Somers   LogPrintf(LogPHASE, "Redialing timer expired.\n");
667af57ed9fSAtsushi Murai }
668af57ed9fSAtsushi Murai 
669af57ed9fSAtsushi Murai static void
670944f7098SBrian Somers StartRedialTimer(int Timeout)
671af57ed9fSAtsushi Murai {
672af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
673a9c6b5dfSAtsushi Murai 
67443ea9d19SBrian Somers   if (Timeout) {
675af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
676a9c6b5dfSAtsushi Murai 
67743ea9d19SBrian Somers     if (Timeout > 0)
67843ea9d19SBrian Somers       RedialTimer.load = Timeout * SECTICKS;
679a9c6b5dfSAtsushi Murai     else
680a9c6b5dfSAtsushi Murai       RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
681a9c6b5dfSAtsushi Murai 
682927145beSBrian Somers     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
68343ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
68443ea9d19SBrian Somers 
685af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
686af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
687af57ed9fSAtsushi Murai   }
688a9c6b5dfSAtsushi Murai }
689af57ed9fSAtsushi Murai 
690af57ed9fSAtsushi Murai 
691af57ed9fSAtsushi Murai static void
692af57ed9fSAtsushi Murai DoLoop()
693af57ed9fSAtsushi Murai {
694af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
695780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
696af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
697af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
698af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
699af57ed9fSAtsushi Murai   u_char *cp;
700af57ed9fSAtsushi Murai   u_char rbuff[MAX_MRU];
701a9c6b5dfSAtsushi Murai   int tries;
70260e218e4SAtsushi Murai   int qlen;
703368aee2bSBrian Somers   int res;
704c3899f8dSAtsushi Murai   pid_t pgroup;
705c3899f8dSAtsushi Murai 
706c3899f8dSAtsushi Murai   pgroup = getpgrp();
707af57ed9fSAtsushi Murai 
7086efd9292SBrian Somers   if (mode & MODE_DIRECT) {
7090706ff38SBrian Somers     LogPrintf(LogDEBUG, "Opening modem\n");
710bc240299SBrian Somers     if (OpenModem(mode) < 0)
711bc240299SBrian Somers       return;
712927145beSBrian Somers     LogPrintf(LogPHASE, "Packet mode enabled\n");
713af57ed9fSAtsushi Murai     PacketMode();
714af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
715780700e5SAndrey A. Chernov     if (modem < 0)
716bc240299SBrian Somers       while (OpenModem(mode) < 0)
7179a571ec7SBrian Somers 	nointr_sleep(VarReconnectTimer);
718af57ed9fSAtsushi Murai   }
719927145beSBrian Somers   fflush(VarTerm);
720af57ed9fSAtsushi Murai 
72184b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
722af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
72325aa96acSBrian Somers   reconnectState = RECON_UNKNOWN;
724af57ed9fSAtsushi Murai 
7256e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
72675240ed1SBrian Somers     dial_up = 1;		/* Bring the line up */
7276e4959f0SBrian Somers   else
72875240ed1SBrian Somers     dial_up = 0;		/* XXXX */
729a9c6b5dfSAtsushi Murai   tries = 0;
730af57ed9fSAtsushi Murai   for (;;) {
731780700e5SAndrey A. Chernov     nfds = 0;
732944f7098SBrian Somers     FD_ZERO(&rfds);
733944f7098SBrian Somers     FD_ZERO(&wfds);
734944f7098SBrian Somers     FD_ZERO(&efds);
73584b8a6ebSAtsushi Murai 
73684b8a6ebSAtsushi Murai     /*
737944f7098SBrian Somers      * If the link is down and we're in DDIAL mode, bring it back up.
738680026d6SNate Williams      */
739680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
74075240ed1SBrian Somers       dial_up = 1;
741680026d6SNate Williams 
742680026d6SNate Williams     /*
743944f7098SBrian Somers      * If we lost carrier and want to re-establish the connection due to the
744944f7098SBrian Somers      * "set reconnect" value, we'd better bring the line back up.
74507030d97SBrian Somers      */
7466efd9292SBrian Somers     if (LcpFsm.state <= ST_CLOSED) {
74775240ed1SBrian Somers       if (!dial_up && reconnectState == RECON_TRUE) {
7486efd9292SBrian Somers 	if (++reconnectCount <= VarReconnectTries) {
749927145beSBrian Somers 	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
7506efd9292SBrian Somers 		    reconnectCount, VarReconnectTries);
75107030d97SBrian Somers 	  StartRedialTimer(VarReconnectTimer);
75275240ed1SBrian Somers 	  dial_up = 1;
753298091daSBrian Somers 	} else {
7546efd9292SBrian Somers 	  if (VarReconnectTries)
755927145beSBrian Somers 	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
756298091daSBrian Somers 		      VarReconnectTries);
7576efd9292SBrian Somers 	  reconnectCount = 0;
7586efd9292SBrian Somers 	  if (mode & MODE_BACKGROUND)
7596efd9292SBrian Somers 	    Cleanup(EX_DEAD);
7606efd9292SBrian Somers 	}
76125aa96acSBrian Somers 	reconnectState = RECON_ENVOKED;
7626efd9292SBrian Somers       }
76307030d97SBrian Somers     }
76407030d97SBrian Somers 
76507030d97SBrian Somers     /*
766944f7098SBrian Somers      * If Ip packet for output is enqueued and require dial up, Just do it!
76784b8a6ebSAtsushi Murai      */
76807030d97SBrian Somers     if (dial_up && RedialTimer.state != TIMER_RUNNING) {
769927145beSBrian Somers       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
770bc240299SBrian Somers       if (OpenModem(mode) < 0) {
7710706ff38SBrian Somers 	tries++;
772712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
7730706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
7740706ff38SBrian Somers 		    tries, VarDialTries);
7750706ff38SBrian Somers 	else
7760706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
7770706ff38SBrian Somers 
778712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
7790706ff38SBrian Somers 	  if (mode & MODE_BACKGROUND)
7800706ff38SBrian Somers 	    Cleanup(EX_DIAL);	/* Can't get the modem */
78175240ed1SBrian Somers 	  dial_up = 0;
7820706ff38SBrian Somers 	  reconnectState = RECON_UNKNOWN;
7830706ff38SBrian Somers 	  reconnectCount = 0;
7840706ff38SBrian Somers 	  tries = 0;
7850706ff38SBrian Somers 	} else
78643ea9d19SBrian Somers 	  StartRedialTimer(VarRedialTimeout);
78784b8a6ebSAtsushi Murai       } else {
788944f7098SBrian Somers 	tries++;		/* Tries are per number, not per list of
789944f7098SBrian Somers 				 * numbers. */
790712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
791712ae387SBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
792c0139fb2SBrian Somers 	else
793927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
794712ae387SBrian Somers 
795368aee2bSBrian Somers 	if ((res = DialModem()) == EX_DONE) {
7969a571ec7SBrian Somers 	  nointr_sleep(1);		/* little pause to allow peer starts */
79784b8a6ebSAtsushi Murai 	  ModemTimeout();
79884b8a6ebSAtsushi Murai 	  PacketMode();
79975240ed1SBrian Somers 	  dial_up = 0;
80025aa96acSBrian Somers 	  reconnectState = RECON_UNKNOWN;
801a9c6b5dfSAtsushi Murai 	  tries = 0;
80284b8a6ebSAtsushi Murai 	} else {
80384b8a6ebSAtsushi Murai 	  CloseModem();
8044ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
805368aee2bSBrian Somers 	    if (VarNextPhone == NULL || res == EX_SIG)
8064ed9958fSBrian Somers 	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
8074ed9958fSBrian Somers 	    else
80843ea9d19SBrian Somers 	      /* Try all numbers in background mode */
80943ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
810368aee2bSBrian Somers 	  } else if (!(mode & MODE_DDIAL) &&
811368aee2bSBrian Somers 		     ((VarDialTries && tries >= VarDialTries) ||
812368aee2bSBrian Somers 		      res == EX_SIG)) {
813c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
81443ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
81575240ed1SBrian Somers 	    dial_up = 0;
81625aa96acSBrian Somers 	    reconnectState = RECON_UNKNOWN;
81725aa96acSBrian Somers 	    reconnectCount = 0;
818a9c6b5dfSAtsushi Murai 	    tries = 0;
819c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
820c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
82143ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
822c0139fb2SBrian Somers 	  else
82343ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
82484b8a6ebSAtsushi Murai 	}
82584b8a6ebSAtsushi Murai       }
82684b8a6ebSAtsushi Murai     }
82760e218e4SAtsushi Murai     qlen = ModemQlen();
82876bd0c0aSDoug Rabson 
82976bd0c0aSDoug Rabson     if (qlen == 0) {
83076bd0c0aSDoug Rabson       IpStartOutput();
83176bd0c0aSDoug Rabson       qlen = ModemQlen();
83276bd0c0aSDoug Rabson     }
833780700e5SAndrey A. Chernov     if (modem >= 0) {
834780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
835780700e5SAndrey A. Chernov 	nfds = modem + 1;
83684b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
83784b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
83860e218e4SAtsushi Murai       if (qlen > 0) {
83984b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
84084b8a6ebSAtsushi Murai       }
84184b8a6ebSAtsushi Murai     }
842780700e5SAndrey A. Chernov     if (server >= 0) {
843780700e5SAndrey A. Chernov       if (server + 1 > nfds)
844780700e5SAndrey A. Chernov 	nfds = server + 1;
845780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
846780700e5SAndrey A. Chernov     }
847af57ed9fSAtsushi Murai 
848944f7098SBrian Somers     /*
849944f7098SBrian Somers      * *** IMPORTANT ***
850af57ed9fSAtsushi Murai      *
851944f7098SBrian Somers      * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
852944f7098SBrian Somers      * with great care. If this values is too big, it results loss of
853944f7098SBrian Somers      * characters from modem and poor responce. If this values is too small,
854944f7098SBrian Somers      * ppp process eats many CPU time.
855af57ed9fSAtsushi Murai      */
85653c9f6c0SAtsushi Murai #ifndef SIGALRM
8579a571ec7SBrian Somers     nointr_usleep(TICKUNIT);
858af57ed9fSAtsushi Murai     TimerService();
859f5ff0f7cSBrian Somers #else
860f5ff0f7cSBrian Somers     handle_signals();
86153c9f6c0SAtsushi Murai #endif
86268d2b4d6SBruce Evans 
86368d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
864780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
865780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
866780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
86784b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
868780700e5SAndrey A. Chernov     }
869780700e5SAndrey A. Chernov     if (netfd >= 0) {
870780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
871780700e5SAndrey A. Chernov 	nfds = netfd + 1;
872af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
873af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
874af57ed9fSAtsushi Murai     }
87553c9f6c0SAtsushi Murai #ifndef SIGALRM
876944f7098SBrian Somers 
877af57ed9fSAtsushi Murai     /*
878944f7098SBrian Somers      * Normally, select() will not block because modem is writable. In AUTO
879944f7098SBrian Somers      * mode, select will block until we find packet from tun
880af57ed9fSAtsushi Murai      */
881af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
882780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
88353c9f6c0SAtsushi Murai #else
884944f7098SBrian Somers 
88584b8a6ebSAtsushi Murai     /*
886944f7098SBrian Somers      * When SIGALRM timer is running, a select function will be return -1 and
887944f7098SBrian Somers      * EINTR after a Time Service signal hundler is done.  If the redial
888944f7098SBrian Somers      * timer is not running and we are trying to dial, poll with a 0 value
889944f7098SBrian Somers      * timer.
89084b8a6ebSAtsushi Murai      */
891a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
892780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
89353c9f6c0SAtsushi Murai #endif
8946b0b88d8SBrian Somers 
895af57ed9fSAtsushi Murai     if (i == 0) {
896af57ed9fSAtsushi Murai       continue;
897af57ed9fSAtsushi Murai     }
898534fe541SBrian Somers     if (i < 0) {
899534fe541SBrian Somers       if (errno == EINTR) {
900f5ff0f7cSBrian Somers 	handle_signals();
901f5ff0f7cSBrian Somers 	continue;
90284b8a6ebSAtsushi Murai       }
903afc7fa2cSBrian Somers       LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
904af57ed9fSAtsushi Murai       break;
905af57ed9fSAtsushi Murai     }
906780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
907927145beSBrian Somers       LogPrintf(LogALERT, "Exception detected.\n");
908af57ed9fSAtsushi Murai       break;
909af57ed9fSAtsushi Murai     }
910780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
911927145beSBrian Somers       LogPrintf(LogPHASE, "connected to client.\n");
912af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
913e0d3e233SAndrey A. Chernov       if (wfd < 0) {
914afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
915e0d3e233SAndrey A. Chernov 	continue;
916e0d3e233SAndrey A. Chernov       }
917780700e5SAndrey A. Chernov       if (netfd >= 0) {
918af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
919af57ed9fSAtsushi Murai 	close(wfd);
920af57ed9fSAtsushi Murai 	continue;
921af57ed9fSAtsushi Murai       } else
922af57ed9fSAtsushi Murai 	netfd = wfd;
923927145beSBrian Somers       VarTerm = fdopen(netfd, "a+");
924af57ed9fSAtsushi Murai       mode |= MODE_INTER;
925af57ed9fSAtsushi Murai       Greetings();
926af57ed9fSAtsushi Murai       (void) IsInteractive();
927274e766cSBrian Somers       Prompt();
928af57ed9fSAtsushi Murai     }
929780700e5SAndrey A. Chernov     if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
930f1884650SAtsushi Murai 	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
931af57ed9fSAtsushi Murai       /* something to read from tty */
932af57ed9fSAtsushi Murai       ReadTty();
933af57ed9fSAtsushi Murai     }
934780700e5SAndrey A. Chernov     if (modem >= 0) {
935af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
936af57ed9fSAtsushi Murai 	ModemStartOutput(modem);
937af57ed9fSAtsushi Murai       }
938af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
93953c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
9409a571ec7SBrian Somers 	  nointr_usleep(10000);
941af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
942af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
943af57ed9fSAtsushi Murai 	  DownConnection();
944af57ed9fSAtsushi Murai 	} else
945927145beSBrian Somers 	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
946af57ed9fSAtsushi Murai 
947af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
948944f7098SBrian Somers 
949af57ed9fSAtsushi Murai 	  /*
950af57ed9fSAtsushi Murai 	   * In dedicated mode, we just discard input until LCP is started.
951af57ed9fSAtsushi Murai 	   */
952af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
953af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
954af57ed9fSAtsushi Murai 	    if (cp) {
955944f7098SBrian Somers 
956af57ed9fSAtsushi Murai 	      /*
957af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
958af57ed9fSAtsushi Murai 	       */
959af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
960927145beSBrian Somers 		write(modem, rbuff, cp - rbuff);
961927145beSBrian Somers 		write(modem, "\r\n", 2);
962af57ed9fSAtsushi Murai 	      }
963af57ed9fSAtsushi Murai 	      PacketMode();
964af57ed9fSAtsushi Murai 	    } else
965927145beSBrian Somers 	      write(fileno(VarTerm), rbuff, n);
966af57ed9fSAtsushi Murai 	  }
967af57ed9fSAtsushi Murai 	} else {
968af57ed9fSAtsushi Murai 	  if (n > 0)
969af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
970af57ed9fSAtsushi Murai 	}
971af57ed9fSAtsushi Murai       }
972af57ed9fSAtsushi Murai     }
973944f7098SBrian Somers     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
974944f7098SBrian Somers 							 * from tun */
975af57ed9fSAtsushi Murai       n = read(tun_in, rbuff, sizeof(rbuff));
976af57ed9fSAtsushi Murai       if (n < 0) {
977afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
978af57ed9fSAtsushi Murai 	continue;
979af57ed9fSAtsushi Murai       }
980de451c68SBrian Somers       if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
981de451c68SBrian Somers 	/* we've been asked to send something addressed *to* us :( */
982de451c68SBrian Somers 	if (VarLoopback) {
983de451c68SBrian Somers 	  pri = PacketCheck(rbuff, n, FL_IN);
984de451c68SBrian Somers 	  if (pri >= 0) {
985de451c68SBrian Somers 	    struct mbuf *bp;
986944f7098SBrian Somers 
987de451c68SBrian Somers 	    if (mode & MODE_ALIAS) {
988de451c68SBrian Somers 	      VarPacketAliasIn(rbuff, sizeof rbuff);
989de451c68SBrian Somers 	      n = ntohs(((struct ip *) rbuff)->ip_len);
990de451c68SBrian Somers 	    }
991de451c68SBrian Somers 	    bp = mballoc(n, MB_IPIN);
99275240ed1SBrian Somers 	    memcpy(MBUF_CTOP(bp), rbuff, n);
993de451c68SBrian Somers 	    IpInput(bp);
994de451c68SBrian Somers 	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
995de451c68SBrian Somers 	  }
996de451c68SBrian Somers 	  continue;
997de451c68SBrian Somers 	} else
998de451c68SBrian Somers 	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
999de451c68SBrian Somers       }
1000de451c68SBrian Somers 
1001af57ed9fSAtsushi Murai       /*
1002af57ed9fSAtsushi Murai        * Process on-demand dialup. Output packets are queued within tunnel
1003af57ed9fSAtsushi Murai        * device until IPCP is opened.
1004af57ed9fSAtsushi Murai        */
1005af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
100684b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1007af57ed9fSAtsushi Murai 	if (pri >= 0) {
1008a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10096ed9fb2fSBrian Somers 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1010a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *) rbuff)->ip_len);
1011a9f484e5SJordan K. Hubbard 	  }
1012af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
101375240ed1SBrian Somers 	  dial_up = 1;	/* XXX */
1014af57ed9fSAtsushi Murai 	}
1015af57ed9fSAtsushi Murai 	continue;
1016af57ed9fSAtsushi Murai       }
101784b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1018a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1019a9f484e5SJordan K. Hubbard 	if (mode & MODE_ALIAS) {
10206ed9fb2fSBrian Somers 	  VarPacketAliasOut(rbuff, sizeof rbuff);
1021a9f484e5SJordan K. Hubbard 	  n = ntohs(((struct ip *) rbuff)->ip_len);
1022a9f484e5SJordan K. Hubbard 	}
1023af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1024af57ed9fSAtsushi Murai       }
1025af57ed9fSAtsushi Murai     }
1026a9f484e5SJordan K. Hubbard   }
1027927145beSBrian Somers   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1028af57ed9fSAtsushi Murai }
1029