xref: /freebsd/usr.sbin/ppp/main.c (revision aefd026afb1b9ca538deac1bcba44946451071c7)
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  *
20aefd026aSBrian Somers  * $Id: main.c,v 1.48 1997/05/10 03:39:53 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"
46af57ed9fSAtsushi Murai #include "vars.h"
4753c9f6c0SAtsushi Murai #include "auth.h"
4884b8a6ebSAtsushi Murai #include "filter.h"
49ed6a16c1SPoul-Henning Kamp #include "systems.h"
50ed6a16c1SPoul-Henning Kamp #include "ip.h"
51a9f484e5SJordan K. Hubbard #include "alias.h"
52f5ff0f7cSBrian Somers #include "sig.h"
5353c9f6c0SAtsushi Murai 
5441db6564SAtsushi Murai #define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55bea0b497SSatoshi Asami #define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\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();
72af57ed9fSAtsushi Murai 
73af57ed9fSAtsushi Murai static struct termios oldtio;		/* Original tty mode */
74af57ed9fSAtsushi Murai static struct termios comtio;		/* Command level tty mode */
751dff3fc5SAndrey A. Chernov int TermMode;
767b64106aSPoul-Henning Kamp static int server;
776d14e2a8SJordan K. Hubbard static pid_t BGPid = 0;
78af57ed9fSAtsushi Murai struct sockaddr_in ifsin;
7941c6c543SBrian Somers static char pid_filename[MAXPATHLEN];
8041c6c543SBrian Somers static char if_filename[MAXPATHLEN];
8163202ff1SAndrey A. Chernov int tunno;
82af57ed9fSAtsushi Murai 
83af57ed9fSAtsushi Murai static void
84af57ed9fSAtsushi Murai TtyInit()
85af57ed9fSAtsushi Murai {
86af57ed9fSAtsushi Murai   struct termios newtio;
87af57ed9fSAtsushi Murai   int stat;
88af57ed9fSAtsushi Murai 
89af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
90274e766cSBrian Somers   if (stat > 0) {
91af57ed9fSAtsushi Murai 	 stat |= O_NONBLOCK;
92274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
93274e766cSBrian Somers   }
94af57ed9fSAtsushi Murai   newtio = oldtio;
95af57ed9fSAtsushi Murai   newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
96af57ed9fSAtsushi Murai   newtio.c_iflag = 0;
97af57ed9fSAtsushi Murai   newtio.c_oflag &= ~OPOST;
98af57ed9fSAtsushi Murai   newtio.c_cc[VEOF] = _POSIX_VDISABLE;
99af57ed9fSAtsushi Murai   newtio.c_cc[VINTR] = _POSIX_VDISABLE;
100af57ed9fSAtsushi Murai   newtio.c_cc[VMIN] = 1;
101af57ed9fSAtsushi Murai   newtio.c_cc[VTIME] = 0;
102af57ed9fSAtsushi Murai   newtio.c_cflag |= CS8;
10353c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
104af57ed9fSAtsushi Murai   comtio = newtio;
105af57ed9fSAtsushi Murai }
106af57ed9fSAtsushi Murai 
107af57ed9fSAtsushi Murai /*
108af57ed9fSAtsushi Murai  *  Set tty into command mode. We allow canonical input and echo processing.
109af57ed9fSAtsushi Murai  */
110c3899f8dSAtsushi Murai void
111c3899f8dSAtsushi Murai TtyCommandMode(prompt)
112c3899f8dSAtsushi Murai int prompt;
113af57ed9fSAtsushi Murai {
114af57ed9fSAtsushi Murai   struct termios newtio;
115af57ed9fSAtsushi Murai   int stat;
116af57ed9fSAtsushi Murai 
117af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER))
118af57ed9fSAtsushi Murai     return;
11953c9f6c0SAtsushi Murai   tcgetattr(0, &newtio);
120c3899f8dSAtsushi Murai   newtio.c_lflag |= (ECHO|ISIG|ICANON);
121af57ed9fSAtsushi Murai   newtio.c_iflag = oldtio.c_iflag;
122af57ed9fSAtsushi Murai   newtio.c_oflag |= OPOST;
12353c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &newtio);
124af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
125274e766cSBrian Somers   if (stat > 0) {
126af57ed9fSAtsushi Murai 	 stat |= O_NONBLOCK;
127274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
128274e766cSBrian Somers   }
129af57ed9fSAtsushi Murai   TermMode = 0;
130274e766cSBrian Somers   if(prompt) Prompt();
131af57ed9fSAtsushi Murai }
132af57ed9fSAtsushi Murai 
133af57ed9fSAtsushi Murai /*
134af57ed9fSAtsushi Murai  * Set tty into terminal mode which is used while we invoke term command.
135af57ed9fSAtsushi Murai  */
136af57ed9fSAtsushi Murai void
137af57ed9fSAtsushi Murai TtyTermMode()
138af57ed9fSAtsushi Murai {
139af57ed9fSAtsushi Murai   int stat;
140af57ed9fSAtsushi Murai 
14153c9f6c0SAtsushi Murai   tcsetattr(0, TCSADRAIN, &comtio);
142af57ed9fSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
143274e766cSBrian Somers   if (stat > 0) {
144af57ed9fSAtsushi Murai 	 stat &= ~O_NONBLOCK;
145274e766cSBrian Somers 	 (void)fcntl(0, F_SETFL, stat);
146274e766cSBrian Somers   }
147af57ed9fSAtsushi Murai   TermMode = 1;
148af57ed9fSAtsushi Murai }
149af57ed9fSAtsushi Murai 
150af57ed9fSAtsushi Murai void
151c3899f8dSAtsushi Murai TtyOldMode()
152c3899f8dSAtsushi Murai {
153c3899f8dSAtsushi Murai   int stat;
154c3899f8dSAtsushi Murai 
155c3899f8dSAtsushi Murai   stat = fcntl(0, F_GETFL, 0);
156274e766cSBrian Somers   if (stat > 0) {
157c3899f8dSAtsushi Murai 	  stat &= ~O_NONBLOCK;
158274e766cSBrian Somers 	  (void)fcntl(0, F_SETFL, stat);
159274e766cSBrian Somers   }
160c3899f8dSAtsushi Murai   tcsetattr(0, TCSANOW, &oldtio);
161c3899f8dSAtsushi Murai }
162c3899f8dSAtsushi Murai 
163c3899f8dSAtsushi Murai void
164af57ed9fSAtsushi Murai Cleanup(excode)
165af57ed9fSAtsushi Murai int excode;
166af57ed9fSAtsushi Murai {
167af57ed9fSAtsushi Murai 
168af57ed9fSAtsushi Murai   OsLinkdown();
169af57ed9fSAtsushi Murai   OsCloseLink(1);
170af57ed9fSAtsushi Murai   sleep(1);
171aefd026aSBrian Somers   if (mode & (MODE_AUTO | MODE_BACKGROUND))
1726e4959f0SBrian Somers     DeleteIfRoutes(1);
173aefd026aSBrian Somers   (void)unlink(pid_filename);
174aefd026aSBrian Somers   (void)unlink(if_filename);
175af57ed9fSAtsushi Murai   OsInterfaceDown(1);
1766e4959f0SBrian Somers   if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1776e4959f0SBrian Somers     char c = EX_ERRDEAD;
1786e4959f0SBrian Somers     if (write(BGFiledes[1],&c,1) == 1)
1796e4959f0SBrian Somers       LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
1806e4959f0SBrian Somers     else
1816e4959f0SBrian Somers       LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
1826e4959f0SBrian Somers     close(BGFiledes[1]);
1836e4959f0SBrian Somers   }
1844ed9958fSBrian Somers   LogPrintf(LOG_PHASE_BIT, "PPP Terminated %d.\n",excode);
185af57ed9fSAtsushi Murai   LogClose();
186780700e5SAndrey A. Chernov   if (server >= 0) {
187af57ed9fSAtsushi Murai     close(server);
188780700e5SAndrey A. Chernov     server = -1;
189780700e5SAndrey A. Chernov   }
190aefd026aSBrian Somers 
191c3899f8dSAtsushi Murai   TtyOldMode();
192af57ed9fSAtsushi Murai 
193af57ed9fSAtsushi Murai   exit(excode);
194af57ed9fSAtsushi Murai }
195af57ed9fSAtsushi Murai 
196af57ed9fSAtsushi Murai static void
1977a8ef19eSAndrey A. Chernov Hangup(signo)
1987a8ef19eSAndrey A. Chernov int signo;
199af57ed9fSAtsushi Murai {
200af83607cSAndrey A. Chernov   if (signo == SIGSEGV) {
201af83607cSAndrey A. Chernov 	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
202af83607cSAndrey A. Chernov 	LogClose();
203af83607cSAndrey A. Chernov 	abort();
204af83607cSAndrey A. Chernov   }
2056d14e2a8SJordan K. Hubbard   if (BGPid) {
206c6c740beSBrian Somers       kill (BGPid, SIGTERM);
2076d14e2a8SJordan K. Hubbard       exit (EX_HANGUP);
2086d14e2a8SJordan K. Hubbard   }
2096d14e2a8SJordan K. Hubbard   else {
2109c749ffbSPoul-Henning Kamp       LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
211af57ed9fSAtsushi Murai       Cleanup(EX_HANGUP);
212af57ed9fSAtsushi Murai   }
2136d14e2a8SJordan K. Hubbard }
214af57ed9fSAtsushi Murai 
215af57ed9fSAtsushi Murai static void
2167a8ef19eSAndrey A. Chernov CloseSession(signo)
2177a8ef19eSAndrey A. Chernov int signo;
218af57ed9fSAtsushi Murai {
2196d14e2a8SJordan K. Hubbard    if (BGPid) {
2206d14e2a8SJordan K. Hubbard      kill (BGPid, SIGINT);
2216d14e2a8SJordan K. Hubbard      exit (EX_TERM);
2226d14e2a8SJordan K. Hubbard    }
2236d14e2a8SJordan K. Hubbard    else {
2249c749ffbSPoul-Henning Kamp      LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
225af57ed9fSAtsushi Murai      LcpClose();
226af57ed9fSAtsushi Murai      Cleanup(EX_TERM);
227af57ed9fSAtsushi Murai    }
2286d14e2a8SJordan K. Hubbard }
229c3899f8dSAtsushi Murai 
230c3899f8dSAtsushi Murai static void
231c3899f8dSAtsushi Murai TerminalCont()
232c3899f8dSAtsushi Murai {
233f5ff0f7cSBrian Somers   pending_signal(SIGCONT, SIG_DFL);
234f5ff0f7cSBrian Somers   pending_signal(SIGTSTP, TerminalStop);
235c3899f8dSAtsushi Murai   TtyCommandMode(getpgrp() == tcgetpgrp(0));
236c3899f8dSAtsushi Murai }
237c3899f8dSAtsushi Murai 
238c3899f8dSAtsushi Murai static void
239c3899f8dSAtsushi Murai TerminalStop(signo)
240c3899f8dSAtsushi Murai 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 
248c3899f8dSAtsushi Murai 
249af57ed9fSAtsushi Murai void
250af57ed9fSAtsushi Murai Usage()
251af57ed9fSAtsushi Murai {
252680026d6SNate Williams   fprintf(stderr,
2536d14e2a8SJordan K. Hubbard           "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
254af57ed9fSAtsushi Murai   exit(EX_START);
255af57ed9fSAtsushi Murai }
256af57ed9fSAtsushi Murai 
257af57ed9fSAtsushi Murai void
258af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv)
259af57ed9fSAtsushi Murai {
260af57ed9fSAtsushi Murai   int optc;
261af57ed9fSAtsushi Murai   char *cp;
262af57ed9fSAtsushi Murai 
263af57ed9fSAtsushi Murai   optc = 0;
264af57ed9fSAtsushi Murai   while (argc > 0 && **argv == '-') {
265af57ed9fSAtsushi Murai     cp = *argv + 1;
266af57ed9fSAtsushi Murai     if (strcmp(cp, "auto") == 0)
267af57ed9fSAtsushi Murai       mode |= MODE_AUTO;
2686d14e2a8SJordan K. Hubbard     else if (strcmp(cp, "background") == 0)
2696d14e2a8SJordan K. Hubbard       mode |= MODE_BACKGROUND;
270af57ed9fSAtsushi Murai     else if (strcmp(cp, "direct") == 0)
271af57ed9fSAtsushi Murai       mode |= MODE_DIRECT;
272af57ed9fSAtsushi Murai     else if (strcmp(cp, "dedicated") == 0)
273af57ed9fSAtsushi Murai       mode |= MODE_DEDICATED;
274680026d6SNate Williams     else if (strcmp(cp, "ddial") == 0)
275680026d6SNate Williams       mode |= MODE_DDIAL|MODE_AUTO;
276a9f484e5SJordan K. Hubbard     else if (strcmp(cp, "alias") == 0) {
277a9f484e5SJordan K. Hubbard       mode |= MODE_ALIAS;
278a9f484e5SJordan K. Hubbard       optc--;             /* this option isn't exclusive */
279a9f484e5SJordan K. Hubbard     }
280af57ed9fSAtsushi Murai     else
281af57ed9fSAtsushi Murai       Usage();
282af57ed9fSAtsushi Murai     optc++;
283af57ed9fSAtsushi Murai     argv++; argc--;
284af57ed9fSAtsushi Murai   }
285af57ed9fSAtsushi Murai   if (argc > 1) {
286af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one system label.\n");
287af57ed9fSAtsushi Murai     exit(EX_START);
288af57ed9fSAtsushi Murai   }
289af57ed9fSAtsushi Murai   if (argc == 1) dstsystem = *argv;
290af57ed9fSAtsushi Murai 
291af57ed9fSAtsushi Murai   if (optc > 1) {
292af57ed9fSAtsushi Murai     fprintf(stderr, "specify only one mode.\n");
293af57ed9fSAtsushi Murai     exit(EX_START);
294af57ed9fSAtsushi Murai   }
295af57ed9fSAtsushi Murai }
296af57ed9fSAtsushi Murai 
297af57ed9fSAtsushi Murai static void
298af57ed9fSAtsushi Murai Greetings()
299af57ed9fSAtsushi Murai {
300af57ed9fSAtsushi Murai   printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
301af57ed9fSAtsushi Murai   fflush(stdout);
302af57ed9fSAtsushi Murai }
303af57ed9fSAtsushi Murai 
304af57ed9fSAtsushi Murai void
305af57ed9fSAtsushi Murai main(argc, argv)
306af57ed9fSAtsushi Murai int argc;
307af57ed9fSAtsushi Murai char **argv;
308af57ed9fSAtsushi Murai {
309aefd026aSBrian Somers   FILE *lockfile;
310af57ed9fSAtsushi Murai   argc--; argv++;
311af57ed9fSAtsushi Murai 
312af57ed9fSAtsushi Murai   mode = MODE_INTER;		/* default operation is interactive mode */
313780700e5SAndrey A. Chernov   netfd = server = modem = tun_in = -1;
314af57ed9fSAtsushi Murai   ProcessArgs(argc, argv);
315af57ed9fSAtsushi Murai   Greetings();
316af57ed9fSAtsushi Murai   GetUid();
317af57ed9fSAtsushi Murai   IpcpDefAddress();
318a9f484e5SJordan K. Hubbard   InitAlias();
319af57ed9fSAtsushi Murai 
320af57ed9fSAtsushi Murai   if (SelectSystem("default", CONFFILE) < 0) {
321af57ed9fSAtsushi Murai     fprintf(stderr, "Warning: No default entry is given in config file.\n");
322af57ed9fSAtsushi Murai   }
323af57ed9fSAtsushi Murai 
32453c9f6c0SAtsushi Murai   switch ( LocalAuthInit() ) {
32553c9f6c0SAtsushi Murai     case NOT_FOUND:
32641db6564SAtsushi Murai     	fprintf(stderr,LAUTH_M1);
32741db6564SAtsushi Murai     	fprintf(stderr,LAUTH_M2);
32841db6564SAtsushi Murai 	fflush (stderr);
32941db6564SAtsushi Murai 	/* Fall down */
33041db6564SAtsushi Murai     case VALID:
33153c9f6c0SAtsushi Murai 	VarLocalAuth = LOCAL_AUTH;
33253c9f6c0SAtsushi Murai 	break;
33353c9f6c0SAtsushi Murai     default:
33453c9f6c0SAtsushi Murai 	break;
33553c9f6c0SAtsushi Murai   }
33653c9f6c0SAtsushi Murai 
337af57ed9fSAtsushi Murai   if (OpenTunnel(&tunno) < 0) {
338af57ed9fSAtsushi Murai     perror("open_tun");
339af57ed9fSAtsushi Murai     exit(EX_START);
340af57ed9fSAtsushi Murai   }
341af57ed9fSAtsushi Murai 
3426d14e2a8SJordan K. Hubbard   if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND))
343af57ed9fSAtsushi Murai     mode &= ~MODE_INTER;
344af57ed9fSAtsushi Murai   if (mode & MODE_INTER) {
345af57ed9fSAtsushi Murai     printf("Interactive mode\n");
346780700e5SAndrey A. Chernov     netfd = STDIN_FILENO;
347af57ed9fSAtsushi Murai   } else if (mode & MODE_AUTO) {
348680026d6SNate Williams     printf("Automatic Dialer mode\n");
349af57ed9fSAtsushi Murai     if (dstsystem == NULL) {
350680026d6SNate Williams       fprintf(stderr,
351680026d6SNate Williams               "Destination system must be specified in auto or ddial mode.\n");
352af57ed9fSAtsushi Murai       exit(EX_START);
353af57ed9fSAtsushi Murai     }
3546d14e2a8SJordan K. Hubbard   } else if (mode & MODE_BACKGROUND) {
3556d14e2a8SJordan K. Hubbard     printf("Background mode\n");
3566d14e2a8SJordan K. Hubbard     if (dstsystem == NULL) {
3576d14e2a8SJordan K. Hubbard       fprintf(stderr, "Destination system must be specified in background mode.\n");
3586d14e2a8SJordan K. Hubbard       exit(EX_START);
3596d14e2a8SJordan K. Hubbard     }
360af57ed9fSAtsushi Murai   }
361af57ed9fSAtsushi Murai 
36253c9f6c0SAtsushi Murai   tcgetattr(0, &oldtio);		/* Save original tty mode */
363af57ed9fSAtsushi Murai 
364c6c740beSBrian Somers   pending_signal(SIGHUP, LogReOpen);
365f5ff0f7cSBrian Somers   pending_signal(SIGTERM, CloseSession);
366f5ff0f7cSBrian Somers   pending_signal(SIGINT, CloseSession);
367f5ff0f7cSBrian Somers   pending_signal(SIGQUIT, CloseSession);
36853c9f6c0SAtsushi Murai #ifdef SIGSEGV
369d7f5ee41SAndrey A. Chernov   signal(SIGSEGV, Hangup);
37053c9f6c0SAtsushi Murai #endif
37153c9f6c0SAtsushi Murai #ifdef SIGPIPE
372e0d3e233SAndrey A. Chernov   signal(SIGPIPE, SIG_IGN);
37353c9f6c0SAtsushi Murai #endif
37453c9f6c0SAtsushi Murai #ifdef SIGALRM
375f5ff0f7cSBrian Somers   pending_signal(SIGALRM, SIG_IGN);
37653c9f6c0SAtsushi Murai #endif
377c3899f8dSAtsushi Murai   if(mode & MODE_INTER)
378c3899f8dSAtsushi Murai     {
379c3899f8dSAtsushi Murai #ifdef SIGTSTP
380f5ff0f7cSBrian Somers       pending_signal(SIGTSTP, TerminalStop);
381c3899f8dSAtsushi Murai #endif
382c3899f8dSAtsushi Murai #ifdef SIGTTIN
383f5ff0f7cSBrian Somers       pending_signal(SIGTTIN, TerminalStop);
384c3899f8dSAtsushi Murai #endif
385c3899f8dSAtsushi Murai #ifdef SIGTTOU
386f5ff0f7cSBrian Somers       pending_signal(SIGTTOU, SIG_IGN);
387c3899f8dSAtsushi Murai #endif
388c3899f8dSAtsushi Murai     }
389af57ed9fSAtsushi Murai 
390af57ed9fSAtsushi Murai   if (dstsystem) {
391af57ed9fSAtsushi Murai     if (SelectSystem(dstsystem, CONFFILE) < 0) {
392af57ed9fSAtsushi Murai       fprintf(stderr, "Destination system not found in conf file.\n");
393af57ed9fSAtsushi Murai       Cleanup(EX_START);
394af57ed9fSAtsushi Murai     }
395af57ed9fSAtsushi Murai     if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
396680026d6SNate Williams       fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
397af57ed9fSAtsushi Murai       Cleanup(EX_START);
398af57ed9fSAtsushi Murai     }
399af57ed9fSAtsushi Murai   }
400af57ed9fSAtsushi Murai   if (mode & MODE_DIRECT)
401af57ed9fSAtsushi Murai     printf("Packet mode enabled.\n");
402af57ed9fSAtsushi Murai 
403af57ed9fSAtsushi Murai   if (!(mode & MODE_INTER)) {
404af57ed9fSAtsushi Murai     int port = SERVER_PORT + tunno;
4056d14e2a8SJordan K. Hubbard     if (mode & MODE_BACKGROUND) {
4066d14e2a8SJordan K. Hubbard       if (pipe (BGFiledes)) {
4076d14e2a8SJordan K. Hubbard 	perror("pipe");
4086d14e2a8SJordan K. Hubbard 	Cleanup(EX_SOCK);
4096d14e2a8SJordan K. Hubbard       }
4106d14e2a8SJordan K. Hubbard     }
4116d14e2a8SJordan K. Hubbard     else {
412af57ed9fSAtsushi Murai       /*
413af57ed9fSAtsushi Murai        *  Create server socket and listen at there.
414af57ed9fSAtsushi Murai        */
415af57ed9fSAtsushi Murai       server = socket(PF_INET, SOCK_STREAM, 0);
416af57ed9fSAtsushi Murai       if (server < 0) {
417af57ed9fSAtsushi Murai 	perror("socket");
418af57ed9fSAtsushi Murai 	Cleanup(EX_SOCK);
419af57ed9fSAtsushi Murai       }
420af57ed9fSAtsushi Murai       ifsin.sin_family = AF_INET;
421af57ed9fSAtsushi Murai       ifsin.sin_addr.s_addr = INADDR_ANY;
422af57ed9fSAtsushi Murai       ifsin.sin_port = htons(port);
423af57ed9fSAtsushi Murai       if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
424af57ed9fSAtsushi Murai 	perror("bind");
425af57ed9fSAtsushi Murai 	if (errno == EADDRINUSE)
426af57ed9fSAtsushi Murai 	  fprintf(stderr, "Wait for a while, then try again.\n");
427af57ed9fSAtsushi Murai 	Cleanup(EX_SOCK);
428af57ed9fSAtsushi Murai       }
429274e766cSBrian Somers       if (listen(server, 5) != 0) {
430274e766cSBrian Somers 	fprintf(stderr, "Unable to listen to socket - OS overload?\n");
431274e766cSBrian Somers       }
4326d14e2a8SJordan K. Hubbard     }
433af57ed9fSAtsushi Murai 
434af57ed9fSAtsushi Murai     DupLog();
435af57ed9fSAtsushi Murai     if (!(mode & MODE_DIRECT)) {
4366d14e2a8SJordan K. Hubbard       pid_t bgpid;
437a9c6b5dfSAtsushi Murai 
4386d14e2a8SJordan K. Hubbard       bgpid = fork ();
4396d14e2a8SJordan K. Hubbard       if (bgpid == -1) {
4406d14e2a8SJordan K. Hubbard 	perror ("fork");
4416d14e2a8SJordan K. Hubbard 	Cleanup (EX_SOCK);
4426d14e2a8SJordan K. Hubbard       }
4436d14e2a8SJordan K. Hubbard       if (bgpid) {
4446d14e2a8SJordan K. Hubbard 	char c = EX_NORMAL;
445a9c6b5dfSAtsushi Murai 
4466d14e2a8SJordan K. Hubbard 	if (mode & MODE_BACKGROUND) {
4476d14e2a8SJordan K. Hubbard 	  /* Wait for our child to close its pipe before we exit. */
4486d14e2a8SJordan K. Hubbard 	  BGPid = bgpid;
4496e4959f0SBrian Somers           close (BGFiledes[1]);
4506e4959f0SBrian Somers 	  if (read(BGFiledes[0], &c, 1) != 1)
4516e4959f0SBrian Somers 	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
4526e4959f0SBrian Somers 	  else if (c == EX_NORMAL)
4536e4959f0SBrian Somers 	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
4546e4959f0SBrian Somers 	  else
4556e4959f0SBrian Somers 	    LogPrintf (LOG_PHASE_BIT, "Parent: Child failed %d.\n",(int)c);
4566e4959f0SBrian Somers           close (BGFiledes[0]);
4576d14e2a8SJordan K. Hubbard 	}
4586d14e2a8SJordan K. Hubbard         exit(c);
4596e4959f0SBrian Somers       } else if (mode & MODE_BACKGROUND)
4606e4959f0SBrian Somers           close(BGFiledes[0]);
461aefd026aSBrian Somers     }
4626d14e2a8SJordan K. Hubbard 
46341c6c543SBrian Somers     snprintf(pid_filename, sizeof (pid_filename), "%s/tun%d.pid",
4646d14e2a8SJordan K. Hubbard              _PATH_VARRUN, tunno);
465aefd026aSBrian Somers     (void)unlink(pid_filename);
466a9c6b5dfSAtsushi Murai 
467aefd026aSBrian Somers     if ((lockfile = fopen(pid_filename, "w")) != NULL) {
46841c6c543SBrian Somers       fprintf(lockfile, "%d\n", (int)getpid());
46941c6c543SBrian Somers       fclose(lockfile);
470aefd026aSBrian Somers     } else
471aefd026aSBrian Somers       logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno));
47241c6c543SBrian Somers 
47341c6c543SBrian Somers     snprintf(if_filename, sizeof if_filename, "%s%s.if",
47441c6c543SBrian Somers              _PATH_VARRUN, VarBaseDevice);
475aefd026aSBrian Somers     (void)unlink(if_filename);
47641c6c543SBrian Somers 
477aefd026aSBrian Somers     if ((lockfile = fopen(if_filename, "w")) != NULL) {
47841c6c543SBrian Somers       fprintf(lockfile, "tun%d\n", tunno);
47941c6c543SBrian Somers       fclose(lockfile);
480aefd026aSBrian Somers     } else
481aefd026aSBrian Somers       logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno));
482aefd026aSBrian Somers 
483780700e5SAndrey A. Chernov     if (server >= 0)
4849c749ffbSPoul-Henning Kamp 	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
485af57ed9fSAtsushi Murai #ifdef DOTTYINIT
48653c9f6c0SAtsushi Murai     if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
487af57ed9fSAtsushi Murai #else
488af57ed9fSAtsushi Murai     if (mode & MODE_DIRECT) {
489af57ed9fSAtsushi Murai #endif
490af57ed9fSAtsushi Murai       TtyInit();
491af57ed9fSAtsushi Murai     } else {
492d91680eaSAndrey A. Chernov       int fd;
493d91680eaSAndrey A. Chernov 
494af57ed9fSAtsushi Murai       setsid();			/* detach control tty */
495d91680eaSAndrey A. Chernov       if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
496d91680eaSAndrey A. Chernov 	(void)dup2(fd, STDIN_FILENO);
497d91680eaSAndrey A. Chernov 	(void)dup2(fd, STDOUT_FILENO);
498d91680eaSAndrey A. Chernov 	(void)dup2(fd, STDERR_FILENO);
499d91680eaSAndrey A. Chernov 	if (fd > 2)
500d91680eaSAndrey A. Chernov 		(void)close (fd);
501d91680eaSAndrey A. Chernov       }
502af57ed9fSAtsushi Murai     }
503af57ed9fSAtsushi Murai   } else {
504af57ed9fSAtsushi Murai     TtyInit();
505c3899f8dSAtsushi Murai     TtyCommandMode(1);
506af57ed9fSAtsushi Murai   }
5079c749ffbSPoul-Henning Kamp   LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
508af57ed9fSAtsushi Murai 
509af57ed9fSAtsushi Murai 
510af57ed9fSAtsushi Murai   do
511af57ed9fSAtsushi Murai    DoLoop();
512af57ed9fSAtsushi Murai   while (mode & MODE_DEDICATED);
513af57ed9fSAtsushi Murai 
514af57ed9fSAtsushi Murai   Cleanup(EX_DONE);
515af57ed9fSAtsushi Murai }
516af57ed9fSAtsushi Murai 
517af57ed9fSAtsushi Murai /*
5186d14e2a8SJordan K. Hubbard  *  Turn into packet mode, where we speak PPP.
519af57ed9fSAtsushi Murai  */
520af57ed9fSAtsushi Murai void
521af57ed9fSAtsushi Murai PacketMode()
522af57ed9fSAtsushi Murai {
523af57ed9fSAtsushi Murai   if (RawModem(modem) < 0) {
524af57ed9fSAtsushi Murai     fprintf(stderr, "Not connected.\r\n");
525af57ed9fSAtsushi Murai     return;
526af57ed9fSAtsushi Murai   }
527af57ed9fSAtsushi Murai 
528af57ed9fSAtsushi Murai   AsyncInit();
529af57ed9fSAtsushi Murai   VjInit();
530af57ed9fSAtsushi Murai   LcpInit();
531af57ed9fSAtsushi Murai   IpcpInit();
532af57ed9fSAtsushi Murai   CcpInit();
533af57ed9fSAtsushi Murai   LcpUp();
534af57ed9fSAtsushi Murai 
535af57ed9fSAtsushi Murai   if (mode & (MODE_DIRECT|MODE_DEDICATED))
536af57ed9fSAtsushi Murai     LcpOpen(OPEN_ACTIVE);
537af57ed9fSAtsushi Murai   else
538af57ed9fSAtsushi Murai     LcpOpen(VarOpenMode);
539af57ed9fSAtsushi Murai   if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
540c3899f8dSAtsushi Murai     TtyCommandMode(1);
541af57ed9fSAtsushi Murai     fprintf(stderr, "Packet mode.\r\n");
542b0cdb3ceSJordan K. Hubbard     aft_cmd = 1;
543af57ed9fSAtsushi Murai   }
544af57ed9fSAtsushi Murai }
545af57ed9fSAtsushi Murai 
546af57ed9fSAtsushi Murai static void
547af57ed9fSAtsushi Murai ShowHelp()
548af57ed9fSAtsushi Murai {
549c3899f8dSAtsushi Murai   fprintf(stderr, "The following commands are available:\r\n");
550af57ed9fSAtsushi Murai   fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
5511dff3fc5SAndrey A. Chernov   fprintf(stderr, " ~-\tDecrease log level\r\n");
5521dff3fc5SAndrey A. Chernov   fprintf(stderr, " ~+\tIncrease log level\r\n");
553af57ed9fSAtsushi Murai   fprintf(stderr, " ~.\tTerminate program\r\n");
5541dff3fc5SAndrey A. Chernov   fprintf(stderr, " ~?\tThis help\r\n");
555af57ed9fSAtsushi Murai }
556af57ed9fSAtsushi Murai 
557af57ed9fSAtsushi Murai static void
558af57ed9fSAtsushi Murai ReadTty()
559af57ed9fSAtsushi Murai {
560af57ed9fSAtsushi Murai   int n;
561af57ed9fSAtsushi Murai   char ch;
562af57ed9fSAtsushi Murai   static int ttystate;
563af57ed9fSAtsushi Murai #define MAXLINESIZE 200
564af57ed9fSAtsushi Murai   char linebuff[MAXLINESIZE];
565af57ed9fSAtsushi Murai 
566af57ed9fSAtsushi Murai #ifdef DEBUG
567af57ed9fSAtsushi Murai   logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
568af57ed9fSAtsushi Murai #endif
569af57ed9fSAtsushi Murai   if (!TermMode) {
570af57ed9fSAtsushi Murai     n = read(netfd, linebuff, sizeof(linebuff)-1);
571b0cdb3ceSJordan K. Hubbard     aft_cmd = 1;
57253c9f6c0SAtsushi Murai     if (n > 0) {
573af57ed9fSAtsushi Murai       DecodeCommand(linebuff, n, 1);
57453c9f6c0SAtsushi Murai     } else {
575e0d3e233SAndrey A. Chernov       LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
576e0d3e233SAndrey A. Chernov       VarLocalAuth = LOCAL_NO_AUTH;
577af57ed9fSAtsushi Murai       close(netfd);
578e0d3e233SAndrey A. Chernov       close(1);
579e0d3e233SAndrey A. Chernov       dup2(2, 1);     /* Have to have something here or the modem will be 1 */
580af57ed9fSAtsushi Murai       netfd = -1;
581af57ed9fSAtsushi Murai       mode &= ~MODE_INTER;
582af57ed9fSAtsushi Murai     }
583af57ed9fSAtsushi Murai     return;
584af57ed9fSAtsushi Murai   }
585af57ed9fSAtsushi Murai 
586af57ed9fSAtsushi Murai   /*
587af57ed9fSAtsushi Murai    *  We are in terminal mode, decode special sequences
588af57ed9fSAtsushi Murai    */
589af57ed9fSAtsushi Murai   n = read(0, &ch, 1);
590af57ed9fSAtsushi Murai #ifdef DEBUG
591af57ed9fSAtsushi Murai   logprintf("got %d bytes\n", n);
592af57ed9fSAtsushi Murai #endif
593af57ed9fSAtsushi Murai 
594af57ed9fSAtsushi Murai   if (n > 0) {
595af57ed9fSAtsushi Murai     switch (ttystate) {
596af57ed9fSAtsushi Murai     case 0:
597af57ed9fSAtsushi Murai       if (ch == '~')
598af57ed9fSAtsushi Murai 	ttystate++;
599af57ed9fSAtsushi Murai       else
600af57ed9fSAtsushi Murai 	write(modem, &ch, n);
601af57ed9fSAtsushi Murai       break;
602af57ed9fSAtsushi Murai     case 1:
603af57ed9fSAtsushi Murai       switch (ch) {
604af57ed9fSAtsushi Murai       case '?':
605af57ed9fSAtsushi Murai 	ShowHelp();
606af57ed9fSAtsushi Murai 	break;
607af57ed9fSAtsushi Murai       case '-':
608af57ed9fSAtsushi Murai 	if (loglevel > 0) {
609af57ed9fSAtsushi Murai 	  loglevel--;
610af57ed9fSAtsushi Murai 	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
611af57ed9fSAtsushi Murai 	}
612af57ed9fSAtsushi Murai 	break;
613af57ed9fSAtsushi Murai       case '+':
614af57ed9fSAtsushi Murai 	loglevel++;
615af57ed9fSAtsushi Murai 	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
616af57ed9fSAtsushi Murai 	break;
617af57ed9fSAtsushi Murai #ifdef DEBUG
618af57ed9fSAtsushi Murai       case 'm':
619af57ed9fSAtsushi Murai 	ShowMemMap();
620af57ed9fSAtsushi Murai 	break;
621af57ed9fSAtsushi Murai #endif
622af57ed9fSAtsushi Murai       case 'p':
623af57ed9fSAtsushi Murai 	/*
624af57ed9fSAtsushi Murai 	 * XXX: Should check carrier.
625af57ed9fSAtsushi Murai 	 */
626af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
627af57ed9fSAtsushi Murai 	  VarOpenMode = OPEN_ACTIVE;
628af57ed9fSAtsushi Murai 	  PacketMode();
629af57ed9fSAtsushi Murai 	}
630af57ed9fSAtsushi Murai 	break;
631af57ed9fSAtsushi Murai #ifdef DEBUG
632af57ed9fSAtsushi Murai       case 't':
633af57ed9fSAtsushi Murai 	ShowTimers();
634af57ed9fSAtsushi Murai 	break;
635af57ed9fSAtsushi Murai #endif
636af57ed9fSAtsushi Murai       case '.':
637af57ed9fSAtsushi Murai 	TermMode = 1;
638c3899f8dSAtsushi Murai 	TtyCommandMode(1);
639af57ed9fSAtsushi Murai 	break;
640af57ed9fSAtsushi Murai       default:
641af57ed9fSAtsushi Murai 	if (write(modem, &ch, n) < 0)
642af57ed9fSAtsushi Murai 	  fprintf(stderr, "err in write.\r\n");
643af57ed9fSAtsushi Murai 	break;
644af57ed9fSAtsushi Murai       }
645af57ed9fSAtsushi Murai       ttystate = 0;
646af57ed9fSAtsushi Murai       break;
647af57ed9fSAtsushi Murai     }
648af57ed9fSAtsushi Murai   }
649af57ed9fSAtsushi Murai }
650af57ed9fSAtsushi Murai 
651af57ed9fSAtsushi Murai 
652af57ed9fSAtsushi Murai /*
653af57ed9fSAtsushi Murai  *  Here, we'll try to detect HDLC frame
654af57ed9fSAtsushi Murai  */
655af57ed9fSAtsushi Murai 
656af57ed9fSAtsushi Murai static char *FrameHeaders[] = {
65753c9f6c0SAtsushi Murai   "\176\377\003\300\041",
65853c9f6c0SAtsushi Murai   "\176\377\175\043\300\041",
65953c9f6c0SAtsushi Murai   "\176\177\175\043\100\041",
66053c9f6c0SAtsushi Murai   "\176\175\337\175\043\300\041",
66153c9f6c0SAtsushi Murai   "\176\175\137\175\043\100\041",
662af57ed9fSAtsushi Murai   NULL,
663af57ed9fSAtsushi Murai };
664af57ed9fSAtsushi Murai 
665af57ed9fSAtsushi Murai u_char *
666af57ed9fSAtsushi Murai HdlcDetect(cp, n)
667af57ed9fSAtsushi Murai u_char *cp;
668af57ed9fSAtsushi Murai int n;
669af57ed9fSAtsushi Murai {
67053c9f6c0SAtsushi Murai   char *ptr, *fp, **hp;
671af57ed9fSAtsushi Murai 
672af57ed9fSAtsushi Murai   cp[n] = '\0';	/* be sure to null terminated */
673af57ed9fSAtsushi Murai   ptr = NULL;
674af57ed9fSAtsushi Murai   for (hp = FrameHeaders; *hp; hp++) {
67553c9f6c0SAtsushi Murai     fp = *hp;
67653c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
67753c9f6c0SAtsushi Murai       fp++;
678ed6a16c1SPoul-Henning Kamp     ptr = strstr((char *)cp, fp);
679ed6a16c1SPoul-Henning Kamp     if (ptr)
680af57ed9fSAtsushi Murai       break;
681af57ed9fSAtsushi Murai   }
682af57ed9fSAtsushi Murai   return((u_char *)ptr);
683af57ed9fSAtsushi Murai }
684af57ed9fSAtsushi Murai 
685af57ed9fSAtsushi Murai static struct pppTimer RedialTimer;
686af57ed9fSAtsushi Murai 
687af57ed9fSAtsushi Murai static void
688af57ed9fSAtsushi Murai RedialTimeout()
689af57ed9fSAtsushi Murai {
690af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
6919c749ffbSPoul-Henning Kamp   LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
692af57ed9fSAtsushi Murai }
693af57ed9fSAtsushi Murai 
694af57ed9fSAtsushi Murai static void
69543ea9d19SBrian Somers StartRedialTimer(Timeout)
69643ea9d19SBrian Somers 	int Timeout;
697af57ed9fSAtsushi Murai {
698af57ed9fSAtsushi Murai   StopTimer(&RedialTimer);
699a9c6b5dfSAtsushi Murai 
70043ea9d19SBrian Somers   if (Timeout) {
701af57ed9fSAtsushi Murai     RedialTimer.state = TIMER_STOPPED;
702a9c6b5dfSAtsushi Murai 
70343ea9d19SBrian Somers     if (Timeout > 0)
70443ea9d19SBrian Somers 	RedialTimer.load = Timeout * SECTICKS;
705a9c6b5dfSAtsushi Murai     else
706a9c6b5dfSAtsushi Murai 	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
707a9c6b5dfSAtsushi Murai 
70843ea9d19SBrian Somers     LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n",
70943ea9d19SBrian Somers 	      RedialTimer.load / SECTICKS);
71043ea9d19SBrian Somers 
711af57ed9fSAtsushi Murai     RedialTimer.func = RedialTimeout;
712af57ed9fSAtsushi Murai     StartTimer(&RedialTimer);
713af57ed9fSAtsushi Murai   }
714a9c6b5dfSAtsushi Murai }
715af57ed9fSAtsushi Murai 
716af57ed9fSAtsushi Murai 
717af57ed9fSAtsushi Murai static void
718af57ed9fSAtsushi Murai DoLoop()
719af57ed9fSAtsushi Murai {
720af57ed9fSAtsushi Murai   fd_set rfds, wfds, efds;
721780700e5SAndrey A. Chernov   int pri, i, n, wfd, nfds;
722af57ed9fSAtsushi Murai   struct sockaddr_in hisaddr;
723af57ed9fSAtsushi Murai   struct timeval timeout, *tp;
724af57ed9fSAtsushi Murai   int ssize = sizeof(hisaddr);
725af57ed9fSAtsushi Murai   u_char *cp;
726af57ed9fSAtsushi Murai   u_char rbuff[MAX_MRU];
72784b8a6ebSAtsushi Murai   int dial_up;
728a9c6b5dfSAtsushi Murai   int tries;
72960e218e4SAtsushi Murai   int qlen;
730c3899f8dSAtsushi Murai   pid_t pgroup;
731c3899f8dSAtsushi Murai 
732c3899f8dSAtsushi Murai   pgroup = getpgrp();
733af57ed9fSAtsushi Murai 
7346e4959f0SBrian Somers   if (mode & (MODE_DIRECT|MODE_BACKGROUND)) {
735af57ed9fSAtsushi Murai     modem = OpenModem(mode);
7369c749ffbSPoul-Henning Kamp     LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
737b0cdb3ceSJordan K. Hubbard     fflush(stderr);
738af57ed9fSAtsushi Murai     PacketMode();
739af57ed9fSAtsushi Murai   } else if (mode & MODE_DEDICATED) {
740780700e5SAndrey A. Chernov     if (modem < 0)
741af57ed9fSAtsushi Murai       modem = OpenModem(mode);
742af57ed9fSAtsushi Murai   }
743af57ed9fSAtsushi Murai 
744af57ed9fSAtsushi Murai   fflush(stdout);
745af57ed9fSAtsushi Murai 
74684b8a6ebSAtsushi Murai   timeout.tv_sec = 0;
747af57ed9fSAtsushi Murai   timeout.tv_usec = 0;
74807030d97SBrian Somers   lostCarrier = 0;
749af57ed9fSAtsushi Murai 
7506e4959f0SBrian Somers   if (mode & MODE_BACKGROUND)
7516e4959f0SBrian Somers     dial_up = TRUE;			/* Bring the line up */
7526e4959f0SBrian Somers   else
75384b8a6ebSAtsushi Murai     dial_up = FALSE;			/* XXXX */
754a9c6b5dfSAtsushi Murai   tries = 0;
755af57ed9fSAtsushi Murai   for (;;) {
756780700e5SAndrey A. Chernov     nfds = 0;
757af57ed9fSAtsushi Murai     FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
75884b8a6ebSAtsushi Murai 
75984b8a6ebSAtsushi Murai     /*
760680026d6SNate Williams      * If the link is down and we're in DDIAL mode, bring it back
761680026d6SNate Williams      * up.
762680026d6SNate Williams      */
763680026d6SNate Williams     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
764680026d6SNate Williams         dial_up = TRUE;
765680026d6SNate Williams 
766680026d6SNate Williams     /*
76707030d97SBrian Somers      * If we lost carrier and want to re-establish the connection
76807030d97SBrian Somers      * due to the "set reconnect" value, we'd better bring the line
76907030d97SBrian Somers      * back up now.
77007030d97SBrian Somers      */
77107030d97SBrian Somers     if (LcpFsm.state <= ST_CLOSED && dial_up != TRUE
77207030d97SBrian Somers         && lostCarrier && lostCarrier <= VarReconnectTries) {
77307030d97SBrian Somers         LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n",
77407030d97SBrian Somers                   lostCarrier, VarReconnectTries);
77507030d97SBrian Somers 	StartRedialTimer(VarReconnectTimer);
77607030d97SBrian Somers         dial_up = TRUE;
77707030d97SBrian Somers     }
77807030d97SBrian Somers 
77907030d97SBrian Somers    /*
78084b8a6ebSAtsushi Murai     * If Ip packet for output is enqueued and require dial up,
78184b8a6ebSAtsushi Murai     * Just do it!
78284b8a6ebSAtsushi Murai     */
78307030d97SBrian Somers     if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
78484b8a6ebSAtsushi Murai #ifdef DEBUG
78584b8a6ebSAtsushi Murai       logprintf("going to dial: modem = %d\n", modem);
78684b8a6ebSAtsushi Murai #endif
78784b8a6ebSAtsushi Murai       modem = OpenModem(mode);
78884b8a6ebSAtsushi Murai       if (modem < 0) {
78943ea9d19SBrian Somers 	StartRedialTimer(VarRedialTimeout);
79084b8a6ebSAtsushi Murai       } else {
791c0139fb2SBrian Somers 	tries++;    /* Tries are per number, not per list of numbers. */
792c0139fb2SBrian Somers         if (VarDialTries)
793c0139fb2SBrian Somers 	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
794c0139fb2SBrian Somers 		    VarDialTries);
795c0139fb2SBrian Somers         else
7969c749ffbSPoul-Henning Kamp 	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
79784b8a6ebSAtsushi Murai 	if (DialModem()) {
79884b8a6ebSAtsushi Murai 	  sleep(1);	       /* little pause to allow peer starts */
79984b8a6ebSAtsushi Murai 	  ModemTimeout();
80084b8a6ebSAtsushi Murai 	  PacketMode();
80184b8a6ebSAtsushi Murai 	  dial_up = FALSE;
802a9c6b5dfSAtsushi Murai 	  tries = 0;
80384b8a6ebSAtsushi Murai 	} else {
80484b8a6ebSAtsushi Murai 	  CloseModem();
8054ed9958fSBrian Somers 	  if (mode & MODE_BACKGROUND) {
8064ed9958fSBrian Somers 	    if (VarNextPhone == NULL)
8074ed9958fSBrian Somers 	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
8084ed9958fSBrian Somers 	    else
80943ea9d19SBrian Somers 	      /* Try all numbers in background mode */
81043ea9d19SBrian Somers 	      StartRedialTimer(VarRedialNextTimeout);
8114ed9958fSBrian Somers 	  } else if (VarDialTries && tries >= VarDialTries) {
812c0139fb2SBrian Somers 	    /* I give up !  Can't get through :( */
81343ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
814a9c6b5dfSAtsushi Murai 	    dial_up = FALSE;
815a9c6b5dfSAtsushi Murai 	    tries = 0;
816c0139fb2SBrian Somers 	  } else if (VarNextPhone == NULL)
817c0139fb2SBrian Somers 	    /* Dial failed. Keep quite during redial wait period. */
81843ea9d19SBrian Somers 	    StartRedialTimer(VarRedialTimeout);
819c0139fb2SBrian Somers 	  else
82043ea9d19SBrian Somers 	    StartRedialTimer(VarRedialNextTimeout);
82184b8a6ebSAtsushi Murai 	}
82284b8a6ebSAtsushi Murai       }
82384b8a6ebSAtsushi Murai     }
82460e218e4SAtsushi Murai     qlen = ModemQlen();
82576bd0c0aSDoug Rabson 
82676bd0c0aSDoug Rabson     if (qlen == 0) {
82776bd0c0aSDoug Rabson       IpStartOutput();
82876bd0c0aSDoug Rabson       qlen = ModemQlen();
82976bd0c0aSDoug Rabson     }
83076bd0c0aSDoug Rabson 
831780700e5SAndrey A. Chernov     if (modem >= 0) {
832780700e5SAndrey A. Chernov       if (modem + 1 > nfds)
833780700e5SAndrey A. Chernov 	nfds = modem + 1;
83484b8a6ebSAtsushi Murai       FD_SET(modem, &rfds);
83584b8a6ebSAtsushi Murai       FD_SET(modem, &efds);
83660e218e4SAtsushi Murai       if (qlen > 0) {
83784b8a6ebSAtsushi Murai 	FD_SET(modem, &wfds);
83884b8a6ebSAtsushi Murai       }
83984b8a6ebSAtsushi Murai     }
840780700e5SAndrey A. Chernov     if (server >= 0) {
841780700e5SAndrey A. Chernov       if (server + 1 > nfds)
842780700e5SAndrey A. Chernov 	nfds = server + 1;
843780700e5SAndrey A. Chernov       FD_SET(server, &rfds);
844780700e5SAndrey A. Chernov     }
845af57ed9fSAtsushi Murai 
846af57ed9fSAtsushi Murai     /*  *** IMPORTANT ***
847af57ed9fSAtsushi Murai      *
848af57ed9fSAtsushi Murai      *  CPU is serviced every TICKUNIT micro seconds.
849af57ed9fSAtsushi Murai      *	This value must be chosen with great care. If this values is
850af57ed9fSAtsushi Murai      *  too big, it results loss of characters from modem and poor responce.
851af57ed9fSAtsushi Murai      *  If this values is too small, ppp process eats many CPU time.
852af57ed9fSAtsushi Murai      */
85353c9f6c0SAtsushi Murai #ifndef SIGALRM
854af57ed9fSAtsushi Murai     usleep(TICKUNIT);
855af57ed9fSAtsushi Murai     TimerService();
856f5ff0f7cSBrian Somers #else
857f5ff0f7cSBrian Somers     handle_signals();
85853c9f6c0SAtsushi Murai #endif
85968d2b4d6SBruce Evans 
86068d2b4d6SBruce Evans     /* If there are aren't many packets queued, look for some more. */
861780700e5SAndrey A. Chernov     if (qlen < 20 && tun_in >= 0) {
862780700e5SAndrey A. Chernov       if (tun_in + 1 > nfds)
863780700e5SAndrey A. Chernov 	nfds = tun_in + 1;
86484b8a6ebSAtsushi Murai       FD_SET(tun_in, &rfds);
865780700e5SAndrey A. Chernov     }
86668d2b4d6SBruce Evans 
867780700e5SAndrey A. Chernov     if (netfd >= 0) {
868780700e5SAndrey A. Chernov       if (netfd + 1 > nfds)
869780700e5SAndrey A. Chernov 	nfds = netfd + 1;
870af57ed9fSAtsushi Murai       FD_SET(netfd, &rfds);
871af57ed9fSAtsushi Murai       FD_SET(netfd, &efds);
872af57ed9fSAtsushi Murai     }
87384b8a6ebSAtsushi Murai 
87453c9f6c0SAtsushi Murai #ifndef SIGALRM
875af57ed9fSAtsushi Murai     /*
87684b8a6ebSAtsushi Murai      *  Normally, select() will not block because modem is writable.
87784b8a6ebSAtsushi Murai      *  In AUTO mode, select will block until we find packet from tun
878af57ed9fSAtsushi Murai      */
879af57ed9fSAtsushi Murai     tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
880780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
88153c9f6c0SAtsushi Murai #else
88284b8a6ebSAtsushi Murai     /*
88384b8a6ebSAtsushi Murai      * When SIGALRM timer is running, a select function will be
88484b8a6ebSAtsushi Murai      * return -1 and EINTR after a Time Service signal hundler
885a9c6b5dfSAtsushi Murai      * is done.  If the redial timer is not running and we are
886a9c6b5dfSAtsushi Murai      * trying to dial, poll with a 0 value timer.
88784b8a6ebSAtsushi Murai      */
888a9c6b5dfSAtsushi Murai     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
889780700e5SAndrey A. Chernov     i = select(nfds, &rfds, &wfds, &efds, tp);
89053c9f6c0SAtsushi Murai #endif
8916b0b88d8SBrian Somers 
892af57ed9fSAtsushi Murai     if ( i == 0 ) {
893af57ed9fSAtsushi Murai         continue;
894af57ed9fSAtsushi Murai     }
89553c9f6c0SAtsushi Murai 
896534fe541SBrian Somers     if ( i < 0 ) {
897534fe541SBrian Somers        if ( errno == EINTR ) {
898f5ff0f7cSBrian Somers           handle_signals();
899f5ff0f7cSBrian Somers           continue;
90084b8a6ebSAtsushi Murai        }
901af57ed9fSAtsushi Murai        perror("select");
902af57ed9fSAtsushi Murai        break;
903af57ed9fSAtsushi Murai     }
90484b8a6ebSAtsushi Murai 
905780700e5SAndrey A. Chernov     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
906af57ed9fSAtsushi Murai       logprintf("Exception detected.\n");
907af57ed9fSAtsushi Murai       break;
908af57ed9fSAtsushi Murai     }
909af57ed9fSAtsushi Murai 
910780700e5SAndrey A. Chernov     if (server >= 0 && FD_ISSET(server, &rfds)) {
911e0d3e233SAndrey A. Chernov       LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
912af57ed9fSAtsushi Murai       wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
913e0d3e233SAndrey A. Chernov       if (wfd < 0) {
914e0d3e233SAndrey A. Chernov 	perror("accept");
915e0d3e233SAndrey A. Chernov 	continue;
916e0d3e233SAndrey A. Chernov       }
917780700e5SAndrey A. Chernov       if (netfd >= 0) {
918af57ed9fSAtsushi Murai 	write(wfd, "already in use.\n", 16);
919af57ed9fSAtsushi Murai 	close(wfd);
920af57ed9fSAtsushi Murai 	continue;
921af57ed9fSAtsushi Murai       } else
922af57ed9fSAtsushi Murai 	netfd = wfd;
923e0d3e233SAndrey A. Chernov       if (dup2(netfd, 1) < 0) {
924af57ed9fSAtsushi Murai 	perror("dup2");
925e0d3e233SAndrey A. Chernov 	close(netfd);
926e0d3e233SAndrey A. Chernov 	netfd = -1;
927e0d3e233SAndrey A. Chernov 	continue;
928e0d3e233SAndrey A. Chernov       }
929af57ed9fSAtsushi Murai       mode |= MODE_INTER;
930af57ed9fSAtsushi Murai       Greetings();
93141db6564SAtsushi Murai       switch ( LocalAuthInit() ) {
93241db6564SAtsushi Murai          case NOT_FOUND:
93341db6564SAtsushi Murai     	    fprintf(stdout,LAUTH_M1);
93441db6564SAtsushi Murai     	    fprintf(stdout,LAUTH_M2);
93541db6564SAtsushi Murai             fflush(stdout);
93641db6564SAtsushi Murai 	    /* Fall down */
93741db6564SAtsushi Murai          case VALID:
93841db6564SAtsushi Murai 	    VarLocalAuth = LOCAL_AUTH;
93941db6564SAtsushi Murai 	    break;
94041db6564SAtsushi Murai          default:
94141db6564SAtsushi Murai 	    break;
94241db6564SAtsushi Murai       }
943af57ed9fSAtsushi Murai       (void) IsInteractive();
944274e766cSBrian Somers       Prompt();
945af57ed9fSAtsushi Murai     }
946af57ed9fSAtsushi Murai 
947780700e5SAndrey A. Chernov     if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
948f1884650SAtsushi Murai 	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
949af57ed9fSAtsushi Murai       /* something to read from tty */
950af57ed9fSAtsushi Murai       ReadTty();
951af57ed9fSAtsushi Murai     }
952780700e5SAndrey A. Chernov     if (modem >= 0) {
953af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
954af57ed9fSAtsushi Murai 	 ModemStartOutput(modem);
955af57ed9fSAtsushi Murai       }
956af57ed9fSAtsushi Murai       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
95753c9f6c0SAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED)
95853c9f6c0SAtsushi Murai 	  usleep(10000);
959af57ed9fSAtsushi Murai 	n = read(modem, rbuff, sizeof(rbuff));
960af57ed9fSAtsushi Murai 	if ((mode & MODE_DIRECT) && n <= 0) {
961af57ed9fSAtsushi Murai 	  DownConnection();
962af57ed9fSAtsushi Murai 	} else
963af57ed9fSAtsushi Murai           LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
964af57ed9fSAtsushi Murai 
965af57ed9fSAtsushi Murai 	if (LcpFsm.state <= ST_CLOSED) {
966af57ed9fSAtsushi Murai 	  /*
967af57ed9fSAtsushi Murai 	   *  In dedicated mode, we just discard input until LCP is started.
968af57ed9fSAtsushi Murai 	   */
969af57ed9fSAtsushi Murai 	  if (!(mode & MODE_DEDICATED)) {
970af57ed9fSAtsushi Murai 	    cp = HdlcDetect(rbuff, n);
971af57ed9fSAtsushi Murai 	    if (cp) {
972af57ed9fSAtsushi Murai 	      /*
973af57ed9fSAtsushi Murai 	       * LCP packet is detected. Turn ourselves into packet mode.
974af57ed9fSAtsushi Murai 	       */
975af57ed9fSAtsushi Murai 	      if (cp != rbuff) {
976af57ed9fSAtsushi Murai 	        write(1, rbuff, cp - rbuff);
977af57ed9fSAtsushi Murai 	        write(1, "\r\n", 2);
978af57ed9fSAtsushi Murai 	      }
979af57ed9fSAtsushi Murai 	      PacketMode();
980af57ed9fSAtsushi Murai 	    } else
981af57ed9fSAtsushi Murai 	      write(1, rbuff, n);
982af57ed9fSAtsushi Murai 	  }
983af57ed9fSAtsushi Murai 	} else {
984af57ed9fSAtsushi Murai 	  if (n > 0)
985af57ed9fSAtsushi Murai 	    AsyncInput(rbuff, n);
986af57ed9fSAtsushi Murai 	}
987af57ed9fSAtsushi Murai       }
988af57ed9fSAtsushi Murai     }
98984b8a6ebSAtsushi Murai 
990780700e5SAndrey A. Chernov     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
991af57ed9fSAtsushi Murai       n = read(tun_in, rbuff, sizeof(rbuff));
992af57ed9fSAtsushi Murai       if (n < 0) {
993af57ed9fSAtsushi Murai 	perror("read from tun");
994af57ed9fSAtsushi Murai 	continue;
995af57ed9fSAtsushi Murai       }
996af57ed9fSAtsushi Murai       /*
997af57ed9fSAtsushi Murai        *  Process on-demand dialup. Output packets are queued within tunnel
998af57ed9fSAtsushi Murai        *  device until IPCP is opened.
999af57ed9fSAtsushi Murai        */
1000af57ed9fSAtsushi Murai       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
100184b8a6ebSAtsushi Murai 	pri = PacketCheck(rbuff, n, FL_DIAL);
1002af57ed9fSAtsushi Murai 	if (pri >= 0) {
1003a9f484e5SJordan K. Hubbard 	  if (mode & MODE_ALIAS) {
10043b92d2deSNate Williams 	    PacketAliasOut((struct ip *)rbuff);
1005a9f484e5SJordan K. Hubbard 	    n = ntohs(((struct ip *)rbuff)->ip_len);
1006a9f484e5SJordan K. Hubbard 	  }
1007af57ed9fSAtsushi Murai 	  IpEnqueue(pri, rbuff, n);
100884b8a6ebSAtsushi Murai 	  dial_up = TRUE;		/* XXX */
1009af57ed9fSAtsushi Murai 	}
1010af57ed9fSAtsushi Murai 	continue;
1011af57ed9fSAtsushi Murai       }
101284b8a6ebSAtsushi Murai       pri = PacketCheck(rbuff, n, FL_OUT);
1013a9f484e5SJordan K. Hubbard       if (pri >= 0) {
1014a9f484e5SJordan K. Hubbard         if (mode & MODE_ALIAS) {
10153b92d2deSNate Williams           PacketAliasOut((struct ip *)rbuff);
1016a9f484e5SJordan K. Hubbard           n = ntohs(((struct ip *)rbuff)->ip_len);
1017a9f484e5SJordan K. Hubbard         }
1018af57ed9fSAtsushi Murai 	IpEnqueue(pri, rbuff, n);
1019af57ed9fSAtsushi Murai       }
1020af57ed9fSAtsushi Murai     }
1021a9f484e5SJordan K. Hubbard   }
1022af57ed9fSAtsushi Murai   logprintf("job done.\n");
1023af57ed9fSAtsushi Murai }
1024