main.c revision 26032
16059Samurai/*
26059Samurai *			User Process PPP
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2026032Sbrian * $Id: main.c,v 1.54 1997/05/23 04:54:03 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Add commands for traffic summary, version display, etc.
246059Samurai *		o Add signal handler for misc controls.
256059Samurai */
266059Samurai#include "fsm.h"
276059Samurai#include <fcntl.h>
2811336Samurai#include <paths.h>
296059Samurai#include <sys/time.h>
306059Samurai#include <termios.h>
3123114Sbrian#include <signal.h>
326059Samurai#include <sys/wait.h>
336059Samurai#include <errno.h>
346059Samurai#include <netdb.h>
3518786Sjkh#include <unistd.h>
366059Samurai#include <sys/socket.h>
376059Samurai#include <arpa/inet.h>
3820365Sjkh#include <netinet/in_systm.h>
3920365Sjkh#include <netinet/ip.h>
4026031Sbrian#include <alias.h>
416059Samurai#include "modem.h"
426059Samurai#include "os.h"
436059Samurai#include "hdlc.h"
4413389Sphk#include "ccp.h"
456059Samurai#include "lcp.h"
466059Samurai#include "ipcp.h"
476059Samurai#include "vars.h"
486735Samurai#include "auth.h"
497001Samurai#include "filter.h"
5013389Sphk#include "systems.h"
5113389Sphk#include "ip.h"
5223840Sbrian#include "sig.h"
536059Samurai
546764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
559410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
566764Samurai
576735Samurai#ifndef O_NONBLOCK
586735Samurai#ifdef O_NDELAY
596735Samurai#define	O_NONBLOCK O_NDELAY
606735Samurai#endif
616735Samurai#endif
626735Samurai
636059Samuraiextern void VjInit(), AsyncInit();
6425630Sbrianextern void AsyncInput();
656059Samuraiextern int  SelectSystem();
666059Samurai
676059Samuraiextern void DecodeCommand(), Prompt();
6818885Sjkhextern int aft_cmd;
696059Samuraiextern int IsInteractive();
706059Samuraistatic void DoLoop(void);
7110528Samuraistatic void TerminalStop();
7225908Sbrianstatic char *ex_desc();
736059Samurai
746059Samuraistatic struct termios oldtio;		/* Original tty mode */
756059Samuraistatic struct termios comtio;		/* Command level tty mode */
7614418Sacheint TermMode;
7713379Sphkstatic int server;
7820813Sjkhstatic pid_t BGPid = 0;
796059Samuraistruct sockaddr_in ifsin;
8025634Sbrianstatic char pid_filename[MAXPATHLEN];
8125634Sbrianstatic char if_filename[MAXPATHLEN];
8225445Sacheint tunno;
836059Samurai
846059Samuraistatic void
856059SamuraiTtyInit()
866059Samurai{
876059Samurai  struct termios newtio;
886059Samurai  int stat;
896059Samurai
906059Samurai  stat = fcntl(0, F_GETFL, 0);
9125630Sbrian  if (stat > 0) {
9225630Sbrian	 stat |= O_NONBLOCK;
9325630Sbrian	 (void)fcntl(0, F_SETFL, stat);
9425630Sbrian  }
956059Samurai  newtio = oldtio;
966059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
976059Samurai  newtio.c_iflag = 0;
986059Samurai  newtio.c_oflag &= ~OPOST;
996059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
1006059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
1016059Samurai  newtio.c_cc[VMIN] = 1;
1026059Samurai  newtio.c_cc[VTIME] = 0;
1036059Samurai  newtio.c_cflag |= CS8;
1046735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1056059Samurai  comtio = newtio;
1066059Samurai}
1076059Samurai
1086059Samurai/*
1096059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1106059Samurai */
11110528Samuraivoid
11210528SamuraiTtyCommandMode(prompt)
11310528Samuraiint prompt;
1146059Samurai{
1156059Samurai  struct termios newtio;
1166059Samurai  int stat;
1176059Samurai
1186059Samurai  if (!(mode & MODE_INTER))
1196059Samurai    return;
1206735Samurai  tcgetattr(0, &newtio);
12110528Samurai  newtio.c_lflag |= (ECHO|ISIG|ICANON);
1226059Samurai  newtio.c_iflag = oldtio.c_iflag;
1236059Samurai  newtio.c_oflag |= OPOST;
1246735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1256059Samurai  stat = fcntl(0, F_GETFL, 0);
12625630Sbrian  if (stat > 0) {
12725630Sbrian	 stat |= O_NONBLOCK;
12825630Sbrian	 (void)fcntl(0, F_SETFL, stat);
12925630Sbrian  }
1306059Samurai  TermMode = 0;
13125630Sbrian  if(prompt) Prompt();
1326059Samurai}
1336059Samurai
1346059Samurai/*
1356059Samurai * Set tty into terminal mode which is used while we invoke term command.
1366059Samurai */
1376059Samuraivoid
1386059SamuraiTtyTermMode()
1396059Samurai{
1406059Samurai  int stat;
1416059Samurai
1426735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1436059Samurai  stat = fcntl(0, F_GETFL, 0);
14425630Sbrian  if (stat > 0) {
14525630Sbrian	 stat &= ~O_NONBLOCK;
14625630Sbrian	 (void)fcntl(0, F_SETFL, stat);
14725630Sbrian  }
1486059Samurai  TermMode = 1;
1496059Samurai}
1506059Samurai
1516059Samuraivoid
15210528SamuraiTtyOldMode()
1536059Samurai{
1546059Samurai  int stat;
1556059Samurai
1566059Samurai  stat = fcntl(0, F_GETFL, 0);
15725630Sbrian  if (stat > 0) {
15825630Sbrian	  stat &= ~O_NONBLOCK;
15925630Sbrian	  (void)fcntl(0, F_SETFL, stat);
16025630Sbrian  }
1616735Samurai  tcsetattr(0, TCSANOW, &oldtio);
16210528Samurai}
16310528Samurai
16410528Samuraivoid
16510528SamuraiCleanup(excode)
16610528Samuraiint excode;
16710528Samurai{
16810528Samurai
16910528Samurai  OsLinkdown();
1706059Samurai  OsCloseLink(1);
1716059Samurai  sleep(1);
17225908Sbrian  if (mode & MODE_AUTO)
1736059Samurai    DeleteIfRoutes(1);
17425707Sbrian  (void)unlink(pid_filename);
17525707Sbrian  (void)unlink(if_filename);
1766059Samurai  OsInterfaceDown(1);
17723863Sbrian  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
17823863Sbrian    char c = EX_ERRDEAD;
17923863Sbrian    if (write(BGFiledes[1],&c,1) == 1)
18023863Sbrian      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
18123863Sbrian    else
18223863Sbrian      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
18323863Sbrian    close(BGFiledes[1]);
18423863Sbrian  }
18525908Sbrian  LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode));
1866059Samurai  LogClose();
18723598Sache  if (server >= 0) {
1886059Samurai    close(server);
18923598Sache    server = -1;
19023598Sache  }
19125707Sbrian
19210528Samurai  TtyOldMode();
1936059Samurai
1946059Samurai  exit(excode);
1956059Samurai}
1966059Samurai
1976059Samuraistatic void
19814930SacheHangup(signo)
19914930Sacheint signo;
2006059Samurai{
20117044Sache  if (signo == SIGSEGV) {
20217044Sache	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
20317044Sache	LogClose();
20417044Sache	abort();
20517044Sache  }
20620813Sjkh  if (BGPid) {
20723842Sbrian      kill (BGPid, SIGTERM);
20820813Sjkh      exit (EX_HANGUP);
20920813Sjkh  }
21020813Sjkh  else {
21120813Sjkh      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
21220813Sjkh      Cleanup(EX_HANGUP);
21320813Sjkh  }
2146059Samurai}
2156059Samurai
2166059Samuraistatic void
21714930SacheCloseSession(signo)
21814930Sacheint signo;
2196059Samurai{
22020813Sjkh   if (BGPid) {
22120813Sjkh     kill (BGPid, SIGINT);
22220813Sjkh     exit (EX_TERM);
22320813Sjkh   }
22420813Sjkh   else {
22520813Sjkh     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
22620813Sjkh     LcpClose();
22725908Sbrian     reconnectCount = 0;
22820813Sjkh     Cleanup(EX_TERM);
22920813Sjkh   }
2306059Samurai}
2316059Samurai
23210528Samuraistatic void
23310528SamuraiTerminalCont()
23410528Samurai{
23523840Sbrian  pending_signal(SIGCONT, SIG_DFL);
23623840Sbrian  pending_signal(SIGTSTP, TerminalStop);
23710528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
23810528Samurai}
23910528Samurai
24010528Samuraistatic void
24110528SamuraiTerminalStop(signo)
24210528Samuraiint signo;
24310528Samurai{
24423840Sbrian  pending_signal(SIGCONT, TerminalCont);
24510528Samurai  TtyOldMode();
24623840Sbrian  pending_signal(SIGTSTP, SIG_DFL);
24710528Samurai  kill(getpid(), signo);
24810528Samurai}
24910528Samurai
25025908Sbrianstatic char *
25125908Sbrianex_desc(int ex)
25225908Sbrian{
25325908Sbrian  static char num[12];
25425908Sbrian  static char *desc[] = { "normal", "start", "sock",
25525908Sbrian    "modem", "dial", "dead", "done", "reboot", "errdead",
25625908Sbrian    "hangup", "term", "nodial", "nologin" };
25710528Samurai
25825908Sbrian  if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc))
25925908Sbrian    return desc[ex];
26025908Sbrian  snprintf(num, sizeof num, "%d", ex);
26125908Sbrian  return num;
26225908Sbrian}
26325908Sbrian
2646059Samuraivoid
2656059SamuraiUsage()
2666059Samurai{
26720120Snate  fprintf(stderr,
26820813Sjkh          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
2696059Samurai  exit(EX_START);
2706059Samurai}
2716059Samurai
2726059Samuraivoid
2736059SamuraiProcessArgs(int argc, char **argv)
2746059Samurai{
2756059Samurai  int optc;
2766059Samurai  char *cp;
2776059Samurai
2786059Samurai  optc = 0;
2796059Samurai  while (argc > 0 && **argv == '-') {
2806059Samurai    cp = *argv + 1;
2816059Samurai    if (strcmp(cp, "auto") == 0)
2826059Samurai      mode |= MODE_AUTO;
28320813Sjkh    else if (strcmp(cp, "background") == 0)
28425908Sbrian      mode |= MODE_BACKGROUND|MODE_AUTO;
2856059Samurai    else if (strcmp(cp, "direct") == 0)
2866059Samurai      mode |= MODE_DIRECT;
2876059Samurai    else if (strcmp(cp, "dedicated") == 0)
2886059Samurai      mode |= MODE_DEDICATED;
28920120Snate    else if (strcmp(cp, "ddial") == 0)
29020120Snate      mode |= MODE_DDIAL|MODE_AUTO;
29120365Sjkh    else if (strcmp(cp, "alias") == 0) {
29220365Sjkh      mode |= MODE_ALIAS;
29320365Sjkh      optc--;             /* this option isn't exclusive */
29420365Sjkh    }
2956059Samurai    else
2966059Samurai      Usage();
2976059Samurai    optc++;
2986059Samurai    argv++; argc--;
2996059Samurai  }
3006059Samurai  if (argc > 1) {
3016059Samurai    fprintf(stderr, "specify only one system label.\n");
3026059Samurai    exit(EX_START);
3036059Samurai  }
3046059Samurai  if (argc == 1) dstsystem = *argv;
3056059Samurai
3066059Samurai  if (optc > 1) {
3076059Samurai    fprintf(stderr, "specify only one mode.\n");
3086059Samurai    exit(EX_START);
3096059Samurai  }
3106059Samurai}
3116059Samurai
3126059Samuraistatic void
3136059SamuraiGreetings()
3146059Samurai{
3156059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
3166059Samurai  fflush(stdout);
3176059Samurai}
3186059Samurai
3196059Samuraivoid
3206059Samuraimain(argc, argv)
3216059Samuraiint argc;
3226059Samuraichar **argv;
3236059Samurai{
32425707Sbrian  FILE *lockfile;
3256059Samurai  argc--; argv++;
3266059Samurai
3276059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
32823598Sache  netfd = server = modem = tun_in = -1;
3296059Samurai  ProcessArgs(argc, argv);
3306059Samurai  Greetings();
3316059Samurai  GetUid();
3326059Samurai  IpcpDefAddress();
33326031Sbrian  InitPacketAlias();
3346059Samurai
3356059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
3366059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
3376059Samurai  }
3386059Samurai
3396735Samurai  switch ( LocalAuthInit() ) {
3406735Samurai    case NOT_FOUND:
3416764Samurai    	fprintf(stderr,LAUTH_M1);
3426764Samurai    	fprintf(stderr,LAUTH_M2);
3436764Samurai	fflush (stderr);
3446764Samurai	/* Fall down */
3456764Samurai    case VALID:
3466735Samurai	VarLocalAuth = LOCAL_AUTH;
3476735Samurai	break;
3486735Samurai    default:
3496735Samurai	break;
3506735Samurai  }
3516735Samurai
3526059Samurai  if (OpenTunnel(&tunno) < 0) {
3536059Samurai    perror("open_tun");
3546059Samurai    exit(EX_START);
3556059Samurai  }
3566059Samurai
35725908Sbrian  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
3586059Samurai    mode &= ~MODE_INTER;
3596059Samurai  if (mode & MODE_INTER) {
3606059Samurai    printf("Interactive mode\n");
36123598Sache    netfd = STDIN_FILENO;
3626059Samurai  } else if (mode & MODE_AUTO) {
36320120Snate    printf("Automatic Dialer mode\n");
3646059Samurai    if (dstsystem == NULL) {
36525908Sbrian      fprintf(stderr, "Destination system must be specified in"
36625908Sbrian              " auto, background or ddial mode.\n");
3676059Samurai      exit(EX_START);
3686059Samurai    }
3696059Samurai  }
3706059Samurai
3716735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
3726059Samurai
37323842Sbrian  pending_signal(SIGHUP, LogReOpen);
37423840Sbrian  pending_signal(SIGTERM, CloseSession);
37523840Sbrian  pending_signal(SIGINT, CloseSession);
37623840Sbrian  pending_signal(SIGQUIT, CloseSession);
3776735Samurai#ifdef SIGSEGV
37823513Sache  signal(SIGSEGV, Hangup);
3796735Samurai#endif
3806735Samurai#ifdef SIGPIPE
38124753Sache  signal(SIGPIPE, SIG_IGN);
3826735Samurai#endif
3836735Samurai#ifdef SIGALRM
38423840Sbrian  pending_signal(SIGALRM, SIG_IGN);
3856735Samurai#endif
38610528Samurai  if(mode & MODE_INTER)
38710528Samurai    {
38810528Samurai#ifdef SIGTSTP
38923840Sbrian      pending_signal(SIGTSTP, TerminalStop);
39010528Samurai#endif
39110528Samurai#ifdef SIGTTIN
39223840Sbrian      pending_signal(SIGTTIN, TerminalStop);
39310528Samurai#endif
39410528Samurai#ifdef SIGTTOU
39523840Sbrian      pending_signal(SIGTTOU, SIG_IGN);
39610528Samurai#endif
39710528Samurai    }
3986059Samurai
3996059Samurai  if (dstsystem) {
4006059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
4016059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
4026059Samurai      Cleanup(EX_START);
4036059Samurai    }
4046059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
40525908Sbrian      fprintf(stderr, "Must specify dstaddr with"
40625908Sbrian              " auto, background or ddial mode.\n");
4076059Samurai      Cleanup(EX_START);
4086059Samurai    }
4096059Samurai  }
4106059Samurai  if (mode & MODE_DIRECT)
4116059Samurai    printf("Packet mode enabled.\n");
4126059Samurai
4136059Samurai  if (!(mode & MODE_INTER)) {
41420813Sjkh    int port = SERVER_PORT + tunno;
41525908Sbrian
41620813Sjkh    if (mode & MODE_BACKGROUND) {
41720813Sjkh      if (pipe (BGFiledes)) {
41820813Sjkh	perror("pipe");
41920813Sjkh	Cleanup(EX_SOCK);
42020813Sjkh      }
4216059Samurai    }
42225908Sbrian
42325908Sbrian    /* Create server socket and listen at there. */
42425908Sbrian    server = socket(PF_INET, SOCK_STREAM, 0);
42525908Sbrian    if (server < 0) {
42625908Sbrian      perror("socket");
42725908Sbrian      Cleanup(EX_SOCK);
4286059Samurai    }
42925908Sbrian    ifsin.sin_family = AF_INET;
43025908Sbrian    ifsin.sin_addr.s_addr = INADDR_ANY;
43125908Sbrian    ifsin.sin_port = htons(port);
43226032Sbrian    setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server);
43325908Sbrian    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
43425908Sbrian      perror("bind");
43525908Sbrian      if (errno == EADDRINUSE)
43625908Sbrian        fprintf(stderr, "Wait for a while, then try again.\n");
43725908Sbrian      Cleanup(EX_SOCK);
43825908Sbrian    }
43925908Sbrian    if (listen(server, 5) != 0) {
44025908Sbrian      fprintf(stderr, "Unable to listen to socket - OS overload?\n");
44125908Sbrian    }
4426059Samurai
4436059Samurai    DupLog();
4446059Samurai    if (!(mode & MODE_DIRECT)) {
44520813Sjkh      pid_t bgpid;
44611336Samurai
44720813Sjkh      bgpid = fork ();
44820813Sjkh      if (bgpid == -1) {
44920813Sjkh	perror ("fork");
45020813Sjkh	Cleanup (EX_SOCK);
45120813Sjkh      }
45220813Sjkh      if (bgpid) {
45320813Sjkh	char c = EX_NORMAL;
45411336Samurai
45520813Sjkh	if (mode & MODE_BACKGROUND) {
45620813Sjkh	  /* Wait for our child to close its pipe before we exit. */
45720813Sjkh	  BGPid = bgpid;
45823863Sbrian          close (BGFiledes[1]);
45925908Sbrian	  if (read(BGFiledes[0], &c, 1) != 1) {
46025908Sbrian	    printf("Child exit, no status.\n");
46123863Sbrian	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
46225908Sbrian	  } else if (c == EX_NORMAL) {
46325908Sbrian	    printf("PPP enabled.\n");
46423863Sbrian	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
46525908Sbrian	  } else {
46625910Sbrian	    printf("Child failed (%s).\n",ex_desc((int)c));
46725910Sbrian	    LogPrintf(LOG_PHASE_BIT, "Parent: Child failed (%s).\n",
46825910Sbrian                      ex_desc((int)c));
46925908Sbrian          }
47023863Sbrian          close (BGFiledes[0]);
47120813Sjkh	}
47220813Sjkh        exit(c);
47323863Sbrian      } else if (mode & MODE_BACKGROUND)
47423863Sbrian          close(BGFiledes[0]);
47525707Sbrian    }
47620813Sjkh
47725801Sbrian    snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid",
47825707Sbrian             _PATH_VARRUN, tunno);
47925707Sbrian    (void)unlink(pid_filename);
48011336Samurai
48125707Sbrian    if ((lockfile = fopen(pid_filename, "w")) != NULL) {
48225707Sbrian      fprintf(lockfile, "%d\n", (int)getpid());
48325707Sbrian      fclose(lockfile);
48425707Sbrian    } else
48525707Sbrian      logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno));
48625634Sbrian
48725707Sbrian    snprintf(if_filename, sizeof if_filename, "%s%s.if",
48825707Sbrian             _PATH_VARRUN, VarBaseDevice);
48925707Sbrian    (void)unlink(if_filename);
49025634Sbrian
49125707Sbrian    if ((lockfile = fopen(if_filename, "w")) != NULL) {
49225707Sbrian      fprintf(lockfile, "tun%d\n", tunno);
49325707Sbrian      fclose(lockfile);
49425707Sbrian    } else
49525707Sbrian      logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno));
49625707Sbrian
49723598Sache    if (server >= 0)
49820813Sjkh	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
4996059Samurai#ifdef DOTTYINIT
5006735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
5016059Samurai#else
5026059Samurai    if (mode & MODE_DIRECT) {
5036059Samurai#endif
5046059Samurai      TtyInit();
5056059Samurai    } else {
50614436Sache      int fd;
50714436Sache
5086059Samurai      setsid();			/* detach control tty */
50914436Sache      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
51014436Sache	(void)dup2(fd, STDIN_FILENO);
51114436Sache	(void)dup2(fd, STDOUT_FILENO);
51214436Sache	(void)dup2(fd, STDERR_FILENO);
51314436Sache	if (fd > 2)
51414436Sache		(void)close (fd);
51514436Sache      }
5166059Samurai    }
5176059Samurai  } else {
5186059Samurai    TtyInit();
51910528Samurai    TtyCommandMode(1);
5206059Samurai  }
52115738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
5226059Samurai
5236059Samurai
5246059Samurai  do
5256059Samurai   DoLoop();
5266059Samurai  while (mode & MODE_DEDICATED);
5276059Samurai
5286059Samurai  Cleanup(EX_DONE);
5296059Samurai}
5306059Samurai
5316059Samurai/*
53220813Sjkh *  Turn into packet mode, where we speak PPP.
5336059Samurai */
5346059Samuraivoid
5356059SamuraiPacketMode()
5366059Samurai{
5376059Samurai  if (RawModem(modem) < 0) {
5386059Samurai    fprintf(stderr, "Not connected.\r\n");
5396059Samurai    return;
5406059Samurai  }
5416059Samurai
5426059Samurai  AsyncInit();
5436059Samurai  VjInit();
5446059Samurai  LcpInit();
5456059Samurai  IpcpInit();
5466059Samurai  CcpInit();
5476059Samurai  LcpUp();
5486059Samurai
54925872Sbrian  LcpOpen(VarOpenMode);
5506059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
55110528Samurai    TtyCommandMode(1);
5526059Samurai    fprintf(stderr, "Packet mode.\r\n");
55318885Sjkh    aft_cmd = 1;
5546059Samurai  }
5556059Samurai}
5566059Samurai
5576059Samuraistatic void
5586059SamuraiShowHelp()
5596059Samurai{
56010528Samurai  fprintf(stderr, "The following commands are available:\r\n");
5616059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
56214418Sache  fprintf(stderr, " ~-\tDecrease log level\r\n");
56314418Sache  fprintf(stderr, " ~+\tIncrease log level\r\n");
5646059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
56514418Sache  fprintf(stderr, " ~?\tThis help\r\n");
5666059Samurai}
5676059Samurai
5686059Samuraistatic void
5696059SamuraiReadTty()
5706059Samurai{
5716059Samurai  int n;
5726059Samurai  char ch;
5736059Samurai  static int ttystate;
5746059Samurai#define MAXLINESIZE 200
5756059Samurai  char linebuff[MAXLINESIZE];
5766059Samurai
5776059Samurai#ifdef DEBUG
5786059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
5796059Samurai#endif
5806059Samurai  if (!TermMode) {
5816059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
58218885Sjkh    aft_cmd = 1;
5836735Samurai    if (n > 0) {
5846059Samurai      DecodeCommand(linebuff, n, 1);
5856735Samurai    } else {
58624753Sache      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
58724753Sache      VarLocalAuth = LOCAL_NO_AUTH;
5886059Samurai      close(netfd);
58924753Sache      close(1);
59024753Sache      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
5916059Samurai      netfd = -1;
5926059Samurai      mode &= ~MODE_INTER;
5936059Samurai    }
5946059Samurai    return;
5956059Samurai  }
5966059Samurai
5976059Samurai  /*
5986059Samurai   *  We are in terminal mode, decode special sequences
5996059Samurai   */
6006059Samurai  n = read(0, &ch, 1);
6016059Samurai#ifdef DEBUG
6026059Samurai  logprintf("got %d bytes\n", n);
6036059Samurai#endif
6046059Samurai
6056059Samurai  if (n > 0) {
6066059Samurai    switch (ttystate) {
6076059Samurai    case 0:
6086059Samurai      if (ch == '~')
6096059Samurai	ttystate++;
6106059Samurai      else
6116059Samurai	write(modem, &ch, n);
6126059Samurai      break;
6136059Samurai    case 1:
6146059Samurai      switch (ch) {
6156059Samurai      case '?':
6166059Samurai	ShowHelp();
6176059Samurai	break;
6186059Samurai      case '-':
6196059Samurai	if (loglevel > 0) {
6206059Samurai	  loglevel--;
6216059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
6226059Samurai	}
6236059Samurai	break;
6246059Samurai      case '+':
6256059Samurai	loglevel++;
6266059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
6276059Samurai	break;
6286059Samurai#ifdef DEBUG
6296059Samurai      case 'm':
6306059Samurai	ShowMemMap();
6316059Samurai	break;
6326059Samurai#endif
6336059Samurai      case 'p':
6346059Samurai	/*
6356059Samurai	 * XXX: Should check carrier.
6366059Samurai	 */
6376059Samurai	if (LcpFsm.state <= ST_CLOSED) {
6386059Samurai	  VarOpenMode = OPEN_ACTIVE;
6396059Samurai	  PacketMode();
6406059Samurai	}
6416059Samurai	break;
6426059Samurai#ifdef DEBUG
6436059Samurai      case 't':
6446059Samurai	ShowTimers();
6456059Samurai	break;
6466059Samurai#endif
6476059Samurai      case '.':
6486059Samurai	TermMode = 1;
64910528Samurai	TtyCommandMode(1);
6506059Samurai	break;
6516059Samurai      default:
6526059Samurai	if (write(modem, &ch, n) < 0)
6536059Samurai	  fprintf(stderr, "err in write.\r\n");
6546059Samurai	break;
6556059Samurai      }
6566059Samurai      ttystate = 0;
6576059Samurai      break;
6586059Samurai    }
6596059Samurai  }
6606059Samurai}
6616059Samurai
6626059Samurai
6636059Samurai/*
6646059Samurai *  Here, we'll try to detect HDLC frame
6656059Samurai */
6666059Samurai
6676059Samuraistatic char *FrameHeaders[] = {
6686735Samurai  "\176\377\003\300\041",
6696735Samurai  "\176\377\175\043\300\041",
6706735Samurai  "\176\177\175\043\100\041",
6716735Samurai  "\176\175\337\175\043\300\041",
6726735Samurai  "\176\175\137\175\043\100\041",
6736059Samurai  NULL,
6746059Samurai};
6756059Samurai
6766059Samuraiu_char *
6776059SamuraiHdlcDetect(cp, n)
6786059Samuraiu_char *cp;
6796059Samuraiint n;
6806059Samurai{
6816735Samurai  char *ptr, *fp, **hp;
6826059Samurai
6836059Samurai  cp[n] = '\0';	/* be sure to null terminated */
6846059Samurai  ptr = NULL;
6856059Samurai  for (hp = FrameHeaders; *hp; hp++) {
6866735Samurai    fp = *hp;
6876735Samurai    if (DEV_IS_SYNC)
6886735Samurai      fp++;
68913389Sphk    ptr = strstr((char *)cp, fp);
69013389Sphk    if (ptr)
6916059Samurai      break;
6926059Samurai  }
6936059Samurai  return((u_char *)ptr);
6946059Samurai}
6956059Samurai
6966059Samuraistatic struct pppTimer RedialTimer;
6976059Samurai
6986059Samuraistatic void
6996059SamuraiRedialTimeout()
7006059Samurai{
7016059Samurai  StopTimer(&RedialTimer);
70215738Sphk  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
7036059Samurai}
7046059Samurai
7056059Samuraistatic void
70624939SbrianStartRedialTimer(Timeout)
70724939Sbrian	int Timeout;
7086059Samurai{
7096059Samurai  StopTimer(&RedialTimer);
71011336Samurai
71124939Sbrian  if (Timeout) {
71211336Samurai    RedialTimer.state = TIMER_STOPPED;
71311336Samurai
71424939Sbrian    if (Timeout > 0)
71524939Sbrian	RedialTimer.load = Timeout * SECTICKS;
71611336Samurai    else
71711336Samurai	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
71811336Samurai
71924939Sbrian    LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n",
72024939Sbrian	      RedialTimer.load / SECTICKS);
72124939Sbrian
72211336Samurai    RedialTimer.func = RedialTimeout;
72311336Samurai    StartTimer(&RedialTimer);
72411336Samurai  }
7256059Samurai}
7266059Samurai
7276059Samurai
7286059Samuraistatic void
7296059SamuraiDoLoop()
7306059Samurai{
7316059Samurai  fd_set rfds, wfds, efds;
73223598Sache  int pri, i, n, wfd, nfds;
7336059Samurai  struct sockaddr_in hisaddr;
7346059Samurai  struct timeval timeout, *tp;
7356059Samurai  int ssize = sizeof(hisaddr);
7366059Samurai  u_char *cp;
7376059Samurai  u_char rbuff[MAX_MRU];
7387001Samurai  int dial_up;
73911336Samurai  int tries;
7409448Samurai  int qlen;
74110528Samurai  pid_t pgroup;
7426059Samurai
74310528Samurai  pgroup = getpgrp();
74410528Samurai
74525908Sbrian  if (mode & MODE_DIRECT) {
7466059Samurai    modem = OpenModem(mode);
74715738Sphk    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
74818885Sjkh    fflush(stderr);
7496059Samurai    PacketMode();
7506059Samurai  } else if (mode & MODE_DEDICATED) {
75123598Sache    if (modem < 0)
7526059Samurai      modem = OpenModem(mode);
7536059Samurai  }
7546059Samurai
7556059Samurai  fflush(stdout);
7566059Samurai
7577001Samurai  timeout.tv_sec = 0;
7586059Samurai  timeout.tv_usec = 0;
75925908Sbrian  reconnectRequired = 0;
7606059Samurai
76123863Sbrian  if (mode & MODE_BACKGROUND)
76223863Sbrian    dial_up = TRUE;			/* Bring the line up */
76323863Sbrian  else
76423863Sbrian    dial_up = FALSE;			/* XXXX */
76511336Samurai  tries = 0;
7666059Samurai  for (;;) {
76723598Sache    nfds = 0;
7686059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
7697001Samurai
77020120Snate    /*
77120120Snate     * If the link is down and we're in DDIAL mode, bring it back
77220120Snate     * up.
77320120Snate     */
77420120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
77520120Snate        dial_up = TRUE;
77620120Snate
77725067Sbrian    /*
77825067Sbrian     * If we lost carrier and want to re-establish the connection
77925067Sbrian     * due to the "set reconnect" value, we'd better bring the line
78025908Sbrian     * back up.
78125067Sbrian     */
78225908Sbrian    if (LcpFsm.state <= ST_CLOSED) {
78325908Sbrian      if (dial_up != TRUE && reconnectRequired) {
78425908Sbrian        if (++reconnectCount <= VarReconnectTries) {
78525908Sbrian          LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n",
78625908Sbrian                    reconnectCount, VarReconnectTries);
78725908Sbrian	  StartRedialTimer(VarReconnectTimer);
78825908Sbrian          dial_up = TRUE;
78925908Sbrian        } else {
79025908Sbrian          if (VarReconnectTries)
79125908Sbrian            LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n",
79225908Sbrian                      VarReconnectTries);
79325908Sbrian          reconnectCount = 0;
79425908Sbrian          if (mode & MODE_BACKGROUND)
79525908Sbrian            Cleanup(EX_DEAD);
79625908Sbrian        }
79725801Sbrian      }
79825908Sbrian      reconnectRequired = 0;
79925908Sbrian    }
80025067Sbrian
8017001Samurai   /*
80225067Sbrian    * If Ip packet for output is enqueued and require dial up,
8037001Samurai    * Just do it!
8047001Samurai    */
80525067Sbrian    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
8067001Samurai#ifdef DEBUG
8077001Samurai      logprintf("going to dial: modem = %d\n", modem);
8087001Samurai#endif
80911336Samurai      modem = OpenModem(mode);
81011336Samurai      if (modem < 0) {
81124939Sbrian	StartRedialTimer(VarRedialTimeout);
81211336Samurai      } else {
81324843Sbrian	tries++;    /* Tries are per number, not per list of numbers. */
81424843Sbrian        if (VarDialTries)
81524843Sbrian	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
81624843Sbrian		    VarDialTries);
81724843Sbrian        else
81824843Sbrian	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
81911336Samurai	if (DialModem()) {
82011336Samurai	  sleep(1);	       /* little pause to allow peer starts */
82111336Samurai	  ModemTimeout();
82211336Samurai	  PacketMode();
82311336Samurai	  dial_up = FALSE;
82411336Samurai	  tries = 0;
82511336Samurai	} else {
82611336Samurai	  CloseModem();
82724844Sbrian	  if (mode & MODE_BACKGROUND) {
82824844Sbrian	    if (VarNextPhone == NULL)
82924844Sbrian	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
83024844Sbrian	    else
83124939Sbrian	      /* Try all numbers in background mode */
83224939Sbrian	      StartRedialTimer(VarRedialNextTimeout);
83324844Sbrian	  } else if (VarDialTries && tries >= VarDialTries) {
83424843Sbrian	    /* I give up !  Can't get through :( */
83524939Sbrian	    StartRedialTimer(VarRedialTimeout);
83624843Sbrian	    dial_up = FALSE;
83724843Sbrian	    tries = 0;
83824843Sbrian	  } else if (VarNextPhone == NULL)
83924843Sbrian	    /* Dial failed. Keep quite during redial wait period. */
84024939Sbrian	    StartRedialTimer(VarRedialTimeout);
84124843Sbrian	  else
84224939Sbrian	    StartRedialTimer(VarRedialNextTimeout);
84311336Samurai	}
84411336Samurai      }
8457001Samurai    }
8469448Samurai    qlen = ModemQlen();
84713733Sdfr
84813733Sdfr    if (qlen == 0) {
84913733Sdfr      IpStartOutput();
85013733Sdfr      qlen = ModemQlen();
85113733Sdfr    }
85213733Sdfr
85323598Sache    if (modem >= 0) {
85423598Sache      if (modem + 1 > nfds)
85523598Sache	nfds = modem + 1;
8567001Samurai      FD_SET(modem, &rfds);
8577001Samurai      FD_SET(modem, &efds);
8589448Samurai      if (qlen > 0) {
8597001Samurai	FD_SET(modem, &wfds);
8607001Samurai      }
8617001Samurai    }
86223598Sache    if (server >= 0) {
86323598Sache      if (server + 1 > nfds)
86423598Sache	nfds = server + 1;
86523598Sache      FD_SET(server, &rfds);
86623598Sache    }
8676059Samurai
8686059Samurai    /*  *** IMPORTANT ***
8696059Samurai     *
8706059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
8716059Samurai     *	This value must be chosen with great care. If this values is
8726059Samurai     *  too big, it results loss of characters from modem and poor responce.
8736059Samurai     *  If this values is too small, ppp process eats many CPU time.
8746059Samurai     */
8756735Samurai#ifndef SIGALRM
8766059Samurai    usleep(TICKUNIT);
8776059Samurai    TimerService();
87823840Sbrian#else
87923840Sbrian    handle_signals();
8806735Samurai#endif
88110877Sbde
88210877Sbde    /* If there are aren't many packets queued, look for some more. */
88323598Sache    if (qlen < 20 && tun_in >= 0) {
88423598Sache      if (tun_in + 1 > nfds)
88523598Sache	nfds = tun_in + 1;
88610877Sbde      FD_SET(tun_in, &rfds);
88723598Sache    }
88810877Sbde
88923598Sache    if (netfd >= 0) {
89023598Sache      if (netfd + 1 > nfds)
89123598Sache	nfds = netfd + 1;
8926059Samurai      FD_SET(netfd, &rfds);
8936059Samurai      FD_SET(netfd, &efds);
8946059Samurai    }
8957001Samurai
8966735Samurai#ifndef SIGALRM
8976059Samurai    /*
8987001Samurai     *  Normally, select() will not block because modem is writable.
8997001Samurai     *  In AUTO mode, select will block until we find packet from tun
9006059Samurai     */
9016059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
90223598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9036735Samurai#else
9048857Srgrimes    /*
9057001Samurai     * When SIGALRM timer is running, a select function will be
9068857Srgrimes     * return -1 and EINTR after a Time Service signal hundler
90711336Samurai     * is done.  If the redial timer is not running and we are
90811336Samurai     * trying to dial, poll with a 0 value timer.
9097001Samurai     */
91011336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
91123598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9126735Samurai#endif
91322074Sbrian
9147001Samurai    if ( i == 0 ) {
9157001Samurai        continue;
9166059Samurai    }
9176735Samurai
9187001Samurai    if ( i < 0 ) {
9197001Samurai       if ( errno == EINTR ) {
92023840Sbrian          handle_signals();
92123840Sbrian          continue;
9227001Samurai       }
9237001Samurai       perror("select");
9247001Samurai       break;
9258857Srgrimes    }
9267001Samurai
92723598Sache    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
9286059Samurai      logprintf("Exception detected.\n");
9296059Samurai      break;
9306059Samurai    }
9316059Samurai
93223598Sache    if (server >= 0 && FD_ISSET(server, &rfds)) {
93324753Sache      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
9346059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
93524753Sache      if (wfd < 0) {
93624753Sache	perror("accept");
93724753Sache	continue;
93824753Sache      }
93923598Sache      if (netfd >= 0) {
9406059Samurai	write(wfd, "already in use.\n", 16);
9416059Samurai	close(wfd);
9426059Samurai	continue;
9436059Samurai      } else
9446059Samurai	netfd = wfd;
94524753Sache      if (dup2(netfd, 1) < 0) {
9466059Samurai	perror("dup2");
94724753Sache	close(netfd);
94824753Sache	netfd = -1;
94924753Sache	continue;
95024753Sache      }
9516059Samurai      mode |= MODE_INTER;
9526059Samurai      Greetings();
9536764Samurai      switch ( LocalAuthInit() ) {
9546764Samurai         case NOT_FOUND:
9556764Samurai    	    fprintf(stdout,LAUTH_M1);
9566764Samurai    	    fprintf(stdout,LAUTH_M2);
9576764Samurai            fflush(stdout);
9586764Samurai	    /* Fall down */
9596764Samurai         case VALID:
9606764Samurai	    VarLocalAuth = LOCAL_AUTH;
9616764Samurai	    break;
9626764Samurai         default:
9636764Samurai	    break;
9646764Samurai      }
9656059Samurai      (void) IsInteractive();
96625630Sbrian      Prompt();
9676059Samurai    }
9686059Samurai
96923598Sache    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
97010858Samurai	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
9716059Samurai      /* something to read from tty */
9726059Samurai      ReadTty();
9736059Samurai    }
97423598Sache    if (modem >= 0) {
9756059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
9766059Samurai	 ModemStartOutput(modem);
9776059Samurai      }
9786059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
9796735Samurai	if (LcpFsm.state <= ST_CLOSED)
9806735Samurai	  usleep(10000);
9816059Samurai	n = read(modem, rbuff, sizeof(rbuff));
9826059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
9836059Samurai	  DownConnection();
9846059Samurai	} else
9856059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
9866059Samurai
9876059Samurai	if (LcpFsm.state <= ST_CLOSED) {
9886059Samurai	  /*
9896059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
9906059Samurai	   */
9916059Samurai	  if (!(mode & MODE_DEDICATED)) {
9926059Samurai	    cp = HdlcDetect(rbuff, n);
9936059Samurai	    if (cp) {
9946059Samurai	      /*
9956059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
9966059Samurai	       */
9976059Samurai	      if (cp != rbuff) {
9986059Samurai	        write(1, rbuff, cp - rbuff);
9996059Samurai	        write(1, "\r\n", 2);
10006059Samurai	      }
10016059Samurai	      PacketMode();
10026059Samurai	    } else
10036059Samurai	      write(1, rbuff, n);
10046059Samurai	  }
10056059Samurai	} else {
10066059Samurai	  if (n > 0)
10076059Samurai	    AsyncInput(rbuff, n);
10086059Samurai	}
10096059Samurai      }
10106059Samurai    }
10117001Samurai
101223598Sache    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
10136059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
10146059Samurai      if (n < 0) {
10156059Samurai	perror("read from tun");
10166059Samurai	continue;
10176059Samurai      }
10186059Samurai      /*
10196059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
10206059Samurai       *  device until IPCP is opened.
10216059Samurai       */
10226059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
10237001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
10246059Samurai	if (pri >= 0) {
102520365Sjkh	  if (mode & MODE_ALIAS) {
102626031Sbrian	    PacketAliasOut(rbuff, sizeof rbuff);
102720666Snate	    n = ntohs(((struct ip *)rbuff)->ip_len);
102820365Sjkh	  }
10296059Samurai	  IpEnqueue(pri, rbuff, n);
103020365Sjkh	  dial_up = TRUE;		/* XXX */
10316059Samurai	}
10326059Samurai	continue;
10336059Samurai      }
10347001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
103520365Sjkh      if (pri >= 0) {
103620365Sjkh        if (mode & MODE_ALIAS) {
103726031Sbrian          PacketAliasOut(rbuff, sizeof rbuff);
103820666Snate          n = ntohs(((struct ip *)rbuff)->ip_len);
103920365Sjkh        }
10406059Samurai	IpEnqueue(pri, rbuff, n);
104120365Sjkh      }
10426059Samurai    }
10436059Samurai  }
10446059Samurai  logprintf("job done.\n");
10456059Samurai}
1046