main.c revision 25908
190792Sgshapiro/*
2147078Sgshapiro *			User Process PPP
390792Sgshapiro *
490792Sgshapiro *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
590792Sgshapiro *
690792Sgshapiro *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
790792Sgshapiro *
890792Sgshapiro * Redistribution and use in source and binary forms are permitted
990792Sgshapiro * provided that the above copyright notice and this paragraph are
1090792Sgshapiro * duplicated in all such forms and that any documentation,
11147078Sgshapiro * advertising materials, and other materials related to such
1290792Sgshapiro * distribution and use acknowledge that the software was developed
1390792Sgshapiro * by the Internet Initiative Japan, Inc.  The name of the
1490792Sgshapiro * IIJ may not be used to endorse or promote products derived
1590792Sgshapiro * from this software without specific prior written permission.
1690792Sgshapiro * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1790792Sgshapiro * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1890792Sgshapiro * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19120256Sgshapiro *
2090792Sgshapiro * $Id: main.c,v 1.51 1997/05/17 16:08:46 brian Exp $
2190792Sgshapiro *
2290792Sgshapiro *	TODO:
2390792Sgshapiro *		o Add commands for traffic summary, version display, etc.
2490792Sgshapiro *		o Add signal handler for misc controls.
2590792Sgshapiro */
2690792Sgshapiro#include "fsm.h"
2790792Sgshapiro#include <fcntl.h>
2890792Sgshapiro#include <paths.h>
2990792Sgshapiro#include <sys/time.h>
3090792Sgshapiro#include <termios.h>
3190792Sgshapiro#include <signal.h>
3290792Sgshapiro#include <sys/wait.h>
3390792Sgshapiro#include <errno.h>
3490792Sgshapiro#include <netdb.h>
3590792Sgshapiro#include <unistd.h>
3690792Sgshapiro#include <sys/socket.h>
3790792Sgshapiro#include <arpa/inet.h>
3890792Sgshapiro#include <netinet/in_systm.h>
3990792Sgshapiro#include <netinet/ip.h>
4090792Sgshapiro#include "modem.h"
4190792Sgshapiro#include "os.h"
4290792Sgshapiro#include "hdlc.h"
4390792Sgshapiro#include "ccp.h"
4490792Sgshapiro#include "lcp.h"
4590792Sgshapiro#include "ipcp.h"
4690792Sgshapiro#include "vars.h"
4790792Sgshapiro#include "auth.h"
4890792Sgshapiro#include "filter.h"
4990792Sgshapiro#include "systems.h"
5090792Sgshapiro#include "ip.h"
5190792Sgshapiro#include "alias.h"
5290792Sgshapiro#include "sig.h"
5390792Sgshapiro
5490792Sgshapiro#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
5590792Sgshapiro#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
5690792Sgshapiro
5790792Sgshapiro#ifndef O_NONBLOCK
5890792Sgshapiro#ifdef O_NDELAY
5990792Sgshapiro#define	O_NONBLOCK O_NDELAY
6090792Sgshapiro#endif
6190792Sgshapiro#endif
6290792Sgshapiro
6390792Sgshapiroextern void VjInit(), AsyncInit();
6490792Sgshapiroextern void AsyncInput();
6590792Sgshapiroextern int  SelectSystem();
6690792Sgshapiro
6790792Sgshapiroextern void DecodeCommand(), Prompt();
6890792Sgshapiroextern int aft_cmd;
6990792Sgshapiroextern int IsInteractive();
7090792Sgshapirostatic void DoLoop(void);
7190792Sgshapirostatic void TerminalStop();
7290792Sgshapirostatic char *ex_desc();
73120256Sgshapiro
7490792Sgshapirostatic struct termios oldtio;		/* Original tty mode */
7590792Sgshapirostatic struct termios comtio;		/* Command level tty mode */
7690792Sgshapiroint TermMode;
7790792Sgshapirostatic int server;
7890792Sgshapirostatic pid_t BGPid = 0;
7990792Sgshapirostruct sockaddr_in ifsin;
8090792Sgshapirostatic char pid_filename[MAXPATHLEN];
8190792Sgshapirostatic char if_filename[MAXPATHLEN];
8290792Sgshapiroint tunno;
8390792Sgshapiro
8490792Sgshapirostatic void
8590792SgshapiroTtyInit()
8690792Sgshapiro{
8790792Sgshapiro  struct termios newtio;
8890792Sgshapiro  int stat;
8990792Sgshapiro
90120256Sgshapiro  stat = fcntl(0, F_GETFL, 0);
9190792Sgshapiro  if (stat > 0) {
9290792Sgshapiro	 stat |= O_NONBLOCK;
9390792Sgshapiro	 (void)fcntl(0, F_SETFL, stat);
9490792Sgshapiro  }
9590792Sgshapiro  newtio = oldtio;
9690792Sgshapiro  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
9790792Sgshapiro  newtio.c_iflag = 0;
9890792Sgshapiro  newtio.c_oflag &= ~OPOST;
9990792Sgshapiro  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
10090792Sgshapiro  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
10190792Sgshapiro  newtio.c_cc[VMIN] = 1;
10290792Sgshapiro  newtio.c_cc[VTIME] = 0;
10390792Sgshapiro  newtio.c_cflag |= CS8;
10490792Sgshapiro  tcsetattr(0, TCSADRAIN, &newtio);
105120256Sgshapiro  comtio = newtio;
106120256Sgshapiro}
107147078Sgshapiro
108147078Sgshapiro/*
109147078Sgshapiro *  Set tty into command mode. We allow canonical input and echo processing.
110147078Sgshapiro */
111147078Sgshapirovoid
112147078SgshapiroTtyCommandMode(prompt)
113147078Sgshapiroint prompt;
114147078Sgshapiro{
115147078Sgshapiro  struct termios newtio;
116147078Sgshapiro  int stat;
117147078Sgshapiro
118147078Sgshapiro  if (!(mode & MODE_INTER))
119147078Sgshapiro    return;
120147078Sgshapiro  tcgetattr(0, &newtio);
121147078Sgshapiro  newtio.c_lflag |= (ECHO|ISIG|ICANON);
122147078Sgshapiro  newtio.c_iflag = oldtio.c_iflag;
123147078Sgshapiro  newtio.c_oflag |= OPOST;
124147078Sgshapiro  tcsetattr(0, TCSADRAIN, &newtio);
125147078Sgshapiro  stat = fcntl(0, F_GETFL, 0);
126147078Sgshapiro  if (stat > 0) {
127147078Sgshapiro	 stat |= O_NONBLOCK;
128147078Sgshapiro	 (void)fcntl(0, F_SETFL, stat);
129147078Sgshapiro  }
130147078Sgshapiro  TermMode = 0;
131147078Sgshapiro  if(prompt) Prompt();
132147078Sgshapiro}
133147078Sgshapiro
134147078Sgshapiro/*
135147078Sgshapiro * Set tty into terminal mode which is used while we invoke term command.
136147078Sgshapiro */
137147078Sgshapirovoid
138147078SgshapiroTtyTermMode()
139147078Sgshapiro{
140147078Sgshapiro  int stat;
14190792Sgshapiro
142  tcsetattr(0, TCSADRAIN, &comtio);
143  stat = fcntl(0, F_GETFL, 0);
144  if (stat > 0) {
145	 stat &= ~O_NONBLOCK;
146	 (void)fcntl(0, F_SETFL, stat);
147  }
148  TermMode = 1;
149}
150
151void
152TtyOldMode()
153{
154  int stat;
155
156  stat = fcntl(0, F_GETFL, 0);
157  if (stat > 0) {
158	  stat &= ~O_NONBLOCK;
159	  (void)fcntl(0, F_SETFL, stat);
160  }
161  tcsetattr(0, TCSANOW, &oldtio);
162}
163
164void
165Cleanup(excode)
166int excode;
167{
168
169  OsLinkdown();
170  OsCloseLink(1);
171  sleep(1);
172  if (mode & MODE_AUTO)
173    DeleteIfRoutes(1);
174  (void)unlink(pid_filename);
175  (void)unlink(if_filename);
176  OsInterfaceDown(1);
177  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
178    char c = EX_ERRDEAD;
179    if (write(BGFiledes[1],&c,1) == 1)
180      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
181    else
182      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
183    close(BGFiledes[1]);
184  }
185  LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode));
186  LogClose();
187  if (server >= 0) {
188    close(server);
189    server = -1;
190  }
191
192  TtyOldMode();
193
194  exit(excode);
195}
196
197static void
198Hangup(signo)
199int signo;
200{
201  if (signo == SIGSEGV) {
202	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
203	LogClose();
204	abort();
205  }
206  if (BGPid) {
207      kill (BGPid, SIGTERM);
208      exit (EX_HANGUP);
209  }
210  else {
211      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
212      Cleanup(EX_HANGUP);
213  }
214}
215
216static void
217CloseSession(signo)
218int signo;
219{
220   if (BGPid) {
221     kill (BGPid, SIGINT);
222     exit (EX_TERM);
223   }
224   else {
225     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
226     LcpClose();
227     reconnectCount = 0;
228     Cleanup(EX_TERM);
229   }
230}
231
232static void
233TerminalCont()
234{
235  pending_signal(SIGCONT, SIG_DFL);
236  pending_signal(SIGTSTP, TerminalStop);
237  TtyCommandMode(getpgrp() == tcgetpgrp(0));
238}
239
240static void
241TerminalStop(signo)
242int signo;
243{
244  pending_signal(SIGCONT, TerminalCont);
245  TtyOldMode();
246  pending_signal(SIGTSTP, SIG_DFL);
247  kill(getpid(), signo);
248}
249
250static char *
251ex_desc(int ex)
252{
253  static char num[12];
254  static char *desc[] = { "normal", "start", "sock",
255    "modem", "dial", "dead", "done", "reboot", "errdead",
256    "hangup", "term", "nodial", "nologin" };
257
258  if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc))
259    return desc[ex];
260  snprintf(num, sizeof num, "%d", ex);
261  return num;
262}
263
264void
265Usage()
266{
267  fprintf(stderr,
268          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
269  exit(EX_START);
270}
271
272void
273ProcessArgs(int argc, char **argv)
274{
275  int optc;
276  char *cp;
277
278  optc = 0;
279  while (argc > 0 && **argv == '-') {
280    cp = *argv + 1;
281    if (strcmp(cp, "auto") == 0)
282      mode |= MODE_AUTO;
283    else if (strcmp(cp, "background") == 0)
284      mode |= MODE_BACKGROUND|MODE_AUTO;
285    else if (strcmp(cp, "direct") == 0)
286      mode |= MODE_DIRECT;
287    else if (strcmp(cp, "dedicated") == 0)
288      mode |= MODE_DEDICATED;
289    else if (strcmp(cp, "ddial") == 0)
290      mode |= MODE_DDIAL|MODE_AUTO;
291    else if (strcmp(cp, "alias") == 0) {
292      mode |= MODE_ALIAS;
293      optc--;             /* this option isn't exclusive */
294    }
295    else
296      Usage();
297    optc++;
298    argv++; argc--;
299  }
300  if (argc > 1) {
301    fprintf(stderr, "specify only one system label.\n");
302    exit(EX_START);
303  }
304  if (argc == 1) dstsystem = *argv;
305
306  if (optc > 1) {
307    fprintf(stderr, "specify only one mode.\n");
308    exit(EX_START);
309  }
310}
311
312static void
313Greetings()
314{
315  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
316  fflush(stdout);
317}
318
319void
320main(argc, argv)
321int argc;
322char **argv;
323{
324  FILE *lockfile;
325  argc--; argv++;
326
327  mode = MODE_INTER;		/* default operation is interactive mode */
328  netfd = server = modem = tun_in = -1;
329  ProcessArgs(argc, argv);
330  Greetings();
331  GetUid();
332  IpcpDefAddress();
333  InitAlias();
334
335  if (SelectSystem("default", CONFFILE) < 0) {
336    fprintf(stderr, "Warning: No default entry is given in config file.\n");
337  }
338
339  switch ( LocalAuthInit() ) {
340    case NOT_FOUND:
341    	fprintf(stderr,LAUTH_M1);
342    	fprintf(stderr,LAUTH_M2);
343	fflush (stderr);
344	/* Fall down */
345    case VALID:
346	VarLocalAuth = LOCAL_AUTH;
347	break;
348    default:
349	break;
350  }
351
352  if (OpenTunnel(&tunno) < 0) {
353    perror("open_tun");
354    exit(EX_START);
355  }
356
357  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
358    mode &= ~MODE_INTER;
359  if (mode & MODE_INTER) {
360    printf("Interactive mode\n");
361    netfd = STDIN_FILENO;
362  } else if (mode & MODE_AUTO) {
363    printf("Automatic Dialer mode\n");
364    if (dstsystem == NULL) {
365      fprintf(stderr, "Destination system must be specified in"
366              " auto, background or ddial mode.\n");
367      exit(EX_START);
368    }
369  }
370
371  tcgetattr(0, &oldtio);		/* Save original tty mode */
372
373  pending_signal(SIGHUP, LogReOpen);
374  pending_signal(SIGTERM, CloseSession);
375  pending_signal(SIGINT, CloseSession);
376  pending_signal(SIGQUIT, CloseSession);
377#ifdef SIGSEGV
378  signal(SIGSEGV, Hangup);
379#endif
380#ifdef SIGPIPE
381  signal(SIGPIPE, SIG_IGN);
382#endif
383#ifdef SIGALRM
384  pending_signal(SIGALRM, SIG_IGN);
385#endif
386  if(mode & MODE_INTER)
387    {
388#ifdef SIGTSTP
389      pending_signal(SIGTSTP, TerminalStop);
390#endif
391#ifdef SIGTTIN
392      pending_signal(SIGTTIN, TerminalStop);
393#endif
394#ifdef SIGTTOU
395      pending_signal(SIGTTOU, SIG_IGN);
396#endif
397    }
398
399  if (dstsystem) {
400    if (SelectSystem(dstsystem, CONFFILE) < 0) {
401      fprintf(stderr, "Destination system not found in conf file.\n");
402      Cleanup(EX_START);
403    }
404    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
405      fprintf(stderr, "Must specify dstaddr with"
406              " auto, background or ddial mode.\n");
407      Cleanup(EX_START);
408    }
409  }
410  if (mode & MODE_DIRECT)
411    printf("Packet mode enabled.\n");
412
413  if (!(mode & MODE_INTER)) {
414    int port = SERVER_PORT + tunno;
415
416    if (mode & MODE_BACKGROUND) {
417      if (pipe (BGFiledes)) {
418	perror("pipe");
419	Cleanup(EX_SOCK);
420      }
421    }
422
423    /* Create server socket and listen at there. */
424    server = socket(PF_INET, SOCK_STREAM, 0);
425    if (server < 0) {
426      perror("socket");
427      Cleanup(EX_SOCK);
428    }
429    ifsin.sin_family = AF_INET;
430    ifsin.sin_addr.s_addr = INADDR_ANY;
431    ifsin.sin_port = htons(port);
432    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
433      perror("bind");
434      if (errno == EADDRINUSE)
435        fprintf(stderr, "Wait for a while, then try again.\n");
436      Cleanup(EX_SOCK);
437    }
438    if (listen(server, 5) != 0) {
439      fprintf(stderr, "Unable to listen to socket - OS overload?\n");
440    }
441
442    DupLog();
443    if (!(mode & MODE_DIRECT)) {
444      pid_t bgpid;
445
446      bgpid = fork ();
447      if (bgpid == -1) {
448	perror ("fork");
449	Cleanup (EX_SOCK);
450      }
451      if (bgpid) {
452	char c = EX_NORMAL;
453
454	if (mode & MODE_BACKGROUND) {
455	  /* Wait for our child to close its pipe before we exit. */
456	  BGPid = bgpid;
457          close (BGFiledes[1]);
458	  if (read(BGFiledes[0], &c, 1) != 1) {
459	    printf("Child exit, no status.\n");
460	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
461	  } else if (c == EX_NORMAL) {
462	    printf("PPP enabled.\n");
463	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
464	  } else {
465	    printf("Child failed %d.\n",(int)c);
466	    LogPrintf (LOG_PHASE_BIT, "Parent: Child failed %d.\n",(int)c);
467          }
468          close (BGFiledes[0]);
469	}
470        exit(c);
471      } else if (mode & MODE_BACKGROUND)
472          close(BGFiledes[0]);
473    }
474
475    snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid",
476             _PATH_VARRUN, tunno);
477    (void)unlink(pid_filename);
478
479    if ((lockfile = fopen(pid_filename, "w")) != NULL) {
480      fprintf(lockfile, "%d\n", (int)getpid());
481      fclose(lockfile);
482    } else
483      logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno));
484
485    snprintf(if_filename, sizeof if_filename, "%s%s.if",
486             _PATH_VARRUN, VarBaseDevice);
487    (void)unlink(if_filename);
488
489    if ((lockfile = fopen(if_filename, "w")) != NULL) {
490      fprintf(lockfile, "tun%d\n", tunno);
491      fclose(lockfile);
492    } else
493      logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno));
494
495    if (server >= 0)
496	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
497#ifdef DOTTYINIT
498    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
499#else
500    if (mode & MODE_DIRECT) {
501#endif
502      TtyInit();
503    } else {
504      int fd;
505
506      setsid();			/* detach control tty */
507      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
508	(void)dup2(fd, STDIN_FILENO);
509	(void)dup2(fd, STDOUT_FILENO);
510	(void)dup2(fd, STDERR_FILENO);
511	if (fd > 2)
512		(void)close (fd);
513      }
514    }
515  } else {
516    TtyInit();
517    TtyCommandMode(1);
518  }
519  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
520
521
522  do
523   DoLoop();
524  while (mode & MODE_DEDICATED);
525
526  Cleanup(EX_DONE);
527}
528
529/*
530 *  Turn into packet mode, where we speak PPP.
531 */
532void
533PacketMode()
534{
535  if (RawModem(modem) < 0) {
536    fprintf(stderr, "Not connected.\r\n");
537    return;
538  }
539
540  AsyncInit();
541  VjInit();
542  LcpInit();
543  IpcpInit();
544  CcpInit();
545  LcpUp();
546
547  LcpOpen(VarOpenMode);
548  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
549    TtyCommandMode(1);
550    fprintf(stderr, "Packet mode.\r\n");
551    aft_cmd = 1;
552  }
553}
554
555static void
556ShowHelp()
557{
558  fprintf(stderr, "The following commands are available:\r\n");
559  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
560  fprintf(stderr, " ~-\tDecrease log level\r\n");
561  fprintf(stderr, " ~+\tIncrease log level\r\n");
562  fprintf(stderr, " ~.\tTerminate program\r\n");
563  fprintf(stderr, " ~?\tThis help\r\n");
564}
565
566static void
567ReadTty()
568{
569  int n;
570  char ch;
571  static int ttystate;
572#define MAXLINESIZE 200
573  char linebuff[MAXLINESIZE];
574
575#ifdef DEBUG
576  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
577#endif
578  if (!TermMode) {
579    n = read(netfd, linebuff, sizeof(linebuff)-1);
580    aft_cmd = 1;
581    if (n > 0) {
582      DecodeCommand(linebuff, n, 1);
583    } else {
584      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
585      VarLocalAuth = LOCAL_NO_AUTH;
586      close(netfd);
587      close(1);
588      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
589      netfd = -1;
590      mode &= ~MODE_INTER;
591    }
592    return;
593  }
594
595  /*
596   *  We are in terminal mode, decode special sequences
597   */
598  n = read(0, &ch, 1);
599#ifdef DEBUG
600  logprintf("got %d bytes\n", n);
601#endif
602
603  if (n > 0) {
604    switch (ttystate) {
605    case 0:
606      if (ch == '~')
607	ttystate++;
608      else
609	write(modem, &ch, n);
610      break;
611    case 1:
612      switch (ch) {
613      case '?':
614	ShowHelp();
615	break;
616      case '-':
617	if (loglevel > 0) {
618	  loglevel--;
619	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
620	}
621	break;
622      case '+':
623	loglevel++;
624	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
625	break;
626#ifdef DEBUG
627      case 'm':
628	ShowMemMap();
629	break;
630#endif
631      case 'p':
632	/*
633	 * XXX: Should check carrier.
634	 */
635	if (LcpFsm.state <= ST_CLOSED) {
636	  VarOpenMode = OPEN_ACTIVE;
637	  PacketMode();
638	}
639	break;
640#ifdef DEBUG
641      case 't':
642	ShowTimers();
643	break;
644#endif
645      case '.':
646	TermMode = 1;
647	TtyCommandMode(1);
648	break;
649      default:
650	if (write(modem, &ch, n) < 0)
651	  fprintf(stderr, "err in write.\r\n");
652	break;
653      }
654      ttystate = 0;
655      break;
656    }
657  }
658}
659
660
661/*
662 *  Here, we'll try to detect HDLC frame
663 */
664
665static char *FrameHeaders[] = {
666  "\176\377\003\300\041",
667  "\176\377\175\043\300\041",
668  "\176\177\175\043\100\041",
669  "\176\175\337\175\043\300\041",
670  "\176\175\137\175\043\100\041",
671  NULL,
672};
673
674u_char *
675HdlcDetect(cp, n)
676u_char *cp;
677int n;
678{
679  char *ptr, *fp, **hp;
680
681  cp[n] = '\0';	/* be sure to null terminated */
682  ptr = NULL;
683  for (hp = FrameHeaders; *hp; hp++) {
684    fp = *hp;
685    if (DEV_IS_SYNC)
686      fp++;
687    ptr = strstr((char *)cp, fp);
688    if (ptr)
689      break;
690  }
691  return((u_char *)ptr);
692}
693
694static struct pppTimer RedialTimer;
695
696static void
697RedialTimeout()
698{
699  StopTimer(&RedialTimer);
700  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
701}
702
703static void
704StartRedialTimer(Timeout)
705	int Timeout;
706{
707  StopTimer(&RedialTimer);
708
709  if (Timeout) {
710    RedialTimer.state = TIMER_STOPPED;
711
712    if (Timeout > 0)
713	RedialTimer.load = Timeout * SECTICKS;
714    else
715	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
716
717    LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n",
718	      RedialTimer.load / SECTICKS);
719
720    RedialTimer.func = RedialTimeout;
721    StartTimer(&RedialTimer);
722  }
723}
724
725
726static void
727DoLoop()
728{
729  fd_set rfds, wfds, efds;
730  int pri, i, n, wfd, nfds;
731  struct sockaddr_in hisaddr;
732  struct timeval timeout, *tp;
733  int ssize = sizeof(hisaddr);
734  u_char *cp;
735  u_char rbuff[MAX_MRU];
736  int dial_up;
737  int tries;
738  int qlen;
739  pid_t pgroup;
740
741  pgroup = getpgrp();
742
743  if (mode & MODE_DIRECT) {
744    modem = OpenModem(mode);
745    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
746    fflush(stderr);
747    PacketMode();
748  } else if (mode & MODE_DEDICATED) {
749    if (modem < 0)
750      modem = OpenModem(mode);
751  }
752
753  fflush(stdout);
754
755  timeout.tv_sec = 0;
756  timeout.tv_usec = 0;
757  reconnectRequired = 0;
758
759  if (mode & MODE_BACKGROUND)
760    dial_up = TRUE;			/* Bring the line up */
761  else
762    dial_up = FALSE;			/* XXXX */
763  tries = 0;
764  for (;;) {
765    nfds = 0;
766    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
767
768    /*
769     * If the link is down and we're in DDIAL mode, bring it back
770     * up.
771     */
772    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
773        dial_up = TRUE;
774
775    /*
776     * If we lost carrier and want to re-establish the connection
777     * due to the "set reconnect" value, we'd better bring the line
778     * back up.
779     */
780    if (LcpFsm.state <= ST_CLOSED) {
781      if (dial_up != TRUE && reconnectRequired) {
782        if (++reconnectCount <= VarReconnectTries) {
783          LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n",
784                    reconnectCount, VarReconnectTries);
785	  StartRedialTimer(VarReconnectTimer);
786          dial_up = TRUE;
787        } else {
788          if (VarReconnectTries)
789            LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n",
790                      VarReconnectTries);
791          reconnectCount = 0;
792          if (mode & MODE_BACKGROUND)
793            Cleanup(EX_DEAD);
794        }
795      }
796      reconnectRequired = 0;
797    }
798
799   /*
800    * If Ip packet for output is enqueued and require dial up,
801    * Just do it!
802    */
803    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
804#ifdef DEBUG
805      logprintf("going to dial: modem = %d\n", modem);
806#endif
807      modem = OpenModem(mode);
808      if (modem < 0) {
809	StartRedialTimer(VarRedialTimeout);
810      } else {
811	tries++;    /* Tries are per number, not per list of numbers. */
812        if (VarDialTries)
813	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
814		    VarDialTries);
815        else
816	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
817	if (DialModem()) {
818	  sleep(1);	       /* little pause to allow peer starts */
819	  ModemTimeout();
820	  PacketMode();
821	  dial_up = FALSE;
822	  tries = 0;
823	} else {
824	  CloseModem();
825	  if (mode & MODE_BACKGROUND) {
826	    if (VarNextPhone == NULL)
827	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
828	    else
829	      /* Try all numbers in background mode */
830	      StartRedialTimer(VarRedialNextTimeout);
831	  } else if (VarDialTries && tries >= VarDialTries) {
832	    /* I give up !  Can't get through :( */
833	    StartRedialTimer(VarRedialTimeout);
834	    dial_up = FALSE;
835	    tries = 0;
836	  } else if (VarNextPhone == NULL)
837	    /* Dial failed. Keep quite during redial wait period. */
838	    StartRedialTimer(VarRedialTimeout);
839	  else
840	    StartRedialTimer(VarRedialNextTimeout);
841	}
842      }
843    }
844    qlen = ModemQlen();
845
846    if (qlen == 0) {
847      IpStartOutput();
848      qlen = ModemQlen();
849    }
850
851    if (modem >= 0) {
852      if (modem + 1 > nfds)
853	nfds = modem + 1;
854      FD_SET(modem, &rfds);
855      FD_SET(modem, &efds);
856      if (qlen > 0) {
857	FD_SET(modem, &wfds);
858      }
859    }
860    if (server >= 0) {
861      if (server + 1 > nfds)
862	nfds = server + 1;
863      FD_SET(server, &rfds);
864    }
865
866    /*  *** IMPORTANT ***
867     *
868     *  CPU is serviced every TICKUNIT micro seconds.
869     *	This value must be chosen with great care. If this values is
870     *  too big, it results loss of characters from modem and poor responce.
871     *  If this values is too small, ppp process eats many CPU time.
872     */
873#ifndef SIGALRM
874    usleep(TICKUNIT);
875    TimerService();
876#else
877    handle_signals();
878#endif
879
880    /* If there are aren't many packets queued, look for some more. */
881    if (qlen < 20 && tun_in >= 0) {
882      if (tun_in + 1 > nfds)
883	nfds = tun_in + 1;
884      FD_SET(tun_in, &rfds);
885    }
886
887    if (netfd >= 0) {
888      if (netfd + 1 > nfds)
889	nfds = netfd + 1;
890      FD_SET(netfd, &rfds);
891      FD_SET(netfd, &efds);
892    }
893
894#ifndef SIGALRM
895    /*
896     *  Normally, select() will not block because modem is writable.
897     *  In AUTO mode, select will block until we find packet from tun
898     */
899    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
900    i = select(nfds, &rfds, &wfds, &efds, tp);
901#else
902    /*
903     * When SIGALRM timer is running, a select function will be
904     * return -1 and EINTR after a Time Service signal hundler
905     * is done.  If the redial timer is not running and we are
906     * trying to dial, poll with a 0 value timer.
907     */
908    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
909    i = select(nfds, &rfds, &wfds, &efds, tp);
910#endif
911
912    if ( i == 0 ) {
913        continue;
914    }
915
916    if ( i < 0 ) {
917       if ( errno == EINTR ) {
918          handle_signals();
919          continue;
920       }
921       perror("select");
922       break;
923    }
924
925    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
926      logprintf("Exception detected.\n");
927      break;
928    }
929
930    if (server >= 0 && FD_ISSET(server, &rfds)) {
931      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
932      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
933      if (wfd < 0) {
934	perror("accept");
935	continue;
936      }
937      if (netfd >= 0) {
938	write(wfd, "already in use.\n", 16);
939	close(wfd);
940	continue;
941      } else
942	netfd = wfd;
943      if (dup2(netfd, 1) < 0) {
944	perror("dup2");
945	close(netfd);
946	netfd = -1;
947	continue;
948      }
949      mode |= MODE_INTER;
950      Greetings();
951      switch ( LocalAuthInit() ) {
952         case NOT_FOUND:
953    	    fprintf(stdout,LAUTH_M1);
954    	    fprintf(stdout,LAUTH_M2);
955            fflush(stdout);
956	    /* Fall down */
957         case VALID:
958	    VarLocalAuth = LOCAL_AUTH;
959	    break;
960         default:
961	    break;
962      }
963      (void) IsInteractive();
964      Prompt();
965    }
966
967    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
968	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
969      /* something to read from tty */
970      ReadTty();
971    }
972    if (modem >= 0) {
973      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
974	 ModemStartOutput(modem);
975      }
976      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
977	if (LcpFsm.state <= ST_CLOSED)
978	  usleep(10000);
979	n = read(modem, rbuff, sizeof(rbuff));
980	if ((mode & MODE_DIRECT) && n <= 0) {
981	  DownConnection();
982	} else
983          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
984
985	if (LcpFsm.state <= ST_CLOSED) {
986	  /*
987	   *  In dedicated mode, we just discard input until LCP is started.
988	   */
989	  if (!(mode & MODE_DEDICATED)) {
990	    cp = HdlcDetect(rbuff, n);
991	    if (cp) {
992	      /*
993	       * LCP packet is detected. Turn ourselves into packet mode.
994	       */
995	      if (cp != rbuff) {
996	        write(1, rbuff, cp - rbuff);
997	        write(1, "\r\n", 2);
998	      }
999	      PacketMode();
1000	    } else
1001	      write(1, rbuff, n);
1002	  }
1003	} else {
1004	  if (n > 0)
1005	    AsyncInput(rbuff, n);
1006	}
1007      }
1008    }
1009
1010    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
1011      n = read(tun_in, rbuff, sizeof(rbuff));
1012      if (n < 0) {
1013	perror("read from tun");
1014	continue;
1015      }
1016      /*
1017       *  Process on-demand dialup. Output packets are queued within tunnel
1018       *  device until IPCP is opened.
1019       */
1020      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
1021	pri = PacketCheck(rbuff, n, FL_DIAL);
1022	if (pri >= 0) {
1023	  if (mode & MODE_ALIAS) {
1024	    PacketAliasOut((struct ip *)rbuff);
1025	    n = ntohs(((struct ip *)rbuff)->ip_len);
1026	  }
1027	  IpEnqueue(pri, rbuff, n);
1028	  dial_up = TRUE;		/* XXX */
1029	}
1030	continue;
1031      }
1032      pri = PacketCheck(rbuff, n, FL_OUT);
1033      if (pri >= 0) {
1034        if (mode & MODE_ALIAS) {
1035          PacketAliasOut((struct ip *)rbuff);
1036          n = ntohs(((struct ip *)rbuff)->ip_len);
1037        }
1038	IpEnqueue(pri, rbuff, n);
1039      }
1040    }
1041  }
1042  logprintf("job done.\n");
1043}
1044