main.c revision 20813
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 *
2020813Sjkh * $Id: main.c,v 1.25 1996/12/19 00:41:42 nate 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>
316059Samurai#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>
406059Samurai#include "modem.h"
416059Samurai#include "os.h"
426059Samurai#include "hdlc.h"
4313389Sphk#include "ccp.h"
446059Samurai#include "lcp.h"
456059Samurai#include "ipcp.h"
466059Samurai#include "vars.h"
476735Samurai#include "auth.h"
487001Samurai#include "filter.h"
4913389Sphk#include "systems.h"
5013389Sphk#include "ip.h"
5120365Sjkh#include "alias.h"
526059Samurai
536764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
549410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
556764Samurai
566735Samurai#ifndef O_NONBLOCK
576735Samurai#ifdef O_NDELAY
586735Samurai#define	O_NONBLOCK O_NDELAY
596735Samurai#endif
606735Samurai#endif
616735Samurai
626059Samuraiextern void VjInit(), AsyncInit();
636059Samuraiextern void AsyncInput(), IpOutput();
646059Samuraiextern int  SelectSystem();
656059Samurai
666059Samuraiextern void DecodeCommand(), Prompt();
6718885Sjkhextern int aft_cmd;
686059Samuraiextern int IsInteractive();
696059Samuraiextern struct in_addr ifnetmask;
706059Samuraistatic void DoLoop(void);
7110528Samuraistatic void TerminalStop();
726059Samurai
736059Samuraistatic struct termios oldtio;		/* Original tty mode */
746059Samuraistatic struct termios comtio;		/* Command level tty mode */
7514418Sacheint TermMode;
7613379Sphkstatic int server;
7720813Sjkhstatic pid_t BGPid = 0;
786059Samuraistruct sockaddr_in ifsin;
7911336Samuraichar pid_filename[128];
806059Samurai
816059Samuraistatic void
826059SamuraiTtyInit()
836059Samurai{
846059Samurai  struct termios newtio;
856059Samurai  int stat;
866059Samurai
876059Samurai  stat = fcntl(0, F_GETFL, 0);
886059Samurai  stat |= O_NONBLOCK;
896059Samurai  fcntl(0, F_SETFL, stat);
906059Samurai  newtio = oldtio;
916059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
926059Samurai  newtio.c_iflag = 0;
936059Samurai  newtio.c_oflag &= ~OPOST;
946059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
956059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
966059Samurai  newtio.c_cc[VMIN] = 1;
976059Samurai  newtio.c_cc[VTIME] = 0;
986059Samurai  newtio.c_cflag |= CS8;
996735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1006059Samurai  comtio = newtio;
1016059Samurai}
1026059Samurai
1036059Samurai/*
1046059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1056059Samurai */
10610528Samuraivoid
10710528SamuraiTtyCommandMode(prompt)
10810528Samuraiint prompt;
1096059Samurai{
1106059Samurai  struct termios newtio;
1116059Samurai  int stat;
1126059Samurai
1136059Samurai  if (!(mode & MODE_INTER))
1146059Samurai    return;
1156735Samurai  tcgetattr(0, &newtio);
11610528Samurai  newtio.c_lflag |= (ECHO|ISIG|ICANON);
1176059Samurai  newtio.c_iflag = oldtio.c_iflag;
1186059Samurai  newtio.c_oflag |= OPOST;
1196735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1206059Samurai  stat = fcntl(0, F_GETFL, 0);
1216059Samurai  stat |= O_NONBLOCK;
1226059Samurai  fcntl(0, F_SETFL, stat);
1236059Samurai  TermMode = 0;
12410528Samurai  if(prompt) Prompt(0);
1256059Samurai}
1266059Samurai
1276059Samurai/*
1286059Samurai * Set tty into terminal mode which is used while we invoke term command.
1296059Samurai */
1306059Samuraivoid
1316059SamuraiTtyTermMode()
1326059Samurai{
1336059Samurai  int stat;
1346059Samurai
1356735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1366059Samurai  stat = fcntl(0, F_GETFL, 0);
1376059Samurai  stat &= ~O_NONBLOCK;
1386059Samurai  fcntl(0, F_SETFL, stat);
1396059Samurai  TermMode = 1;
1406059Samurai}
1416059Samurai
1426059Samuraivoid
14310528SamuraiTtyOldMode()
1446059Samurai{
1456059Samurai  int stat;
1466059Samurai
1476059Samurai  stat = fcntl(0, F_GETFL, 0);
1486059Samurai  stat &= ~O_NONBLOCK;
1496059Samurai  fcntl(0, F_SETFL, stat);
1506735Samurai  tcsetattr(0, TCSANOW, &oldtio);
15110528Samurai}
15210528Samurai
15310528Samuraivoid
15410528SamuraiCleanup(excode)
15510528Samuraiint excode;
15610528Samurai{
15710528Samurai
15810528Samurai  OsLinkdown();
1596059Samurai  OsCloseLink(1);
1606059Samurai  sleep(1);
16111336Samurai  if (mode & MODE_AUTO) {
1626059Samurai    DeleteIfRoutes(1);
16320813Sjkh  }
16420813Sjkh  if (mode & (MODE_AUTO | MODE_BACKGROUND)) {
16511336Samurai    unlink(pid_filename);
16611336Samurai  }
1676059Samurai  OsInterfaceDown(1);
16815738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n");
1696059Samurai  LogClose();
1706059Samurai  if (server > 0)
1716059Samurai    close(server);
17210528Samurai  TtyOldMode();
1736059Samurai
1746059Samurai  exit(excode);
1756059Samurai}
1766059Samurai
1776059Samuraistatic void
17814930SacheHangup(signo)
17914930Sacheint signo;
1806059Samurai{
18117044Sache  if (signo == SIGSEGV) {
18217044Sache	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
18317044Sache	LogClose();
18417044Sache	abort();
18517044Sache  }
18620813Sjkh  if (BGPid) {
18720813Sjkh      kill (BGPid, SIGHUP);
18820813Sjkh      exit (EX_HANGUP);
18920813Sjkh  }
19020813Sjkh  else {
19120813Sjkh      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
19220813Sjkh      Cleanup(EX_HANGUP);
19320813Sjkh  }
1946059Samurai}
1956059Samurai
1966059Samuraistatic void
19714930SacheCloseSession(signo)
19814930Sacheint signo;
1996059Samurai{
20020813Sjkh   if (BGPid) {
20120813Sjkh     kill (BGPid, SIGINT);
20220813Sjkh     exit (EX_TERM);
20320813Sjkh   }
20420813Sjkh   else {
20520813Sjkh     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
20620813Sjkh     LcpClose();
20720813Sjkh     Cleanup(EX_TERM);
20820813Sjkh   }
2096059Samurai}
2106059Samurai
21110528Samuraistatic void
21210528SamuraiTerminalCont()
21310528Samurai{
21410528Samurai  (void)signal(SIGCONT, SIG_DFL);
21510528Samurai  (void)signal(SIGTSTP, TerminalStop);
21610528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
21710528Samurai}
21810528Samurai
21910528Samuraistatic void
22010528SamuraiTerminalStop(signo)
22110528Samuraiint signo;
22210528Samurai{
22310528Samurai  (void)signal(SIGCONT, TerminalCont);
22410528Samurai  TtyOldMode();
22510528Samurai  signal(SIGTSTP, SIG_DFL);
22610528Samurai  kill(getpid(), signo);
22710528Samurai}
22810528Samurai
22910528Samurai
2306059Samuraivoid
2316059SamuraiUsage()
2326059Samurai{
23320120Snate  fprintf(stderr,
23420813Sjkh          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
2356059Samurai  exit(EX_START);
2366059Samurai}
2376059Samurai
2386059Samuraivoid
2396059SamuraiProcessArgs(int argc, char **argv)
2406059Samurai{
2416059Samurai  int optc;
2426059Samurai  char *cp;
2436059Samurai
2446059Samurai  optc = 0;
2456059Samurai  while (argc > 0 && **argv == '-') {
2466059Samurai    cp = *argv + 1;
2476059Samurai    if (strcmp(cp, "auto") == 0)
2486059Samurai      mode |= MODE_AUTO;
24920813Sjkh    else if (strcmp(cp, "background") == 0)
25020813Sjkh      mode |= MODE_BACKGROUND;
2516059Samurai    else if (strcmp(cp, "direct") == 0)
2526059Samurai      mode |= MODE_DIRECT;
2536059Samurai    else if (strcmp(cp, "dedicated") == 0)
2546059Samurai      mode |= MODE_DEDICATED;
25520120Snate    else if (strcmp(cp, "ddial") == 0)
25620120Snate      mode |= MODE_DDIAL|MODE_AUTO;
25720365Sjkh    else if (strcmp(cp, "alias") == 0) {
25820365Sjkh      mode |= MODE_ALIAS;
25920365Sjkh      optc--;             /* this option isn't exclusive */
26020365Sjkh    }
2616059Samurai    else
2626059Samurai      Usage();
2636059Samurai    optc++;
2646059Samurai    argv++; argc--;
2656059Samurai  }
2666059Samurai  if (argc > 1) {
2676059Samurai    fprintf(stderr, "specify only one system label.\n");
2686059Samurai    exit(EX_START);
2696059Samurai  }
2706059Samurai  if (argc == 1) dstsystem = *argv;
2716059Samurai
2726059Samurai  if (optc > 1) {
2736059Samurai    fprintf(stderr, "specify only one mode.\n");
2746059Samurai    exit(EX_START);
2756059Samurai  }
2766059Samurai}
2776059Samurai
2786059Samuraistatic void
2796059SamuraiGreetings()
2806059Samurai{
2816059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2826059Samurai  fflush(stdout);
2836059Samurai}
2846059Samurai
2856059Samuraivoid
2866059Samuraimain(argc, argv)
2876059Samuraiint argc;
2886059Samuraichar **argv;
2896059Samurai{
2906059Samurai  int tunno;
2916059Samurai
2926059Samurai  argc--; argv++;
2936059Samurai
2946059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2956059Samurai  netfd = -1;
2966059Samurai  ProcessArgs(argc, argv);
2976059Samurai  Greetings();
2986059Samurai  GetUid();
2996059Samurai  IpcpDefAddress();
30020365Sjkh  InitAlias();
3016059Samurai
3026059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
3036059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
3046059Samurai  }
3056059Samurai
3066059Samurai  if (LogOpen())
3076059Samurai    exit(EX_START);
3086059Samurai
3096735Samurai  switch ( LocalAuthInit() ) {
3106735Samurai    case NOT_FOUND:
3116764Samurai    	fprintf(stderr,LAUTH_M1);
3126764Samurai    	fprintf(stderr,LAUTH_M2);
3136764Samurai	fflush (stderr);
3146764Samurai	/* Fall down */
3156764Samurai    case VALID:
3166735Samurai	VarLocalAuth = LOCAL_AUTH;
3176735Samurai	break;
3186735Samurai    default:
3196735Samurai	break;
3206735Samurai  }
3216735Samurai
3226059Samurai  if (OpenTunnel(&tunno) < 0) {
3236059Samurai    perror("open_tun");
3246059Samurai    exit(EX_START);
3256059Samurai  }
3266059Samurai
32720813Sjkh  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND))
3286059Samurai    mode &= ~MODE_INTER;
3296059Samurai  if (mode & MODE_INTER) {
3306059Samurai    printf("Interactive mode\n");
3316059Samurai    netfd = 0;
3326059Samurai  } else if (mode & MODE_AUTO) {
33320120Snate    printf("Automatic Dialer mode\n");
3346059Samurai    if (dstsystem == NULL) {
33520120Snate      fprintf(stderr,
33620120Snate              "Destination system must be specified in auto or ddial mode.\n");
3376059Samurai      exit(EX_START);
3386059Samurai    }
33920813Sjkh  } else if (mode & MODE_BACKGROUND) {
34020813Sjkh    printf("Background mode\n");
34120813Sjkh    if (dstsystem == NULL) {
34220813Sjkh      fprintf(stderr, "Destination system must be specified in background mode.\n");
34320813Sjkh      exit(EX_START);
34420813Sjkh    }
3456059Samurai  }
3466059Samurai
3476735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
3486059Samurai
3496059Samurai  signal(SIGHUP, Hangup);
3506059Samurai  signal(SIGTERM, CloseSession);
3516059Samurai  signal(SIGINT, CloseSession);
35210528Samurai  signal(SIGQUIT, CloseSession);
3536735Samurai#ifdef SIGSEGV
3546059Samurai  signal(SIGSEGV, Hangup);
3556735Samurai#endif
3566735Samurai#ifdef SIGPIPE
3576735Samurai  signal(SIGPIPE, Hangup);
3586735Samurai#endif
3596735Samurai#ifdef SIGALRM
3606735Samurai  signal(SIGALRM, SIG_IGN);
3616735Samurai#endif
36210528Samurai  if(mode & MODE_INTER)
36310528Samurai    {
36410528Samurai#ifdef SIGTSTP
36510528Samurai      signal(SIGTSTP, TerminalStop);
36610528Samurai#endif
36710528Samurai#ifdef SIGTTIN
36810528Samurai      signal(SIGTTIN, TerminalStop);
36910528Samurai#endif
37010528Samurai#ifdef SIGTTOU
37110528Samurai      signal(SIGTTOU, SIG_IGN);
37210528Samurai#endif
37310528Samurai    }
3746059Samurai
3756059Samurai  if (dstsystem) {
3766059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
3776059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
3786059Samurai      Cleanup(EX_START);
3796059Samurai    }
3806059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
38120120Snate      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
3826059Samurai      Cleanup(EX_START);
3836059Samurai    }
3846059Samurai  }
3856059Samurai  if (mode & MODE_DIRECT)
3866059Samurai    printf("Packet mode enabled.\n");
3876059Samurai
3886059Samurai#ifdef notdef
3896059Samurai  if (mode & MODE_AUTO) {
3906059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3916059Samurai  }
3926059Samurai#endif
3936059Samurai
3946059Samurai  if (!(mode & MODE_INTER)) {
39520813Sjkh    int port = SERVER_PORT + tunno;
39620813Sjkh    if (mode & MODE_BACKGROUND) {
39720813Sjkh      if (pipe (BGFiledes)) {
39820813Sjkh	perror("pipe");
39920813Sjkh	Cleanup(EX_SOCK);
40020813Sjkh      }
40120813Sjkh      server = -1;
4026059Samurai    }
40320813Sjkh    else {
40420813Sjkh      /*
40520813Sjkh       *  Create server socket and listen at there.
40620813Sjkh       */
40720813Sjkh      server = socket(PF_INET, SOCK_STREAM, 0);
40820813Sjkh      if (server < 0) {
40920813Sjkh	perror("socket");
41020813Sjkh	Cleanup(EX_SOCK);
41120813Sjkh      }
41220813Sjkh      ifsin.sin_family = AF_INET;
41320813Sjkh      ifsin.sin_addr.s_addr = INADDR_ANY;
41420813Sjkh      ifsin.sin_port = htons(port);
41520813Sjkh      if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
41620813Sjkh	perror("bind");
41720813Sjkh	if (errno == EADDRINUSE)
41820813Sjkh	  fprintf(stderr, "Wait for a while, then try again.\n");
41920813Sjkh	Cleanup(EX_SOCK);
42020813Sjkh      }
42120813Sjkh      listen(server, 5);
4226059Samurai    }
4236059Samurai
4246059Samurai    DupLog();
4256059Samurai    if (!(mode & MODE_DIRECT)) {
42611336Samurai      int fd;
42711336Samurai      char pid[32];
42820813Sjkh      pid_t bgpid;
42911336Samurai
43020813Sjkh      bgpid = fork ();
43120813Sjkh      if (bgpid == -1) {
43220813Sjkh	perror ("fork");
43320813Sjkh	Cleanup (EX_SOCK);
43420813Sjkh      }
43520813Sjkh      if (bgpid) {
43620813Sjkh	char c = EX_NORMAL;
43711336Samurai
43820813Sjkh	if (mode & MODE_BACKGROUND) {
43920813Sjkh	  /* Wait for our child to close its pipe before we exit. */
44020813Sjkh	  BGPid = bgpid;
44120813Sjkh	  read (BGFiledes[0], &c, 1);
44220813Sjkh	  if (c == EX_NORMAL)
44320813Sjkh	    LogPrintf (LOG_CHAT, "PPP enabled.\n");
44420813Sjkh	}
44520813Sjkh        exit(c);
44620813Sjkh      }
44720813Sjkh
44820813Sjkh      snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid",
44920813Sjkh		  _PATH_VARRUN, tunno);
45011336Samurai      unlink(pid_filename);
45120120Snate      sprintf(pid, "%d\n", (int)getpid());
45211336Samurai
45311336Samurai      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
45411336Samurai      {
45511336Samurai	  write(fd, pid, strlen(pid));
45611336Samurai	  close(fd);
45711336Samurai      }
4586059Samurai    }
45920813Sjkh    if (server > 0)
46020813Sjkh	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
4616059Samurai#ifdef DOTTYINIT
4626735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
4636059Samurai#else
4646059Samurai    if (mode & MODE_DIRECT) {
4656059Samurai#endif
4666059Samurai      TtyInit();
4676059Samurai    } else {
46814436Sache      int fd;
46914436Sache
4706059Samurai      setsid();			/* detach control tty */
47114436Sache      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
47214436Sache	(void)dup2(fd, STDIN_FILENO);
47314436Sache	(void)dup2(fd, STDOUT_FILENO);
47414436Sache	(void)dup2(fd, STDERR_FILENO);
47514436Sache	if (fd > 2)
47614436Sache		(void)close (fd);
47714436Sache      }
4786059Samurai    }
4796059Samurai  } else {
4806059Samurai    server = -1;
4816059Samurai    TtyInit();
48210528Samurai    TtyCommandMode(1);
4836059Samurai  }
48415738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
4856059Samurai
4866059Samurai
4876059Samurai  do
4886059Samurai   DoLoop();
4896059Samurai  while (mode & MODE_DEDICATED);
4906059Samurai
4916059Samurai  Cleanup(EX_DONE);
4926059Samurai}
4936059Samurai
4946059Samurai/*
49520813Sjkh *  Turn into packet mode, where we speak PPP.
4966059Samurai */
4976059Samuraivoid
4986059SamuraiPacketMode()
4996059Samurai{
5006059Samurai  if (RawModem(modem) < 0) {
5016059Samurai    fprintf(stderr, "Not connected.\r\n");
5026059Samurai    return;
5036059Samurai  }
5046059Samurai
5056059Samurai  AsyncInit();
5066059Samurai  VjInit();
5076059Samurai  LcpInit();
5086059Samurai  IpcpInit();
5096059Samurai  CcpInit();
5106059Samurai  LcpUp();
5116059Samurai
5126059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
5136059Samurai    LcpOpen(OPEN_ACTIVE);
5146059Samurai  else
5156059Samurai    LcpOpen(VarOpenMode);
5166059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
51710528Samurai    TtyCommandMode(1);
5186059Samurai    fprintf(stderr, "Packet mode.\r\n");
51918885Sjkh    aft_cmd = 1;
5206059Samurai  }
5216059Samurai}
5226059Samurai
5236059Samuraistatic void
5246059SamuraiShowHelp()
5256059Samurai{
52610528Samurai  fprintf(stderr, "The following commands are available:\r\n");
5276059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
52814418Sache  fprintf(stderr, " ~-\tDecrease log level\r\n");
52914418Sache  fprintf(stderr, " ~+\tIncrease log level\r\n");
5306059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
53114418Sache  fprintf(stderr, " ~?\tThis help\r\n");
5326059Samurai}
5336059Samurai
5346059Samuraistatic void
5356059SamuraiReadTty()
5366059Samurai{
5376059Samurai  int n;
5386059Samurai  char ch;
5396059Samurai  static int ttystate;
5406059Samurai#define MAXLINESIZE 200
5416059Samurai  char linebuff[MAXLINESIZE];
5426059Samurai
5436059Samurai#ifdef DEBUG
5446059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
5456059Samurai#endif
5466059Samurai  if (!TermMode) {
5476059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
54818885Sjkh    aft_cmd = 1;
5496735Samurai    if (n > 0) {
5506059Samurai      DecodeCommand(linebuff, n, 1);
5516735Samurai    } else {
5526059Samurai#ifdef DEBUG
5536059Samurai      logprintf("connection closed.\n");
5546059Samurai#endif
5556059Samurai      close(netfd);
5566059Samurai      netfd = -1;
5576059Samurai      mode &= ~MODE_INTER;
5586059Samurai    }
5596059Samurai    return;
5606059Samurai  }
5616059Samurai
5626059Samurai  /*
5636059Samurai   *  We are in terminal mode, decode special sequences
5646059Samurai   */
5656059Samurai  n = read(0, &ch, 1);
5666059Samurai#ifdef DEBUG
5676059Samurai  logprintf("got %d bytes\n", n);
5686059Samurai#endif
5696059Samurai
5706059Samurai  if (n > 0) {
5716059Samurai    switch (ttystate) {
5726059Samurai    case 0:
5736059Samurai      if (ch == '~')
5746059Samurai	ttystate++;
5756059Samurai      else
5766059Samurai	write(modem, &ch, n);
5776059Samurai      break;
5786059Samurai    case 1:
5796059Samurai      switch (ch) {
5806059Samurai      case '?':
5816059Samurai	ShowHelp();
5826059Samurai	break;
5836059Samurai      case '-':
5846059Samurai	if (loglevel > 0) {
5856059Samurai	  loglevel--;
5866059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5876059Samurai	}
5886059Samurai	break;
5896059Samurai      case '+':
5906059Samurai	loglevel++;
5916059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5926059Samurai	break;
5936059Samurai#ifdef DEBUG
5946059Samurai      case 'm':
5956059Samurai	ShowMemMap();
5966059Samurai	break;
5976059Samurai#endif
5986059Samurai      case 'p':
5996059Samurai	/*
6006059Samurai	 * XXX: Should check carrier.
6016059Samurai	 */
6026059Samurai	if (LcpFsm.state <= ST_CLOSED) {
6036059Samurai	  VarOpenMode = OPEN_ACTIVE;
6046059Samurai	  PacketMode();
6056059Samurai	}
6066059Samurai	break;
6076059Samurai#ifdef DEBUG
6086059Samurai      case 't':
6096059Samurai	ShowTimers();
6106059Samurai	break;
6116059Samurai#endif
6126059Samurai      case '.':
6136059Samurai	TermMode = 1;
61410528Samurai	TtyCommandMode(1);
6156059Samurai	break;
6166059Samurai      default:
6176059Samurai	if (write(modem, &ch, n) < 0)
6186059Samurai	  fprintf(stderr, "err in write.\r\n");
6196059Samurai	break;
6206059Samurai      }
6216059Samurai      ttystate = 0;
6226059Samurai      break;
6236059Samurai    }
6246059Samurai  }
6256059Samurai}
6266059Samurai
6276059Samurai
6286059Samurai/*
6296059Samurai *  Here, we'll try to detect HDLC frame
6306059Samurai */
6316059Samurai
6326059Samuraistatic char *FrameHeaders[] = {
6336735Samurai  "\176\377\003\300\041",
6346735Samurai  "\176\377\175\043\300\041",
6356735Samurai  "\176\177\175\043\100\041",
6366735Samurai  "\176\175\337\175\043\300\041",
6376735Samurai  "\176\175\137\175\043\100\041",
6386059Samurai  NULL,
6396059Samurai};
6406059Samurai
6416059Samuraiu_char *
6426059SamuraiHdlcDetect(cp, n)
6436059Samuraiu_char *cp;
6446059Samuraiint n;
6456059Samurai{
6466735Samurai  char *ptr, *fp, **hp;
6476059Samurai
6486059Samurai  cp[n] = '\0';	/* be sure to null terminated */
6496059Samurai  ptr = NULL;
6506059Samurai  for (hp = FrameHeaders; *hp; hp++) {
6516735Samurai    fp = *hp;
6526735Samurai    if (DEV_IS_SYNC)
6536735Samurai      fp++;
65413389Sphk    ptr = strstr((char *)cp, fp);
65513389Sphk    if (ptr)
6566059Samurai      break;
6576059Samurai  }
6586059Samurai  return((u_char *)ptr);
6596059Samurai}
6606059Samurai
6616059Samuraistatic struct pppTimer RedialTimer;
6626059Samurai
6636059Samuraistatic void
6646059SamuraiRedialTimeout()
6656059Samurai{
6666059Samurai  StopTimer(&RedialTimer);
66715738Sphk  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
6686059Samurai}
6696059Samurai
6706059Samuraistatic void
6716059SamuraiStartRedialTimer()
6726059Samurai{
6736059Samurai  StopTimer(&RedialTimer);
67411336Samurai
67511336Samurai  if (VarRedialTimeout) {
67615738Sphk    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
67711336Samurai    RedialTimer.state = TIMER_STOPPED;
67811336Samurai
67911336Samurai    if (VarRedialTimeout > 0)
68011336Samurai	RedialTimer.load = VarRedialTimeout * SECTICKS;
68111336Samurai    else
68211336Samurai	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
68311336Samurai
68411336Samurai    RedialTimer.func = RedialTimeout;
68511336Samurai    StartTimer(&RedialTimer);
68611336Samurai  }
6876059Samurai}
6886059Samurai
6896059Samurai
6906059Samuraistatic void
6916059SamuraiDoLoop()
6926059Samurai{
6936059Samurai  fd_set rfds, wfds, efds;
6946059Samurai  int pri, i, n, wfd;
6956059Samurai  struct sockaddr_in hisaddr;
6966059Samurai  struct timeval timeout, *tp;
6976059Samurai  int ssize = sizeof(hisaddr);
6986059Samurai  u_char *cp;
6996059Samurai  u_char rbuff[MAX_MRU];
7007001Samurai  int dial_up;
70111336Samurai  int tries;
7029448Samurai  int qlen;
70310528Samurai  pid_t pgroup;
7046059Samurai
70510528Samurai  pgroup = getpgrp();
70610528Samurai
7076059Samurai  if (mode & MODE_DIRECT) {
7086059Samurai    modem = OpenModem(mode);
70915738Sphk    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
71018885Sjkh    fflush(stderr);
7116059Samurai    PacketMode();
7126059Samurai  } else if (mode & MODE_DEDICATED) {
7136059Samurai    if (!modem)
7146059Samurai      modem = OpenModem(mode);
7156059Samurai  }
7166059Samurai
7176059Samurai  fflush(stdout);
7186059Samurai
7197001Samurai  timeout.tv_sec = 0;
7206059Samurai  timeout.tv_usec = 0;
7216059Samurai
7227001Samurai  dial_up = FALSE;			/* XXXX */
72311336Samurai  tries = 0;
7246059Samurai  for (;;) {
7256059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
7267001Samurai
72720120Snate    /*
72820120Snate     * If the link is down and we're in DDIAL mode, bring it back
72920120Snate     * up.
73020120Snate     */
73120120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
73220120Snate        dial_up = TRUE;
73320120Snate
7347001Samurai   /*
7357001Samurai    * If Ip packet for output is enqueued and require dial up,
7367001Samurai    * Just do it!
7377001Samurai    */
7387001Samurai    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
7397001Samurai#ifdef DEBUG
7407001Samurai      logprintf("going to dial: modem = %d\n", modem);
7417001Samurai#endif
74211336Samurai      modem = OpenModem(mode);
74311336Samurai      if (modem < 0) {
74411336Samurai	modem = 0;	       /* Set intial value for next OpenModem */
74511336Samurai	StartRedialTimer();
74611336Samurai      } else {
74711336Samurai	tries++;
74815738Sphk	LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
74911336Samurai	if (DialModem()) {
75011336Samurai	  sleep(1);	       /* little pause to allow peer starts */
75111336Samurai	  ModemTimeout();
75211336Samurai	  PacketMode();
75311336Samurai	  dial_up = FALSE;
75411336Samurai	  tries = 0;
75511336Samurai	} else {
75611336Samurai	  CloseModem();
75711336Samurai	  /* Dial failed. Keep quite during redial wait period. */
75811336Samurai	  StartRedialTimer();
75911336Samurai
76011336Samurai	  if (VarDialTries && tries >= VarDialTries) {
76111336Samurai	      dial_up = FALSE;
76211336Samurai	      tries = 0;
76311336Samurai	  }
76411336Samurai	}
76511336Samurai      }
7667001Samurai    }
7679448Samurai    qlen = ModemQlen();
76813733Sdfr
76913733Sdfr    if (qlen == 0) {
77013733Sdfr      IpStartOutput();
77113733Sdfr      qlen = ModemQlen();
77213733Sdfr    }
77313733Sdfr
7747001Samurai    if (modem) {
7757001Samurai      FD_SET(modem, &rfds);
7767001Samurai      FD_SET(modem, &efds);
7779448Samurai      if (qlen > 0) {
7787001Samurai	FD_SET(modem, &wfds);
7797001Samurai      }
7807001Samurai    }
7816059Samurai    if (server > 0) FD_SET(server, &rfds);
7826059Samurai
7836059Samurai    /*  *** IMPORTANT ***
7846059Samurai     *
7856059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
7866059Samurai     *	This value must be chosen with great care. If this values is
7876059Samurai     *  too big, it results loss of characters from modem and poor responce.
7886059Samurai     *  If this values is too small, ppp process eats many CPU time.
7896059Samurai     */
7906735Samurai#ifndef SIGALRM
7916059Samurai    usleep(TICKUNIT);
7926059Samurai    TimerService();
7936735Samurai#endif
79410877Sbde
79510877Sbde    /* If there are aren't many packets queued, look for some more. */
79610877Sbde    if (qlen < 20)
79710877Sbde      FD_SET(tun_in, &rfds);
79810877Sbde
7996059Samurai    if (netfd > -1) {
8006059Samurai      FD_SET(netfd, &rfds);
8016059Samurai      FD_SET(netfd, &efds);
8026059Samurai    }
8037001Samurai
8046735Samurai#ifndef SIGALRM
8056059Samurai    /*
8067001Samurai     *  Normally, select() will not block because modem is writable.
8077001Samurai     *  In AUTO mode, select will block until we find packet from tun
8086059Samurai     */
8096059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
8106059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
8116735Samurai#else
8128857Srgrimes    /*
8137001Samurai     * When SIGALRM timer is running, a select function will be
8148857Srgrimes     * return -1 and EINTR after a Time Service signal hundler
81511336Samurai     * is done.  If the redial timer is not running and we are
81611336Samurai     * trying to dial, poll with a 0 value timer.
8177001Samurai     */
81811336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
81911336Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
8206735Samurai#endif
8217001Samurai    if ( i == 0 ) {
8227001Samurai        continue;
8236059Samurai    }
8246735Samurai
8257001Samurai    if ( i < 0 ) {
8267001Samurai       if ( errno == EINTR ) {
82711336Samurai          continue;            /* Got SIGALRM, Do check a queue for dialing */
8287001Samurai       }
8297001Samurai       perror("select");
8307001Samurai       break;
8318857Srgrimes    }
8327001Samurai
8336059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
8346059Samurai      logprintf("Exception detected.\n");
8356059Samurai      break;
8366059Samurai    }
8376059Samurai
8386059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
8396059Samurai#ifdef DEBUG
8406059Samurai      logprintf("connected to client.\n");
8416059Samurai#endif
8426059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
8436059Samurai      if (netfd > 0) {
8446059Samurai	write(wfd, "already in use.\n", 16);
8456059Samurai	close(wfd);
8466059Samurai	continue;
8476059Samurai      } else
8486059Samurai	netfd = wfd;
8496059Samurai      if (dup2(netfd, 1) < 0)
8506059Samurai	perror("dup2");
8516059Samurai      mode |= MODE_INTER;
8526059Samurai      Greetings();
8536764Samurai      switch ( LocalAuthInit() ) {
8546764Samurai         case NOT_FOUND:
8556764Samurai    	    fprintf(stdout,LAUTH_M1);
8566764Samurai    	    fprintf(stdout,LAUTH_M2);
8576764Samurai            fflush(stdout);
8586764Samurai	    /* Fall down */
8596764Samurai         case VALID:
8606764Samurai	    VarLocalAuth = LOCAL_AUTH;
8616764Samurai	    break;
8626764Samurai         default:
8636764Samurai	    break;
8646764Samurai      }
8656059Samurai      (void) IsInteractive();
8666059Samurai      Prompt(0);
8676059Samurai    }
8686059Samurai
86910528Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) &&
87010858Samurai	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
8716059Samurai      /* something to read from tty */
8726059Samurai      ReadTty();
8736059Samurai    }
8746059Samurai    if (modem) {
8756059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
8766059Samurai	 ModemStartOutput(modem);
8776059Samurai      }
8786059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
8796735Samurai	if (LcpFsm.state <= ST_CLOSED)
8806735Samurai	  usleep(10000);
8816059Samurai	n = read(modem, rbuff, sizeof(rbuff));
8826059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
8836059Samurai	  DownConnection();
8846059Samurai	} else
8856059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
8866059Samurai
8876059Samurai	if (LcpFsm.state <= ST_CLOSED) {
8886059Samurai	  /*
8896059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
8906059Samurai	   */
8916059Samurai	  if (!(mode & MODE_DEDICATED)) {
8926059Samurai	    cp = HdlcDetect(rbuff, n);
8936059Samurai	    if (cp) {
8946059Samurai	      /*
8956059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
8966059Samurai	       */
8976059Samurai	      if (cp != rbuff) {
8986059Samurai	        write(1, rbuff, cp - rbuff);
8996059Samurai	        write(1, "\r\n", 2);
9006059Samurai	      }
9016059Samurai	      PacketMode();
9026059Samurai#ifdef notdef
9036059Samurai	      AsyncInput(cp, n - (cp - rbuff));
9046059Samurai#endif
9056059Samurai	    } else
9066059Samurai	      write(1, rbuff, n);
9076059Samurai	  }
9086059Samurai	} else {
9096059Samurai	  if (n > 0)
9106059Samurai	    AsyncInput(rbuff, n);
9116059Samurai#ifdef notdef
9126059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
9136059Samurai#endif
9146059Samurai	}
9156059Samurai      }
9166059Samurai    }
9177001Samurai
9186059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
9196059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
9206059Samurai      if (n < 0) {
9216059Samurai	perror("read from tun");
9226059Samurai	continue;
9236059Samurai      }
9246059Samurai      /*
9256059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
9266059Samurai       *  device until IPCP is opened.
9276059Samurai       */
9286059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
9297001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
9306059Samurai	if (pri >= 0) {
93120365Sjkh	  if (mode & MODE_ALIAS) {
93220666Snate	    PacketAliasOut((struct ip *)rbuff);
93320666Snate	    n = ntohs(((struct ip *)rbuff)->ip_len);
93420365Sjkh	  }
9356059Samurai	  IpEnqueue(pri, rbuff, n);
93620365Sjkh	  dial_up = TRUE;		/* XXX */
9376059Samurai	}
9386059Samurai	continue;
9396059Samurai      }
9407001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
94120365Sjkh      if (pri >= 0) {
94220365Sjkh        if (mode & MODE_ALIAS) {
94320666Snate          PacketAliasOut((struct ip *)rbuff);
94420666Snate          n = ntohs(((struct ip *)rbuff)->ip_len);
94520365Sjkh        }
9466059Samurai	IpEnqueue(pri, rbuff, n);
94720365Sjkh      }
9486059Samurai    }
9496059Samurai  }
9506059Samurai  logprintf("job done.\n");
9516059Samurai}
952