main.c revision 20666
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 *
2020666Snate * $Id: main.c,v 1.24 1996/12/12 14:39:45 jkh 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;
776059Samuraistruct sockaddr_in ifsin;
7811336Samuraichar pid_filename[128];
796059Samurai
806059Samuraistatic void
816059SamuraiTtyInit()
826059Samurai{
836059Samurai  struct termios newtio;
846059Samurai  int stat;
856059Samurai
866059Samurai  stat = fcntl(0, F_GETFL, 0);
876059Samurai  stat |= O_NONBLOCK;
886059Samurai  fcntl(0, F_SETFL, stat);
896059Samurai  newtio = oldtio;
906059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
916059Samurai  newtio.c_iflag = 0;
926059Samurai  newtio.c_oflag &= ~OPOST;
936059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
946059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
956059Samurai  newtio.c_cc[VMIN] = 1;
966059Samurai  newtio.c_cc[VTIME] = 0;
976059Samurai  newtio.c_cflag |= CS8;
986735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
996059Samurai  comtio = newtio;
1006059Samurai}
1016059Samurai
1026059Samurai/*
1036059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1046059Samurai */
10510528Samuraivoid
10610528SamuraiTtyCommandMode(prompt)
10710528Samuraiint prompt;
1086059Samurai{
1096059Samurai  struct termios newtio;
1106059Samurai  int stat;
1116059Samurai
1126059Samurai  if (!(mode & MODE_INTER))
1136059Samurai    return;
1146735Samurai  tcgetattr(0, &newtio);
11510528Samurai  newtio.c_lflag |= (ECHO|ISIG|ICANON);
1166059Samurai  newtio.c_iflag = oldtio.c_iflag;
1176059Samurai  newtio.c_oflag |= OPOST;
1186735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1196059Samurai  stat = fcntl(0, F_GETFL, 0);
1206059Samurai  stat |= O_NONBLOCK;
1216059Samurai  fcntl(0, F_SETFL, stat);
1226059Samurai  TermMode = 0;
12310528Samurai  if(prompt) Prompt(0);
1246059Samurai}
1256059Samurai
1266059Samurai/*
1276059Samurai * Set tty into terminal mode which is used while we invoke term command.
1286059Samurai */
1296059Samuraivoid
1306059SamuraiTtyTermMode()
1316059Samurai{
1326059Samurai  int stat;
1336059Samurai
1346735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1356059Samurai  stat = fcntl(0, F_GETFL, 0);
1366059Samurai  stat &= ~O_NONBLOCK;
1376059Samurai  fcntl(0, F_SETFL, stat);
1386059Samurai  TermMode = 1;
1396059Samurai}
1406059Samurai
1416059Samuraivoid
14210528SamuraiTtyOldMode()
1436059Samurai{
1446059Samurai  int stat;
1456059Samurai
1466059Samurai  stat = fcntl(0, F_GETFL, 0);
1476059Samurai  stat &= ~O_NONBLOCK;
1486059Samurai  fcntl(0, F_SETFL, stat);
1496735Samurai  tcsetattr(0, TCSANOW, &oldtio);
15010528Samurai}
15110528Samurai
15210528Samuraivoid
15310528SamuraiCleanup(excode)
15410528Samuraiint excode;
15510528Samurai{
15610528Samurai
15710528Samurai  OsLinkdown();
1586059Samurai  OsCloseLink(1);
1596059Samurai  sleep(1);
16011336Samurai  if (mode & MODE_AUTO) {
1616059Samurai    DeleteIfRoutes(1);
16211336Samurai    unlink(pid_filename);
16311336Samurai  }
1646059Samurai  OsInterfaceDown(1);
16515738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n");
1666059Samurai  LogClose();
1676059Samurai  if (server > 0)
1686059Samurai    close(server);
16910528Samurai  TtyOldMode();
1706059Samurai
1716059Samurai  exit(excode);
1726059Samurai}
1736059Samurai
1746059Samuraistatic void
17514930SacheHangup(signo)
17614930Sacheint signo;
1776059Samurai{
17817044Sache  if (signo == SIGSEGV) {
17917044Sache	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
18017044Sache	LogClose();
18117044Sache	abort();
18217044Sache  }
18315738Sphk  LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
1846059Samurai  Cleanup(EX_HANGUP);
1856059Samurai}
1866059Samurai
1876059Samuraistatic void
18814930SacheCloseSession(signo)
18914930Sacheint signo;
1906059Samurai{
19115738Sphk  LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
1926059Samurai  LcpClose();
1936059Samurai  Cleanup(EX_TERM);
1946059Samurai}
1956059Samurai
19610528Samurai
19710528Samuraistatic void
19810528SamuraiTerminalCont()
19910528Samurai{
20010528Samurai  (void)signal(SIGCONT, SIG_DFL);
20110528Samurai  (void)signal(SIGTSTP, TerminalStop);
20210528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
20310528Samurai}
20410528Samurai
20510528Samuraistatic void
20610528SamuraiTerminalStop(signo)
20710528Samuraiint signo;
20810528Samurai{
20910528Samurai  (void)signal(SIGCONT, TerminalCont);
21010528Samurai  TtyOldMode();
21110528Samurai  signal(SIGTSTP, SIG_DFL);
21210528Samurai  kill(getpid(), signo);
21310528Samurai}
21410528Samurai
21510528Samurai
2166059Samuraivoid
2176059SamuraiUsage()
2186059Samurai{
21920120Snate  fprintf(stderr,
22020365Sjkh          "Usage: ppp [-auto | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
2216059Samurai  exit(EX_START);
2226059Samurai}
2236059Samurai
2246059Samuraivoid
2256059SamuraiProcessArgs(int argc, char **argv)
2266059Samurai{
2276059Samurai  int optc;
2286059Samurai  char *cp;
2296059Samurai
2306059Samurai  optc = 0;
2316059Samurai  while (argc > 0 && **argv == '-') {
2326059Samurai    cp = *argv + 1;
2336059Samurai    if (strcmp(cp, "auto") == 0)
2346059Samurai      mode |= MODE_AUTO;
2356059Samurai    else if (strcmp(cp, "direct") == 0)
2366059Samurai      mode |= MODE_DIRECT;
2376059Samurai    else if (strcmp(cp, "dedicated") == 0)
2386059Samurai      mode |= MODE_DEDICATED;
23920120Snate    else if (strcmp(cp, "ddial") == 0)
24020120Snate      mode |= MODE_DDIAL|MODE_AUTO;
24120365Sjkh    else if (strcmp(cp, "alias") == 0) {
24220365Sjkh      mode |= MODE_ALIAS;
24320365Sjkh      optc--;             /* this option isn't exclusive */
24420365Sjkh    }
2456059Samurai    else
2466059Samurai      Usage();
2476059Samurai    optc++;
2486059Samurai    argv++; argc--;
2496059Samurai  }
2506059Samurai  if (argc > 1) {
2516059Samurai    fprintf(stderr, "specify only one system label.\n");
2526059Samurai    exit(EX_START);
2536059Samurai  }
2546059Samurai  if (argc == 1) dstsystem = *argv;
2556059Samurai
2566059Samurai  if (optc > 1) {
2576059Samurai    fprintf(stderr, "specify only one mode.\n");
2586059Samurai    exit(EX_START);
2596059Samurai  }
2606059Samurai}
2616059Samurai
2626059Samuraistatic void
2636059SamuraiGreetings()
2646059Samurai{
2656059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2666059Samurai  fflush(stdout);
2676059Samurai}
2686059Samurai
2696059Samuraivoid
2706059Samuraimain(argc, argv)
2716059Samuraiint argc;
2726059Samuraichar **argv;
2736059Samurai{
2746059Samurai  int tunno;
2756059Samurai
2766059Samurai  argc--; argv++;
2776059Samurai
2786059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2796059Samurai  netfd = -1;
2806059Samurai  ProcessArgs(argc, argv);
2816059Samurai  Greetings();
2826059Samurai  GetUid();
2836059Samurai  IpcpDefAddress();
28420365Sjkh  InitAlias();
2856059Samurai
2866059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
2876059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
2886059Samurai  }
2896059Samurai
2906059Samurai  if (LogOpen())
2916059Samurai    exit(EX_START);
2926059Samurai
2936735Samurai  switch ( LocalAuthInit() ) {
2946735Samurai    case NOT_FOUND:
2956764Samurai    	fprintf(stderr,LAUTH_M1);
2966764Samurai    	fprintf(stderr,LAUTH_M2);
2976764Samurai	fflush (stderr);
2986764Samurai	/* Fall down */
2996764Samurai    case VALID:
3006735Samurai	VarLocalAuth = LOCAL_AUTH;
3016735Samurai	break;
3026735Samurai    default:
3036735Samurai	break;
3046735Samurai  }
3056735Samurai
3066059Samurai  if (OpenTunnel(&tunno) < 0) {
3076059Samurai    perror("open_tun");
3086059Samurai    exit(EX_START);
3096059Samurai  }
3106059Samurai
3116059Samurai  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
3126059Samurai    mode &= ~MODE_INTER;
3136059Samurai  if (mode & MODE_INTER) {
3146059Samurai    printf("Interactive mode\n");
3156059Samurai    netfd = 0;
3166059Samurai  } else if (mode & MODE_AUTO) {
31720120Snate    printf("Automatic Dialer mode\n");
3186059Samurai    if (dstsystem == NULL) {
31920120Snate      fprintf(stderr,
32020120Snate              "Destination system must be specified in auto or ddial mode.\n");
3216059Samurai      exit(EX_START);
3226059Samurai    }
3236059Samurai  }
3246059Samurai
3256735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
3266059Samurai
3276059Samurai  signal(SIGHUP, Hangup);
3286059Samurai  signal(SIGTERM, CloseSession);
3296059Samurai  signal(SIGINT, CloseSession);
33010528Samurai  signal(SIGQUIT, CloseSession);
3316735Samurai#ifdef SIGSEGV
3326059Samurai  signal(SIGSEGV, Hangup);
3336735Samurai#endif
3346735Samurai#ifdef SIGPIPE
3356735Samurai  signal(SIGPIPE, Hangup);
3366735Samurai#endif
3376735Samurai#ifdef SIGALRM
3386735Samurai  signal(SIGALRM, SIG_IGN);
3396735Samurai#endif
34010528Samurai  if(mode & MODE_INTER)
34110528Samurai    {
34210528Samurai#ifdef SIGTSTP
34310528Samurai      signal(SIGTSTP, TerminalStop);
34410528Samurai#endif
34510528Samurai#ifdef SIGTTIN
34610528Samurai      signal(SIGTTIN, TerminalStop);
34710528Samurai#endif
34810528Samurai#ifdef SIGTTOU
34910528Samurai      signal(SIGTTOU, SIG_IGN);
35010528Samurai#endif
35110528Samurai    }
3526059Samurai
3536059Samurai  if (dstsystem) {
3546059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
3556059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
3566059Samurai      Cleanup(EX_START);
3576059Samurai    }
3586059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
35920120Snate      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
3606059Samurai      Cleanup(EX_START);
3616059Samurai    }
3626059Samurai  }
3636059Samurai  if (mode & MODE_DIRECT)
3646059Samurai    printf("Packet mode enabled.\n");
3656059Samurai
3666059Samurai#ifdef notdef
3676059Samurai  if (mode & MODE_AUTO) {
3686059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3696059Samurai  }
3706059Samurai#endif
3716059Samurai
3726059Samurai  if (!(mode & MODE_INTER)) {
3736059Samurai     int port = SERVER_PORT + tunno;
3746059Samurai    /*
3756059Samurai     *  Create server socket and listen at there.
3766059Samurai     */
3776059Samurai    server = socket(PF_INET, SOCK_STREAM, 0);
3786059Samurai    if (server < 0) {
3796059Samurai      perror("socket");
3806059Samurai      Cleanup(EX_SOCK);
3816059Samurai    }
3826059Samurai    ifsin.sin_family = AF_INET;
3836059Samurai    ifsin.sin_addr.s_addr = INADDR_ANY;
3846059Samurai    ifsin.sin_port = htons(port);
3856059Samurai    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
3866059Samurai      perror("bind");
3876059Samurai      if (errno == EADDRINUSE)
3886059Samurai	fprintf(stderr, "Wait for a while, then try again.\n");
3896059Samurai      Cleanup(EX_SOCK);
3906059Samurai    }
3916059Samurai    listen(server, 5);
3926059Samurai
3936059Samurai    DupLog();
3946059Samurai    if (!(mode & MODE_DIRECT)) {
39511336Samurai      int fd;
39611336Samurai      char pid[32];
39711336Samurai
3986059Samurai      if (fork())
3996059Samurai        exit(0);
40011336Samurai
40111336Samurai      snprintf(pid_filename, sizeof (pid_filename), "%s/PPP.%s",
40211336Samurai		  _PATH_VARRUN, dstsystem);
40311336Samurai      unlink(pid_filename);
40420120Snate      sprintf(pid, "%d\n", (int)getpid());
40511336Samurai
40611336Samurai      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
40711336Samurai      {
40811336Samurai	  write(fd, pid, strlen(pid));
40911336Samurai	  close(fd);
41011336Samurai      }
4116059Samurai    }
41215738Sphk    LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
4136059Samurai#ifdef DOTTYINIT
4146735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
4156059Samurai#else
4166059Samurai    if (mode & MODE_DIRECT) {
4176059Samurai#endif
4186059Samurai      TtyInit();
4196059Samurai    } else {
42014436Sache      int fd;
42114436Sache
4226059Samurai      setsid();			/* detach control tty */
42314436Sache      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
42414436Sache	(void)dup2(fd, STDIN_FILENO);
42514436Sache	(void)dup2(fd, STDOUT_FILENO);
42614436Sache	(void)dup2(fd, STDERR_FILENO);
42714436Sache	if (fd > 2)
42814436Sache		(void)close (fd);
42914436Sache      }
4306059Samurai    }
4316059Samurai  } else {
4326059Samurai    server = -1;
4336059Samurai    TtyInit();
43410528Samurai    TtyCommandMode(1);
4356059Samurai  }
43615738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
4376059Samurai
4386059Samurai
4396059Samurai  do
4406059Samurai   DoLoop();
4416059Samurai  while (mode & MODE_DEDICATED);
4426059Samurai
4436059Samurai  Cleanup(EX_DONE);
4446059Samurai}
4456059Samurai
4466059Samurai/*
4476059Samurai *  Turn into packet mode, where we speek PPP.
4486059Samurai */
4496059Samuraivoid
4506059SamuraiPacketMode()
4516059Samurai{
4526059Samurai  if (RawModem(modem) < 0) {
4536059Samurai    fprintf(stderr, "Not connected.\r\n");
4546059Samurai    return;
4556059Samurai  }
4566059Samurai
4576059Samurai  AsyncInit();
4586059Samurai  VjInit();
4596059Samurai  LcpInit();
4606059Samurai  IpcpInit();
4616059Samurai  CcpInit();
4626059Samurai  LcpUp();
4636059Samurai
4646059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
4656059Samurai    LcpOpen(OPEN_ACTIVE);
4666059Samurai  else
4676059Samurai    LcpOpen(VarOpenMode);
4686059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
46910528Samurai    TtyCommandMode(1);
4706059Samurai    fprintf(stderr, "Packet mode.\r\n");
47118885Sjkh    aft_cmd = 1;
4726059Samurai  }
4736059Samurai}
4746059Samurai
4756059Samuraistatic void
4766059SamuraiShowHelp()
4776059Samurai{
47810528Samurai  fprintf(stderr, "The following commands are available:\r\n");
4796059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
48014418Sache  fprintf(stderr, " ~-\tDecrease log level\r\n");
48114418Sache  fprintf(stderr, " ~+\tIncrease log level\r\n");
4826059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
48314418Sache  fprintf(stderr, " ~?\tThis help\r\n");
4846059Samurai}
4856059Samurai
4866059Samuraistatic void
4876059SamuraiReadTty()
4886059Samurai{
4896059Samurai  int n;
4906059Samurai  char ch;
4916059Samurai  static int ttystate;
4926059Samurai#define MAXLINESIZE 200
4936059Samurai  char linebuff[MAXLINESIZE];
4946059Samurai
4956059Samurai#ifdef DEBUG
4966059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
4976059Samurai#endif
4986059Samurai  if (!TermMode) {
4996059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
50018885Sjkh    aft_cmd = 1;
5016735Samurai    if (n > 0) {
5026059Samurai      DecodeCommand(linebuff, n, 1);
5036735Samurai    } else {
5046059Samurai#ifdef DEBUG
5056059Samurai      logprintf("connection closed.\n");
5066059Samurai#endif
5076059Samurai      close(netfd);
5086059Samurai      netfd = -1;
5096059Samurai      mode &= ~MODE_INTER;
5106059Samurai    }
5116059Samurai    return;
5126059Samurai  }
5136059Samurai
5146059Samurai  /*
5156059Samurai   *  We are in terminal mode, decode special sequences
5166059Samurai   */
5176059Samurai  n = read(0, &ch, 1);
5186059Samurai#ifdef DEBUG
5196059Samurai  logprintf("got %d bytes\n", n);
5206059Samurai#endif
5216059Samurai
5226059Samurai  if (n > 0) {
5236059Samurai    switch (ttystate) {
5246059Samurai    case 0:
5256059Samurai      if (ch == '~')
5266059Samurai	ttystate++;
5276059Samurai      else
5286059Samurai	write(modem, &ch, n);
5296059Samurai      break;
5306059Samurai    case 1:
5316059Samurai      switch (ch) {
5326059Samurai      case '?':
5336059Samurai	ShowHelp();
5346059Samurai	break;
5356059Samurai      case '-':
5366059Samurai	if (loglevel > 0) {
5376059Samurai	  loglevel--;
5386059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5396059Samurai	}
5406059Samurai	break;
5416059Samurai      case '+':
5426059Samurai	loglevel++;
5436059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5446059Samurai	break;
5456059Samurai#ifdef DEBUG
5466059Samurai      case 'm':
5476059Samurai	ShowMemMap();
5486059Samurai	break;
5496059Samurai#endif
5506059Samurai      case 'p':
5516059Samurai	/*
5526059Samurai	 * XXX: Should check carrier.
5536059Samurai	 */
5546059Samurai	if (LcpFsm.state <= ST_CLOSED) {
5556059Samurai	  VarOpenMode = OPEN_ACTIVE;
5566059Samurai	  PacketMode();
5576059Samurai	}
5586059Samurai	break;
5596059Samurai#ifdef DEBUG
5606059Samurai      case 't':
5616059Samurai	ShowTimers();
5626059Samurai	break;
5636059Samurai#endif
5646059Samurai      case '.':
5656059Samurai	TermMode = 1;
56610528Samurai	TtyCommandMode(1);
5676059Samurai	break;
5686059Samurai      default:
5696059Samurai	if (write(modem, &ch, n) < 0)
5706059Samurai	  fprintf(stderr, "err in write.\r\n");
5716059Samurai	break;
5726059Samurai      }
5736059Samurai      ttystate = 0;
5746059Samurai      break;
5756059Samurai    }
5766059Samurai  }
5776059Samurai}
5786059Samurai
5796059Samurai
5806059Samurai/*
5816059Samurai *  Here, we'll try to detect HDLC frame
5826059Samurai */
5836059Samurai
5846059Samuraistatic char *FrameHeaders[] = {
5856735Samurai  "\176\377\003\300\041",
5866735Samurai  "\176\377\175\043\300\041",
5876735Samurai  "\176\177\175\043\100\041",
5886735Samurai  "\176\175\337\175\043\300\041",
5896735Samurai  "\176\175\137\175\043\100\041",
5906059Samurai  NULL,
5916059Samurai};
5926059Samurai
5936059Samuraiu_char *
5946059SamuraiHdlcDetect(cp, n)
5956059Samuraiu_char *cp;
5966059Samuraiint n;
5976059Samurai{
5986735Samurai  char *ptr, *fp, **hp;
5996059Samurai
6006059Samurai  cp[n] = '\0';	/* be sure to null terminated */
6016059Samurai  ptr = NULL;
6026059Samurai  for (hp = FrameHeaders; *hp; hp++) {
6036735Samurai    fp = *hp;
6046735Samurai    if (DEV_IS_SYNC)
6056735Samurai      fp++;
60613389Sphk    ptr = strstr((char *)cp, fp);
60713389Sphk    if (ptr)
6086059Samurai      break;
6096059Samurai  }
6106059Samurai  return((u_char *)ptr);
6116059Samurai}
6126059Samurai
6136059Samuraistatic struct pppTimer RedialTimer;
6146059Samurai
6156059Samuraistatic void
6166059SamuraiRedialTimeout()
6176059Samurai{
6186059Samurai  StopTimer(&RedialTimer);
61915738Sphk  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
6206059Samurai}
6216059Samurai
6226059Samuraistatic void
6236059SamuraiStartRedialTimer()
6246059Samurai{
6256059Samurai  StopTimer(&RedialTimer);
62611336Samurai
62711336Samurai  if (VarRedialTimeout) {
62815738Sphk    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
62911336Samurai    RedialTimer.state = TIMER_STOPPED;
63011336Samurai
63111336Samurai    if (VarRedialTimeout > 0)
63211336Samurai	RedialTimer.load = VarRedialTimeout * SECTICKS;
63311336Samurai    else
63411336Samurai	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
63511336Samurai
63611336Samurai    RedialTimer.func = RedialTimeout;
63711336Samurai    StartTimer(&RedialTimer);
63811336Samurai  }
6396059Samurai}
6406059Samurai
6416059Samurai
6426059Samuraistatic void
6436059SamuraiDoLoop()
6446059Samurai{
6456059Samurai  fd_set rfds, wfds, efds;
6466059Samurai  int pri, i, n, wfd;
6476059Samurai  struct sockaddr_in hisaddr;
6486059Samurai  struct timeval timeout, *tp;
6496059Samurai  int ssize = sizeof(hisaddr);
6506059Samurai  u_char *cp;
6516059Samurai  u_char rbuff[MAX_MRU];
6527001Samurai  int dial_up;
65311336Samurai  int tries;
6549448Samurai  int qlen;
65510528Samurai  pid_t pgroup;
6566059Samurai
65710528Samurai  pgroup = getpgrp();
65810528Samurai
6596059Samurai  if (mode & MODE_DIRECT) {
6606059Samurai    modem = OpenModem(mode);
66115738Sphk    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
66218885Sjkh    fflush(stderr);
6636059Samurai    PacketMode();
6646059Samurai  } else if (mode & MODE_DEDICATED) {
6656059Samurai    if (!modem)
6666059Samurai      modem = OpenModem(mode);
6676059Samurai  }
6686059Samurai
6696059Samurai  fflush(stdout);
6706059Samurai
6717001Samurai  timeout.tv_sec = 0;
6726059Samurai  timeout.tv_usec = 0;
6736059Samurai
6747001Samurai  dial_up = FALSE;			/* XXXX */
67511336Samurai  tries = 0;
6766059Samurai  for (;;) {
6776059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
6787001Samurai
67920120Snate    /*
68020120Snate     * If the link is down and we're in DDIAL mode, bring it back
68120120Snate     * up.
68220120Snate     */
68320120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
68420120Snate        dial_up = TRUE;
68520120Snate
6867001Samurai   /*
6877001Samurai    * If Ip packet for output is enqueued and require dial up,
6887001Samurai    * Just do it!
6897001Samurai    */
6907001Samurai    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
6917001Samurai#ifdef DEBUG
6927001Samurai      logprintf("going to dial: modem = %d\n", modem);
6937001Samurai#endif
69411336Samurai      modem = OpenModem(mode);
69511336Samurai      if (modem < 0) {
69611336Samurai	modem = 0;	       /* Set intial value for next OpenModem */
69711336Samurai	StartRedialTimer();
69811336Samurai      } else {
69911336Samurai	tries++;
70015738Sphk	LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
70111336Samurai	if (DialModem()) {
70211336Samurai	  sleep(1);	       /* little pause to allow peer starts */
70311336Samurai	  ModemTimeout();
70411336Samurai	  PacketMode();
70511336Samurai	  dial_up = FALSE;
70611336Samurai	  tries = 0;
70711336Samurai	} else {
70811336Samurai	  CloseModem();
70911336Samurai	  /* Dial failed. Keep quite during redial wait period. */
71011336Samurai	  StartRedialTimer();
71111336Samurai
71211336Samurai	  if (VarDialTries && tries >= VarDialTries) {
71311336Samurai	      dial_up = FALSE;
71411336Samurai	      tries = 0;
71511336Samurai	  }
71611336Samurai	}
71711336Samurai      }
7187001Samurai    }
7199448Samurai    qlen = ModemQlen();
72013733Sdfr
72113733Sdfr    if (qlen == 0) {
72213733Sdfr      IpStartOutput();
72313733Sdfr      qlen = ModemQlen();
72413733Sdfr    }
72513733Sdfr
7267001Samurai    if (modem) {
7277001Samurai      FD_SET(modem, &rfds);
7287001Samurai      FD_SET(modem, &efds);
7299448Samurai      if (qlen > 0) {
7307001Samurai	FD_SET(modem, &wfds);
7317001Samurai      }
7327001Samurai    }
7336059Samurai    if (server > 0) FD_SET(server, &rfds);
7346059Samurai
7356059Samurai    /*  *** IMPORTANT ***
7366059Samurai     *
7376059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
7386059Samurai     *	This value must be chosen with great care. If this values is
7396059Samurai     *  too big, it results loss of characters from modem and poor responce.
7406059Samurai     *  If this values is too small, ppp process eats many CPU time.
7416059Samurai     */
7426735Samurai#ifndef SIGALRM
7436059Samurai    usleep(TICKUNIT);
7446059Samurai    TimerService();
7456735Samurai#endif
74610877Sbde
74710877Sbde    /* If there are aren't many packets queued, look for some more. */
74810877Sbde    if (qlen < 20)
74910877Sbde      FD_SET(tun_in, &rfds);
75010877Sbde
7516059Samurai    if (netfd > -1) {
7526059Samurai      FD_SET(netfd, &rfds);
7536059Samurai      FD_SET(netfd, &efds);
7546059Samurai    }
7557001Samurai
7566735Samurai#ifndef SIGALRM
7576059Samurai    /*
7587001Samurai     *  Normally, select() will not block because modem is writable.
7597001Samurai     *  In AUTO mode, select will block until we find packet from tun
7606059Samurai     */
7616059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
7626059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7636735Samurai#else
7648857Srgrimes    /*
7657001Samurai     * When SIGALRM timer is running, a select function will be
7668857Srgrimes     * return -1 and EINTR after a Time Service signal hundler
76711336Samurai     * is done.  If the redial timer is not running and we are
76811336Samurai     * trying to dial, poll with a 0 value timer.
7697001Samurai     */
77011336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
77111336Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7726735Samurai#endif
7737001Samurai    if ( i == 0 ) {
7747001Samurai        continue;
7756059Samurai    }
7766735Samurai
7777001Samurai    if ( i < 0 ) {
7787001Samurai       if ( errno == EINTR ) {
77911336Samurai          continue;            /* Got SIGALRM, Do check a queue for dialing */
7807001Samurai       }
7817001Samurai       perror("select");
7827001Samurai       break;
7838857Srgrimes    }
7847001Samurai
7856059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
7866059Samurai      logprintf("Exception detected.\n");
7876059Samurai      break;
7886059Samurai    }
7896059Samurai
7906059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
7916059Samurai#ifdef DEBUG
7926059Samurai      logprintf("connected to client.\n");
7936059Samurai#endif
7946059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
7956059Samurai      if (netfd > 0) {
7966059Samurai	write(wfd, "already in use.\n", 16);
7976059Samurai	close(wfd);
7986059Samurai	continue;
7996059Samurai      } else
8006059Samurai	netfd = wfd;
8016059Samurai      if (dup2(netfd, 1) < 0)
8026059Samurai	perror("dup2");
8036059Samurai      mode |= MODE_INTER;
8046059Samurai      Greetings();
8056764Samurai      switch ( LocalAuthInit() ) {
8066764Samurai         case NOT_FOUND:
8076764Samurai    	    fprintf(stdout,LAUTH_M1);
8086764Samurai    	    fprintf(stdout,LAUTH_M2);
8096764Samurai            fflush(stdout);
8106764Samurai	    /* Fall down */
8116764Samurai         case VALID:
8126764Samurai	    VarLocalAuth = LOCAL_AUTH;
8136764Samurai	    break;
8146764Samurai         default:
8156764Samurai	    break;
8166764Samurai      }
8176059Samurai      (void) IsInteractive();
8186059Samurai      Prompt(0);
8196059Samurai    }
8206059Samurai
82110528Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) &&
82210858Samurai	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
8236059Samurai      /* something to read from tty */
8246059Samurai      ReadTty();
8256059Samurai    }
8266059Samurai    if (modem) {
8276059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
8286059Samurai	 ModemStartOutput(modem);
8296059Samurai      }
8306059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
8316735Samurai	if (LcpFsm.state <= ST_CLOSED)
8326735Samurai	  usleep(10000);
8336059Samurai	n = read(modem, rbuff, sizeof(rbuff));
8346059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
8356059Samurai	  DownConnection();
8366059Samurai	} else
8376059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
8386059Samurai
8396059Samurai	if (LcpFsm.state <= ST_CLOSED) {
8406059Samurai	  /*
8416059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
8426059Samurai	   */
8436059Samurai	  if (!(mode & MODE_DEDICATED)) {
8446059Samurai	    cp = HdlcDetect(rbuff, n);
8456059Samurai	    if (cp) {
8466059Samurai	      /*
8476059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
8486059Samurai	       */
8496059Samurai	      if (cp != rbuff) {
8506059Samurai	        write(1, rbuff, cp - rbuff);
8516059Samurai	        write(1, "\r\n", 2);
8526059Samurai	      }
8536059Samurai	      PacketMode();
8546059Samurai#ifdef notdef
8556059Samurai	      AsyncInput(cp, n - (cp - rbuff));
8566059Samurai#endif
8576059Samurai	    } else
8586059Samurai	      write(1, rbuff, n);
8596059Samurai	  }
8606059Samurai	} else {
8616059Samurai	  if (n > 0)
8626059Samurai	    AsyncInput(rbuff, n);
8636059Samurai#ifdef notdef
8646059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
8656059Samurai#endif
8666059Samurai	}
8676059Samurai      }
8686059Samurai    }
8697001Samurai
8706059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
8716059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
8726059Samurai      if (n < 0) {
8736059Samurai	perror("read from tun");
8746059Samurai	continue;
8756059Samurai      }
8766059Samurai      /*
8776059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
8786059Samurai       *  device until IPCP is opened.
8796059Samurai       */
8806059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
8817001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
8826059Samurai	if (pri >= 0) {
88320365Sjkh	  if (mode & MODE_ALIAS) {
88420666Snate	    PacketAliasOut((struct ip *)rbuff);
88520666Snate	    n = ntohs(((struct ip *)rbuff)->ip_len);
88620365Sjkh	  }
8876059Samurai	  IpEnqueue(pri, rbuff, n);
88820365Sjkh	  dial_up = TRUE;		/* XXX */
8896059Samurai	}
8906059Samurai	continue;
8916059Samurai      }
8927001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
89320365Sjkh      if (pri >= 0) {
89420365Sjkh        if (mode & MODE_ALIAS) {
89520666Snate          PacketAliasOut((struct ip *)rbuff);
89620666Snate          n = ntohs(((struct ip *)rbuff)->ip_len);
89720365Sjkh        }
8986059Samurai	IpEnqueue(pri, rbuff, n);
89920365Sjkh      }
9006059Samurai    }
9016059Samurai  }
9026059Samurai  logprintf("job done.\n");
9036059Samurai}
904