main.c revision 24844
1169689Skan/*
2169689Skan *			User Process PPP
3169689Skan *
4169689Skan *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5169689Skan *
6169689Skan *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7169689Skan *
8169689Skan * Redistribution and use in source and binary forms are permitted
9169689Skan * provided that the above copyright notice and this paragraph are
10169689Skan * duplicated in all such forms and that any documentation,
11169689Skan * advertising materials, and other materials related to such
12169689Skan * distribution and use acknowledge that the software was developed
13169689Skan * by the Internet Initiative Japan, Inc.  The name of the
14169689Skan * IIJ may not be used to endorse or promote products derived
15169689Skan * from this software without specific prior written permission.
16169689Skan * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17169689Skan * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18169689Skan * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19169689Skan *
20169689Skan * $Id: main.c,v 1.42 1997/04/12 22:58:39 brian Exp $
21169689Skan *
22169689Skan *	TODO:
23169689Skan *		o Add commands for traffic summary, version display, etc.
24169689Skan *		o Add signal handler for misc controls.
25169689Skan */
26169689Skan#include "fsm.h"
27169689Skan#include <fcntl.h>
28169689Skan#include <paths.h>
29169689Skan#include <sys/time.h>
30169689Skan#include <termios.h>
31169689Skan#include <signal.h>
32169689Skan#include <sys/wait.h>
33169689Skan#include <errno.h>
34169689Skan#include <netdb.h>
35169689Skan#include <unistd.h>
36169689Skan#include <sys/socket.h>
37169689Skan#include <arpa/inet.h>
38169689Skan#include <netinet/in_systm.h>
39169689Skan#include <netinet/ip.h>
40169689Skan#include "modem.h"
41169689Skan#include "os.h"
42169689Skan#include "hdlc.h"
43169689Skan#include "ccp.h"
44169689Skan#include "lcp.h"
45169689Skan#include "ipcp.h"
46169689Skan#include "vars.h"
47169689Skan#include "auth.h"
48169689Skan#include "filter.h"
49169689Skan#include "systems.h"
50169689Skan#include "ip.h"
51169689Skan#include "alias.h"
52169689Skan#include "sig.h"
53169689Skan
54169689Skan#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55169689Skan#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
56169689Skan
57169689Skan#ifndef O_NONBLOCK
58169689Skan#ifdef O_NDELAY
59169689Skan#define	O_NONBLOCK O_NDELAY
60169689Skan#endif
61169689Skan#endif
62169689Skan
63169689Skanextern void VjInit(), AsyncInit();
64169689Skanextern void AsyncInput(), IpOutput();
65169689Skanextern int  SelectSystem();
66169689Skan
67169689Skanextern void DecodeCommand(), Prompt();
68169689Skanextern int aft_cmd;
69169689Skanextern int IsInteractive();
70169689Skanextern struct in_addr ifnetmask;
71169689Skanstatic void DoLoop(void);
72169689Skanstatic void TerminalStop();
73169689Skan
74169689Skanstatic struct termios oldtio;		/* Original tty mode */
75169689Skanstatic struct termios comtio;		/* Command level tty mode */
76169689Skanint TermMode;
77169689Skanstatic int server;
78169689Skanstatic pid_t BGPid = 0;
79169689Skanstruct sockaddr_in ifsin;
80169689Skanchar pid_filename[128];
81169689Skan
82169689Skanstatic void
83169689SkanTtyInit()
84169689Skan{
85169689Skan  struct termios newtio;
86169689Skan  int stat;
87169689Skan
88169689Skan  stat = fcntl(0, F_GETFL, 0);
89169689Skan  stat |= O_NONBLOCK;
90169689Skan  fcntl(0, F_SETFL, stat);
91169689Skan  newtio = oldtio;
92169689Skan  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
93169689Skan  newtio.c_iflag = 0;
94169689Skan  newtio.c_oflag &= ~OPOST;
95169689Skan  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
96169689Skan  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
97169689Skan  newtio.c_cc[VMIN] = 1;
98169689Skan  newtio.c_cc[VTIME] = 0;
99169689Skan  newtio.c_cflag |= CS8;
100169689Skan  tcsetattr(0, TCSADRAIN, &newtio);
101169689Skan  comtio = newtio;
102169689Skan}
103169689Skan
104169689Skan/*
105169689Skan *  Set tty into command mode. We allow canonical input and echo processing.
106169689Skan */
107169689Skanvoid
108169689SkanTtyCommandMode(prompt)
109169689Skanint prompt;
110169689Skan{
111169689Skan  struct termios newtio;
112169689Skan  int stat;
113169689Skan
114169689Skan  if (!(mode & MODE_INTER))
115169689Skan    return;
116169689Skan  tcgetattr(0, &newtio);
117169689Skan  newtio.c_lflag |= (ECHO|ISIG|ICANON);
118169689Skan  newtio.c_iflag = oldtio.c_iflag;
119169689Skan  newtio.c_oflag |= OPOST;
120169689Skan  tcsetattr(0, TCSADRAIN, &newtio);
121169689Skan  stat = fcntl(0, F_GETFL, 0);
122169689Skan  stat |= O_NONBLOCK;
123169689Skan  fcntl(0, F_SETFL, stat);
124169689Skan  TermMode = 0;
125169689Skan  if(prompt) Prompt(0);
126169689Skan}
127169689Skan
128169689Skan/*
129169689Skan * Set tty into terminal mode which is used while we invoke term command.
130169689Skan */
131169689Skanvoid
132169689SkanTtyTermMode()
133169689Skan{
134169689Skan  int stat;
135169689Skan
136169689Skan  tcsetattr(0, TCSADRAIN, &comtio);
137169689Skan  stat = fcntl(0, F_GETFL, 0);
138169689Skan  stat &= ~O_NONBLOCK;
139169689Skan  fcntl(0, F_SETFL, stat);
140169689Skan  TermMode = 1;
141169689Skan}
142169689Skan
143169689Skanvoid
144169689SkanTtyOldMode()
145169689Skan{
146169689Skan  int stat;
147169689Skan
148169689Skan  stat = fcntl(0, F_GETFL, 0);
149169689Skan  stat &= ~O_NONBLOCK;
150169689Skan  fcntl(0, F_SETFL, stat);
151169689Skan  tcsetattr(0, TCSANOW, &oldtio);
152169689Skan}
153169689Skan
154169689Skanvoid
155169689SkanCleanup(excode)
156169689Skanint excode;
157169689Skan{
158169689Skan
159169689Skan  OsLinkdown();
160169689Skan  OsCloseLink(1);
161169689Skan  sleep(1);
162169689Skan  if (mode & (MODE_AUTO | MODE_BACKGROUND)) {
163169689Skan    DeleteIfRoutes(1);
164169689Skan    unlink(pid_filename);
165169689Skan  }
166169689Skan  OsInterfaceDown(1);
167169689Skan  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
168169689Skan    char c = EX_ERRDEAD;
169169689Skan    if (write(BGFiledes[1],&c,1) == 1)
170169689Skan      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
171169689Skan    else
172169689Skan      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
173169689Skan    close(BGFiledes[1]);
174169689Skan  }
175169689Skan  LogPrintf(LOG_PHASE_BIT, "PPP Terminated %d.\n",excode);
176169689Skan  LogClose();
177169689Skan  if (server >= 0) {
178169689Skan    close(server);
179169689Skan    server = -1;
180169689Skan  }
181169689Skan  TtyOldMode();
182169689Skan
183169689Skan  exit(excode);
184169689Skan}
185169689Skan
186169689Skanstatic void
187169689SkanHangup(signo)
188169689Skanint signo;
189169689Skan{
190169689Skan  if (signo == SIGSEGV) {
191169689Skan	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
192169689Skan	LogClose();
193169689Skan	abort();
194169689Skan  }
195169689Skan  if (BGPid) {
196169689Skan      kill (BGPid, SIGTERM);
197169689Skan      exit (EX_HANGUP);
198169689Skan  }
199169689Skan  else {
200169689Skan      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
201169689Skan      Cleanup(EX_HANGUP);
202169689Skan  }
203169689Skan}
204169689Skan
205169689Skanstatic void
206169689SkanCloseSession(signo)
207169689Skanint signo;
208169689Skan{
209169689Skan   if (BGPid) {
210169689Skan     kill (BGPid, SIGINT);
211169689Skan     exit (EX_TERM);
212169689Skan   }
213169689Skan   else {
214169689Skan     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
215169689Skan     LcpClose();
216169689Skan     Cleanup(EX_TERM);
217169689Skan   }
218169689Skan}
219169689Skan
220169689Skanstatic void
221169689SkanTerminalCont()
222169689Skan{
223169689Skan  pending_signal(SIGCONT, SIG_DFL);
224169689Skan  pending_signal(SIGTSTP, TerminalStop);
225169689Skan  TtyCommandMode(getpgrp() == tcgetpgrp(0));
226169689Skan}
227169689Skan
228169689Skanstatic void
229169689SkanTerminalStop(signo)
230169689Skanint signo;
231169689Skan{
232169689Skan  pending_signal(SIGCONT, TerminalCont);
233169689Skan  TtyOldMode();
234169689Skan  pending_signal(SIGTSTP, SIG_DFL);
235169689Skan  kill(getpid(), signo);
236169689Skan}
237169689Skan
238169689Skan
239169689Skanvoid
240169689SkanUsage()
241169689Skan{
242169689Skan  fprintf(stderr,
243169689Skan          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
244169689Skan  exit(EX_START);
245169689Skan}
246169689Skan
247169689Skanvoid
248169689SkanProcessArgs(int argc, char **argv)
249169689Skan{
250169689Skan  int optc;
251169689Skan  char *cp;
252169689Skan
253169689Skan  optc = 0;
254169689Skan  while (argc > 0 && **argv == '-') {
255169689Skan    cp = *argv + 1;
256169689Skan    if (strcmp(cp, "auto") == 0)
257169689Skan      mode |= MODE_AUTO;
258169689Skan    else if (strcmp(cp, "background") == 0)
259169689Skan      mode |= MODE_BACKGROUND;
260169689Skan    else if (strcmp(cp, "direct") == 0)
261169689Skan      mode |= MODE_DIRECT;
262169689Skan    else if (strcmp(cp, "dedicated") == 0)
263169689Skan      mode |= MODE_DEDICATED;
264169689Skan    else if (strcmp(cp, "ddial") == 0)
265169689Skan      mode |= MODE_DDIAL|MODE_AUTO;
266169689Skan    else if (strcmp(cp, "alias") == 0) {
267169689Skan      mode |= MODE_ALIAS;
268169689Skan      optc--;             /* this option isn't exclusive */
269169689Skan    }
270169689Skan    else
271169689Skan      Usage();
272169689Skan    optc++;
273169689Skan    argv++; argc--;
274169689Skan  }
275169689Skan  if (argc > 1) {
276169689Skan    fprintf(stderr, "specify only one system label.\n");
277169689Skan    exit(EX_START);
278169689Skan  }
279169689Skan  if (argc == 1) dstsystem = *argv;
280169689Skan
281169689Skan  if (optc > 1) {
282169689Skan    fprintf(stderr, "specify only one mode.\n");
283169689Skan    exit(EX_START);
284169689Skan  }
285169689Skan}
286169689Skan
287169689Skanstatic void
288169689SkanGreetings()
289169689Skan{
290169689Skan  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
291169689Skan  fflush(stdout);
292169689Skan}
293169689Skan
294169689Skanvoid
295169689Skanmain(argc, argv)
296169689Skanint argc;
297169689Skanchar **argv;
298169689Skan{
299169689Skan  int tunno;
300169689Skan
301169689Skan  argc--; argv++;
302169689Skan
303169689Skan  mode = MODE_INTER;		/* default operation is interactive mode */
304169689Skan  netfd = server = modem = tun_in = -1;
305169689Skan  ProcessArgs(argc, argv);
306169689Skan  Greetings();
307169689Skan  GetUid();
308169689Skan  IpcpDefAddress();
309169689Skan  InitAlias();
310169689Skan
311169689Skan  if (SelectSystem("default", CONFFILE) < 0) {
312169689Skan    fprintf(stderr, "Warning: No default entry is given in config file.\n");
313169689Skan  }
314169689Skan
315169689Skan  if (LogOpen())
316169689Skan    exit(EX_START);
317169689Skan
318169689Skan  switch ( LocalAuthInit() ) {
319169689Skan    case NOT_FOUND:
320169689Skan    	fprintf(stderr,LAUTH_M1);
321169689Skan    	fprintf(stderr,LAUTH_M2);
322169689Skan	fflush (stderr);
323169689Skan	/* Fall down */
324169689Skan    case VALID:
325169689Skan	VarLocalAuth = LOCAL_AUTH;
326169689Skan	break;
327169689Skan    default:
328169689Skan	break;
329169689Skan  }
330169689Skan
331169689Skan  if (OpenTunnel(&tunno) < 0) {
332169689Skan    perror("open_tun");
333169689Skan    exit(EX_START);
334169689Skan  }
335169689Skan
336169689Skan  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND))
337169689Skan    mode &= ~MODE_INTER;
338169689Skan  if (mode & MODE_INTER) {
339169689Skan    printf("Interactive mode\n");
340169689Skan    netfd = STDIN_FILENO;
341169689Skan  } else if (mode & MODE_AUTO) {
342169689Skan    printf("Automatic Dialer mode\n");
343169689Skan    if (dstsystem == NULL) {
344169689Skan      fprintf(stderr,
345169689Skan              "Destination system must be specified in auto or ddial mode.\n");
346169689Skan      exit(EX_START);
347169689Skan    }
348169689Skan  } else if (mode & MODE_BACKGROUND) {
349169689Skan    printf("Background mode\n");
350169689Skan    if (dstsystem == NULL) {
351169689Skan      fprintf(stderr, "Destination system must be specified in background mode.\n");
352169689Skan      exit(EX_START);
353169689Skan    }
354169689Skan  }
355169689Skan
356169689Skan  tcgetattr(0, &oldtio);		/* Save original tty mode */
357169689Skan
358169689Skan  pending_signal(SIGHUP, LogReOpen);
359169689Skan  pending_signal(SIGTERM, CloseSession);
360169689Skan  pending_signal(SIGINT, CloseSession);
361169689Skan  pending_signal(SIGQUIT, CloseSession);
362169689Skan#ifdef SIGSEGV
363169689Skan  signal(SIGSEGV, Hangup);
364169689Skan#endif
365169689Skan#ifdef SIGPIPE
366169689Skan  signal(SIGPIPE, SIG_IGN);
367169689Skan#endif
368169689Skan#ifdef SIGALRM
369169689Skan  pending_signal(SIGALRM, SIG_IGN);
370169689Skan#endif
371169689Skan  if(mode & MODE_INTER)
372169689Skan    {
373169689Skan#ifdef SIGTSTP
374169689Skan      pending_signal(SIGTSTP, TerminalStop);
375169689Skan#endif
376169689Skan#ifdef SIGTTIN
377169689Skan      pending_signal(SIGTTIN, TerminalStop);
378169689Skan#endif
379169689Skan#ifdef SIGTTOU
380169689Skan      pending_signal(SIGTTOU, SIG_IGN);
381169689Skan#endif
382169689Skan    }
383169689Skan
384169689Skan  if (dstsystem) {
385169689Skan    if (SelectSystem(dstsystem, CONFFILE) < 0) {
386169689Skan      fprintf(stderr, "Destination system not found in conf file.\n");
387169689Skan      Cleanup(EX_START);
388169689Skan    }
389169689Skan    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
390169689Skan      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
391169689Skan      Cleanup(EX_START);
392169689Skan    }
393169689Skan  }
394169689Skan  if (mode & MODE_DIRECT)
395169689Skan    printf("Packet mode enabled.\n");
396169689Skan
397169689Skan#ifdef notdef
398169689Skan  if (mode & MODE_AUTO) {
399169689Skan    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
400169689Skan  }
401169689Skan#endif
402169689Skan
403169689Skan  if (!(mode & MODE_INTER)) {
404169689Skan    int port = SERVER_PORT + tunno;
405169689Skan    if (mode & MODE_BACKGROUND) {
406169689Skan      if (pipe (BGFiledes)) {
407169689Skan	perror("pipe");
408169689Skan	Cleanup(EX_SOCK);
409169689Skan      }
410169689Skan    }
411169689Skan    else {
412169689Skan      /*
413169689Skan       *  Create server socket and listen at there.
414169689Skan       */
415169689Skan      server = socket(PF_INET, SOCK_STREAM, 0);
416169689Skan      if (server < 0) {
417169689Skan	perror("socket");
418169689Skan	Cleanup(EX_SOCK);
419169689Skan      }
420169689Skan      ifsin.sin_family = AF_INET;
421169689Skan      ifsin.sin_addr.s_addr = INADDR_ANY;
422169689Skan      ifsin.sin_port = htons(port);
423169689Skan      if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
424169689Skan	perror("bind");
425169689Skan	if (errno == EADDRINUSE)
426169689Skan	  fprintf(stderr, "Wait for a while, then try again.\n");
427169689Skan	Cleanup(EX_SOCK);
428169689Skan      }
429169689Skan      listen(server, 5);
430169689Skan    }
431169689Skan
432169689Skan    DupLog();
433169689Skan    if (!(mode & MODE_DIRECT)) {
434169689Skan      int fd;
435169689Skan      char pid[32];
436169689Skan      pid_t bgpid;
437169689Skan
438169689Skan      bgpid = fork ();
439169689Skan      if (bgpid == -1) {
440169689Skan	perror ("fork");
441169689Skan	Cleanup (EX_SOCK);
442169689Skan      }
443169689Skan      if (bgpid) {
444169689Skan	char c = EX_NORMAL;
445169689Skan
446169689Skan	if (mode & MODE_BACKGROUND) {
447169689Skan	  /* Wait for our child to close its pipe before we exit. */
448169689Skan	  BGPid = bgpid;
449169689Skan          close (BGFiledes[1]);
450169689Skan	  if (read(BGFiledes[0], &c, 1) != 1)
451169689Skan	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
452169689Skan	  else if (c == EX_NORMAL)
453169689Skan	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
454169689Skan	  else
455169689Skan	    LogPrintf (LOG_PHASE_BIT, "Parent: Child failed %d.\n",(int)c);
456169689Skan          close (BGFiledes[0]);
457169689Skan	}
458169689Skan        exit(c);
459169689Skan      } else if (mode & MODE_BACKGROUND)
460169689Skan          close(BGFiledes[0]);
461169689Skan
462169689Skan      snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid",
463169689Skan		  _PATH_VARRUN, tunno);
464169689Skan      unlink(pid_filename);
465169689Skan      snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
466169689Skan
467169689Skan      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
468169689Skan      {
469169689Skan	  write(fd, pid, strlen(pid));
470169689Skan	  close(fd);
471169689Skan      }
472169689Skan    }
473169689Skan    if (server >= 0)
474169689Skan	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
475169689Skan#ifdef DOTTYINIT
476169689Skan    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
477169689Skan#else
478169689Skan    if (mode & MODE_DIRECT) {
479169689Skan#endif
480169689Skan      TtyInit();
481169689Skan    } else {
482169689Skan      int fd;
483169689Skan
484169689Skan      setsid();			/* detach control tty */
485169689Skan      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
486169689Skan	(void)dup2(fd, STDIN_FILENO);
487169689Skan	(void)dup2(fd, STDOUT_FILENO);
488169689Skan	(void)dup2(fd, STDERR_FILENO);
489169689Skan	if (fd > 2)
490169689Skan		(void)close (fd);
491169689Skan      }
492169689Skan    }
493169689Skan  } else {
494169689Skan    TtyInit();
495169689Skan    TtyCommandMode(1);
496169689Skan  }
497169689Skan  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
498169689Skan
499169689Skan
500169689Skan  do
501169689Skan   DoLoop();
502169689Skan  while (mode & MODE_DEDICATED);
503169689Skan
504169689Skan  Cleanup(EX_DONE);
505169689Skan}
506169689Skan
507169689Skan/*
508169689Skan *  Turn into packet mode, where we speak PPP.
509169689Skan */
510169689Skanvoid
511169689SkanPacketMode()
512169689Skan{
513169689Skan  if (RawModem(modem) < 0) {
514169689Skan    fprintf(stderr, "Not connected.\r\n");
515169689Skan    return;
516169689Skan  }
517169689Skan
518169689Skan  AsyncInit();
519169689Skan  VjInit();
520169689Skan  LcpInit();
521169689Skan  IpcpInit();
522169689Skan  CcpInit();
523169689Skan  LcpUp();
524169689Skan
525169689Skan  if (mode & (MODE_DIRECT|MODE_DEDICATED))
526169689Skan    LcpOpen(OPEN_ACTIVE);
527169689Skan  else
528169689Skan    LcpOpen(VarOpenMode);
529169689Skan  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
530169689Skan    TtyCommandMode(1);
531169689Skan    fprintf(stderr, "Packet mode.\r\n");
532169689Skan    aft_cmd = 1;
533169689Skan  }
534169689Skan}
535169689Skan
536169689Skanstatic void
537169689SkanShowHelp()
538169689Skan{
539169689Skan  fprintf(stderr, "The following commands are available:\r\n");
540169689Skan  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
541169689Skan  fprintf(stderr, " ~-\tDecrease log level\r\n");
542169689Skan  fprintf(stderr, " ~+\tIncrease log level\r\n");
543169689Skan  fprintf(stderr, " ~.\tTerminate program\r\n");
544169689Skan  fprintf(stderr, " ~?\tThis help\r\n");
545169689Skan}
546169689Skan
547169689Skanstatic void
548169689SkanReadTty()
549169689Skan{
550169689Skan  int n;
551169689Skan  char ch;
552169689Skan  static int ttystate;
553169689Skan#define MAXLINESIZE 200
554169689Skan  char linebuff[MAXLINESIZE];
555169689Skan
556169689Skan#ifdef DEBUG
557169689Skan  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
558169689Skan#endif
559169689Skan  if (!TermMode) {
560169689Skan    n = read(netfd, linebuff, sizeof(linebuff)-1);
561169689Skan    aft_cmd = 1;
562169689Skan    if (n > 0) {
563169689Skan      DecodeCommand(linebuff, n, 1);
564169689Skan    } else {
565169689Skan      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
566169689Skan      VarLocalAuth = LOCAL_NO_AUTH;
567169689Skan      close(netfd);
568169689Skan      close(1);
569169689Skan      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
570169689Skan      netfd = -1;
571169689Skan      mode &= ~MODE_INTER;
572169689Skan    }
573169689Skan    return;
574169689Skan  }
575169689Skan
576169689Skan  /*
577169689Skan   *  We are in terminal mode, decode special sequences
578169689Skan   */
579169689Skan  n = read(0, &ch, 1);
580169689Skan#ifdef DEBUG
581169689Skan  logprintf("got %d bytes\n", n);
582169689Skan#endif
583169689Skan
584169689Skan  if (n > 0) {
585169689Skan    switch (ttystate) {
586169689Skan    case 0:
587169689Skan      if (ch == '~')
588169689Skan	ttystate++;
589169689Skan      else
590169689Skan	write(modem, &ch, n);
591169689Skan      break;
592169689Skan    case 1:
593169689Skan      switch (ch) {
594169689Skan      case '?':
595169689Skan	ShowHelp();
596169689Skan	break;
597169689Skan      case '-':
598169689Skan	if (loglevel > 0) {
599169689Skan	  loglevel--;
600169689Skan	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
601169689Skan	}
602169689Skan	break;
603169689Skan      case '+':
604169689Skan	loglevel++;
605169689Skan	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
606169689Skan	break;
607169689Skan#ifdef DEBUG
608169689Skan      case 'm':
609169689Skan	ShowMemMap();
610169689Skan	break;
611169689Skan#endif
612169689Skan      case 'p':
613169689Skan	/*
614169689Skan	 * XXX: Should check carrier.
615169689Skan	 */
616169689Skan	if (LcpFsm.state <= ST_CLOSED) {
617169689Skan	  VarOpenMode = OPEN_ACTIVE;
618169689Skan	  PacketMode();
619169689Skan	}
620169689Skan	break;
621169689Skan#ifdef DEBUG
622169689Skan      case 't':
623169689Skan	ShowTimers();
624169689Skan	break;
625169689Skan#endif
626169689Skan      case '.':
627169689Skan	TermMode = 1;
628169689Skan	TtyCommandMode(1);
629169689Skan	break;
630169689Skan      default:
631169689Skan	if (write(modem, &ch, n) < 0)
632169689Skan	  fprintf(stderr, "err in write.\r\n");
633169689Skan	break;
634169689Skan      }
635169689Skan      ttystate = 0;
636169689Skan      break;
637169689Skan    }
638169689Skan  }
639169689Skan}
640169689Skan
641169689Skan
642169689Skan/*
643169689Skan *  Here, we'll try to detect HDLC frame
644169689Skan */
645169689Skan
646169689Skanstatic char *FrameHeaders[] = {
647169689Skan  "\176\377\003\300\041",
648169689Skan  "\176\377\175\043\300\041",
649169689Skan  "\176\177\175\043\100\041",
650169689Skan  "\176\175\337\175\043\300\041",
651169689Skan  "\176\175\137\175\043\100\041",
652169689Skan  NULL,
653169689Skan};
654169689Skan
655169689Skanu_char *
656169689SkanHdlcDetect(cp, n)
657169689Skanu_char *cp;
658169689Skanint n;
659169689Skan{
660169689Skan  char *ptr, *fp, **hp;
661169689Skan
662169689Skan  cp[n] = '\0';	/* be sure to null terminated */
663169689Skan  ptr = NULL;
664169689Skan  for (hp = FrameHeaders; *hp; hp++) {
665169689Skan    fp = *hp;
666169689Skan    if (DEV_IS_SYNC)
667169689Skan      fp++;
668169689Skan    ptr = strstr((char *)cp, fp);
669169689Skan    if (ptr)
670169689Skan      break;
671169689Skan  }
672169689Skan  return((u_char *)ptr);
673169689Skan}
674169689Skan
675169689Skanstatic struct pppTimer RedialTimer;
676169689Skan
677169689Skanstatic void
678169689SkanRedialTimeout()
679169689Skan{
680169689Skan  StopTimer(&RedialTimer);
681169689Skan  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
682169689Skan}
683169689Skan
684169689Skanstatic void
685169689SkanStartRedialTimer()
686169689Skan{
687169689Skan  StopTimer(&RedialTimer);
688169689Skan
689169689Skan  if (VarRedialTimeout) {
690169689Skan    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
691169689Skan    RedialTimer.state = TIMER_STOPPED;
692169689Skan
693169689Skan    if (VarRedialTimeout > 0)
694169689Skan	RedialTimer.load = VarRedialTimeout * SECTICKS;
695169689Skan    else
696169689Skan	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
697169689Skan
698169689Skan    RedialTimer.func = RedialTimeout;
699169689Skan    StartTimer(&RedialTimer);
700169689Skan  }
701169689Skan}
702169689Skan
703169689Skan
704169689Skanstatic void
705169689SkanDoLoop()
706169689Skan{
707169689Skan  fd_set rfds, wfds, efds;
708169689Skan  int pri, i, n, wfd, nfds;
709169689Skan  struct sockaddr_in hisaddr;
710169689Skan  struct timeval timeout, *tp;
711169689Skan  int ssize = sizeof(hisaddr);
712169689Skan  u_char *cp;
713169689Skan  u_char rbuff[MAX_MRU];
714169689Skan  int dial_up;
715169689Skan  int tries;
716169689Skan  int qlen;
717169689Skan  pid_t pgroup;
718169689Skan
719169689Skan  pgroup = getpgrp();
720169689Skan
721169689Skan  if (mode & (MODE_DIRECT|MODE_BACKGROUND)) {
722169689Skan    modem = OpenModem(mode);
723169689Skan    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
724169689Skan    fflush(stderr);
725169689Skan    PacketMode();
726169689Skan  } else if (mode & MODE_DEDICATED) {
727169689Skan    if (modem < 0)
728169689Skan      modem = OpenModem(mode);
729169689Skan  }
730169689Skan
731169689Skan  fflush(stdout);
732169689Skan
733169689Skan  timeout.tv_sec = 0;
734169689Skan  timeout.tv_usec = 0;
735169689Skan
736169689Skan  if (mode & MODE_BACKGROUND)
737169689Skan    dial_up = TRUE;			/* Bring the line up */
738169689Skan  else
739169689Skan    dial_up = FALSE;			/* XXXX */
740169689Skan  tries = 0;
741169689Skan  for (;;) {
742169689Skan    nfds = 0;
743169689Skan    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
744169689Skan
745169689Skan    /*
746169689Skan     * If the link is down and we're in DDIAL mode, bring it back
747169689Skan     * up.
748169689Skan     */
749169689Skan    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
750169689Skan        dial_up = TRUE;
751169689Skan
752169689Skan   /*
753169689Skan    * If Ip packet for output is enqueued and require dial up,
754169689Skan    * Just do it!
755169689Skan    */
756169689Skan    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
757169689Skan#ifdef DEBUG
758169689Skan      logprintf("going to dial: modem = %d\n", modem);
759169689Skan#endif
760169689Skan      modem = OpenModem(mode);
761169689Skan      if (modem < 0) {
762169689Skan	StartRedialTimer();
763169689Skan      } else {
764169689Skan	tries++;    /* Tries are per number, not per list of numbers. */
765169689Skan        if (VarDialTries)
766169689Skan	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
767169689Skan		    VarDialTries);
768169689Skan        else
769169689Skan	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
770169689Skan	if (DialModem()) {
771169689Skan	  sleep(1);	       /* little pause to allow peer starts */
772169689Skan	  ModemTimeout();
773169689Skan	  PacketMode();
774169689Skan	  dial_up = FALSE;
775169689Skan	  tries = 0;
776169689Skan	} else {
777169689Skan	  CloseModem();
778169689Skan	  if (mode & MODE_BACKGROUND) {
779169689Skan	    if (VarNextPhone == NULL)
780169689Skan	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
781169689Skan	    else
782169689Skan	      sleep(1);          /* Try all numbers in background mode */
783169689Skan	  } else if (VarDialTries && tries >= VarDialTries) {
784169689Skan	    /* I give up !  Can't get through :( */
785169689Skan	    StartRedialTimer();
786169689Skan	    dial_up = FALSE;
787169689Skan	    tries = 0;
788169689Skan	  } else if (VarNextPhone == NULL)
789169689Skan	    /* Dial failed. Keep quite during redial wait period. */
790169689Skan	    StartRedialTimer();
791169689Skan	  else
792169689Skan	    /*
793169689Skan	     * Give the modem a chance to recover, then dial the next
794169689Skan	     * number in our list
795169689Skan	     */
796169689Skan	    sleep(1);
797169689Skan	}
798169689Skan      }
799169689Skan    }
800169689Skan    qlen = ModemQlen();
801169689Skan
802169689Skan    if (qlen == 0) {
803169689Skan      IpStartOutput();
804169689Skan      qlen = ModemQlen();
805169689Skan    }
806169689Skan
807169689Skan    if (modem >= 0) {
808169689Skan      if (modem + 1 > nfds)
809169689Skan	nfds = modem + 1;
810169689Skan      FD_SET(modem, &rfds);
811169689Skan      FD_SET(modem, &efds);
812169689Skan      if (qlen > 0) {
813169689Skan	FD_SET(modem, &wfds);
814169689Skan      }
815169689Skan    }
816169689Skan    if (server >= 0) {
817169689Skan      if (server + 1 > nfds)
818169689Skan	nfds = server + 1;
819169689Skan      FD_SET(server, &rfds);
820169689Skan    }
821169689Skan
822169689Skan    /*  *** IMPORTANT ***
823169689Skan     *
824169689Skan     *  CPU is serviced every TICKUNIT micro seconds.
825169689Skan     *	This value must be chosen with great care. If this values is
826169689Skan     *  too big, it results loss of characters from modem and poor responce.
827169689Skan     *  If this values is too small, ppp process eats many CPU time.
828169689Skan     */
829169689Skan#ifndef SIGALRM
830169689Skan    usleep(TICKUNIT);
831169689Skan    TimerService();
832169689Skan#else
833169689Skan    handle_signals();
834169689Skan#endif
835169689Skan
836169689Skan    /* If there are aren't many packets queued, look for some more. */
837169689Skan    if (qlen < 20 && tun_in >= 0) {
838169689Skan      if (tun_in + 1 > nfds)
839169689Skan	nfds = tun_in + 1;
840169689Skan      FD_SET(tun_in, &rfds);
841169689Skan    }
842169689Skan
843169689Skan    if (netfd >= 0) {
844169689Skan      if (netfd + 1 > nfds)
845169689Skan	nfds = netfd + 1;
846169689Skan      FD_SET(netfd, &rfds);
847169689Skan      FD_SET(netfd, &efds);
848169689Skan    }
849169689Skan
850169689Skan#ifndef SIGALRM
851169689Skan    /*
852169689Skan     *  Normally, select() will not block because modem is writable.
853169689Skan     *  In AUTO mode, select will block until we find packet from tun
854169689Skan     */
855169689Skan    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
856169689Skan    i = select(nfds, &rfds, &wfds, &efds, tp);
857169689Skan#else
858169689Skan    /*
859169689Skan     * When SIGALRM timer is running, a select function will be
860169689Skan     * return -1 and EINTR after a Time Service signal hundler
861169689Skan     * is done.  If the redial timer is not running and we are
862169689Skan     * trying to dial, poll with a 0 value timer.
863169689Skan     */
864169689Skan    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
865169689Skan    i = select(nfds, &rfds, &wfds, &efds, tp);
866169689Skan#endif
867169689Skan
868169689Skan    if ( i == 0 ) {
869169689Skan        continue;
870169689Skan    }
871169689Skan
872169689Skan    if ( i < 0 ) {
873169689Skan       if ( errno == EINTR ) {
874169689Skan          handle_signals();
875169689Skan          continue;
876169689Skan       }
877169689Skan       perror("select");
878169689Skan       break;
879169689Skan    }
880169689Skan
881169689Skan    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
882169689Skan      logprintf("Exception detected.\n");
883169689Skan      break;
884169689Skan    }
885169689Skan
886169689Skan    if (server >= 0 && FD_ISSET(server, &rfds)) {
887169689Skan      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
888169689Skan      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
889169689Skan      if (wfd < 0) {
890169689Skan	perror("accept");
891169689Skan	continue;
892169689Skan      }
893169689Skan      if (netfd >= 0) {
894169689Skan	write(wfd, "already in use.\n", 16);
895169689Skan	close(wfd);
896169689Skan	continue;
897169689Skan      } else
898169689Skan	netfd = wfd;
899169689Skan      if (dup2(netfd, 1) < 0) {
900169689Skan	perror("dup2");
901169689Skan	close(netfd);
902169689Skan	netfd = -1;
903169689Skan	continue;
904169689Skan      }
905169689Skan      mode |= MODE_INTER;
906169689Skan      Greetings();
907169689Skan      switch ( LocalAuthInit() ) {
908169689Skan         case NOT_FOUND:
909169689Skan    	    fprintf(stdout,LAUTH_M1);
910169689Skan    	    fprintf(stdout,LAUTH_M2);
911169689Skan            fflush(stdout);
912169689Skan	    /* Fall down */
913169689Skan         case VALID:
914169689Skan	    VarLocalAuth = LOCAL_AUTH;
915169689Skan	    break;
916169689Skan         default:
917169689Skan	    break;
918169689Skan      }
919169689Skan      (void) IsInteractive();
920169689Skan      Prompt(0);
921169689Skan    }
922169689Skan
923169689Skan    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
924169689Skan	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
925169689Skan      /* something to read from tty */
926169689Skan      ReadTty();
927169689Skan    }
928169689Skan    if (modem >= 0) {
929169689Skan      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
930169689Skan	 ModemStartOutput(modem);
931169689Skan      }
932169689Skan      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
933169689Skan	if (LcpFsm.state <= ST_CLOSED)
934169689Skan	  usleep(10000);
935169689Skan	n = read(modem, rbuff, sizeof(rbuff));
936169689Skan	if ((mode & MODE_DIRECT) && n <= 0) {
937169689Skan	  DownConnection();
938169689Skan	} else
939169689Skan          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
940169689Skan
941169689Skan	if (LcpFsm.state <= ST_CLOSED) {
942169689Skan	  /*
943169689Skan	   *  In dedicated mode, we just discard input until LCP is started.
944169689Skan	   */
945169689Skan	  if (!(mode & MODE_DEDICATED)) {
946169689Skan	    cp = HdlcDetect(rbuff, n);
947169689Skan	    if (cp) {
948169689Skan	      /*
949169689Skan	       * LCP packet is detected. Turn ourselves into packet mode.
950169689Skan	       */
951169689Skan	      if (cp != rbuff) {
952169689Skan	        write(1, rbuff, cp - rbuff);
953169689Skan	        write(1, "\r\n", 2);
954169689Skan	      }
955169689Skan	      PacketMode();
956169689Skan#ifdef notdef
957169689Skan	      AsyncInput(cp, n - (cp - rbuff));
958169689Skan#endif
959169689Skan	    } else
960169689Skan	      write(1, rbuff, n);
961169689Skan	  }
962169689Skan	} else {
963169689Skan	  if (n > 0)
964169689Skan	    AsyncInput(rbuff, n);
965169689Skan#ifdef notdef
966169689Skan	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
967169689Skan#endif
968169689Skan	}
969169689Skan      }
970169689Skan    }
971169689Skan
972169689Skan    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
973169689Skan      n = read(tun_in, rbuff, sizeof(rbuff));
974169689Skan      if (n < 0) {
975169689Skan	perror("read from tun");
976169689Skan	continue;
977169689Skan      }
978169689Skan      /*
979169689Skan       *  Process on-demand dialup. Output packets are queued within tunnel
980169689Skan       *  device until IPCP is opened.
981169689Skan       */
982169689Skan      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
983169689Skan	pri = PacketCheck(rbuff, n, FL_DIAL);
984169689Skan	if (pri >= 0) {
985169689Skan	  if (mode & MODE_ALIAS) {
986169689Skan	    PacketAliasOut((struct ip *)rbuff);
987169689Skan	    n = ntohs(((struct ip *)rbuff)->ip_len);
988169689Skan	  }
989169689Skan	  IpEnqueue(pri, rbuff, n);
990169689Skan	  dial_up = TRUE;		/* XXX */
991169689Skan	}
992169689Skan	continue;
993169689Skan      }
994169689Skan      pri = PacketCheck(rbuff, n, FL_OUT);
995169689Skan      if (pri >= 0) {
996169689Skan        if (mode & MODE_ALIAS) {
997169689Skan          PacketAliasOut((struct ip *)rbuff);
998169689Skan          n = ntohs(((struct ip *)rbuff)->ip_len);
999169689Skan        }
1000169689Skan	IpEnqueue(pri, rbuff, n);
1001169689Skan      }
1002169689Skan    }
1003169689Skan  }
1004169689Skan  logprintf("job done.\n");
1005169689Skan}
1006169689Skan