xref: /freebsd/usr.sbin/ppp/main.c (revision 39f94eddcdf0ea6f060779b9f00080d39eaa0ff3)
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  *
2039f94eddSBrian Somers  * $Id: main.c,v 1.100 1997/11/17 00:42:40 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>
276a6b4bbbSBrian Somers #include <sys/time.h>
286a6b4bbbSBrian Somers #include <sys/select.h>
29af57ed9fSAtsushi Murai #include <sys/socket.h>
3075240ed1SBrian Somers #include <netinet/in.h>
31a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h>
32a9f484e5SJordan K. Hubbard #include <netinet/ip.h>
3375240ed1SBrian Somers #include <arpa/inet.h>
3475240ed1SBrian Somers #include <netdb.h>
356a6b4bbbSBrian Somers #include <net/if.h>
366a6b4bbbSBrian Somers #include <net/if_var.h>
376a6b4bbbSBrian Somers #include <net/if_tun.h>
3875240ed1SBrian Somers 
3975240ed1SBrian Somers #include <errno.h>
4075240ed1SBrian Somers #include <fcntl.h>
4175240ed1SBrian Somers #include <paths.h>
4275240ed1SBrian Somers #include <signal.h>
4375240ed1SBrian Somers #include <stdio.h>
4475240ed1SBrian Somers #include <stdlib.h>
4575240ed1SBrian Somers #include <string.h>
4675240ed1SBrian Somers #include <sys/time.h>
4775240ed1SBrian Somers #include <sys/wait.h>
48683cef3cSBrian Somers #include <sysexits.h>
4975240ed1SBrian Somers #include <termios.h>
5075240ed1SBrian Somers #include <unistd.h>
5175240ed1SBrian Somers 
5275240ed1SBrian Somers #include "mbuf.h"
5375240ed1SBrian Somers #include "log.h"
5475240ed1SBrian Somers #include "defs.h"
555106c671SBrian Somers #include "id.h"
5675240ed1SBrian Somers #include "timer.h"
5775240ed1SBrian Somers #include "fsm.h"
58af57ed9fSAtsushi Murai #include "modem.h"
59af57ed9fSAtsushi Murai #include "os.h"
60af57ed9fSAtsushi Murai #include "hdlc.h"
61ed6a16c1SPoul-Henning Kamp #include "ccp.h"
62af57ed9fSAtsushi Murai #include "lcp.h"
63af57ed9fSAtsushi Murai #include "ipcp.h"
646ed9fb2fSBrian Somers #include "loadalias.h"
6575240ed1SBrian Somers #include "command.h"
66af57ed9fSAtsushi Murai #include "vars.h"
6753c9f6c0SAtsushi Murai #include "auth.h"
6884b8a6ebSAtsushi Murai #include "filter.h"
69ed6a16c1SPoul-Henning Kamp #include "systems.h"
70ed6a16c1SPoul-Henning Kamp #include "ip.h"
71f5ff0f7cSBrian Somers #include "sig.h"
724ef16f24SBrian Somers #include "server.h"
73de451c68SBrian Somers #include "lcpproto.h"
7475240ed1SBrian Somers #include "main.h"
7575240ed1SBrian Somers #include "vjcomp.h"
7675240ed1SBrian Somers #include "async.h"
774562be74SBrian Somers #include "pathnames.h"
786a6b4bbbSBrian Somers #include "tun.h"
7953c9f6c0SAtsushi Murai 
8053c9f6c0SAtsushi Murai #ifndef O_NONBLOCK
8153c9f6c0SAtsushi Murai #ifdef O_NDELAY
8253c9f6c0SAtsushi Murai #define	O_NONBLOCK O_NDELAY
8353c9f6c0SAtsushi Murai #endif
8453c9f6c0SAtsushi Murai #endif
85af57ed9fSAtsushi Murai 
8675240ed1SBrian Somers int TermMode = 0;
8775240ed1SBrian Somers int tunno = 0;
88af57ed9fSAtsushi Murai 
89af57ed9fSAtsushi Murai static struct termios oldtio;	/* Original tty mode */
90af57ed9fSAtsushi Murai static struct termios comtio;	/* Command level tty mode */
916d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
9241c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
9376c5241dSBrian Somers static int dial_up;
94af57ed9fSAtsushi Murai 
9575240ed1SBrian Somers static void DoLoop(void);
9675240ed1SBrian Somers static void TerminalStop(int);
9775240ed1SBrian Somers static char *ex_desc(int);
9875240ed1SBrian Somers 
99af57ed9fSAtsushi Murai static void
100368aee2bSBrian Somers TtyInit(int DontWantInt)
101af57ed9fSAtsushi Murai {
102af57ed9fSAtsushi Murai   struct termios newtio;
103af57ed9fSAtsushi Murai   int stat;
104af57ed9fSAtsushi Murai 
105af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
106274e766cSBrian Somers   if (stat > 0) {
107af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
108274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
109274e766cSBrian Somers   }
110af57ed9fSAtsushi Murai   newtio = oldtio;
111af57ed9fSAtsushi Murai   newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
112af57ed9fSAtsushi Murai   newtio.c_iflag = 0;
113af57ed9fSAtsushi Murai   newtio.c_oflag &= ~OPOST;
114af57ed9fSAtsushi Murai   newtio.c_cc[VEOF] = _POSIX_VDISABLE;
115368aee2bSBrian Somers   if (DontWantInt)
116af57ed9fSAtsushi Murai     newtio.c_cc[VINTR] = _POSIX_VDISABLE;
117af57ed9fSAtsushi Murai   newtio.c_cc[VMIN] = 1;
118af57ed9fSAtsushi Murai   newtio.c_cc[VTIME] = 0;
119af57ed9fSAtsushi Murai   newtio.c_cflag |= CS8;
12053c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
121af57ed9fSAtsushi Murai   comtio = newtio;
122af57ed9fSAtsushi Murai }
123af57ed9fSAtsushi Murai 
124af57ed9fSAtsushi Murai /*
125af57ed9fSAtsushi Murai  *  Set tty into command mode. We allow canonical input and echo processing.
126af57ed9fSAtsushi Murai  */
127c3899f8dSAtsushi Murai void
128944f7098SBrian Somers TtyCommandMode(int prompt)
129af57ed9fSAtsushi Murai {
130af57ed9fSAtsushi Murai   struct termios newtio;
131af57ed9fSAtsushi Murai   int stat;
132af57ed9fSAtsushi Murai 
133af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER))
134af57ed9fSAtsushi Murai     return;
13553c9f6c0SAtsushi Murai   tcgetattr(0, &newtio);
136c3899f8dSAtsushi Murai   newtio.c_lflag |= (ECHO | ISIG | ICANON);
137af57ed9fSAtsushi Murai   newtio.c_iflag = oldtio.c_iflag;
138af57ed9fSAtsushi Murai   newtio.c_oflag |= OPOST;
13953c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
140af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
141274e766cSBrian Somers   if (stat > 0) {
142af57ed9fSAtsushi Murai     stat |= O_NONBLOCK;
143274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
144274e766cSBrian Somers   }
145af57ed9fSAtsushi Murai   TermMode = 0;
146944f7098SBrian Somers   if (prompt)
147944f7098SBrian Somers     Prompt();
148af57ed9fSAtsushi Murai }
149af57ed9fSAtsushi Murai 
150af57ed9fSAtsushi Murai /*
151af57ed9fSAtsushi Murai  * Set tty into terminal mode which is used while we invoke term command.
152af57ed9fSAtsushi Murai  */
153af57ed9fSAtsushi Murai void
154af57ed9fSAtsushi Murai TtyTermMode()
155af57ed9fSAtsushi Murai {
156af57ed9fSAtsushi Murai   int stat;
157af57ed9fSAtsushi Murai 
15853c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &comtio);
159af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
160274e766cSBrian Somers   if (stat > 0) {
161af57ed9fSAtsushi Murai     stat &= ~O_NONBLOCK;
162274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
163274e766cSBrian Somers   }
164af57ed9fSAtsushi Murai   TermMode = 1;
165af57ed9fSAtsushi Murai }
166af57ed9fSAtsushi Murai 
167af57ed9fSAtsushi Murai void
168c3899f8dSAtsushi Murai TtyOldMode()
169c3899f8dSAtsushi Murai {
170c3899f8dSAtsushi Murai   int stat;
171c3899f8dSAtsushi Murai 
172c3899f8dSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
173274e766cSBrian Somers   if (stat > 0) {
174c3899f8dSAtsushi Murai     stat &= ~O_NONBLOCK;
175274e766cSBrian Somers     (void) fcntl(0, F_SETFL, stat);
176274e766cSBrian Somers   }
177c3899f8dSAtsushi Murai   tcsetattr(0, TCSANOW, &oldtio);
178c3899f8dSAtsushi Murai }
179c3899f8dSAtsushi Murai 
180c3899f8dSAtsushi Murai void
181944f7098SBrian Somers Cleanup(int excode)
182af57ed9fSAtsushi Murai {
1838ea8442cSBrian Somers   ServerClose();
1840fe7ca31SBrian Somers   OsInterfaceDown(1);
1850fe7ca31SBrian Somers   HangupModem(1);
1869a571ec7SBrian Somers   nointr_sleep(1);
1876e4959f0SBrian Somers   DeleteIfRoutes(1);
1885106c671SBrian Somers   ID0unlink(pid_filename);
1896e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1906e4959f0SBrian Somers     char c = EX_ERRDEAD;
191944f7098SBrian Somers 
1926e4959f0SBrian Somers     if (write(BGFiledes[1], &c, 1) == 1)
193927145beSBrian Somers       LogPrintf(LogPHASE, "Parent notified of failure.\n");
1946e4959f0SBrian Somers     else
195927145beSBrian Somers       LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
1966e4959f0SBrian Somers     close(BGFiledes[1]);
1976e4959f0SBrian Somers   }
198927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
199c3899f8dSAtsushi Murai   TtyOldMode();
2005106c671SBrian Somers   LogClose();
201af57ed9fSAtsushi Murai 
202af57ed9fSAtsushi Murai   exit(excode);
203af57ed9fSAtsushi Murai }
204af57ed9fSAtsushi Murai 
205af57ed9fSAtsushi Murai static void
206944f7098SBrian Somers CloseConnection(int signo)
207af57ed9fSAtsushi Murai {
208368aee2bSBrian Somers   /* NOTE, these are manual, we've done a setsid() */
20912ef29a8SBrian Somers   pending_signal(SIGINT, SIG_IGN);
210873725ccSBrian Somers   LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
211944f7098SBrian Somers   reconnectState = RECON_FALSE;
212944f7098SBrian Somers   reconnectCount = 0;
213368aee2bSBrian Somers   DownConnection();
21475240ed1SBrian Somers   dial_up = 0;
21512ef29a8SBrian Somers   pending_signal(SIGINT, CloseConnection);
2166d14e2a8SJordan K. Hubbard }
217af57ed9fSAtsushi Murai 
218af57ed9fSAtsushi Murai static void
219944f7098SBrian Somers CloseSession(int signo)
220af57ed9fSAtsushi Murai {
2216d14e2a8SJordan K. Hubbard   if (BGPid) {
2226d14e2a8SJordan K. Hubbard     kill(BGPid, SIGINT);
2236d14e2a8SJordan K. Hubbard     exit(EX_TERM);
2246d14e2a8SJordan K. Hubbard   }
225927145beSBrian Somers   LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
22625aa96acSBrian Somers   reconnect(RECON_FALSE);
227af57ed9fSAtsushi Murai   LcpClose();
228af57ed9fSAtsushi Murai   Cleanup(EX_TERM);
229af57ed9fSAtsushi Murai }
230c3899f8dSAtsushi Murai 
231c3899f8dSAtsushi Murai static void
232c3899f8dSAtsushi Murai TerminalCont()
233c3899f8dSAtsushi Murai {
234f5ff0f7cSBrian Somers   pending_signal(SIGCONT, SIG_DFL);
235f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, TerminalStop);
236c3899f8dSAtsushi Murai   TtyCommandMode(getpgrp() == tcgetpgrp(0));
237c3899f8dSAtsushi Murai }
238c3899f8dSAtsushi Murai 
239c3899f8dSAtsushi Murai static void
240944f7098SBrian Somers TerminalStop(int signo)
241c3899f8dSAtsushi Murai {
242f5ff0f7cSBrian Somers   pending_signal(SIGCONT, TerminalCont);
243c3899f8dSAtsushi Murai   TtyOldMode();
244f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, SIG_DFL);
245c3899f8dSAtsushi Murai   kill(getpid(), signo);
246c3899f8dSAtsushi Murai }
247c3899f8dSAtsushi Murai 
2484ef16f24SBrian Somers static void
249944f7098SBrian Somers SetUpServer(int signo)
2504ef16f24SBrian Somers {
2514ef16f24SBrian Somers   int res;
252944f7098SBrian Somers 
2538ea8442cSBrian Somers   VarHaveLocalAuthKey = 0;
2548ea8442cSBrian Somers   LocalAuthInit();
2554ef16f24SBrian Somers   if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
256683cef3cSBrian Somers     LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
257683cef3cSBrian Somers 	      res, SERVER_PORT + tunno);
2584ef16f24SBrian Somers }
2594ef16f24SBrian Somers 
2608ea8442cSBrian Somers static void
2618ea8442cSBrian Somers BringDownServer(int signo)
2628ea8442cSBrian Somers {
2638ea8442cSBrian Somers   VarHaveLocalAuthKey = 0;
2648ea8442cSBrian Somers   LocalAuthInit();
2658ea8442cSBrian Somers   ServerClose();
2668ea8442cSBrian Somers }
2678ea8442cSBrian Somers 
2686efd9292SBrian Somers static char *
2696efd9292SBrian Somers ex_desc(int ex)
2706efd9292SBrian Somers {
2716efd9292SBrian Somers   static char num[12];
2726efd9292SBrian Somers   static char *desc[] = {"normal", "start", "sock",
2736efd9292SBrian Somers     "modem", "dial", "dead", "done", "reboot", "errdead",
2746efd9292SBrian Somers   "hangup", "term", "nodial", "nologin"};
2756efd9292SBrian Somers 
2766efd9292SBrian Somers   if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
2776efd9292SBrian Somers     return desc[ex];
2786efd9292SBrian Somers   snprintf(num, sizeof num, "%d", ex);
2796efd9292SBrian Somers   return num;
2806efd9292SBrian Somers }
281c3899f8dSAtsushi Murai 
28275240ed1SBrian Somers static void
283af57ed9fSAtsushi Murai Usage()
284af57ed9fSAtsushi Murai {
285680026d6SNate Williams   fprintf(stderr,
2866d14e2a8SJordan K. Hubbard 	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
287af57ed9fSAtsushi Murai   exit(EX_START);
288af57ed9fSAtsushi Murai }
289af57ed9fSAtsushi Murai 
29039f94eddSBrian Somers static char *
291af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
292af57ed9fSAtsushi Murai {
293af57ed9fSAtsushi Murai   int optc;
294af57ed9fSAtsushi Murai   char *cp;
295af57ed9fSAtsushi Murai 
296af57ed9fSAtsushi Murai   optc = 0;
29712ef29a8SBrian Somers   mode = MODE_INTER;
298af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
299af57ed9fSAtsushi Murai     cp = *argv + 1;
30012ef29a8SBrian Somers     if (strcmp(cp, "auto") == 0) {
301af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
30212ef29a8SBrian Somers       mode &= ~MODE_INTER;
30312ef29a8SBrian Somers     } else if (strcmp(cp, "background") == 0) {
30412ef29a8SBrian Somers       mode |= MODE_BACKGROUND;
30512ef29a8SBrian Somers       mode &= ~MODE_INTER;
30612ef29a8SBrian Somers     } else if (strcmp(cp, "direct") == 0) {
307af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
30812ef29a8SBrian Somers       mode &= ~MODE_INTER;
30912ef29a8SBrian Somers     } else if (strcmp(cp, "dedicated") == 0) {
310af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
31112ef29a8SBrian Somers       mode &= ~MODE_INTER;
31212ef29a8SBrian Somers     } else if (strcmp(cp, "ddial") == 0) {
31312ef29a8SBrian Somers       mode |= MODE_DDIAL;
31412ef29a8SBrian Somers       mode &= ~MODE_INTER;
31512ef29a8SBrian Somers     } else if (strcmp(cp, "alias") == 0) {
3166ed9fb2fSBrian Somers       if (loadAliasHandlers(&VarAliasHandlers) == 0)
317a9f484e5SJordan K. Hubbard 	mode |= MODE_ALIAS;
3186ed9fb2fSBrian Somers       else
319927145beSBrian Somers 	LogPrintf(LogWARN, "Cannot load alias library\n");
320a9f484e5SJordan K. Hubbard       optc--;			/* this option isn't exclusive */
321944f7098SBrian Somers     } else
322af57ed9fSAtsushi Murai       Usage();
323af57ed9fSAtsushi Murai     optc++;
324944f7098SBrian Somers     argv++;
325944f7098SBrian Somers     argc--;
326af57ed9fSAtsushi Murai   }
327af57ed9fSAtsushi Murai   if (argc > 1) {
328af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
329af57ed9fSAtsushi Murai     exit(EX_START);
330af57ed9fSAtsushi Murai   }
331af57ed9fSAtsushi Murai 
332af57ed9fSAtsushi Murai   if (optc > 1) {
333af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
334af57ed9fSAtsushi Murai     exit(EX_START);
335af57ed9fSAtsushi Murai   }
33639f94eddSBrian Somers 
33739f94eddSBrian Somers   return argc == 1 ? *argv : NULL;	/* Don't SetLabel yet ! */
338af57ed9fSAtsushi Murai }
339af57ed9fSAtsushi Murai 
340af57ed9fSAtsushi Murai static void
341af57ed9fSAtsushi Murai Greetings()
342af57ed9fSAtsushi Murai {
343927145beSBrian Somers   if (VarTerm) {
344927145beSBrian Somers     fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
345927145beSBrian Somers     fflush(VarTerm);
346927145beSBrian Somers   }
347af57ed9fSAtsushi Murai }
348af57ed9fSAtsushi Murai 
3494ef16f24SBrian Somers int
350944f7098SBrian Somers main(int argc, char **argv)
351af57ed9fSAtsushi Murai {
352aefd026aSBrian Somers   FILE *lockfile;
35339f94eddSBrian Somers   char *name, *label;
354af57ed9fSAtsushi Murai 
3550706ff38SBrian Somers   VarTerm = 0;
35675240ed1SBrian Somers   name = strrchr(argv[0], '/');
357927145beSBrian Somers   LogOpen(name ? name + 1 : argv[0]);
358927145beSBrian Somers 
359944f7098SBrian Somers   argc--;
360944f7098SBrian Somers   argv++;
36139f94eddSBrian Somers   label = ProcessArgs(argc, argv);
36212ef29a8SBrian Somers   if (!(mode & MODE_DIRECT))
3630706ff38SBrian Somers     VarTerm = stdout;
36412ef29a8SBrian Somers 
3655106c671SBrian Somers   ID0init();
3664562be74SBrian Somers   if (ID0realuid() != 0) {
3674562be74SBrian Somers     char conf[200], *ptr;
3684562be74SBrian Somers 
3694562be74SBrian Somers     snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
3704562be74SBrian Somers     do {
3714562be74SBrian Somers       if (!access(conf, W_OK)) {
3724562be74SBrian Somers         LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
3734562be74SBrian Somers         return -1;
3744562be74SBrian Somers       }
3754562be74SBrian Somers       ptr = conf + strlen(conf)-2;
3764562be74SBrian Somers       while (ptr > conf && *ptr != '/')
3774562be74SBrian Somers         *ptr-- = '\0';
3784562be74SBrian Somers     } while (ptr >= conf);
3794562be74SBrian Somers   }
3804562be74SBrian Somers 
38139f94eddSBrian Somers   if (!ValidSystem(label)) {
38212ef29a8SBrian Somers     fprintf(stderr, "You may not use ppp in this mode with this label\n");
383815624cfSBrian Somers     if (mode & MODE_DIRECT) {
384815624cfSBrian Somers       const char *l;
38539f94eddSBrian Somers       l = label ? label : "default";
386815624cfSBrian Somers       VarTerm = 0;
387815624cfSBrian Somers       LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
388815624cfSBrian Somers     }
389815624cfSBrian Somers     LogClose();
39012ef29a8SBrian Somers     return 1;
39112ef29a8SBrian Somers   }
39212ef29a8SBrian Somers 
393c7d4711fSBrian Somers   if (!GetShortHost())
394c7d4711fSBrian Somers     return 1;
395af57ed9fSAtsushi Murai   Greetings();
396af57ed9fSAtsushi Murai   IpcpDefAddress();
397af57ed9fSAtsushi Murai 
398927145beSBrian Somers   if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
399927145beSBrian Somers     fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
400af57ed9fSAtsushi Murai 
401af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
4024ef16f24SBrian Somers     LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
4034ef16f24SBrian Somers     return EX_START;
404af57ed9fSAtsushi Murai   }
405af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
406927145beSBrian Somers     fprintf(VarTerm, "Interactive mode\n");
407cc39a98fSBrian Somers     netfd = STDOUT_FILENO;
40812ef29a8SBrian Somers   } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
40939f94eddSBrian Somers     if (label == NULL) {
410927145beSBrian Somers       if (VarTerm)
411927145beSBrian Somers 	fprintf(VarTerm, "Destination system must be specified in"
4126efd9292SBrian Somers 		" auto, background or ddial mode.\n");
4134ef16f24SBrian Somers       return EX_START;
4146d14e2a8SJordan K. Hubbard     }
41512ef29a8SBrian Somers 
41653c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);	/* Save original tty mode */
417af57ed9fSAtsushi Murai 
418873725ccSBrian Somers   pending_signal(SIGHUP, CloseSession);
419f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
420873725ccSBrian Somers   pending_signal(SIGINT, CloseConnection);
421f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
42253c9f6c0SAtsushi Murai #ifdef SIGPIPE
423e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
42453c9f6c0SAtsushi Murai #endif
42553c9f6c0SAtsushi Murai #ifdef SIGALRM
426f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
42753c9f6c0SAtsushi Murai #endif
4284ef16f24SBrian Somers   if (mode & MODE_INTER) {
429c3899f8dSAtsushi Murai #ifdef SIGTSTP
430f5ff0f7cSBrian Somers     pending_signal(SIGTSTP, TerminalStop);
431c3899f8dSAtsushi Murai #endif
432c3899f8dSAtsushi Murai #ifdef SIGTTIN
433f5ff0f7cSBrian Somers     pending_signal(SIGTTIN, TerminalStop);
434c3899f8dSAtsushi Murai #endif
435c3899f8dSAtsushi Murai #ifdef SIGTTOU
436f5ff0f7cSBrian Somers     pending_signal(SIGTTOU, SIG_IGN);
437c3899f8dSAtsushi Murai #endif
438c3899f8dSAtsushi Murai   }
43912ef29a8SBrian Somers   if (!(mode & MODE_INTER)) {
4404ef16f24SBrian Somers #ifdef SIGUSR1
4414ef16f24SBrian Somers     pending_signal(SIGUSR1, SetUpServer);
4424ef16f24SBrian Somers #endif
4438ea8442cSBrian Somers #ifdef SIGUSR2
4448ea8442cSBrian Somers     pending_signal(SIGUSR2, BringDownServer);
4458ea8442cSBrian Somers #endif
44612ef29a8SBrian Somers   }
447af57ed9fSAtsushi Murai 
44839f94eddSBrian Somers   if (label) {
44939f94eddSBrian Somers     if (SelectSystem(label, CONFFILE) < 0) {
450e4450123SBrian Somers       LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
451e4450123SBrian Somers                 GetLabel());
452af57ed9fSAtsushi Murai       Cleanup(EX_START);
453af57ed9fSAtsushi Murai     }
45439f94eddSBrian Somers     /*
45539f94eddSBrian Somers      * We don't SetLabel() 'till now in case SelectSystem() has an
45639f94eddSBrian Somers      * embeded load "otherlabel" command.
45739f94eddSBrian Somers      */
45839f94eddSBrian Somers     SetLabel(label);
45912ef29a8SBrian Somers     if (mode & MODE_OUTGOING_DAEMON &&
46012ef29a8SBrian Somers 	DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
461e4450123SBrian Somers       LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
46239f94eddSBrian Somers 		" auto, background or ddial mode.\n", label);
463af57ed9fSAtsushi Murai       Cleanup(EX_START);
464af57ed9fSAtsushi Murai     }
465af57ed9fSAtsushi Murai   }
4666efd9292SBrian Somers 
46712ef29a8SBrian Somers   if (mode & MODE_DAEMON) {
4686d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4696d14e2a8SJordan K. Hubbard       if (pipe(BGFiledes)) {
470afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
4716d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4726d14e2a8SJordan K. Hubbard       }
4736d14e2a8SJordan K. Hubbard     }
474af57ed9fSAtsushi Murai 
475af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4766d14e2a8SJordan K. Hubbard       pid_t bgpid;
477a9c6b5dfSAtsushi Murai 
4786d14e2a8SJordan K. Hubbard       bgpid = fork();
4796d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
480afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
4816d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4826d14e2a8SJordan K. Hubbard       }
4836d14e2a8SJordan K. Hubbard       if (bgpid) {
4846d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
485a9c6b5dfSAtsushi Murai 
4866d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4876d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4886d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4896e4959f0SBrian Somers 	  close(BGFiledes[1]);
4906efd9292SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1) {
491927145beSBrian Somers 	    fprintf(VarTerm, "Child exit, no status.\n");
492927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
4936efd9292SBrian Somers 	  } else if (c == EX_NORMAL) {
494927145beSBrian Somers 	    fprintf(VarTerm, "PPP enabled.\n");
495927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
4966efd9292SBrian Somers 	  } else {
497927145beSBrian Somers 	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
498927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
49980e37c72SBrian Somers 		      ex_desc((int) c));
5006efd9292SBrian Somers 	  }
5016e4959f0SBrian Somers 	  close(BGFiledes[0]);
5026d14e2a8SJordan K. Hubbard 	}
5034ef16f24SBrian Somers 	return c;
5046e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
5056e4959f0SBrian Somers 	close(BGFiledes[0]);
506aefd026aSBrian Somers     }
507aefd026aSBrian Somers 
508d656a4c5SBrian Somers     VarTerm = 0;		/* We know it's currently stdout */
509fd2bc5ebSBrian Somers     close(1);
510d656a4c5SBrian Somers     close(2);
5110706ff38SBrian Somers 
512d656a4c5SBrian Somers     if (mode & MODE_DIRECT)
513368aee2bSBrian Somers       TtyInit(1);
51412ef29a8SBrian Somers     else if (mode & MODE_DAEMON) {
515d656a4c5SBrian Somers       setsid();
516fd2bc5ebSBrian Somers       close(0);
517d656a4c5SBrian Somers     }
518af57ed9fSAtsushi Murai   } else {
519368aee2bSBrian Somers     TtyInit(0);
520c3899f8dSAtsushi Murai     TtyCommandMode(1);
521af57ed9fSAtsushi Murai   }
52235495becSBrian Somers 
52335495becSBrian Somers   snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
52435495becSBrian Somers            _PATH_VARRUN, tunno);
5255106c671SBrian Somers   lockfile = ID0fopen(pid_filename, "w");
5265106c671SBrian Somers   if (lockfile != NULL) {
52735495becSBrian Somers     fprintf(lockfile, "%d\n", (int) getpid());
52835495becSBrian Somers     fclose(lockfile);
52935495becSBrian Somers   } else
53035495becSBrian Somers     LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
53135495becSBrian Somers               pid_filename, strerror(errno));
53235495becSBrian Somers 
533927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Started.\n");
534af57ed9fSAtsushi Murai 
535af57ed9fSAtsushi Murai 
536af57ed9fSAtsushi Murai   do
537af57ed9fSAtsushi Murai     DoLoop();
538af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
539af57ed9fSAtsushi Murai 
540af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
5414ef16f24SBrian Somers   return 0;
542af57ed9fSAtsushi Murai }
543af57ed9fSAtsushi Murai 
544af57ed9fSAtsushi Murai /*
5456d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
546af57ed9fSAtsushi Murai  */
547af57ed9fSAtsushi Murai void
548af57ed9fSAtsushi Murai PacketMode()
549af57ed9fSAtsushi Murai {
5509780ef31SBrian Somers   if (RawModem() < 0) {
551927145beSBrian Somers     LogPrintf(LogWARN, "PacketMode: Not connected.\n");
552af57ed9fSAtsushi Murai     return;
553af57ed9fSAtsushi Murai   }
554af57ed9fSAtsushi Murai   AsyncInit();
55503604f35SBrian Somers   VjInit(15);
556af57ed9fSAtsushi Murai   LcpInit();
557af57ed9fSAtsushi Murai   IpcpInit();
558af57ed9fSAtsushi Murai   CcpInit();
559af57ed9fSAtsushi Murai   LcpUp();
560af57ed9fSAtsushi Murai 
561af57ed9fSAtsushi Murai   LcpOpen(VarOpenMode);
56212ef29a8SBrian Somers   if (mode & MODE_INTER)
563c3899f8dSAtsushi Murai     TtyCommandMode(1);
564927145beSBrian Somers   if (VarTerm) {
565927145beSBrian Somers     fprintf(VarTerm, "Packet mode.\n");
566b0cdb3ceSJordan K. Hubbard     aft_cmd = 1;
567af57ed9fSAtsushi Murai   }
568af57ed9fSAtsushi Murai }
569af57ed9fSAtsushi Murai 
570af57ed9fSAtsushi Murai static void
571af57ed9fSAtsushi Murai ShowHelp()
572af57ed9fSAtsushi Murai {
573030d3ce6SBrian Somers   fprintf(stderr, "The following commands are available:\r\n");
574030d3ce6SBrian Somers   fprintf(stderr, " ~p\tEnter Packet mode\r\n");
575030d3ce6SBrian Somers   fprintf(stderr, " ~-\tDecrease log level\r\n");
576030d3ce6SBrian Somers   fprintf(stderr, " ~+\tIncrease log level\r\n");
577030d3ce6SBrian Somers   fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
578030d3ce6SBrian Somers   fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
579030d3ce6SBrian Somers   fprintf(stderr, " ~.\tTerminate program\r\n");
580030d3ce6SBrian Somers   fprintf(stderr, " ~?\tThis help\r\n");
581af57ed9fSAtsushi Murai }
582af57ed9fSAtsushi Murai 
583af57ed9fSAtsushi Murai static void
584af57ed9fSAtsushi Murai ReadTty()
585af57ed9fSAtsushi Murai {
586af57ed9fSAtsushi Murai   int n;
587af57ed9fSAtsushi Murai   char ch;
588af57ed9fSAtsushi Murai   static int ttystate;
589927145beSBrian Somers   FILE *oVarTerm;
59086e02934SBrian Somers   char linebuff[LINE_LEN];
591af57ed9fSAtsushi Murai 
592927145beSBrian Somers   LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
593927145beSBrian Somers 	    TermMode, netfd, mode);
594af57ed9fSAtsushi Murai   if (!TermMode) {
595af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff) - 1);
59653c9f6c0SAtsushi Murai     if (n > 0) {
597927145beSBrian Somers       aft_cmd = 1;
598a1e8f937SBrian Somers       if (linebuff[n-1] == '\n')
599a1e8f937SBrian Somers         linebuff[--n] = '\0';
600d9181b05SBrian Somers       if (n)
601d9181b05SBrian Somers         DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
602a1e8f937SBrian Somers       Prompt();
60353c9f6c0SAtsushi Murai     } else {
604927145beSBrian Somers       LogPrintf(LogPHASE, "client connection closed.\n");
605927145beSBrian Somers       oVarTerm = VarTerm;
606927145beSBrian Somers       VarTerm = 0;
607927145beSBrian Somers       if (oVarTerm && oVarTerm != stdout)
608927145beSBrian Somers 	fclose(oVarTerm);
609927145beSBrian Somers       close(netfd);
610927145beSBrian Somers       netfd = -1;
611af57ed9fSAtsushi Murai     }
612af57ed9fSAtsushi Murai     return;
613af57ed9fSAtsushi Murai   }
614af57ed9fSAtsushi Murai 
615af57ed9fSAtsushi Murai   /*
616af57ed9fSAtsushi Murai    * We are in terminal mode, decode special sequences
617af57ed9fSAtsushi Murai    */
618927145beSBrian Somers   n = read(fileno(VarTerm), &ch, 1);
619afc7fa2cSBrian Somers   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
620af57ed9fSAtsushi Murai 
621af57ed9fSAtsushi Murai   if (n > 0) {
622af57ed9fSAtsushi Murai     switch (ttystate) {
623af57ed9fSAtsushi Murai     case 0:
624af57ed9fSAtsushi Murai       if (ch == '~')
625af57ed9fSAtsushi Murai 	ttystate++;
626af57ed9fSAtsushi Murai       else
627af57ed9fSAtsushi Murai 	write(modem, &ch, n);
628af57ed9fSAtsushi Murai       break;
629af57ed9fSAtsushi Murai     case 1:
630af57ed9fSAtsushi Murai       switch (ch) {
631af57ed9fSAtsushi Murai       case '?':
632af57ed9fSAtsushi Murai 	ShowHelp();
633af57ed9fSAtsushi Murai 	break;
634af57ed9fSAtsushi Murai       case 'p':
635944f7098SBrian Somers 
636af57ed9fSAtsushi Murai 	/*
637af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
638af57ed9fSAtsushi Murai 	 */
639af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
640af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
641af57ed9fSAtsushi Murai 	  PacketMode();
642af57ed9fSAtsushi Murai 	}
643af57ed9fSAtsushi Murai 	break;
644af57ed9fSAtsushi Murai       case '.':
645af57ed9fSAtsushi Murai 	TermMode = 1;
646927145beSBrian Somers 	aft_cmd = 1;
647c3899f8dSAtsushi Murai 	TtyCommandMode(1);
648af57ed9fSAtsushi Murai 	break;
649927145beSBrian Somers       case 't':
650927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
651927145beSBrian Somers 	  ShowTimers();
652927145beSBrian Somers 	  break;
653927145beSBrian Somers 	}
654927145beSBrian Somers       case 'm':
655927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
656927145beSBrian Somers 	  ShowMemMap();
657927145beSBrian Somers 	  break;
658927145beSBrian Somers 	}
659af57ed9fSAtsushi Murai       default:
660af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
661927145beSBrian Somers 	  LogPrintf(LogERROR, "error writing to modem.\n");
662af57ed9fSAtsushi Murai 	break;
663af57ed9fSAtsushi Murai       }
664af57ed9fSAtsushi Murai       ttystate = 0;
665af57ed9fSAtsushi Murai       break;
666af57ed9fSAtsushi Murai     }
667af57ed9fSAtsushi Murai   }
668af57ed9fSAtsushi Murai }
669af57ed9fSAtsushi Murai 
670af57ed9fSAtsushi Murai 
671af57ed9fSAtsushi Murai /*
672af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
673af57ed9fSAtsushi Murai  */
674af57ed9fSAtsushi Murai 
675af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
67653c9f6c0SAtsushi Murai   "\176\377\003\300\041",
67753c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
67853c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
67953c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
68053c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
681af57ed9fSAtsushi Murai   NULL,
682af57ed9fSAtsushi Murai };
683af57ed9fSAtsushi Murai 
68475240ed1SBrian Somers static u_char *
685944f7098SBrian Somers HdlcDetect(u_char * cp, int n)
686af57ed9fSAtsushi Murai {
68753c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
688af57ed9fSAtsushi Murai 
689af57ed9fSAtsushi Murai   cp[n] = '\0';			/* be sure to null terminated */
690af57ed9fSAtsushi Murai   ptr = NULL;
691af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
69253c9f6c0SAtsushi Murai     fp = *hp;
69353c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
69453c9f6c0SAtsushi Murai       fp++;
695ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *) cp, fp);
696ed6a16c1SPoul-Henning Kamp     if (ptr)
697af57ed9fSAtsushi Murai       break;
698af57ed9fSAtsushi Murai   }
699af57ed9fSAtsushi Murai   return ((u_char *) ptr);
700af57ed9fSAtsushi Murai }
701af57ed9fSAtsushi Murai 
702af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
703af57ed9fSAtsushi Murai 
704af57ed9fSAtsushi Murai static void
705af57ed9fSAtsushi Murai RedialTimeout()
706af57ed9fSAtsushi Murai {
707af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
708927145beSBrian Somers   LogPrintf(LogPHASE, "Redialing timer expired.\n");
709af57ed9fSAtsushi Murai }
710af57ed9fSAtsushi Murai 
711af57ed9fSAtsushi Murai static void
712944f7098SBrian Somers StartRedialTimer(int Timeout)
713af57ed9fSAtsushi Murai {
714af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
715a9c6b5dfSAtsushi Murai 
71643ea9d19SBrian Somers   if (Timeout) {
717af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
718a9c6b5dfSAtsushi Murai 
71943ea9d19SBrian Somers     if (Timeout > 0)
72043ea9d19SBrian Somers       RedialTimer.load = Timeout * SECTICKS;
721a9c6b5dfSAtsushi Murai     else
722a9c6b5dfSAtsushi Murai       RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
723a9c6b5dfSAtsushi Murai 
724927145beSBrian Somers     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
72543ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
72643ea9d19SBrian Somers 
727af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
728af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
729af57ed9fSAtsushi Murai   }
730a9c6b5dfSAtsushi Murai }
731af57ed9fSAtsushi Murai 
732af57ed9fSAtsushi Murai 
733af57ed9fSAtsushi Murai static void
734af57ed9fSAtsushi Murai DoLoop()
735af57ed9fSAtsushi Murai {
736af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
737780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
738af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
739af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
740af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
741af57ed9fSAtsushi Murai   u_char *cp;
742a9c6b5dfSAtsushi Murai   int tries;
74360e218e4SAtsushi Murai   int qlen;
744368aee2bSBrian Somers   int res;
745c3899f8dSAtsushi Murai   pid_t pgroup;
7466a6b4bbbSBrian Somers   struct tun_data tun;
7476a6b4bbbSBrian Somers #define rbuff tun.data
748c3899f8dSAtsushi Murai 
749c3899f8dSAtsushi Murai   pgroup = getpgrp();
750af57ed9fSAtsushi Murai 
7516efd9292SBrian Somers   if (mode & MODE_DIRECT) {
7520706ff38SBrian Somers     LogPrintf(LogDEBUG, "Opening modem\n");
7539780ef31SBrian Somers     if (OpenModem() < 0)
754bc240299SBrian Somers       return;
755927145beSBrian Somers     LogPrintf(LogPHASE, "Packet mode enabled\n");
756af57ed9fSAtsushi Murai     PacketMode();
757af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
758780700e5SAndrey A. Chernov     if (modem < 0)
7599780ef31SBrian Somers       while (OpenModem() < 0)
7609a571ec7SBrian Somers 	nointr_sleep(VarReconnectTimer);
761af57ed9fSAtsushi Murai   }
762927145beSBrian Somers   fflush(VarTerm);
763af57ed9fSAtsushi Murai 
76484b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
765af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
76625aa96acSBrian Somers   reconnectState = RECON_UNKNOWN;
767af57ed9fSAtsushi Murai 
7686e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
76975240ed1SBrian Somers     dial_up = 1;		/* Bring the line up */
7706e4959f0SBrian Somers   else
77175240ed1SBrian Somers     dial_up = 0;		/* XXXX */
772a9c6b5dfSAtsushi Murai   tries = 0;
773af57ed9fSAtsushi Murai   for (;;) {
774780700e5SAndrey A. Chernov     nfds = 0;
775944f7098SBrian Somers     FD_ZERO(&rfds);
776944f7098SBrian Somers     FD_ZERO(&wfds);
777944f7098SBrian Somers     FD_ZERO(&efds);
77884b8a6ebSAtsushi Murai 
77984b8a6ebSAtsushi Murai     /*
780944f7098SBrian Somers      * If the link is down and we're in DDIAL mode, bring it back up.
781680026d6SNate Williams      */
782680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
78375240ed1SBrian Somers       dial_up = 1;
784680026d6SNate Williams 
785680026d6SNate Williams     /*
786944f7098SBrian Somers      * If we lost carrier and want to re-establish the connection due to the
787944f7098SBrian Somers      * "set reconnect" value, we'd better bring the line back up.
78807030d97SBrian Somers      */
7896efd9292SBrian Somers     if (LcpFsm.state <= ST_CLOSED) {
79075240ed1SBrian Somers       if (!dial_up && reconnectState == RECON_TRUE) {
7916efd9292SBrian Somers 	if (++reconnectCount <= VarReconnectTries) {
792927145beSBrian Somers 	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
7936efd9292SBrian Somers 		    reconnectCount, VarReconnectTries);
79407030d97SBrian Somers 	  StartRedialTimer(VarReconnectTimer);
79575240ed1SBrian Somers 	  dial_up = 1;
796298091daSBrian Somers 	} else {
7976efd9292SBrian Somers 	  if (VarReconnectTries)
798927145beSBrian Somers 	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
799298091daSBrian Somers 		      VarReconnectTries);
8006efd9292SBrian Somers 	  reconnectCount = 0;
8016efd9292SBrian Somers 	  if (mode & MODE_BACKGROUND)
8026efd9292SBrian Somers 	    Cleanup(EX_DEAD);
8036efd9292SBrian Somers 	}
80425aa96acSBrian Somers 	reconnectState = RECON_ENVOKED;
80512ef29a8SBrian Somers       } else if (mode & MODE_DEDICATED)
80612ef29a8SBrian Somers         if (VarOpenMode == OPEN_ACTIVE)
80712ef29a8SBrian Somers           PacketMode();
80807030d97SBrian Somers     }
80907030d97SBrian Somers 
81007030d97SBrian Somers     /*
811944f7098SBrian Somers      * If Ip packet for output is enqueued and require dial up, Just do it!
81284b8a6ebSAtsushi Murai      */
81307030d97SBrian Somers     if (dial_up && RedialTimer.state != TIMER_RUNNING) {
814927145beSBrian Somers       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
8159780ef31SBrian Somers       if (OpenModem() < 0) {
8160706ff38SBrian Somers 	tries++;
817712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
8180706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
8190706ff38SBrian Somers 		    tries, VarDialTries);
8200706ff38SBrian Somers 	else
8210706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
8220706ff38SBrian Somers 
823712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
8240706ff38SBrian Somers 	  if (mode & MODE_BACKGROUND)
8250706ff38SBrian Somers 	    Cleanup(EX_DIAL);	/* Can't get the modem */
82675240ed1SBrian Somers 	  dial_up = 0;
8270706ff38SBrian Somers 	  reconnectState = RECON_UNKNOWN;
8280706ff38SBrian Somers 	  reconnectCount = 0;
8290706ff38SBrian Somers 	  tries = 0;
8300706ff38SBrian Somers 	} else
83143ea9d19SBrian Somers 	  StartRedialTimer(VarRedialTimeout);
83284b8a6ebSAtsushi Murai       } else {
833944f7098SBrian Somers 	tries++;		/* Tries are per number, not per list of
834944f7098SBrian Somers 				 * numbers. */
835712ae387SBrian Somers 	if (!(mode & MODE_DDIAL) && VarDialTries)
836712ae387SBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
837c0139fb2SBrian Somers 	else
838927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
839712ae387SBrian Somers 
840368aee2bSBrian Somers 	if ((res = DialModem()) == EX_DONE) {
8419a571ec7SBrian Somers 	  nointr_sleep(1);		/* little pause to allow peer starts */
84284b8a6ebSAtsushi Murai 	  ModemTimeout();
84384b8a6ebSAtsushi Murai 	  PacketMode();
84475240ed1SBrian Somers 	  dial_up = 0;
84525aa96acSBrian Somers 	  reconnectState = RECON_UNKNOWN;
846a9c6b5dfSAtsushi Murai 	  tries = 0;
84784b8a6ebSAtsushi Murai 	} else {
8484ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
849368aee2bSBrian Somers 	    if (VarNextPhone == NULL || res == EX_SIG)
8504ed9958fSBrian Somers 	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
8514ed9958fSBrian Somers 	    else
85243ea9d19SBrian Somers 	      /* Try all numbers in background mode */
85343ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
854368aee2bSBrian Somers 	  } else if (!(mode & MODE_DDIAL) &&
855368aee2bSBrian Somers 		     ((VarDialTries && tries >= VarDialTries) ||
856368aee2bSBrian Somers 		      res == EX_SIG)) {
857c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
85843ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
85975240ed1SBrian Somers 	    dial_up = 0;
86025aa96acSBrian Somers 	    reconnectState = RECON_UNKNOWN;
86125aa96acSBrian Somers 	    reconnectCount = 0;
862a9c6b5dfSAtsushi Murai 	    tries = 0;
863c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
864c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
86543ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
866c0139fb2SBrian Somers 	  else
86743ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
86884b8a6ebSAtsushi Murai 	}
86984b8a6ebSAtsushi Murai       }
87084b8a6ebSAtsushi Murai     }
87160e218e4SAtsushi Murai     qlen = ModemQlen();
87276bd0c0aSDoug Rabson 
87376bd0c0aSDoug Rabson     if (qlen == 0) {
87476bd0c0aSDoug Rabson       IpStartOutput();
87576bd0c0aSDoug Rabson       qlen = ModemQlen();
87676bd0c0aSDoug Rabson     }
877780700e5SAndrey A. Chernov     if (modem >= 0) {
878780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
879780700e5SAndrey A. Chernov 	nfds = modem + 1;
88084b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
88184b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
88260e218e4SAtsushi Murai       if (qlen > 0) {
88384b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
88484b8a6ebSAtsushi Murai       }
88584b8a6ebSAtsushi Murai     }
886780700e5SAndrey A. Chernov     if (server >= 0) {
887780700e5SAndrey A. Chernov       if (server + 1 > nfds)
888780700e5SAndrey A. Chernov 	nfds = server + 1;
889780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
890780700e5SAndrey A. Chernov     }
891af57ed9fSAtsushi Murai 
892944f7098SBrian Somers     /*
893944f7098SBrian Somers      * *** IMPORTANT ***
894af57ed9fSAtsushi Murai      *
895944f7098SBrian Somers      * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
896944f7098SBrian Somers      * with great care. If this values is too big, it results loss of
897944f7098SBrian Somers      * characters from modem and poor responce. If this values is too small,
898944f7098SBrian Somers      * ppp process eats many CPU time.
899af57ed9fSAtsushi Murai      */
90053c9f6c0SAtsushi Murai #ifndef SIGALRM
9019a571ec7SBrian Somers     nointr_usleep(TICKUNIT);
902af57ed9fSAtsushi Murai     TimerService();
903f5ff0f7cSBrian Somers #else
904f5ff0f7cSBrian Somers     handle_signals();
90553c9f6c0SAtsushi Murai #endif
90668d2b4d6SBruce Evans 
90768d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
908780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
909780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
910780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
91184b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
912780700e5SAndrey A. Chernov     }
913780700e5SAndrey A. Chernov     if (netfd >= 0) {
914780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
915780700e5SAndrey A. Chernov 	nfds = netfd + 1;
916af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
917af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
918af57ed9fSAtsushi Murai     }
91953c9f6c0SAtsushi Murai #ifndef SIGALRM
920944f7098SBrian Somers 
921af57ed9fSAtsushi Murai     /*
922944f7098SBrian Somers      * Normally, select() will not block because modem is writable. In AUTO
923944f7098SBrian Somers      * mode, select will block until we find packet from tun
924af57ed9fSAtsushi Murai      */
925af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
926780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
92753c9f6c0SAtsushi Murai #else
928944f7098SBrian Somers 
92984b8a6ebSAtsushi Murai     /*
930944f7098SBrian Somers      * When SIGALRM timer is running, a select function will be return -1 and
931944f7098SBrian Somers      * EINTR after a Time Service signal hundler is done.  If the redial
932944f7098SBrian Somers      * timer is not running and we are trying to dial, poll with a 0 value
933944f7098SBrian Somers      * timer.
93484b8a6ebSAtsushi Murai      */
935a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
936780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
93753c9f6c0SAtsushi Murai #endif
9386b0b88d8SBrian Somers 
939af57ed9fSAtsushi Murai     if (i == 0) {
940af57ed9fSAtsushi Murai       continue;
941af57ed9fSAtsushi Murai     }
942534fe541SBrian Somers     if (i < 0) {
943534fe541SBrian Somers       if (errno == EINTR) {
944f5ff0f7cSBrian Somers 	handle_signals();
945f5ff0f7cSBrian Somers 	continue;
94684b8a6ebSAtsushi Murai       }
947afc7fa2cSBrian Somers       LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
948af57ed9fSAtsushi Murai       break;
949af57ed9fSAtsushi Murai     }
950780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
951927145beSBrian Somers       LogPrintf(LogALERT, "Exception detected.\n");
952af57ed9fSAtsushi Murai       break;
953af57ed9fSAtsushi Murai     }
954780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
955927145beSBrian Somers       LogPrintf(LogPHASE, "connected to client.\n");
956af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
957e0d3e233SAndrey A. Chernov       if (wfd < 0) {
958afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
959e0d3e233SAndrey A. Chernov 	continue;
960e0d3e233SAndrey A. Chernov       }
961780700e5SAndrey A. Chernov       if (netfd >= 0) {
962af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
963af57ed9fSAtsushi Murai 	close(wfd);
964af57ed9fSAtsushi Murai 	continue;
965af57ed9fSAtsushi Murai       } else
966af57ed9fSAtsushi Murai 	netfd = wfd;
967927145beSBrian Somers       VarTerm = fdopen(netfd, "a+");
9688ea8442cSBrian Somers       LocalAuthInit();
969af57ed9fSAtsushi Murai       Greetings();
970a1e8f937SBrian Somers       IsInteractive(1);
971274e766cSBrian Somers       Prompt();
972af57ed9fSAtsushi Murai     }
97312ef29a8SBrian Somers     if (netfd >= 0 && FD_ISSET(netfd, &rfds) &&
97412ef29a8SBrian Somers 	((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) {
975af57ed9fSAtsushi Murai       /* something to read from tty */
976af57ed9fSAtsushi Murai       ReadTty();
977af57ed9fSAtsushi Murai     }
978780700e5SAndrey A. Chernov     if (modem >= 0) {
979af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
980af57ed9fSAtsushi Murai 	ModemStartOutput(modem);
981af57ed9fSAtsushi Murai       }
982af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
98353c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
9849a571ec7SBrian Somers 	  nointr_usleep(10000);
985af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
986af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
987af57ed9fSAtsushi Murai 	  DownConnection();
988af57ed9fSAtsushi Murai 	} else
989927145beSBrian Somers 	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
990af57ed9fSAtsushi Murai 
991af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
992944f7098SBrian Somers 
993af57ed9fSAtsushi Murai 	  /*
994af57ed9fSAtsushi Murai 	   * In dedicated mode, we just discard input until LCP is started.
995af57ed9fSAtsushi Murai 	   */
996af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
997af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
998af57ed9fSAtsushi Murai 	    if (cp) {
999944f7098SBrian Somers 
1000af57ed9fSAtsushi Murai 	      /*
1001af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
1002af57ed9fSAtsushi Murai 	       */
1003af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
1004927145beSBrian Somers 		write(modem, rbuff, cp - rbuff);
1005927145beSBrian Somers 		write(modem, "\r\n", 2);
1006af57ed9fSAtsushi Murai 	      }
1007af57ed9fSAtsushi Murai 	      PacketMode();
1008af57ed9fSAtsushi Murai 	    } else
1009927145beSBrian Somers 	      write(fileno(VarTerm), rbuff, n);
1010af57ed9fSAtsushi Murai 	  }
1011af57ed9fSAtsushi Murai 	} else {
1012af57ed9fSAtsushi Murai 	  if (n > 0)
1013af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
1014af57ed9fSAtsushi Murai 	}
1015af57ed9fSAtsushi Murai       }
1016af57ed9fSAtsushi Murai     }
1017944f7098SBrian Somers     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
1018944f7098SBrian Somers 							 * from tun */
10196a6b4bbbSBrian Somers       n = read(tun_in, &tun, sizeof(tun));
1020af57ed9fSAtsushi Murai       if (n < 0) {
1021afc7fa2cSBrian Somers 	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
1022af57ed9fSAtsushi Murai 	continue;
1023af57ed9fSAtsushi Murai       }
10246a6b4bbbSBrian Somers       n -= sizeof(tun)-sizeof(tun.data);
10256a6b4bbbSBrian Somers       if (n <= 0) {
10266a6b4bbbSBrian Somers 	LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n);
10276a6b4bbbSBrian Somers 	continue;
10286a6b4bbbSBrian Somers       }
10296a6b4bbbSBrian Somers       if (!tun_check_header(tun, AF_INET))
10306a6b4bbbSBrian Somers           continue;
1031de451c68SBrian Somers       if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
1032de451c68SBrian Somers 	/* we've been asked to send something addressed *to* us :( */
1033de451c68SBrian Somers 	if (VarLoopback) {
1034de451c68SBrian Somers 	  pri = PacketCheck(rbuff, n, FL_IN);
1035de451c68SBrian Somers 	  if (pri >= 0) {
1036de451c68SBrian Somers 	    struct mbuf *bp;
1037944f7098SBrian Somers 
1038de451c68SBrian Somers 	    if (mode & MODE_ALIAS) {
1039de451c68SBrian Somers 	      VarPacketAliasIn(rbuff, sizeof rbuff);
1040de451c68SBrian Somers 	      n = ntohs(((struct ip *) rbuff)->ip_len);
1041de451c68SBrian Somers 	    }
1042de451c68SBrian Somers 	    bp = mballoc(n, MB_IPIN);
104375240ed1SBrian Somers 	    memcpy(MBUF_CTOP(bp), rbuff, n);
1044de451c68SBrian Somers 	    IpInput(bp);
1045de451c68SBrian Somers 	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
1046de451c68SBrian Somers 	  }
1047de451c68SBrian Somers 	  continue;
1048de451c68SBrian Somers 	} else
1049de451c68SBrian Somers 	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
1050de451c68SBrian Somers       }
1051de451c68SBrian Somers 
1052af57ed9fSAtsushi Murai       /*
1053af57ed9fSAtsushi Murai        * Process on-demand dialup. Output packets are queued within tunnel
1054af57ed9fSAtsushi Murai        * device until IPCP is opened.
1055af57ed9fSAtsushi Murai        */
1056af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
105784b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1058af57ed9fSAtsushi Murai 	if (pri >= 0) {
1059a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10606ed9fb2fSBrian Somers 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1061a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *) rbuff)->ip_len);
1062a9f484e5SJordan K. Hubbard 	  }
1063af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
106475240ed1SBrian Somers 	  dial_up = 1;	/* XXX */
1065af57ed9fSAtsushi Murai 	}
1066af57ed9fSAtsushi Murai 	continue;
1067af57ed9fSAtsushi Murai       }
106884b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1069a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1070a9f484e5SJordan K. Hubbard 	if (mode & MODE_ALIAS) {
10716ed9fb2fSBrian Somers 	  VarPacketAliasOut(rbuff, sizeof rbuff);
1072a9f484e5SJordan K. Hubbard 	  n = ntohs(((struct ip *) rbuff)->ip_len);
1073a9f484e5SJordan K. Hubbard 	}
1074af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1075af57ed9fSAtsushi Murai       }
1076af57ed9fSAtsushi Murai     }
1077a9f484e5SJordan K. Hubbard   }
1078927145beSBrian Somers   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1079af57ed9fSAtsushi Murai }
1080