main.c revision 20120
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 *
2020120Snate * $Id: main.c,v 1.22 1996/10/12 16:20:32 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>
386059Samurai#include "modem.h"
396059Samurai#include "os.h"
406059Samurai#include "hdlc.h"
4113389Sphk#include "ccp.h"
426059Samurai#include "lcp.h"
436059Samurai#include "ipcp.h"
446059Samurai#include "vars.h"
456735Samurai#include "auth.h"
467001Samurai#include "filter.h"
4713389Sphk#include "systems.h"
4813389Sphk#include "ip.h"
496059Samurai
506764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
519410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
526764Samurai
536735Samurai#ifndef O_NONBLOCK
546735Samurai#ifdef O_NDELAY
556735Samurai#define	O_NONBLOCK O_NDELAY
566735Samurai#endif
576735Samurai#endif
586735Samurai
596059Samuraiextern void VjInit(), AsyncInit();
606059Samuraiextern void AsyncInput(), IpOutput();
616059Samuraiextern int  SelectSystem();
626059Samurai
636059Samuraiextern void DecodeCommand(), Prompt();
6418885Sjkhextern int aft_cmd;
656059Samuraiextern int IsInteractive();
666059Samuraiextern struct in_addr ifnetmask;
676059Samuraistatic void DoLoop(void);
6810528Samuraistatic void TerminalStop();
696059Samurai
706059Samuraistatic struct termios oldtio;		/* Original tty mode */
716059Samuraistatic struct termios comtio;		/* Command level tty mode */
7214418Sacheint TermMode;
7313379Sphkstatic int server;
746059Samuraistruct sockaddr_in ifsin;
7511336Samuraichar pid_filename[128];
766059Samurai
776059Samuraistatic void
786059SamuraiTtyInit()
796059Samurai{
806059Samurai  struct termios newtio;
816059Samurai  int stat;
826059Samurai
836059Samurai  stat = fcntl(0, F_GETFL, 0);
846059Samurai  stat |= O_NONBLOCK;
856059Samurai  fcntl(0, F_SETFL, stat);
866059Samurai  newtio = oldtio;
876059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
886059Samurai  newtio.c_iflag = 0;
896059Samurai  newtio.c_oflag &= ~OPOST;
906059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
916059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
926059Samurai  newtio.c_cc[VMIN] = 1;
936059Samurai  newtio.c_cc[VTIME] = 0;
946059Samurai  newtio.c_cflag |= CS8;
956735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
966059Samurai  comtio = newtio;
976059Samurai}
986059Samurai
996059Samurai/*
1006059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1016059Samurai */
10210528Samuraivoid
10310528SamuraiTtyCommandMode(prompt)
10410528Samuraiint prompt;
1056059Samurai{
1066059Samurai  struct termios newtio;
1076059Samurai  int stat;
1086059Samurai
1096059Samurai  if (!(mode & MODE_INTER))
1106059Samurai    return;
1116735Samurai  tcgetattr(0, &newtio);
11210528Samurai  newtio.c_lflag |= (ECHO|ISIG|ICANON);
1136059Samurai  newtio.c_iflag = oldtio.c_iflag;
1146059Samurai  newtio.c_oflag |= OPOST;
1156735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1166059Samurai  stat = fcntl(0, F_GETFL, 0);
1176059Samurai  stat |= O_NONBLOCK;
1186059Samurai  fcntl(0, F_SETFL, stat);
1196059Samurai  TermMode = 0;
12010528Samurai  if(prompt) Prompt(0);
1216059Samurai}
1226059Samurai
1236059Samurai/*
1246059Samurai * Set tty into terminal mode which is used while we invoke term command.
1256059Samurai */
1266059Samuraivoid
1276059SamuraiTtyTermMode()
1286059Samurai{
1296059Samurai  int stat;
1306059Samurai
1316735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1326059Samurai  stat = fcntl(0, F_GETFL, 0);
1336059Samurai  stat &= ~O_NONBLOCK;
1346059Samurai  fcntl(0, F_SETFL, stat);
1356059Samurai  TermMode = 1;
1366059Samurai}
1376059Samurai
1386059Samuraivoid
13910528SamuraiTtyOldMode()
1406059Samurai{
1416059Samurai  int stat;
1426059Samurai
1436059Samurai  stat = fcntl(0, F_GETFL, 0);
1446059Samurai  stat &= ~O_NONBLOCK;
1456059Samurai  fcntl(0, F_SETFL, stat);
1466735Samurai  tcsetattr(0, TCSANOW, &oldtio);
14710528Samurai}
14810528Samurai
14910528Samuraivoid
15010528SamuraiCleanup(excode)
15110528Samuraiint excode;
15210528Samurai{
15310528Samurai
15410528Samurai  OsLinkdown();
1556059Samurai  OsCloseLink(1);
1566059Samurai  sleep(1);
15711336Samurai  if (mode & MODE_AUTO) {
1586059Samurai    DeleteIfRoutes(1);
15911336Samurai    unlink(pid_filename);
16011336Samurai  }
1616059Samurai  OsInterfaceDown(1);
16215738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n");
1636059Samurai  LogClose();
1646059Samurai  if (server > 0)
1656059Samurai    close(server);
16610528Samurai  TtyOldMode();
1676059Samurai
1686059Samurai  exit(excode);
1696059Samurai}
1706059Samurai
1716059Samuraistatic void
17214930SacheHangup(signo)
17314930Sacheint signo;
1746059Samurai{
17517044Sache  if (signo == SIGSEGV) {
17617044Sache	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
17717044Sache	LogClose();
17817044Sache	abort();
17917044Sache  }
18015738Sphk  LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
1816059Samurai  Cleanup(EX_HANGUP);
1826059Samurai}
1836059Samurai
1846059Samuraistatic void
18514930SacheCloseSession(signo)
18614930Sacheint signo;
1876059Samurai{
18815738Sphk  LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
1896059Samurai  LcpClose();
1906059Samurai  Cleanup(EX_TERM);
1916059Samurai}
1926059Samurai
19310528Samurai
19410528Samuraistatic void
19510528SamuraiTerminalCont()
19610528Samurai{
19710528Samurai  (void)signal(SIGCONT, SIG_DFL);
19810528Samurai  (void)signal(SIGTSTP, TerminalStop);
19910528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
20010528Samurai}
20110528Samurai
20210528Samuraistatic void
20310528SamuraiTerminalStop(signo)
20410528Samuraiint signo;
20510528Samurai{
20610528Samurai  (void)signal(SIGCONT, TerminalCont);
20710528Samurai  TtyOldMode();
20810528Samurai  signal(SIGTSTP, SIG_DFL);
20910528Samurai  kill(getpid(), signo);
21010528Samurai}
21110528Samurai
21210528Samurai
2136059Samuraivoid
2146059SamuraiUsage()
2156059Samurai{
21620120Snate  fprintf(stderr,
21720120Snate          "Usage: ppp [-auto | -direct | -dedicated | -ddial ] [system]\n");
2186059Samurai  exit(EX_START);
2196059Samurai}
2206059Samurai
2216059Samuraivoid
2226059SamuraiProcessArgs(int argc, char **argv)
2236059Samurai{
2246059Samurai  int optc;
2256059Samurai  char *cp;
2266059Samurai
2276059Samurai  optc = 0;
2286059Samurai  while (argc > 0 && **argv == '-') {
2296059Samurai    cp = *argv + 1;
2306059Samurai    if (strcmp(cp, "auto") == 0)
2316059Samurai      mode |= MODE_AUTO;
2326059Samurai    else if (strcmp(cp, "direct") == 0)
2336059Samurai      mode |= MODE_DIRECT;
2346059Samurai    else if (strcmp(cp, "dedicated") == 0)
2356059Samurai      mode |= MODE_DEDICATED;
23620120Snate    else if (strcmp(cp, "ddial") == 0)
23720120Snate      mode |= MODE_DDIAL|MODE_AUTO;
2386059Samurai    else
2396059Samurai      Usage();
2406059Samurai    optc++;
2416059Samurai    argv++; argc--;
2426059Samurai  }
2436059Samurai  if (argc > 1) {
2446059Samurai    fprintf(stderr, "specify only one system label.\n");
2456059Samurai    exit(EX_START);
2466059Samurai  }
2476059Samurai  if (argc == 1) dstsystem = *argv;
2486059Samurai
2496059Samurai  if (optc > 1) {
2506059Samurai    fprintf(stderr, "specify only one mode.\n");
2516059Samurai    exit(EX_START);
2526059Samurai  }
2536059Samurai}
2546059Samurai
2556059Samuraistatic void
2566059SamuraiGreetings()
2576059Samurai{
2586059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2596059Samurai  fflush(stdout);
2606059Samurai}
2616059Samurai
2626059Samuraivoid
2636059Samuraimain(argc, argv)
2646059Samuraiint argc;
2656059Samuraichar **argv;
2666059Samurai{
2676059Samurai  int tunno;
2686059Samurai
2696059Samurai  argc--; argv++;
2706059Samurai
2716059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2726059Samurai  netfd = -1;
2736059Samurai  ProcessArgs(argc, argv);
2746059Samurai  Greetings();
2756059Samurai  GetUid();
2766059Samurai  IpcpDefAddress();
2776059Samurai
2786059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
2796059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
2806059Samurai  }
2816059Samurai
2826059Samurai  if (LogOpen())
2836059Samurai    exit(EX_START);
2846059Samurai
2856735Samurai  switch ( LocalAuthInit() ) {
2866735Samurai    case NOT_FOUND:
2876764Samurai    	fprintf(stderr,LAUTH_M1);
2886764Samurai    	fprintf(stderr,LAUTH_M2);
2896764Samurai	fflush (stderr);
2906764Samurai	/* Fall down */
2916764Samurai    case VALID:
2926735Samurai	VarLocalAuth = LOCAL_AUTH;
2936735Samurai	break;
2946735Samurai    default:
2956735Samurai	break;
2966735Samurai  }
2976735Samurai
2986059Samurai  if (OpenTunnel(&tunno) < 0) {
2996059Samurai    perror("open_tun");
3006059Samurai    exit(EX_START);
3016059Samurai  }
3026059Samurai
3036059Samurai  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
3046059Samurai    mode &= ~MODE_INTER;
3056059Samurai  if (mode & MODE_INTER) {
3066059Samurai    printf("Interactive mode\n");
3076059Samurai    netfd = 0;
3086059Samurai  } else if (mode & MODE_AUTO) {
30920120Snate    printf("Automatic Dialer mode\n");
3106059Samurai    if (dstsystem == NULL) {
31120120Snate      fprintf(stderr,
31220120Snate              "Destination system must be specified in auto or ddial mode.\n");
3136059Samurai      exit(EX_START);
3146059Samurai    }
3156059Samurai  }
3166059Samurai
3176735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
3186059Samurai
3196059Samurai  signal(SIGHUP, Hangup);
3206059Samurai  signal(SIGTERM, CloseSession);
3216059Samurai  signal(SIGINT, CloseSession);
32210528Samurai  signal(SIGQUIT, CloseSession);
3236735Samurai#ifdef SIGSEGV
3246059Samurai  signal(SIGSEGV, Hangup);
3256735Samurai#endif
3266735Samurai#ifdef SIGPIPE
3276735Samurai  signal(SIGPIPE, Hangup);
3286735Samurai#endif
3296735Samurai#ifdef SIGALRM
3306735Samurai  signal(SIGALRM, SIG_IGN);
3316735Samurai#endif
33210528Samurai  if(mode & MODE_INTER)
33310528Samurai    {
33410528Samurai#ifdef SIGTSTP
33510528Samurai      signal(SIGTSTP, TerminalStop);
33610528Samurai#endif
33710528Samurai#ifdef SIGTTIN
33810528Samurai      signal(SIGTTIN, TerminalStop);
33910528Samurai#endif
34010528Samurai#ifdef SIGTTOU
34110528Samurai      signal(SIGTTOU, SIG_IGN);
34210528Samurai#endif
34310528Samurai    }
3446059Samurai
3456059Samurai  if (dstsystem) {
3466059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
3476059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
3486059Samurai      Cleanup(EX_START);
3496059Samurai    }
3506059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
35120120Snate      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
3526059Samurai      Cleanup(EX_START);
3536059Samurai    }
3546059Samurai  }
3556059Samurai  if (mode & MODE_DIRECT)
3566059Samurai    printf("Packet mode enabled.\n");
3576059Samurai
3586059Samurai#ifdef notdef
3596059Samurai  if (mode & MODE_AUTO) {
3606059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3616059Samurai  }
3626059Samurai#endif
3636059Samurai
3646059Samurai  if (!(mode & MODE_INTER)) {
3656059Samurai     int port = SERVER_PORT + tunno;
3666059Samurai    /*
3676059Samurai     *  Create server socket and listen at there.
3686059Samurai     */
3696059Samurai    server = socket(PF_INET, SOCK_STREAM, 0);
3706059Samurai    if (server < 0) {
3716059Samurai      perror("socket");
3726059Samurai      Cleanup(EX_SOCK);
3736059Samurai    }
3746059Samurai    ifsin.sin_family = AF_INET;
3756059Samurai    ifsin.sin_addr.s_addr = INADDR_ANY;
3766059Samurai    ifsin.sin_port = htons(port);
3776059Samurai    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
3786059Samurai      perror("bind");
3796059Samurai      if (errno == EADDRINUSE)
3806059Samurai	fprintf(stderr, "Wait for a while, then try again.\n");
3816059Samurai      Cleanup(EX_SOCK);
3826059Samurai    }
3836059Samurai    listen(server, 5);
3846059Samurai
3856059Samurai    DupLog();
3866059Samurai    if (!(mode & MODE_DIRECT)) {
38711336Samurai      int fd;
38811336Samurai      char pid[32];
38911336Samurai
3906059Samurai      if (fork())
3916059Samurai        exit(0);
39211336Samurai
39311336Samurai      snprintf(pid_filename, sizeof (pid_filename), "%s/PPP.%s",
39411336Samurai		  _PATH_VARRUN, dstsystem);
39511336Samurai      unlink(pid_filename);
39620120Snate      sprintf(pid, "%d\n", (int)getpid());
39711336Samurai
39811336Samurai      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
39911336Samurai      {
40011336Samurai	  write(fd, pid, strlen(pid));
40111336Samurai	  close(fd);
40211336Samurai      }
4036059Samurai    }
40415738Sphk    LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
4056059Samurai#ifdef DOTTYINIT
4066735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
4076059Samurai#else
4086059Samurai    if (mode & MODE_DIRECT) {
4096059Samurai#endif
4106059Samurai      TtyInit();
4116059Samurai    } else {
41214436Sache      int fd;
41314436Sache
4146059Samurai      setsid();			/* detach control tty */
41514436Sache      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
41614436Sache	(void)dup2(fd, STDIN_FILENO);
41714436Sache	(void)dup2(fd, STDOUT_FILENO);
41814436Sache	(void)dup2(fd, STDERR_FILENO);
41914436Sache	if (fd > 2)
42014436Sache		(void)close (fd);
42114436Sache      }
4226059Samurai    }
4236059Samurai  } else {
4246059Samurai    server = -1;
4256059Samurai    TtyInit();
42610528Samurai    TtyCommandMode(1);
4276059Samurai  }
42815738Sphk  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
4296059Samurai
4306059Samurai
4316059Samurai  do
4326059Samurai   DoLoop();
4336059Samurai  while (mode & MODE_DEDICATED);
4346059Samurai
4356059Samurai  Cleanup(EX_DONE);
4366059Samurai}
4376059Samurai
4386059Samurai/*
4396059Samurai *  Turn into packet mode, where we speek PPP.
4406059Samurai */
4416059Samuraivoid
4426059SamuraiPacketMode()
4436059Samurai{
4446059Samurai  if (RawModem(modem) < 0) {
4456059Samurai    fprintf(stderr, "Not connected.\r\n");
4466059Samurai    return;
4476059Samurai  }
4486059Samurai
4496059Samurai  AsyncInit();
4506059Samurai  VjInit();
4516059Samurai  LcpInit();
4526059Samurai  IpcpInit();
4536059Samurai  CcpInit();
4546059Samurai  LcpUp();
4556059Samurai
4566059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
4576059Samurai    LcpOpen(OPEN_ACTIVE);
4586059Samurai  else
4596059Samurai    LcpOpen(VarOpenMode);
4606059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
46110528Samurai    TtyCommandMode(1);
4626059Samurai    fprintf(stderr, "Packet mode.\r\n");
46318885Sjkh    aft_cmd = 1;
4646059Samurai  }
4656059Samurai}
4666059Samurai
4676059Samuraistatic void
4686059SamuraiShowHelp()
4696059Samurai{
47010528Samurai  fprintf(stderr, "The following commands are available:\r\n");
4716059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
47214418Sache  fprintf(stderr, " ~-\tDecrease log level\r\n");
47314418Sache  fprintf(stderr, " ~+\tIncrease log level\r\n");
4746059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
47514418Sache  fprintf(stderr, " ~?\tThis help\r\n");
4766059Samurai}
4776059Samurai
4786059Samuraistatic void
4796059SamuraiReadTty()
4806059Samurai{
4816059Samurai  int n;
4826059Samurai  char ch;
4836059Samurai  static int ttystate;
4846059Samurai#define MAXLINESIZE 200
4856059Samurai  char linebuff[MAXLINESIZE];
4866059Samurai
4876059Samurai#ifdef DEBUG
4886059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
4896059Samurai#endif
4906059Samurai  if (!TermMode) {
4916059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
49218885Sjkh    aft_cmd = 1;
4936735Samurai    if (n > 0) {
4946059Samurai      DecodeCommand(linebuff, n, 1);
4956735Samurai    } else {
4966059Samurai#ifdef DEBUG
4976059Samurai      logprintf("connection closed.\n");
4986059Samurai#endif
4996059Samurai      close(netfd);
5006059Samurai      netfd = -1;
5016059Samurai      mode &= ~MODE_INTER;
5026059Samurai    }
5036059Samurai    return;
5046059Samurai  }
5056059Samurai
5066059Samurai  /*
5076059Samurai   *  We are in terminal mode, decode special sequences
5086059Samurai   */
5096059Samurai  n = read(0, &ch, 1);
5106059Samurai#ifdef DEBUG
5116059Samurai  logprintf("got %d bytes\n", n);
5126059Samurai#endif
5136059Samurai
5146059Samurai  if (n > 0) {
5156059Samurai    switch (ttystate) {
5166059Samurai    case 0:
5176059Samurai      if (ch == '~')
5186059Samurai	ttystate++;
5196059Samurai      else
5206059Samurai	write(modem, &ch, n);
5216059Samurai      break;
5226059Samurai    case 1:
5236059Samurai      switch (ch) {
5246059Samurai      case '?':
5256059Samurai	ShowHelp();
5266059Samurai	break;
5276059Samurai      case '-':
5286059Samurai	if (loglevel > 0) {
5296059Samurai	  loglevel--;
5306059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5316059Samurai	}
5326059Samurai	break;
5336059Samurai      case '+':
5346059Samurai	loglevel++;
5356059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5366059Samurai	break;
5376059Samurai#ifdef DEBUG
5386059Samurai      case 'm':
5396059Samurai	ShowMemMap();
5406059Samurai	break;
5416059Samurai#endif
5426059Samurai      case 'p':
5436059Samurai	/*
5446059Samurai	 * XXX: Should check carrier.
5456059Samurai	 */
5466059Samurai	if (LcpFsm.state <= ST_CLOSED) {
5476059Samurai	  VarOpenMode = OPEN_ACTIVE;
5486059Samurai	  PacketMode();
5496059Samurai	}
5506059Samurai	break;
5516059Samurai#ifdef DEBUG
5526059Samurai      case 't':
5536059Samurai	ShowTimers();
5546059Samurai	break;
5556059Samurai#endif
5566059Samurai      case '.':
5576059Samurai	TermMode = 1;
55810528Samurai	TtyCommandMode(1);
5596059Samurai	break;
5606059Samurai      default:
5616059Samurai	if (write(modem, &ch, n) < 0)
5626059Samurai	  fprintf(stderr, "err in write.\r\n");
5636059Samurai	break;
5646059Samurai      }
5656059Samurai      ttystate = 0;
5666059Samurai      break;
5676059Samurai    }
5686059Samurai  }
5696059Samurai}
5706059Samurai
5716059Samurai
5726059Samurai/*
5736059Samurai *  Here, we'll try to detect HDLC frame
5746059Samurai */
5756059Samurai
5766059Samuraistatic char *FrameHeaders[] = {
5776735Samurai  "\176\377\003\300\041",
5786735Samurai  "\176\377\175\043\300\041",
5796735Samurai  "\176\177\175\043\100\041",
5806735Samurai  "\176\175\337\175\043\300\041",
5816735Samurai  "\176\175\137\175\043\100\041",
5826059Samurai  NULL,
5836059Samurai};
5846059Samurai
5856059Samuraiu_char *
5866059SamuraiHdlcDetect(cp, n)
5876059Samuraiu_char *cp;
5886059Samuraiint n;
5896059Samurai{
5906735Samurai  char *ptr, *fp, **hp;
5916059Samurai
5926059Samurai  cp[n] = '\0';	/* be sure to null terminated */
5936059Samurai  ptr = NULL;
5946059Samurai  for (hp = FrameHeaders; *hp; hp++) {
5956735Samurai    fp = *hp;
5966735Samurai    if (DEV_IS_SYNC)
5976735Samurai      fp++;
59813389Sphk    ptr = strstr((char *)cp, fp);
59913389Sphk    if (ptr)
6006059Samurai      break;
6016059Samurai  }
6026059Samurai  return((u_char *)ptr);
6036059Samurai}
6046059Samurai
6056059Samuraistatic struct pppTimer RedialTimer;
6066059Samurai
6076059Samuraistatic void
6086059SamuraiRedialTimeout()
6096059Samurai{
6106059Samurai  StopTimer(&RedialTimer);
61115738Sphk  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
6126059Samurai}
6136059Samurai
6146059Samuraistatic void
6156059SamuraiStartRedialTimer()
6166059Samurai{
6176059Samurai  StopTimer(&RedialTimer);
61811336Samurai
61911336Samurai  if (VarRedialTimeout) {
62015738Sphk    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
62111336Samurai    RedialTimer.state = TIMER_STOPPED;
62211336Samurai
62311336Samurai    if (VarRedialTimeout > 0)
62411336Samurai	RedialTimer.load = VarRedialTimeout * SECTICKS;
62511336Samurai    else
62611336Samurai	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
62711336Samurai
62811336Samurai    RedialTimer.func = RedialTimeout;
62911336Samurai    StartTimer(&RedialTimer);
63011336Samurai  }
6316059Samurai}
6326059Samurai
6336059Samurai
6346059Samuraistatic void
6356059SamuraiDoLoop()
6366059Samurai{
6376059Samurai  fd_set rfds, wfds, efds;
6386059Samurai  int pri, i, n, wfd;
6396059Samurai  struct sockaddr_in hisaddr;
6406059Samurai  struct timeval timeout, *tp;
6416059Samurai  int ssize = sizeof(hisaddr);
6426059Samurai  u_char *cp;
6436059Samurai  u_char rbuff[MAX_MRU];
6447001Samurai  int dial_up;
64511336Samurai  int tries;
6469448Samurai  int qlen;
64710528Samurai  pid_t pgroup;
6486059Samurai
64910528Samurai  pgroup = getpgrp();
65010528Samurai
6516059Samurai  if (mode & MODE_DIRECT) {
6526059Samurai    modem = OpenModem(mode);
65315738Sphk    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
65418885Sjkh    fflush(stderr);
6556059Samurai    PacketMode();
6566059Samurai  } else if (mode & MODE_DEDICATED) {
6576059Samurai    if (!modem)
6586059Samurai      modem = OpenModem(mode);
6596059Samurai  }
6606059Samurai
6616059Samurai  fflush(stdout);
6626059Samurai
6637001Samurai  timeout.tv_sec = 0;
6646059Samurai  timeout.tv_usec = 0;
6656059Samurai
6667001Samurai  dial_up = FALSE;			/* XXXX */
66711336Samurai  tries = 0;
6686059Samurai  for (;;) {
6696059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
6707001Samurai
67120120Snate    /*
67220120Snate     * If the link is down and we're in DDIAL mode, bring it back
67320120Snate     * up.
67420120Snate     */
67520120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
67620120Snate        dial_up = TRUE;
67720120Snate
6787001Samurai   /*
6797001Samurai    * If Ip packet for output is enqueued and require dial up,
6807001Samurai    * Just do it!
6817001Samurai    */
6827001Samurai    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
6837001Samurai#ifdef DEBUG
6847001Samurai      logprintf("going to dial: modem = %d\n", modem);
6857001Samurai#endif
68611336Samurai      modem = OpenModem(mode);
68711336Samurai      if (modem < 0) {
68811336Samurai	modem = 0;	       /* Set intial value for next OpenModem */
68911336Samurai	StartRedialTimer();
69011336Samurai      } else {
69111336Samurai	tries++;
69215738Sphk	LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
69311336Samurai	if (DialModem()) {
69411336Samurai	  sleep(1);	       /* little pause to allow peer starts */
69511336Samurai	  ModemTimeout();
69611336Samurai	  PacketMode();
69711336Samurai	  dial_up = FALSE;
69811336Samurai	  tries = 0;
69911336Samurai	} else {
70011336Samurai	  CloseModem();
70111336Samurai	  /* Dial failed. Keep quite during redial wait period. */
70211336Samurai	  StartRedialTimer();
70311336Samurai
70411336Samurai	  if (VarDialTries && tries >= VarDialTries) {
70511336Samurai	      dial_up = FALSE;
70611336Samurai	      tries = 0;
70711336Samurai	  }
70811336Samurai	}
70911336Samurai      }
7107001Samurai    }
7119448Samurai    qlen = ModemQlen();
71213733Sdfr
71313733Sdfr    if (qlen == 0) {
71413733Sdfr      IpStartOutput();
71513733Sdfr      qlen = ModemQlen();
71613733Sdfr    }
71713733Sdfr
7187001Samurai    if (modem) {
7197001Samurai      FD_SET(modem, &rfds);
7207001Samurai      FD_SET(modem, &efds);
7219448Samurai      if (qlen > 0) {
7227001Samurai	FD_SET(modem, &wfds);
7237001Samurai      }
7247001Samurai    }
7256059Samurai    if (server > 0) FD_SET(server, &rfds);
7266059Samurai
7276059Samurai    /*  *** IMPORTANT ***
7286059Samurai     *
7296059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
7306059Samurai     *	This value must be chosen with great care. If this values is
7316059Samurai     *  too big, it results loss of characters from modem and poor responce.
7326059Samurai     *  If this values is too small, ppp process eats many CPU time.
7336059Samurai     */
7346735Samurai#ifndef SIGALRM
7356059Samurai    usleep(TICKUNIT);
7366059Samurai    TimerService();
7376735Samurai#endif
73810877Sbde
73910877Sbde    /* If there are aren't many packets queued, look for some more. */
74010877Sbde    if (qlen < 20)
74110877Sbde      FD_SET(tun_in, &rfds);
74210877Sbde
7436059Samurai    if (netfd > -1) {
7446059Samurai      FD_SET(netfd, &rfds);
7456059Samurai      FD_SET(netfd, &efds);
7466059Samurai    }
7477001Samurai
7486735Samurai#ifndef SIGALRM
7496059Samurai    /*
7507001Samurai     *  Normally, select() will not block because modem is writable.
7517001Samurai     *  In AUTO mode, select will block until we find packet from tun
7526059Samurai     */
7536059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
7546059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7556735Samurai#else
7568857Srgrimes    /*
7577001Samurai     * When SIGALRM timer is running, a select function will be
7588857Srgrimes     * return -1 and EINTR after a Time Service signal hundler
75911336Samurai     * is done.  If the redial timer is not running and we are
76011336Samurai     * trying to dial, poll with a 0 value timer.
7617001Samurai     */
76211336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
76311336Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7646735Samurai#endif
7657001Samurai    if ( i == 0 ) {
7667001Samurai        continue;
7676059Samurai    }
7686735Samurai
7697001Samurai    if ( i < 0 ) {
7707001Samurai       if ( errno == EINTR ) {
77111336Samurai          continue;            /* Got SIGALRM, Do check a queue for dialing */
7727001Samurai       }
7737001Samurai       perror("select");
7747001Samurai       break;
7758857Srgrimes    }
7767001Samurai
7776059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
7786059Samurai      logprintf("Exception detected.\n");
7796059Samurai      break;
7806059Samurai    }
7816059Samurai
7826059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
7836059Samurai#ifdef DEBUG
7846059Samurai      logprintf("connected to client.\n");
7856059Samurai#endif
7866059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
7876059Samurai      if (netfd > 0) {
7886059Samurai	write(wfd, "already in use.\n", 16);
7896059Samurai	close(wfd);
7906059Samurai	continue;
7916059Samurai      } else
7926059Samurai	netfd = wfd;
7936059Samurai      if (dup2(netfd, 1) < 0)
7946059Samurai	perror("dup2");
7956059Samurai      mode |= MODE_INTER;
7966059Samurai      Greetings();
7976764Samurai      switch ( LocalAuthInit() ) {
7986764Samurai         case NOT_FOUND:
7996764Samurai    	    fprintf(stdout,LAUTH_M1);
8006764Samurai    	    fprintf(stdout,LAUTH_M2);
8016764Samurai            fflush(stdout);
8026764Samurai	    /* Fall down */
8036764Samurai         case VALID:
8046764Samurai	    VarLocalAuth = LOCAL_AUTH;
8056764Samurai	    break;
8066764Samurai         default:
8076764Samurai	    break;
8086764Samurai      }
8096059Samurai      (void) IsInteractive();
8106059Samurai      Prompt(0);
8116059Samurai    }
8126059Samurai
81310528Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) &&
81410858Samurai	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
8156059Samurai      /* something to read from tty */
8166059Samurai      ReadTty();
8176059Samurai    }
8186059Samurai    if (modem) {
8196059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
8206059Samurai	 ModemStartOutput(modem);
8216059Samurai      }
8226059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
8236735Samurai	if (LcpFsm.state <= ST_CLOSED)
8246735Samurai	  usleep(10000);
8256059Samurai	n = read(modem, rbuff, sizeof(rbuff));
8266059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
8276059Samurai	  DownConnection();
8286059Samurai	} else
8296059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
8306059Samurai
8316059Samurai	if (LcpFsm.state <= ST_CLOSED) {
8326059Samurai	  /*
8336059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
8346059Samurai	   */
8356059Samurai	  if (!(mode & MODE_DEDICATED)) {
8366059Samurai	    cp = HdlcDetect(rbuff, n);
8376059Samurai	    if (cp) {
8386059Samurai	      /*
8396059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
8406059Samurai	       */
8416059Samurai	      if (cp != rbuff) {
8426059Samurai	        write(1, rbuff, cp - rbuff);
8436059Samurai	        write(1, "\r\n", 2);
8446059Samurai	      }
8456059Samurai	      PacketMode();
8466059Samurai#ifdef notdef
8476059Samurai	      AsyncInput(cp, n - (cp - rbuff));
8486059Samurai#endif
8496059Samurai	    } else
8506059Samurai	      write(1, rbuff, n);
8516059Samurai	  }
8526059Samurai	} else {
8536059Samurai	  if (n > 0)
8546059Samurai	    AsyncInput(rbuff, n);
8556059Samurai#ifdef notdef
8566059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
8576059Samurai#endif
8586059Samurai	}
8596059Samurai      }
8606059Samurai    }
8617001Samurai
8626059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
8636059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
8646059Samurai      if (n < 0) {
8656059Samurai	perror("read from tun");
8666059Samurai	continue;
8676059Samurai      }
8686059Samurai      /*
8696059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
8706059Samurai       *  device until IPCP is opened.
8716059Samurai       */
8726059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
8737001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
8746059Samurai	if (pri >= 0) {
8756059Samurai	  IpEnqueue(pri, rbuff, n);
8767001Samurai          dial_up = TRUE;		/* XXX */
8776059Samurai	}
8786059Samurai	continue;
8796059Samurai      }
8807001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
8816059Samurai      if (pri >= 0)
8826059Samurai	IpEnqueue(pri, rbuff, n);
8836059Samurai    }
8846059Samurai  }
8856059Samurai  logprintf("job done.\n");
8866059Samurai}
887