xref: /freebsd/usr.sbin/ppp/main.c (revision 0706ff38068def4949593a877183699c26b5f002)
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  *
200706ff38SBrian Somers  * $Id: main.c,v 1.60 1997/06/09 03:27:28 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  */
26af57ed9fSAtsushi Murai #include "fsm.h"
27af57ed9fSAtsushi Murai #include <fcntl.h>
28a9c6b5dfSAtsushi Murai #include <paths.h>
29af57ed9fSAtsushi Murai #include <sys/time.h>
30af57ed9fSAtsushi Murai #include <termios.h>
31c3b6ad66SBrian Somers #include <signal.h>
32af57ed9fSAtsushi Murai #include <sys/wait.h>
33af57ed9fSAtsushi Murai #include <errno.h>
34af57ed9fSAtsushi Murai #include <netdb.h>
359f202f0cSJordan K. Hubbard #include <unistd.h>
36af57ed9fSAtsushi Murai #include <sys/socket.h>
37af57ed9fSAtsushi Murai #include <arpa/inet.h>
38a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h>
39a9f484e5SJordan K. Hubbard #include <netinet/ip.h>
40af57ed9fSAtsushi Murai #include "modem.h"
41af57ed9fSAtsushi Murai #include "os.h"
42af57ed9fSAtsushi Murai #include "hdlc.h"
43ed6a16c1SPoul-Henning Kamp #include "ccp.h"
44af57ed9fSAtsushi Murai #include "lcp.h"
45af57ed9fSAtsushi Murai #include "ipcp.h"
466ed9fb2fSBrian Somers #include "loadalias.h"
47af57ed9fSAtsushi Murai #include "vars.h"
4853c9f6c0SAtsushi Murai #include "auth.h"
4984b8a6ebSAtsushi Murai #include "filter.h"
50ed6a16c1SPoul-Henning Kamp #include "systems.h"
51ed6a16c1SPoul-Henning Kamp #include "ip.h"
52f5ff0f7cSBrian Somers #include "sig.h"
5353c9f6c0SAtsushi Murai 
5441db6564SAtsushi Murai #define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55927145beSBrian Somers #define LAUTH_M2 "Warning: Manipulation is allowed by anyone\n"
5641db6564SAtsushi Murai 
5753c9f6c0SAtsushi Murai #ifndef O_NONBLOCK
5853c9f6c0SAtsushi Murai #ifdef O_NDELAY
5953c9f6c0SAtsushi Murai #define	O_NONBLOCK O_NDELAY
6053c9f6c0SAtsushi Murai #endif
6153c9f6c0SAtsushi Murai #endif
62af57ed9fSAtsushi Murai 
63af57ed9fSAtsushi Murai extern void VjInit(), AsyncInit();
64274e766cSBrian Somers extern void AsyncInput();
65af57ed9fSAtsushi Murai extern int  SelectSystem();
66af57ed9fSAtsushi Murai 
67af57ed9fSAtsushi Murai extern void DecodeCommand(), Prompt();
68b0cdb3ceSJordan K. Hubbard extern int aft_cmd;
69af57ed9fSAtsushi Murai extern int IsInteractive();
70af57ed9fSAtsushi Murai static void DoLoop(void);
71c3899f8dSAtsushi Murai static void TerminalStop();
726efd9292SBrian Somers static char *ex_desc();
73af57ed9fSAtsushi Murai 
74af57ed9fSAtsushi Murai static struct termios oldtio;		/* Original tty mode */
75af57ed9fSAtsushi Murai static struct termios comtio;		/* Command level tty mode */
761dff3fc5SAndrey A. Chernov int TermMode;
777b64106aSPoul-Henning Kamp static int server;
786d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
79af57ed9fSAtsushi Murai struct sockaddr_in ifsin;
8041c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
8141c6c543SBrian Somers static char if_filename[MAXPATHLEN];
8263202ff1SAndrey A. Chernov int tunno;
83af57ed9fSAtsushi Murai 
84af57ed9fSAtsushi Murai static void
85af57ed9fSAtsushi Murai TtyInit()
86af57ed9fSAtsushi Murai {
87af57ed9fSAtsushi Murai   struct termios newtio;
88af57ed9fSAtsushi Murai   int stat;
89af57ed9fSAtsushi Murai 
90af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
91274e766cSBrian Somers   if (stat > 0) {
92af57ed9fSAtsushi Murai 	 stat |= O_NONBLOCK;
93274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
94274e766cSBrian Somers   }
95af57ed9fSAtsushi Murai   newtio = oldtio;
96af57ed9fSAtsushi Murai   newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
97af57ed9fSAtsushi Murai   newtio.c_iflag = 0;
98af57ed9fSAtsushi Murai   newtio.c_oflag &= ~OPOST;
99af57ed9fSAtsushi Murai   newtio.c_cc[VEOF] = _POSIX_VDISABLE;
100af57ed9fSAtsushi Murai   newtio.c_cc[VINTR] = _POSIX_VDISABLE;
101af57ed9fSAtsushi Murai   newtio.c_cc[VMIN] = 1;
102af57ed9fSAtsushi Murai   newtio.c_cc[VTIME] = 0;
103af57ed9fSAtsushi Murai   newtio.c_cflag |= CS8;
10453c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
105af57ed9fSAtsushi Murai   comtio = newtio;
106af57ed9fSAtsushi Murai }
107af57ed9fSAtsushi Murai 
108af57ed9fSAtsushi Murai /*
109af57ed9fSAtsushi Murai  *  Set tty into command mode. We allow canonical input and echo processing.
110af57ed9fSAtsushi Murai  */
111c3899f8dSAtsushi Murai void
112c3899f8dSAtsushi Murai TtyCommandMode(prompt)
113c3899f8dSAtsushi Murai int prompt;
114af57ed9fSAtsushi Murai {
115af57ed9fSAtsushi Murai   struct termios newtio;
116af57ed9fSAtsushi Murai   int stat;
117af57ed9fSAtsushi Murai 
118af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER))
119af57ed9fSAtsushi Murai     return;
12053c9f6c0SAtsushi Murai   tcgetattr(0, &newtio);
121c3899f8dSAtsushi Murai   newtio.c_lflag |= (ECHO|ISIG|ICANON);
122af57ed9fSAtsushi Murai   newtio.c_iflag = oldtio.c_iflag;
123af57ed9fSAtsushi Murai   newtio.c_oflag |= OPOST;
12453c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
125af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
126274e766cSBrian Somers   if (stat > 0) {
127af57ed9fSAtsushi Murai 	 stat |= O_NONBLOCK;
128274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
129274e766cSBrian Somers   }
130af57ed9fSAtsushi Murai   TermMode = 0;
131274e766cSBrian Somers   if(prompt) Prompt();
132af57ed9fSAtsushi Murai }
133af57ed9fSAtsushi Murai 
134af57ed9fSAtsushi Murai /*
135af57ed9fSAtsushi Murai  * Set tty into terminal mode which is used while we invoke term command.
136af57ed9fSAtsushi Murai  */
137af57ed9fSAtsushi Murai void
138af57ed9fSAtsushi Murai TtyTermMode()
139af57ed9fSAtsushi Murai {
140af57ed9fSAtsushi Murai   int stat;
141af57ed9fSAtsushi Murai 
14253c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &comtio);
143af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
144274e766cSBrian Somers   if (stat > 0) {
145af57ed9fSAtsushi Murai 	 stat &= ~O_NONBLOCK;
146274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
147274e766cSBrian Somers   }
148af57ed9fSAtsushi Murai   TermMode = 1;
149af57ed9fSAtsushi Murai }
150af57ed9fSAtsushi Murai 
151af57ed9fSAtsushi Murai void
152c3899f8dSAtsushi Murai TtyOldMode()
153c3899f8dSAtsushi Murai {
154c3899f8dSAtsushi Murai   int stat;
155c3899f8dSAtsushi Murai 
156c3899f8dSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
157274e766cSBrian Somers   if (stat > 0) {
158c3899f8dSAtsushi Murai 	  stat &= ~O_NONBLOCK;
159274e766cSBrian Somers 	  (void)fcntl(0, F_SETFL, stat);
160274e766cSBrian Somers   }
161c3899f8dSAtsushi Murai   tcsetattr(0, TCSANOW, &oldtio);
162c3899f8dSAtsushi Murai }
163c3899f8dSAtsushi Murai 
164c3899f8dSAtsushi Murai void
165af57ed9fSAtsushi Murai Cleanup(excode)
166af57ed9fSAtsushi Murai int excode;
167af57ed9fSAtsushi Murai {
168af57ed9fSAtsushi Murai 
169af57ed9fSAtsushi Murai   OsLinkdown();
170af57ed9fSAtsushi Murai   OsCloseLink(1);
171af57ed9fSAtsushi Murai   sleep(1);
1726efd9292SBrian Somers   if (mode & MODE_AUTO)
1736e4959f0SBrian Somers     DeleteIfRoutes(1);
174aefd026aSBrian Somers   (void)unlink(pid_filename);
175aefd026aSBrian Somers   (void)unlink(if_filename);
176af57ed9fSAtsushi Murai   OsInterfaceDown(1);
1776e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1786e4959f0SBrian Somers     char c = EX_ERRDEAD;
1796e4959f0SBrian Somers     if (write(BGFiledes[1],&c,1) == 1)
180927145beSBrian Somers       LogPrintf(LogPHASE,"Parent notified of failure.\n");
1816e4959f0SBrian Somers     else
182927145beSBrian Somers       LogPrintf(LogPHASE,"Failed to notify parent of failure.\n");
1836e4959f0SBrian Somers     close(BGFiledes[1]);
1846e4959f0SBrian Somers   }
185927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Terminated (%s).\n",ex_desc(excode));
186af57ed9fSAtsushi Murai   LogClose();
187780700e5SAndrey A. Chernov   if (server >= 0) {
188af57ed9fSAtsushi Murai     close(server);
189780700e5SAndrey A. Chernov     server = -1;
190780700e5SAndrey A. Chernov   }
191aefd026aSBrian Somers 
192c3899f8dSAtsushi Murai   TtyOldMode();
193af57ed9fSAtsushi Murai 
194af57ed9fSAtsushi Murai   exit(excode);
195af57ed9fSAtsushi Murai }
196af57ed9fSAtsushi Murai 
197af57ed9fSAtsushi Murai static void
1987a8ef19eSAndrey A. Chernov Hangup(signo)
1997a8ef19eSAndrey A. Chernov int signo;
200af57ed9fSAtsushi Murai {
201927145beSBrian Somers #ifdef TRAPSEGV
202af83607cSAndrey A. Chernov   if (signo == SIGSEGV) {
203927145beSBrian Somers 	LogPrintf(LogPHASE, "Signal %d, core dump.\n", signo);
204af83607cSAndrey A. Chernov 	LogClose();
205af83607cSAndrey A. Chernov 	abort();
206af83607cSAndrey A. Chernov   }
207927145beSBrian Somers #endif
2086d14e2a8SJordan K. Hubbard   if (BGPid) {
209c6c740beSBrian Somers       kill (BGPid, SIGTERM);
2106d14e2a8SJordan K. Hubbard       exit (EX_HANGUP);
2116d14e2a8SJordan K. Hubbard   }
2126d14e2a8SJordan K. Hubbard   else {
213927145beSBrian Somers       LogPrintf(LogPHASE, "Signal %d, hangup.\n", signo);
214af57ed9fSAtsushi Murai       Cleanup(EX_HANGUP);
215af57ed9fSAtsushi Murai   }
2166d14e2a8SJordan K. Hubbard }
217af57ed9fSAtsushi Murai 
218af57ed9fSAtsushi Murai static void
2197a8ef19eSAndrey A. Chernov CloseSession(signo)
2207a8ef19eSAndrey A. Chernov int signo;
221af57ed9fSAtsushi Murai {
2226d14e2a8SJordan K. Hubbard    if (BGPid) {
2236d14e2a8SJordan K. Hubbard      kill (BGPid, SIGINT);
2246d14e2a8SJordan K. Hubbard      exit (EX_TERM);
2256d14e2a8SJordan K. Hubbard    }
226927145beSBrian Somers    LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
22725aa96acSBrian Somers    reconnect(RECON_FALSE);
228af57ed9fSAtsushi Murai    LcpClose();
229af57ed9fSAtsushi Murai    Cleanup(EX_TERM);
230af57ed9fSAtsushi Murai }
231c3899f8dSAtsushi Murai 
232c3899f8dSAtsushi Murai static void
233c3899f8dSAtsushi Murai TerminalCont()
234c3899f8dSAtsushi Murai {
235f5ff0f7cSBrian Somers   pending_signal(SIGCONT, SIG_DFL);
236f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, TerminalStop);
237c3899f8dSAtsushi Murai   TtyCommandMode(getpgrp() == tcgetpgrp(0));
238c3899f8dSAtsushi Murai }
239c3899f8dSAtsushi Murai 
240c3899f8dSAtsushi Murai static void
241c3899f8dSAtsushi Murai TerminalStop(signo)
242c3899f8dSAtsushi Murai int signo;
243c3899f8dSAtsushi Murai {
244f5ff0f7cSBrian Somers   pending_signal(SIGCONT, TerminalCont);
245c3899f8dSAtsushi Murai   TtyOldMode();
246f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, SIG_DFL);
247c3899f8dSAtsushi Murai   kill(getpid(), signo);
248c3899f8dSAtsushi Murai }
249c3899f8dSAtsushi Murai 
2506efd9292SBrian Somers static char *
2516efd9292SBrian Somers ex_desc(int ex)
2526efd9292SBrian Somers {
2536efd9292SBrian Somers   static char num[12];
2546efd9292SBrian Somers   static char *desc[] = { "normal", "start", "sock",
2556efd9292SBrian Somers     "modem", "dial", "dead", "done", "reboot", "errdead",
2566efd9292SBrian Somers     "hangup", "term", "nodial", "nologin" };
2576efd9292SBrian Somers 
2586efd9292SBrian Somers   if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc))
2596efd9292SBrian Somers     return desc[ex];
2606efd9292SBrian Somers   snprintf(num, sizeof num, "%d", ex);
2616efd9292SBrian Somers   return num;
2626efd9292SBrian Somers }
263c3899f8dSAtsushi Murai 
264af57ed9fSAtsushi Murai void
265af57ed9fSAtsushi Murai Usage()
266af57ed9fSAtsushi Murai {
267680026d6SNate Williams   fprintf(stderr,
2686d14e2a8SJordan K. Hubbard           "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
269af57ed9fSAtsushi Murai   exit(EX_START);
270af57ed9fSAtsushi Murai }
271af57ed9fSAtsushi Murai 
272af57ed9fSAtsushi Murai void
273af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
274af57ed9fSAtsushi Murai {
275af57ed9fSAtsushi Murai   int optc;
276af57ed9fSAtsushi Murai   char *cp;
277af57ed9fSAtsushi Murai 
278af57ed9fSAtsushi Murai   optc = 0;
279af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
280af57ed9fSAtsushi Murai     cp = *argv + 1;
281af57ed9fSAtsushi Murai     if (strcmp(cp, "auto") == 0)
282af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
2836d14e2a8SJordan K. Hubbard     else if (strcmp(cp, "background") == 0)
2846efd9292SBrian Somers       mode |= MODE_BACKGROUND|MODE_AUTO;
285af57ed9fSAtsushi Murai     else if (strcmp(cp, "direct") == 0)
286af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
287af57ed9fSAtsushi Murai     else if (strcmp(cp, "dedicated") == 0)
288af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
289680026d6SNate Williams     else if (strcmp(cp, "ddial") == 0)
290680026d6SNate Williams       mode |= MODE_DDIAL|MODE_AUTO;
291a9f484e5SJordan K. Hubbard     else if (strcmp(cp, "alias") == 0) {
2926ed9fb2fSBrian Somers       if (loadAliasHandlers(&VarAliasHandlers) == 0)
293a9f484e5SJordan K. Hubbard         mode |= MODE_ALIAS;
2946ed9fb2fSBrian Somers       else
295927145beSBrian Somers         LogPrintf(LogWARN, "Cannot load alias library\n");
296a9f484e5SJordan K. Hubbard       optc--;             /* this option isn't exclusive */
297a9f484e5SJordan K. Hubbard     }
298af57ed9fSAtsushi Murai     else
299af57ed9fSAtsushi Murai       Usage();
300af57ed9fSAtsushi Murai     optc++;
301af57ed9fSAtsushi Murai     argv++; argc--;
302af57ed9fSAtsushi Murai   }
303af57ed9fSAtsushi Murai   if (argc > 1) {
304af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
305af57ed9fSAtsushi Murai     exit(EX_START);
306af57ed9fSAtsushi Murai   }
307af57ed9fSAtsushi Murai   if (argc == 1) dstsystem = *argv;
308af57ed9fSAtsushi Murai 
309af57ed9fSAtsushi Murai   if (optc > 1) {
310af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
311af57ed9fSAtsushi Murai     exit(EX_START);
312af57ed9fSAtsushi Murai   }
313af57ed9fSAtsushi Murai }
314af57ed9fSAtsushi Murai 
315af57ed9fSAtsushi Murai static void
316af57ed9fSAtsushi Murai Greetings()
317af57ed9fSAtsushi Murai {
318927145beSBrian Somers   if (VarTerm) {
319927145beSBrian Somers     fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
320927145beSBrian Somers     fflush(VarTerm);
321927145beSBrian Somers   }
322af57ed9fSAtsushi Murai }
323af57ed9fSAtsushi Murai 
324af57ed9fSAtsushi Murai void
325af57ed9fSAtsushi Murai main(argc, argv)
326af57ed9fSAtsushi Murai int argc;
327af57ed9fSAtsushi Murai char **argv;
328af57ed9fSAtsushi Murai {
329aefd026aSBrian Somers   FILE *lockfile;
330927145beSBrian Somers   char *name;
331af57ed9fSAtsushi Murai 
3320706ff38SBrian Somers   VarTerm = 0;
333927145beSBrian Somers   name = rindex(argv[0], '/');
334927145beSBrian Somers   LogOpen(name ? name+1 : argv[0]);
335927145beSBrian Somers 
336927145beSBrian Somers   argc--; argv++;
337af57ed9fSAtsushi Murai   mode = MODE_INTER;		/* default operation is interactive mode */
338780700e5SAndrey A. Chernov   netfd = server = modem = tun_in = -1;
339af57ed9fSAtsushi Murai   ProcessArgs(argc, argv);
3401f3dee4cSBrian Somers   if (!(mode & MODE_DIRECT))
3410706ff38SBrian Somers     VarTerm = stdout;
342af57ed9fSAtsushi Murai   Greetings();
343af57ed9fSAtsushi Murai   GetUid();
344af57ed9fSAtsushi Murai   IpcpDefAddress();
345af57ed9fSAtsushi Murai 
346927145beSBrian Somers   if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
347927145beSBrian Somers     fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
348af57ed9fSAtsushi Murai 
34953c9f6c0SAtsushi Murai   switch ( LocalAuthInit() ) {
35053c9f6c0SAtsushi Murai     case NOT_FOUND:
351927145beSBrian Somers         if (VarTerm) {
352927145beSBrian Somers     	  fprintf(VarTerm,LAUTH_M1);
353927145beSBrian Somers     	  fprintf(VarTerm,LAUTH_M2);
3540706ff38SBrian Somers           fflush(VarTerm);
3551f3dee4cSBrian Somers         }
35641db6564SAtsushi Murai 	/* Fall down */
35741db6564SAtsushi Murai     case VALID:
35853c9f6c0SAtsushi Murai 	VarLocalAuth = LOCAL_AUTH;
35953c9f6c0SAtsushi Murai 	break;
36053c9f6c0SAtsushi Murai     default:
36153c9f6c0SAtsushi Murai 	break;
36253c9f6c0SAtsushi Murai   }
36353c9f6c0SAtsushi Murai 
364af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
365927145beSBrian Somers     LogPrintf(LogWARN, "open_tun: %s", strerror(errno));
366af57ed9fSAtsushi Murai     exit(EX_START);
367af57ed9fSAtsushi Murai   }
368af57ed9fSAtsushi Murai 
3696efd9292SBrian Somers   if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
370af57ed9fSAtsushi Murai     mode &= ~MODE_INTER;
371af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
372927145beSBrian Somers     fprintf(VarTerm, "Interactive mode\n");
373780700e5SAndrey A. Chernov     netfd = STDIN_FILENO;
374af57ed9fSAtsushi Murai   } else if (mode & MODE_AUTO) {
375927145beSBrian Somers     fprintf(VarTerm, "Automatic Dialer mode\n");
376af57ed9fSAtsushi Murai     if (dstsystem == NULL) {
377927145beSBrian Somers       if (VarTerm)
378927145beSBrian Somers         fprintf(VarTerm, "Destination system must be specified in"
3796efd9292SBrian Somers               " auto, background or ddial mode.\n");
3806d14e2a8SJordan K. Hubbard       exit(EX_START);
3816d14e2a8SJordan K. Hubbard     }
382af57ed9fSAtsushi Murai   }
383af57ed9fSAtsushi Murai 
38453c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);		/* Save original tty mode */
385af57ed9fSAtsushi Murai 
386927145beSBrian Somers   pending_signal(SIGHUP, Hangup);
387f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
388f5ff0f7cSBrian Somers   pending_signal(SIGINT, CloseSession);
389f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
390927145beSBrian Somers #ifdef TRAPSEGV
391d7f5ee41SAndrey A. Chernov   signal(SIGSEGV, Hangup);
39253c9f6c0SAtsushi Murai #endif
39353c9f6c0SAtsushi Murai #ifdef SIGPIPE
394e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
39553c9f6c0SAtsushi Murai #endif
39653c9f6c0SAtsushi Murai #ifdef SIGALRM
397f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
39853c9f6c0SAtsushi Murai #endif
399c3899f8dSAtsushi Murai   if(mode & MODE_INTER)
400c3899f8dSAtsushi Murai     {
401c3899f8dSAtsushi Murai #ifdef SIGTSTP
402f5ff0f7cSBrian Somers       pending_signal(SIGTSTP, TerminalStop);
403c3899f8dSAtsushi Murai #endif
404c3899f8dSAtsushi Murai #ifdef SIGTTIN
405f5ff0f7cSBrian Somers       pending_signal(SIGTTIN, TerminalStop);
406c3899f8dSAtsushi Murai #endif
407c3899f8dSAtsushi Murai #ifdef SIGTTOU
408f5ff0f7cSBrian Somers       pending_signal(SIGTTOU, SIG_IGN);
409c3899f8dSAtsushi Murai #endif
410c3899f8dSAtsushi Murai     }
411af57ed9fSAtsushi Murai 
412af57ed9fSAtsushi Murai   if (dstsystem) {
413af57ed9fSAtsushi Murai     if (SelectSystem(dstsystem, CONFFILE) < 0) {
4140706ff38SBrian Somers       LogPrintf(LogWARN, "Destination system not found in conf file.\n");
415af57ed9fSAtsushi Murai       Cleanup(EX_START);
416af57ed9fSAtsushi Murai     }
417af57ed9fSAtsushi Murai     if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
4180706ff38SBrian Somers       LogPrintf(LogWARN, "Must specify dstaddr with"
4196efd9292SBrian Somers               " auto, background or ddial mode.\n");
420af57ed9fSAtsushi Murai       Cleanup(EX_START);
421af57ed9fSAtsushi Murai     }
422af57ed9fSAtsushi Murai   }
423af57ed9fSAtsushi Murai 
424af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER)) {
425af57ed9fSAtsushi Murai     int port = SERVER_PORT + tunno;
4266efd9292SBrian Somers 
4276d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4286d14e2a8SJordan K. Hubbard       if (pipe (BGFiledes)) {
429927145beSBrian Somers         LogPrintf(LogERROR, "pipe: %s", strerror(errno));
4306d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4316d14e2a8SJordan K. Hubbard       }
4326d14e2a8SJordan K. Hubbard     }
4336efd9292SBrian Somers 
4346efd9292SBrian Somers     /* Create server socket and listen at there. */
435af57ed9fSAtsushi Murai     server = socket(PF_INET, SOCK_STREAM, 0);
436af57ed9fSAtsushi Murai     if (server < 0) {
437927145beSBrian Somers       LogPrintf(LogERROR, "socket: %s", strerror(errno));
438af57ed9fSAtsushi Murai       Cleanup(EX_SOCK);
439af57ed9fSAtsushi Murai     }
440af57ed9fSAtsushi Murai     ifsin.sin_family = AF_INET;
441af57ed9fSAtsushi Murai     ifsin.sin_addr.s_addr = INADDR_ANY;
442af57ed9fSAtsushi Murai     ifsin.sin_port = htons(port);
443c9bf343aSBrian Somers     setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server);
444af57ed9fSAtsushi Murai     if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
445927145beSBrian Somers       LogPrintf(LogERROR, "bind: %s", strerror(errno));
446927145beSBrian Somers       if (errno == EADDRINUSE && VarTerm)
447927145beSBrian Somers         fprintf(VarTerm, "Wait for a while, then try again.\n");
448af57ed9fSAtsushi Murai       Cleanup(EX_SOCK);
449af57ed9fSAtsushi Murai     }
450274e766cSBrian Somers     if (listen(server, 5) != 0) {
451927145beSBrian Somers       LogPrintf(LogERROR, "Unable to listen to socket - OS overload?\n");
452927145beSBrian Somers       Cleanup(EX_SOCK);
453274e766cSBrian Somers     }
454af57ed9fSAtsushi Murai 
455af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4566d14e2a8SJordan K. Hubbard       pid_t bgpid;
457a9c6b5dfSAtsushi Murai 
4586d14e2a8SJordan K. Hubbard       bgpid = fork ();
4596d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
460927145beSBrian Somers         LogPrintf(LogERROR, "fork: %s", strerror(errno));
4616d14e2a8SJordan K. Hubbard 	Cleanup (EX_SOCK);
4626d14e2a8SJordan K. Hubbard       }
4636d14e2a8SJordan K. Hubbard       if (bgpid) {
4646d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
465a9c6b5dfSAtsushi Murai 
4666d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4676d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4686d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4696e4959f0SBrian Somers           close(BGFiledes[1]);
4706efd9292SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1) {
471927145beSBrian Somers 	    fprintf(VarTerm, "Child exit, no status.\n");
472927145beSBrian Somers 	    LogPrintf (LogPHASE, "Parent: Child exit, no status.\n");
4736efd9292SBrian Somers 	  } else if (c == EX_NORMAL) {
474927145beSBrian Somers 	    fprintf(VarTerm, "PPP enabled.\n");
475927145beSBrian Somers 	    LogPrintf (LogPHASE, "Parent: PPP enabled.\n");
4766efd9292SBrian Somers 	  } else {
477927145beSBrian Somers 	    fprintf(VarTerm, "Child failed (%s).\n",ex_desc((int)c));
478927145beSBrian Somers 	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
47980e37c72SBrian Somers                       ex_desc((int)c));
4806efd9292SBrian Somers           }
4816e4959f0SBrian Somers           close(BGFiledes[0]);
4826d14e2a8SJordan K. Hubbard 	}
4836d14e2a8SJordan K. Hubbard         exit(c);
4846e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
4856e4959f0SBrian Somers           close(BGFiledes[0]);
486aefd026aSBrian Somers     }
4876d14e2a8SJordan K. Hubbard 
488298091daSBrian Somers     snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid",
4896d14e2a8SJordan K. Hubbard              _PATH_VARRUN, tunno);
490aefd026aSBrian Somers     (void)unlink(pid_filename);
491a9c6b5dfSAtsushi Murai 
492aefd026aSBrian Somers     if ((lockfile = fopen(pid_filename, "w")) != NULL) {
49341c6c543SBrian Somers       fprintf(lockfile, "%d\n", (int)getpid());
49441c6c543SBrian Somers       fclose(lockfile);
495aefd026aSBrian Somers     } else
496927145beSBrian Somers       LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
497927145beSBrian Somers                 pid_filename, strerror(errno));
49841c6c543SBrian Somers 
49941c6c543SBrian Somers     snprintf(if_filename, sizeof if_filename, "%s%s.if",
50041c6c543SBrian Somers              _PATH_VARRUN, VarBaseDevice);
501aefd026aSBrian Somers     (void)unlink(if_filename);
50241c6c543SBrian Somers 
503aefd026aSBrian Somers     if ((lockfile = fopen(if_filename, "w")) != NULL) {
50441c6c543SBrian Somers       fprintf(lockfile, "tun%d\n", tunno);
50541c6c543SBrian Somers       fclose(lockfile);
506aefd026aSBrian Somers     } else
507927145beSBrian Somers       LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
508927145beSBrian Somers                 if_filename, strerror(errno));
509aefd026aSBrian Somers 
510780700e5SAndrey A. Chernov     if (server >= 0)
511927145beSBrian Somers 	LogPrintf(LogPHASE, "Listening at %d.\n", port);
5120706ff38SBrian Somers 
5130706ff38SBrian Somers     VarTerm = 0;   /* We know it's currently stdin */
5140706ff38SBrian Somers 
515af57ed9fSAtsushi Murai #ifdef DOTTYINIT
5160706ff38SBrian Somers     if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
517af57ed9fSAtsushi Murai #else
5180706ff38SBrian Somers     if (mode & MODE_DIRECT) {
519af57ed9fSAtsushi Murai #endif
5200706ff38SBrian Somers       chdir("/");  /* Be consistent with daemon() */
521af57ed9fSAtsushi Murai       TtyInit();
5220706ff38SBrian Somers     } else
523927145beSBrian Somers       daemon(0,0);
524af57ed9fSAtsushi Murai   } else {
525af57ed9fSAtsushi Murai     TtyInit();
526c3899f8dSAtsushi Murai     TtyCommandMode(1);
527af57ed9fSAtsushi Murai   }
528927145beSBrian Somers   LogPrintf(LogPHASE, "PPP Started.\n");
529af57ed9fSAtsushi Murai 
530af57ed9fSAtsushi Murai 
531af57ed9fSAtsushi Murai   do
532af57ed9fSAtsushi Murai    DoLoop();
533af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
534af57ed9fSAtsushi Murai 
535af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
536af57ed9fSAtsushi Murai }
537af57ed9fSAtsushi Murai 
538af57ed9fSAtsushi Murai /*
5396d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
540af57ed9fSAtsushi Murai  */
541af57ed9fSAtsushi Murai void
542af57ed9fSAtsushi Murai PacketMode()
543af57ed9fSAtsushi Murai {
544af57ed9fSAtsushi Murai   if (RawModem(modem) < 0) {
545927145beSBrian Somers     LogPrintf(LogWARN, "PacketMode: Not connected.\n");
546af57ed9fSAtsushi Murai     return;
547af57ed9fSAtsushi Murai   }
548af57ed9fSAtsushi Murai 
549af57ed9fSAtsushi Murai   AsyncInit();
550af57ed9fSAtsushi Murai   VjInit();
551af57ed9fSAtsushi Murai   LcpInit();
552af57ed9fSAtsushi Murai   IpcpInit();
553af57ed9fSAtsushi Murai   CcpInit();
554af57ed9fSAtsushi Murai   LcpUp();
555af57ed9fSAtsushi Murai 
556af57ed9fSAtsushi Murai   LcpOpen(VarOpenMode);
557af57ed9fSAtsushi Murai   if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
558c3899f8dSAtsushi Murai     TtyCommandMode(1);
559927145beSBrian Somers     if (VarTerm) {
560927145beSBrian Somers       fprintf(VarTerm, "Packet mode.\n");
561b0cdb3ceSJordan K. Hubbard       aft_cmd = 1;
562af57ed9fSAtsushi Murai     }
563af57ed9fSAtsushi Murai   }
564927145beSBrian Somers }
565af57ed9fSAtsushi Murai 
566af57ed9fSAtsushi Murai static void
567af57ed9fSAtsushi Murai ShowHelp()
568af57ed9fSAtsushi Murai {
569927145beSBrian Somers   fprintf(stderr, "The following commands are available:\n");
570927145beSBrian Somers   fprintf(stderr, " ~p\tEnter Packet mode\n");
571927145beSBrian Somers   fprintf(stderr, " ~-\tDecrease log level\n");
572927145beSBrian Somers   fprintf(stderr, " ~+\tIncrease log level\n");
573927145beSBrian Somers   fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\n");
574927145beSBrian Somers   fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\n");
575927145beSBrian Somers   fprintf(stderr, " ~.\tTerminate program\n");
576927145beSBrian Somers   fprintf(stderr, " ~?\tThis help\n");
577af57ed9fSAtsushi Murai }
578af57ed9fSAtsushi Murai 
579af57ed9fSAtsushi Murai static void
580af57ed9fSAtsushi Murai ReadTty()
581af57ed9fSAtsushi Murai {
582af57ed9fSAtsushi Murai   int n;
583af57ed9fSAtsushi Murai   char ch;
584af57ed9fSAtsushi Murai   static int ttystate;
585927145beSBrian Somers   FILE *oVarTerm;
586af57ed9fSAtsushi Murai #define MAXLINESIZE 200
587af57ed9fSAtsushi Murai   char linebuff[MAXLINESIZE];
588af57ed9fSAtsushi Murai 
589927145beSBrian Somers   LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
590927145beSBrian Somers             TermMode, netfd, mode);
591af57ed9fSAtsushi Murai   if (!TermMode) {
592af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff)-1);
59353c9f6c0SAtsushi Murai     if (n > 0) {
594927145beSBrian Somers       aft_cmd = 1;
595af57ed9fSAtsushi Murai       DecodeCommand(linebuff, n, 1);
59653c9f6c0SAtsushi Murai     } else {
597927145beSBrian Somers       LogPrintf(LogPHASE, "client connection closed.\n");
598e0d3e233SAndrey A. Chernov       VarLocalAuth = LOCAL_NO_AUTH;
599af57ed9fSAtsushi Murai       mode &= ~MODE_INTER;
600927145beSBrian Somers       oVarTerm = VarTerm;
601927145beSBrian Somers       VarTerm = 0;
602927145beSBrian Somers       if (oVarTerm && oVarTerm != stdout)
603927145beSBrian Somers         fclose(oVarTerm);
604927145beSBrian Somers       close(netfd);
605927145beSBrian Somers       netfd = -1;
606af57ed9fSAtsushi Murai     }
607af57ed9fSAtsushi Murai     return;
608af57ed9fSAtsushi Murai   }
609af57ed9fSAtsushi Murai 
610af57ed9fSAtsushi Murai   /*
611af57ed9fSAtsushi Murai    *  We are in terminal mode, decode special sequences
612af57ed9fSAtsushi Murai    */
613927145beSBrian Somers   n = read(fileno(VarTerm), &ch, 1);
614927145beSBrian Somers   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)", n);
615af57ed9fSAtsushi Murai 
616af57ed9fSAtsushi Murai   if (n > 0) {
617af57ed9fSAtsushi Murai     switch (ttystate) {
618af57ed9fSAtsushi Murai     case 0:
619af57ed9fSAtsushi Murai       if (ch == '~')
620af57ed9fSAtsushi Murai 	ttystate++;
621af57ed9fSAtsushi Murai       else
622af57ed9fSAtsushi Murai 	write(modem, &ch, n);
623af57ed9fSAtsushi Murai       break;
624af57ed9fSAtsushi Murai     case 1:
625af57ed9fSAtsushi Murai       switch (ch) {
626af57ed9fSAtsushi Murai       case '?':
627af57ed9fSAtsushi Murai 	ShowHelp();
628af57ed9fSAtsushi Murai 	break;
629af57ed9fSAtsushi Murai       case 'p':
630af57ed9fSAtsushi Murai 	/*
631af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
632af57ed9fSAtsushi Murai 	 */
633af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
634af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
635af57ed9fSAtsushi Murai 	  PacketMode();
636af57ed9fSAtsushi Murai 	}
637af57ed9fSAtsushi Murai 	break;
638af57ed9fSAtsushi Murai       case '.':
639af57ed9fSAtsushi Murai 	TermMode = 1;
640927145beSBrian Somers 	aft_cmd = 1;
641c3899f8dSAtsushi Murai 	TtyCommandMode(1);
642af57ed9fSAtsushi Murai 	break;
643927145beSBrian Somers       case 't':
644927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
645927145beSBrian Somers 	  ShowTimers();
646927145beSBrian Somers 	  break;
647927145beSBrian Somers 	}
648927145beSBrian Somers       case 'm':
649927145beSBrian Somers 	if (LogIsKept(LogDEBUG)) {
650927145beSBrian Somers 	  ShowMemMap();
651927145beSBrian Somers 	  break;
652927145beSBrian Somers 	}
653af57ed9fSAtsushi Murai       default:
654af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
655927145beSBrian Somers 	  LogPrintf(LogERROR, "error writing to modem.\n");
656af57ed9fSAtsushi Murai 	break;
657af57ed9fSAtsushi Murai       }
658af57ed9fSAtsushi Murai       ttystate = 0;
659af57ed9fSAtsushi Murai       break;
660af57ed9fSAtsushi Murai     }
661af57ed9fSAtsushi Murai   }
662af57ed9fSAtsushi Murai }
663af57ed9fSAtsushi Murai 
664af57ed9fSAtsushi Murai 
665af57ed9fSAtsushi Murai /*
666af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
667af57ed9fSAtsushi Murai  */
668af57ed9fSAtsushi Murai 
669af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
67053c9f6c0SAtsushi Murai   "\176\377\003\300\041",
67153c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
67253c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
67353c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
67453c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
675af57ed9fSAtsushi Murai   NULL,
676af57ed9fSAtsushi Murai };
677af57ed9fSAtsushi Murai 
678af57ed9fSAtsushi Murai u_char *
679af57ed9fSAtsushi Murai HdlcDetect(cp, n)
680af57ed9fSAtsushi Murai u_char *cp;
681af57ed9fSAtsushi Murai int n;
682af57ed9fSAtsushi Murai {
68353c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
684af57ed9fSAtsushi Murai 
685af57ed9fSAtsushi Murai   cp[n] = '\0';	/* be sure to null terminated */
686af57ed9fSAtsushi Murai   ptr = NULL;
687af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
68853c9f6c0SAtsushi Murai     fp = *hp;
68953c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
69053c9f6c0SAtsushi Murai       fp++;
691ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *)cp, fp);
692ed6a16c1SPoul-Henning Kamp     if (ptr)
693af57ed9fSAtsushi Murai       break;
694af57ed9fSAtsushi Murai   }
695af57ed9fSAtsushi Murai   return((u_char *)ptr);
696af57ed9fSAtsushi Murai }
697af57ed9fSAtsushi Murai 
698af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
699af57ed9fSAtsushi Murai 
700af57ed9fSAtsushi Murai static void
701af57ed9fSAtsushi Murai RedialTimeout()
702af57ed9fSAtsushi Murai {
703af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
704927145beSBrian Somers   LogPrintf(LogPHASE, "Redialing timer expired.\n");
705af57ed9fSAtsushi Murai }
706af57ed9fSAtsushi Murai 
707af57ed9fSAtsushi Murai static void
70843ea9d19SBrian Somers StartRedialTimer(Timeout)
70943ea9d19SBrian Somers 	int Timeout;
710af57ed9fSAtsushi Murai {
711af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
712a9c6b5dfSAtsushi Murai 
71343ea9d19SBrian Somers   if (Timeout) {
714af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
715a9c6b5dfSAtsushi Murai 
71643ea9d19SBrian Somers     if (Timeout > 0)
71743ea9d19SBrian Somers 	RedialTimer.load = Timeout * SECTICKS;
718a9c6b5dfSAtsushi Murai     else
719a9c6b5dfSAtsushi Murai 	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
720a9c6b5dfSAtsushi Murai 
721927145beSBrian Somers     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
72243ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
72343ea9d19SBrian Somers 
724af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
725af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
726af57ed9fSAtsushi Murai   }
727a9c6b5dfSAtsushi Murai }
728af57ed9fSAtsushi Murai 
729af57ed9fSAtsushi Murai 
730af57ed9fSAtsushi Murai static void
731af57ed9fSAtsushi Murai DoLoop()
732af57ed9fSAtsushi Murai {
733af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
734780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
735af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
736af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
737af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
738af57ed9fSAtsushi Murai   u_char *cp;
739af57ed9fSAtsushi Murai   u_char rbuff[MAX_MRU];
74084b8a6ebSAtsushi Murai   int dial_up;
741a9c6b5dfSAtsushi Murai   int tries;
74260e218e4SAtsushi Murai   int qlen;
743c3899f8dSAtsushi Murai   pid_t pgroup;
744c3899f8dSAtsushi Murai 
745c3899f8dSAtsushi Murai   pgroup = getpgrp();
746af57ed9fSAtsushi Murai 
7476efd9292SBrian Somers   if (mode & MODE_DIRECT) {
7480706ff38SBrian Somers     LogPrintf(LogDEBUG, "Opening modem\n");
749af57ed9fSAtsushi Murai     modem = OpenModem(mode);
750927145beSBrian Somers     LogPrintf(LogPHASE, "Packet mode enabled\n");
751af57ed9fSAtsushi Murai     PacketMode();
752af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
753780700e5SAndrey A. Chernov     if (modem < 0)
754af57ed9fSAtsushi Murai       modem = OpenModem(mode);
755af57ed9fSAtsushi Murai   }
756af57ed9fSAtsushi Murai 
757927145beSBrian Somers   fflush(VarTerm);
758af57ed9fSAtsushi Murai 
75984b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
760af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
76125aa96acSBrian Somers   reconnectState = RECON_UNKNOWN;
762af57ed9fSAtsushi Murai 
7636e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
7646e4959f0SBrian Somers     dial_up = TRUE;			/* Bring the line up */
7656e4959f0SBrian Somers   else
76684b8a6ebSAtsushi Murai     dial_up = FALSE;			/* XXXX */
767a9c6b5dfSAtsushi Murai   tries = 0;
768af57ed9fSAtsushi Murai   for (;;) {
769780700e5SAndrey A. Chernov     nfds = 0;
770af57ed9fSAtsushi Murai     FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
77184b8a6ebSAtsushi Murai 
77284b8a6ebSAtsushi Murai     /*
773680026d6SNate Williams      * If the link is down and we're in DDIAL mode, bring it back
774680026d6SNate Williams      * up.
775680026d6SNate Williams      */
776680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
777680026d6SNate Williams         dial_up = TRUE;
778680026d6SNate Williams 
779680026d6SNate Williams     /*
78007030d97SBrian Somers      * If we lost carrier and want to re-establish the connection
78107030d97SBrian Somers      * due to the "set reconnect" value, we'd better bring the line
7826efd9292SBrian Somers      * back up.
78307030d97SBrian Somers      */
7846efd9292SBrian Somers     if (LcpFsm.state <= ST_CLOSED) {
78525aa96acSBrian Somers       if (dial_up != TRUE && reconnectState == RECON_TRUE) {
7866efd9292SBrian Somers         if (++reconnectCount <= VarReconnectTries) {
787927145beSBrian Somers           LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
7886efd9292SBrian Somers                     reconnectCount, VarReconnectTries);
78907030d97SBrian Somers 	  StartRedialTimer(VarReconnectTimer);
79007030d97SBrian Somers           dial_up = TRUE;
791298091daSBrian Somers         } else {
7926efd9292SBrian Somers           if (VarReconnectTries)
793927145beSBrian Somers             LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
794298091daSBrian Somers                       VarReconnectTries);
7956efd9292SBrian Somers           reconnectCount = 0;
7966efd9292SBrian Somers           if (mode & MODE_BACKGROUND)
7976efd9292SBrian Somers             Cleanup(EX_DEAD);
7986efd9292SBrian Somers         }
79925aa96acSBrian Somers         reconnectState = RECON_ENVOKED;
8006efd9292SBrian Somers       }
80107030d97SBrian Somers     }
80207030d97SBrian Somers 
80307030d97SBrian Somers    /*
80484b8a6ebSAtsushi Murai     * If Ip packet for output is enqueued and require dial up,
80584b8a6ebSAtsushi Murai     * Just do it!
80684b8a6ebSAtsushi Murai     */
80707030d97SBrian Somers     if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
808927145beSBrian Somers       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
80984b8a6ebSAtsushi Murai       modem = OpenModem(mode);
81084b8a6ebSAtsushi Murai       if (modem < 0) {
8110706ff38SBrian Somers         tries++;
8120706ff38SBrian Somers         if (VarDialTries)
8130706ff38SBrian Somers           LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
8140706ff38SBrian Somers 	            tries, VarDialTries);
8150706ff38SBrian Somers         else
8160706ff38SBrian Somers 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
8170706ff38SBrian Somers 
8180706ff38SBrian Somers 	if (VarDialTries && tries >= VarDialTries) {
8190706ff38SBrian Somers 	  if (mode & MODE_BACKGROUND)
8200706ff38SBrian Somers 	    Cleanup(EX_DIAL);  /* Can't get the modem */
8210706ff38SBrian Somers 	  dial_up = FALSE;
8220706ff38SBrian Somers           reconnectState = RECON_UNKNOWN;
8230706ff38SBrian Somers           reconnectCount = 0;
8240706ff38SBrian Somers 	  tries = 0;
8250706ff38SBrian Somers         } else
82643ea9d19SBrian Somers 	  StartRedialTimer(VarRedialTimeout);
82784b8a6ebSAtsushi Murai       } else {
828c0139fb2SBrian Somers 	tries++;    /* Tries are per number, not per list of numbers. */
829c0139fb2SBrian Somers         if (VarDialTries)
830927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries,
831c0139fb2SBrian Somers 		    VarDialTries);
832c0139fb2SBrian Somers         else
833927145beSBrian Somers 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
834e83481f9SBrian Somers 	if (DialModem() == EX_DONE) {
83584b8a6ebSAtsushi Murai 	  sleep(1);	       /* little pause to allow peer starts */
83684b8a6ebSAtsushi Murai 	  ModemTimeout();
83784b8a6ebSAtsushi Murai 	  PacketMode();
83884b8a6ebSAtsushi Murai 	  dial_up = FALSE;
83925aa96acSBrian Somers           reconnectState = RECON_UNKNOWN;
840a9c6b5dfSAtsushi Murai 	  tries = 0;
84184b8a6ebSAtsushi Murai 	} else {
84284b8a6ebSAtsushi Murai 	  CloseModem();
8434ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
8444ed9958fSBrian Somers 	    if (VarNextPhone == NULL)
8454ed9958fSBrian Somers 	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
8464ed9958fSBrian Somers 	    else
84743ea9d19SBrian Somers 	      /* Try all numbers in background mode */
84843ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
8494ed9958fSBrian Somers 	  } else if (VarDialTries && tries >= VarDialTries) {
850c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
85143ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
852a9c6b5dfSAtsushi Murai 	    dial_up = FALSE;
85325aa96acSBrian Somers             reconnectState = RECON_UNKNOWN;
85425aa96acSBrian Somers             reconnectCount = 0;
855a9c6b5dfSAtsushi Murai 	    tries = 0;
856c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
857c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
85843ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
859c0139fb2SBrian Somers 	  else
86043ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
86184b8a6ebSAtsushi Murai 	}
86284b8a6ebSAtsushi Murai       }
86384b8a6ebSAtsushi Murai     }
86460e218e4SAtsushi Murai     qlen = ModemQlen();
86576bd0c0aSDoug Rabson 
86676bd0c0aSDoug Rabson     if (qlen == 0) {
86776bd0c0aSDoug Rabson       IpStartOutput();
86876bd0c0aSDoug Rabson       qlen = ModemQlen();
86976bd0c0aSDoug Rabson     }
87076bd0c0aSDoug Rabson 
871780700e5SAndrey A. Chernov     if (modem >= 0) {
872780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
873780700e5SAndrey A. Chernov 	nfds = modem + 1;
87484b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
87584b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
87660e218e4SAtsushi Murai       if (qlen > 0) {
87784b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
87884b8a6ebSAtsushi Murai       }
87984b8a6ebSAtsushi Murai     }
880780700e5SAndrey A. Chernov     if (server >= 0) {
881780700e5SAndrey A. Chernov       if (server + 1 > nfds)
882780700e5SAndrey A. Chernov 	nfds = server + 1;
883780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
884780700e5SAndrey A. Chernov     }
885af57ed9fSAtsushi Murai 
886af57ed9fSAtsushi Murai     /*  *** IMPORTANT ***
887af57ed9fSAtsushi Murai      *
888af57ed9fSAtsushi Murai      *  CPU is serviced every TICKUNIT micro seconds.
889af57ed9fSAtsushi Murai      *	This value must be chosen with great care. If this values is
890af57ed9fSAtsushi Murai      *  too big, it results loss of characters from modem and poor responce.
891af57ed9fSAtsushi Murai      *  If this values is too small, ppp process eats many CPU time.
892af57ed9fSAtsushi Murai      */
89353c9f6c0SAtsushi Murai #ifndef SIGALRM
894af57ed9fSAtsushi Murai     usleep(TICKUNIT);
895af57ed9fSAtsushi Murai     TimerService();
896f5ff0f7cSBrian Somers #else
897f5ff0f7cSBrian Somers     handle_signals();
89853c9f6c0SAtsushi Murai #endif
89968d2b4d6SBruce Evans 
90068d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
901780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
902780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
903780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
90484b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
905780700e5SAndrey A. Chernov     }
90668d2b4d6SBruce Evans 
907780700e5SAndrey A. Chernov     if (netfd >= 0) {
908780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
909780700e5SAndrey A. Chernov 	nfds = netfd + 1;
910af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
911af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
912af57ed9fSAtsushi Murai     }
91384b8a6ebSAtsushi Murai 
91453c9f6c0SAtsushi Murai #ifndef SIGALRM
915af57ed9fSAtsushi Murai     /*
91684b8a6ebSAtsushi Murai      *  Normally, select() will not block because modem is writable.
91784b8a6ebSAtsushi Murai      *  In AUTO mode, select will block until we find packet from tun
918af57ed9fSAtsushi Murai      */
919af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
920780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
92153c9f6c0SAtsushi Murai #else
92284b8a6ebSAtsushi Murai     /*
92384b8a6ebSAtsushi Murai      * When SIGALRM timer is running, a select function will be
92484b8a6ebSAtsushi Murai      * return -1 and EINTR after a Time Service signal hundler
925a9c6b5dfSAtsushi Murai      * is done.  If the redial timer is not running and we are
926a9c6b5dfSAtsushi Murai      * trying to dial, poll with a 0 value timer.
92784b8a6ebSAtsushi Murai      */
928a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
929780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
93053c9f6c0SAtsushi Murai #endif
9316b0b88d8SBrian Somers 
932af57ed9fSAtsushi Murai     if ( i == 0 ) {
933af57ed9fSAtsushi Murai         continue;
934af57ed9fSAtsushi Murai     }
93553c9f6c0SAtsushi Murai 
936534fe541SBrian Somers     if ( i < 0 ) {
937534fe541SBrian Somers        if ( errno == EINTR ) {
938f5ff0f7cSBrian Somers           handle_signals();
939f5ff0f7cSBrian Somers           continue;
94084b8a6ebSAtsushi Murai        }
941927145beSBrian Somers        LogPrintf(LogERROR, "select: %s", strerror(errno));
942af57ed9fSAtsushi Murai        break;
943af57ed9fSAtsushi Murai     }
94484b8a6ebSAtsushi Murai 
945780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
946927145beSBrian Somers       LogPrintf(LogALERT, "Exception detected.\n");
947af57ed9fSAtsushi Murai       break;
948af57ed9fSAtsushi Murai     }
949af57ed9fSAtsushi Murai 
950780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
951927145beSBrian Somers       LogPrintf(LogPHASE, "connected to client.\n");
952af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
953e0d3e233SAndrey A. Chernov       if (wfd < 0) {
954927145beSBrian Somers         LogPrintf(LogERROR, "accept: %s", strerror(errno));
955e0d3e233SAndrey A. Chernov 	continue;
956e0d3e233SAndrey A. Chernov       }
957780700e5SAndrey A. Chernov       if (netfd >= 0) {
958af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
959af57ed9fSAtsushi Murai 	close(wfd);
960af57ed9fSAtsushi Murai 	continue;
961af57ed9fSAtsushi Murai       } else
962af57ed9fSAtsushi Murai 	netfd = wfd;
963927145beSBrian Somers       VarTerm = fdopen(netfd, "a+");
964af57ed9fSAtsushi Murai       mode |= MODE_INTER;
965af57ed9fSAtsushi Murai       Greetings();
96641db6564SAtsushi Murai       switch ( LocalAuthInit() ) {
96741db6564SAtsushi Murai          case NOT_FOUND:
968927145beSBrian Somers 	    if (VarTerm) {
969927145beSBrian Somers     	      fprintf(VarTerm,LAUTH_M1);
970927145beSBrian Somers     	      fprintf(VarTerm,LAUTH_M2);
971927145beSBrian Somers               fflush(VarTerm);
972927145beSBrian Somers             }
97341db6564SAtsushi Murai 	    /* Fall down */
97441db6564SAtsushi Murai          case VALID:
97541db6564SAtsushi Murai 	    VarLocalAuth = LOCAL_AUTH;
97641db6564SAtsushi Murai 	    break;
97741db6564SAtsushi Murai          default:
97841db6564SAtsushi Murai 	    break;
97941db6564SAtsushi Murai       }
980af57ed9fSAtsushi Murai       (void) IsInteractive();
981274e766cSBrian Somers       Prompt();
982af57ed9fSAtsushi Murai     }
983af57ed9fSAtsushi Murai 
984780700e5SAndrey A. Chernov     if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
985f1884650SAtsushi Murai 	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
986af57ed9fSAtsushi Murai       /* something to read from tty */
987af57ed9fSAtsushi Murai       ReadTty();
988af57ed9fSAtsushi Murai     }
989780700e5SAndrey A. Chernov     if (modem >= 0) {
990af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
991af57ed9fSAtsushi Murai 	 ModemStartOutput(modem);
992af57ed9fSAtsushi Murai       }
993af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
99453c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
99553c9f6c0SAtsushi Murai 	  usleep(10000);
996af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
997af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
998af57ed9fSAtsushi Murai 	  DownConnection();
999af57ed9fSAtsushi Murai 	} else
1000927145beSBrian Somers           LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
1001af57ed9fSAtsushi Murai 
1002af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
1003af57ed9fSAtsushi Murai 	  /*
1004af57ed9fSAtsushi Murai 	   *  In dedicated mode, we just discard input until LCP is started.
1005af57ed9fSAtsushi Murai 	   */
1006af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
1007af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
1008af57ed9fSAtsushi Murai 	    if (cp) {
1009af57ed9fSAtsushi Murai 	      /*
1010af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
1011af57ed9fSAtsushi Murai 	       */
1012af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
1013927145beSBrian Somers 	        write(modem, rbuff, cp - rbuff);
1014927145beSBrian Somers 	        write(modem, "\r\n", 2);
1015af57ed9fSAtsushi Murai 	      }
1016af57ed9fSAtsushi Murai 	      PacketMode();
1017af57ed9fSAtsushi Murai 	    } else
1018927145beSBrian Somers 	      write(fileno(VarTerm), rbuff, n);
1019af57ed9fSAtsushi Murai 	  }
1020af57ed9fSAtsushi Murai 	} else {
1021af57ed9fSAtsushi Murai 	  if (n > 0)
1022af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
1023af57ed9fSAtsushi Murai 	}
1024af57ed9fSAtsushi Murai       }
1025af57ed9fSAtsushi Murai     }
102684b8a6ebSAtsushi Murai 
1027780700e5SAndrey A. Chernov     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
1028af57ed9fSAtsushi Murai       n = read(tun_in, rbuff, sizeof(rbuff));
1029af57ed9fSAtsushi Murai       if (n < 0) {
1030927145beSBrian Somers         LogPrintf(LogERROR, "read from tun: %s", strerror(errno));
1031af57ed9fSAtsushi Murai 	continue;
1032af57ed9fSAtsushi Murai       }
1033af57ed9fSAtsushi Murai       /*
1034af57ed9fSAtsushi Murai        *  Process on-demand dialup. Output packets are queued within tunnel
1035af57ed9fSAtsushi Murai        *  device until IPCP is opened.
1036af57ed9fSAtsushi Murai        */
1037af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
103884b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1039af57ed9fSAtsushi Murai 	if (pri >= 0) {
1040a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10416ed9fb2fSBrian Somers 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1042a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *)rbuff)->ip_len);
1043a9f484e5SJordan K. Hubbard 	  }
1044af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
104584b8a6ebSAtsushi Murai 	  dial_up = TRUE;		/* XXX */
1046af57ed9fSAtsushi Murai 	}
1047af57ed9fSAtsushi Murai 	continue;
1048af57ed9fSAtsushi Murai       }
104984b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1050a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1051a9f484e5SJordan K. Hubbard         if (mode & MODE_ALIAS) {
10526ed9fb2fSBrian Somers           VarPacketAliasOut(rbuff, sizeof rbuff);
1053a9f484e5SJordan K. Hubbard           n = ntohs(((struct ip *)rbuff)->ip_len);
1054a9f484e5SJordan K. Hubbard         }
1055af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1056af57ed9fSAtsushi Murai       }
1057af57ed9fSAtsushi Murai     }
1058a9f484e5SJordan K. Hubbard   }
1059927145beSBrian Somers   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1060af57ed9fSAtsushi Murai }
1061