main.c revision 13389
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 *
2013389Sphk * $Id: main.c,v 1.12 1996/01/10 21:27:53 phk 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>
356059Samurai#include <sys/socket.h>
366059Samurai#include <arpa/inet.h>
376059Samurai#include "modem.h"
386059Samurai#include "os.h"
396059Samurai#include "hdlc.h"
4013389Sphk#include "ccp.h"
416059Samurai#include "lcp.h"
426059Samurai#include "ipcp.h"
436059Samurai#include "vars.h"
446735Samurai#include "auth.h"
457001Samurai#include "filter.h"
4613389Sphk#include "systems.h"
4713389Sphk#include "ip.h"
486059Samurai
496764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
509410Sasami#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
516764Samurai
526735Samurai#ifndef O_NONBLOCK
536735Samurai#ifdef O_NDELAY
546735Samurai#define	O_NONBLOCK O_NDELAY
556735Samurai#endif
566735Samurai#endif
576735Samurai
586059Samuraiextern void VjInit(), AsyncInit();
596059Samuraiextern void AsyncInput(), IpOutput();
606059Samuraiextern int  SelectSystem();
616059Samurai
626059Samuraiextern void DecodeCommand(), Prompt();
636059Samuraiextern int IsInteractive();
646059Samuraiextern struct in_addr ifnetmask;
656059Samuraistatic void DoLoop(void);
6610528Samuraistatic void TerminalStop();
676059Samurai
686059Samuraistatic struct termios oldtio;		/* Original tty mode */
696059Samuraistatic struct termios comtio;		/* Command level tty mode */
706059Samuraistatic int TermMode;
7113379Sphkstatic int server;
726059Samuraistruct sockaddr_in ifsin;
7311336Samuraichar pid_filename[128];
746059Samurai
756059Samuraistatic void
766059SamuraiTtyInit()
776059Samurai{
786059Samurai  struct termios newtio;
796059Samurai  int stat;
806059Samurai
816059Samurai  stat = fcntl(0, F_GETFL, 0);
826059Samurai  stat |= O_NONBLOCK;
836059Samurai  fcntl(0, F_SETFL, stat);
846059Samurai  newtio = oldtio;
856059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
866059Samurai  newtio.c_iflag = 0;
876059Samurai  newtio.c_oflag &= ~OPOST;
886059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
896059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
906059Samurai  newtio.c_cc[VMIN] = 1;
916059Samurai  newtio.c_cc[VTIME] = 0;
926059Samurai  newtio.c_cflag |= CS8;
936735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
946059Samurai  comtio = newtio;
956059Samurai}
966059Samurai
976059Samurai/*
986059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
996059Samurai */
10010528Samuraivoid
10110528SamuraiTtyCommandMode(prompt)
10210528Samuraiint prompt;
1036059Samurai{
1046059Samurai  struct termios newtio;
1056059Samurai  int stat;
1066059Samurai
1076059Samurai  if (!(mode & MODE_INTER))
1086059Samurai    return;
1096735Samurai  tcgetattr(0, &newtio);
11010528Samurai  newtio.c_lflag |= (ECHO|ISIG|ICANON);
1116059Samurai  newtio.c_iflag = oldtio.c_iflag;
1126059Samurai  newtio.c_oflag |= OPOST;
1136735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1146059Samurai  stat = fcntl(0, F_GETFL, 0);
1156059Samurai  stat |= O_NONBLOCK;
1166059Samurai  fcntl(0, F_SETFL, stat);
1176059Samurai  TermMode = 0;
11810528Samurai  if(prompt) Prompt(0);
1196059Samurai}
1206059Samurai
1216059Samurai/*
1226059Samurai * Set tty into terminal mode which is used while we invoke term command.
1236059Samurai */
1246059Samuraivoid
1256059SamuraiTtyTermMode()
1266059Samurai{
1276059Samurai  int stat;
1286059Samurai
1296735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1306059Samurai  stat = fcntl(0, F_GETFL, 0);
1316059Samurai  stat &= ~O_NONBLOCK;
1326059Samurai  fcntl(0, F_SETFL, stat);
1336059Samurai  TermMode = 1;
1346059Samurai}
1356059Samurai
1366059Samuraivoid
13710528SamuraiTtyOldMode()
1386059Samurai{
1396059Samurai  int stat;
1406059Samurai
1416059Samurai  stat = fcntl(0, F_GETFL, 0);
1426059Samurai  stat &= ~O_NONBLOCK;
1436059Samurai  fcntl(0, F_SETFL, stat);
1446735Samurai  tcsetattr(0, TCSANOW, &oldtio);
14510528Samurai}
14610528Samurai
14710528Samuraivoid
14810528SamuraiCleanup(excode)
14910528Samuraiint excode;
15010528Samurai{
15110528Samurai
15210528Samurai  OsLinkdown();
1536059Samurai  OsCloseLink(1);
1546059Samurai  sleep(1);
15511336Samurai  if (mode & MODE_AUTO) {
1566059Samurai    DeleteIfRoutes(1);
15711336Samurai    unlink(pid_filename);
15811336Samurai  }
1596059Samurai  OsInterfaceDown(1);
1606059Samurai  LogPrintf(LOG_PHASE, "PPP Terminated.\n");
1616059Samurai  LogClose();
1626059Samurai  if (server > 0)
1636059Samurai    close(server);
16410528Samurai  TtyOldMode();
1656059Samurai
1666059Samurai  exit(excode);
1676059Samurai}
1686059Samurai
1696059Samuraistatic void
1706059SamuraiHangup()
1716059Samurai{
1726059Samurai  LogPrintf(LOG_PHASE, "SIGHUP\n");
1736059Samurai  Cleanup(EX_HANGUP);
1746059Samurai}
1756059Samurai
1766059Samuraistatic void
1776059SamuraiCloseSession()
1786059Samurai{
1796059Samurai  LogPrintf(LOG_PHASE, "SIGTERM\n");
1806059Samurai  LcpClose();
1816059Samurai  Cleanup(EX_TERM);
1826059Samurai}
1836059Samurai
18410528Samurai
18510528Samuraistatic void
18610528SamuraiTerminalCont()
18710528Samurai{
18810528Samurai  (void)signal(SIGCONT, SIG_DFL);
18910528Samurai  (void)signal(SIGTSTP, TerminalStop);
19010528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
19110528Samurai}
19210528Samurai
19310528Samuraistatic void
19410528SamuraiTerminalStop(signo)
19510528Samuraiint signo;
19610528Samurai{
19710528Samurai  (void)signal(SIGCONT, TerminalCont);
19810528Samurai  TtyOldMode();
19910528Samurai  signal(SIGTSTP, SIG_DFL);
20010528Samurai  kill(getpid(), signo);
20110528Samurai}
20210528Samurai
20310528Samurai
2046059Samuraivoid
2056059SamuraiUsage()
2066059Samurai{
20710528Samurai  fprintf(stderr, "Usage: ppp [-auto | -direct | -dedicated] [system]\n");
2086059Samurai  exit(EX_START);
2096059Samurai}
2106059Samurai
2116059Samuraivoid
2126059SamuraiProcessArgs(int argc, char **argv)
2136059Samurai{
2146059Samurai  int optc;
2156059Samurai  char *cp;
2166059Samurai
2176059Samurai  optc = 0;
2186059Samurai  while (argc > 0 && **argv == '-') {
2196059Samurai    cp = *argv + 1;
2206059Samurai    if (strcmp(cp, "auto") == 0)
2216059Samurai      mode |= MODE_AUTO;
2226059Samurai    else if (strcmp(cp, "direct") == 0)
2236059Samurai      mode |= MODE_DIRECT;
2246059Samurai    else if (strcmp(cp, "dedicated") == 0)
2256059Samurai      mode |= MODE_DEDICATED;
2266059Samurai    else
2276059Samurai      Usage();
2286059Samurai    optc++;
2296059Samurai    argv++; argc--;
2306059Samurai  }
2316059Samurai  if (argc > 1) {
2326059Samurai    fprintf(stderr, "specify only one system label.\n");
2336059Samurai    exit(EX_START);
2346059Samurai  }
2356059Samurai  if (argc == 1) dstsystem = *argv;
2366059Samurai
2376059Samurai  if (optc > 1) {
2386059Samurai    fprintf(stderr, "specify only one mode.\n");
2396059Samurai    exit(EX_START);
2406059Samurai  }
2416059Samurai}
2426059Samurai
2436059Samuraistatic void
2446059SamuraiGreetings()
2456059Samurai{
2466059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2476059Samurai  fflush(stdout);
2486059Samurai}
2496059Samurai
2506059Samuraivoid
2516059Samuraimain(argc, argv)
2526059Samuraiint argc;
2536059Samuraichar **argv;
2546059Samurai{
2556059Samurai  int tunno;
2566059Samurai
2576059Samurai  argc--; argv++;
2586059Samurai
2596059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2606059Samurai  netfd = -1;
2616059Samurai  ProcessArgs(argc, argv);
2626059Samurai  Greetings();
2636059Samurai  GetUid();
2646059Samurai  IpcpDefAddress();
2656059Samurai
2666059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
2676059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
2686059Samurai  }
2696059Samurai
2706059Samurai  if (LogOpen())
2716059Samurai    exit(EX_START);
2726059Samurai
2736735Samurai  switch ( LocalAuthInit() ) {
2746735Samurai    case NOT_FOUND:
2756764Samurai    	fprintf(stderr,LAUTH_M1);
2766764Samurai    	fprintf(stderr,LAUTH_M2);
2776764Samurai	fflush (stderr);
2786764Samurai	/* Fall down */
2796764Samurai    case VALID:
2806735Samurai	VarLocalAuth = LOCAL_AUTH;
2816735Samurai	break;
2826735Samurai    default:
2836735Samurai	break;
2846735Samurai  }
2856735Samurai
2866059Samurai  if (OpenTunnel(&tunno) < 0) {
2876059Samurai    perror("open_tun");
2886059Samurai    exit(EX_START);
2896059Samurai  }
2906059Samurai
2916059Samurai  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
2926059Samurai    mode &= ~MODE_INTER;
2936059Samurai  if (mode & MODE_INTER) {
2946059Samurai    printf("Interactive mode\n");
2956059Samurai    netfd = 0;
2966059Samurai  } else if (mode & MODE_AUTO) {
2976059Samurai    printf("Automatic mode\n");
2986059Samurai    if (dstsystem == NULL) {
2996059Samurai      fprintf(stderr, "Destination system must be specified in auto mode.\n");
3006059Samurai      exit(EX_START);
3016059Samurai    }
3026059Samurai  }
3036059Samurai
3046735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
3056059Samurai
3066059Samurai  signal(SIGHUP, Hangup);
3076059Samurai  signal(SIGTERM, CloseSession);
3086059Samurai  signal(SIGINT, CloseSession);
30910528Samurai  signal(SIGQUIT, CloseSession);
3106735Samurai#ifdef SIGSEGV
3116059Samurai  signal(SIGSEGV, Hangup);
3126735Samurai#endif
3136735Samurai#ifdef SIGPIPE
3146735Samurai  signal(SIGPIPE, Hangup);
3156735Samurai#endif
3166735Samurai#ifdef SIGALRM
3176735Samurai  signal(SIGALRM, SIG_IGN);
3186735Samurai#endif
31910528Samurai  if(mode & MODE_INTER)
32010528Samurai    {
32110528Samurai#ifdef SIGTSTP
32210528Samurai      signal(SIGTSTP, TerminalStop);
32310528Samurai#endif
32410528Samurai#ifdef SIGTTIN
32510528Samurai      signal(SIGTTIN, TerminalStop);
32610528Samurai#endif
32710528Samurai#ifdef SIGTTOU
32810528Samurai      signal(SIGTTOU, SIG_IGN);
32910528Samurai#endif
33010528Samurai    }
3316059Samurai
3326059Samurai  if (dstsystem) {
3336059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
3346059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
3356059Samurai      Cleanup(EX_START);
3366059Samurai    }
3376059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
3386059Samurai      fprintf(stderr, "Must specify dstaddr with auto mode.\n");
3396059Samurai      Cleanup(EX_START);
3406059Samurai    }
3416059Samurai  }
3426059Samurai  if (mode & MODE_DIRECT)
3436059Samurai    printf("Packet mode enabled.\n");
3446059Samurai
3456059Samurai#ifdef notdef
3466059Samurai  if (mode & MODE_AUTO) {
3476059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3486059Samurai  }
3496059Samurai#endif
3506059Samurai
3516059Samurai  if (!(mode & MODE_INTER)) {
3526059Samurai     int port = SERVER_PORT + tunno;
3536059Samurai    /*
3546059Samurai     *  Create server socket and listen at there.
3556059Samurai     */
3566059Samurai    server = socket(PF_INET, SOCK_STREAM, 0);
3576059Samurai    if (server < 0) {
3586059Samurai      perror("socket");
3596059Samurai      Cleanup(EX_SOCK);
3606059Samurai    }
3616059Samurai    ifsin.sin_family = AF_INET;
3626059Samurai    ifsin.sin_addr.s_addr = INADDR_ANY;
3636059Samurai    ifsin.sin_port = htons(port);
3646059Samurai    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
3656059Samurai      perror("bind");
3666059Samurai      if (errno == EADDRINUSE)
3676059Samurai	fprintf(stderr, "Wait for a while, then try again.\n");
3686059Samurai      Cleanup(EX_SOCK);
3696059Samurai    }
3706059Samurai    listen(server, 5);
3716059Samurai
3726059Samurai    DupLog();
3736059Samurai    if (!(mode & MODE_DIRECT)) {
37411336Samurai      int fd;
37511336Samurai      char pid[32];
37611336Samurai
3776059Samurai      if (fork())
3786059Samurai        exit(0);
37911336Samurai
38011336Samurai      snprintf(pid_filename, sizeof (pid_filename), "%s/PPP.%s",
38111336Samurai		  _PATH_VARRUN, dstsystem);
38211336Samurai      unlink(pid_filename);
38313389Sphk      sprintf(pid, "%lu\n", getpid());
38411336Samurai
38511336Samurai      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
38611336Samurai      {
38711336Samurai	  write(fd, pid, strlen(pid));
38811336Samurai	  close(fd);
38911336Samurai      }
3906059Samurai    }
3916059Samurai    LogPrintf(LOG_PHASE, "Listening at %d.\n", port);
3926059Samurai#ifdef DOTTYINIT
3936735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
3946059Samurai#else
3956059Samurai    if (mode & MODE_DIRECT) {
3966059Samurai#endif
3976059Samurai      TtyInit();
3986059Samurai    } else {
3996059Samurai      setsid();			/* detach control tty */
4006059Samurai    }
4016059Samurai  } else {
4026059Samurai    server = -1;
4036059Samurai    TtyInit();
40410528Samurai    TtyCommandMode(1);
4056059Samurai  }
4066059Samurai  LogPrintf(LOG_PHASE, "PPP Started.\n");
4076059Samurai
4086059Samurai
4096059Samurai  do
4106059Samurai   DoLoop();
4116059Samurai  while (mode & MODE_DEDICATED);
4126059Samurai
4136059Samurai  Cleanup(EX_DONE);
4146059Samurai}
4156059Samurai
4166059Samurai/*
4176059Samurai *  Turn into packet mode, where we speek PPP.
4186059Samurai */
4196059Samuraivoid
4206059SamuraiPacketMode()
4216059Samurai{
4226059Samurai  if (RawModem(modem) < 0) {
4236059Samurai    fprintf(stderr, "Not connected.\r\n");
4246059Samurai    return;
4256059Samurai  }
4266059Samurai
4276059Samurai  AsyncInit();
4286059Samurai  VjInit();
4296059Samurai  LcpInit();
4306059Samurai  IpcpInit();
4316059Samurai  CcpInit();
4326059Samurai  LcpUp();
4336059Samurai
4346059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
4356059Samurai    LcpOpen(OPEN_ACTIVE);
4366059Samurai  else
4376059Samurai    LcpOpen(VarOpenMode);
4386059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
43910528Samurai    TtyCommandMode(1);
4406059Samurai    fprintf(stderr, "Packet mode.\r\n");
4416059Samurai  }
4426059Samurai}
4436059Samurai
4446059Samuraistatic void
4456059SamuraiShowHelp()
4466059Samurai{
44710528Samurai  fprintf(stderr, "The following commands are available:\r\n");
4486059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
4496059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
4506059Samurai}
4516059Samurai
4526059Samuraistatic void
4536059SamuraiReadTty()
4546059Samurai{
4556059Samurai  int n;
4566059Samurai  char ch;
4576059Samurai  static int ttystate;
4586059Samurai#define MAXLINESIZE 200
4596059Samurai  char linebuff[MAXLINESIZE];
4606059Samurai
4616059Samurai#ifdef DEBUG
4626059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
4636059Samurai#endif
4646059Samurai  if (!TermMode) {
4656059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
4666735Samurai    if (n > 0) {
4676059Samurai      DecodeCommand(linebuff, n, 1);
4686735Samurai    } else {
4696059Samurai#ifdef DEBUG
4706059Samurai      logprintf("connection closed.\n");
4716059Samurai#endif
4726059Samurai      close(netfd);
4736059Samurai      netfd = -1;
4746059Samurai      mode &= ~MODE_INTER;
4756059Samurai    }
4766059Samurai    return;
4776059Samurai  }
4786059Samurai
4796059Samurai  /*
4806059Samurai   *  We are in terminal mode, decode special sequences
4816059Samurai   */
4826059Samurai  n = read(0, &ch, 1);
4836059Samurai#ifdef DEBUG
4846059Samurai  logprintf("got %d bytes\n", n);
4856059Samurai#endif
4866059Samurai
4876059Samurai  if (n > 0) {
4886059Samurai    switch (ttystate) {
4896059Samurai    case 0:
4906059Samurai      if (ch == '~')
4916059Samurai	ttystate++;
4926059Samurai      else
4936059Samurai	write(modem, &ch, n);
4946059Samurai      break;
4956059Samurai    case 1:
4966059Samurai      switch (ch) {
4976059Samurai      case '?':
4986059Samurai	ShowHelp();
4996059Samurai	break;
5006059Samurai      case '-':
5016059Samurai	if (loglevel > 0) {
5026059Samurai	  loglevel--;
5036059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5046059Samurai	}
5056059Samurai	break;
5066059Samurai      case '+':
5076059Samurai	loglevel++;
5086059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
5096059Samurai	break;
5106059Samurai#ifdef DEBUG
5116059Samurai      case 'm':
5126059Samurai	ShowMemMap();
5136059Samurai	break;
5146059Samurai#endif
5156059Samurai      case 'p':
5166059Samurai	/*
5176059Samurai	 * XXX: Should check carrier.
5186059Samurai	 */
5196059Samurai	if (LcpFsm.state <= ST_CLOSED) {
5206059Samurai	  VarOpenMode = OPEN_ACTIVE;
5216059Samurai	  PacketMode();
5226059Samurai	}
5236059Samurai	break;
5246059Samurai#ifdef DEBUG
5256059Samurai      case 't':
5266059Samurai	ShowTimers();
5276059Samurai	break;
5286059Samurai#endif
5296059Samurai      case '.':
5306059Samurai	TermMode = 1;
53110528Samurai	TtyCommandMode(1);
5326059Samurai	break;
5336059Samurai      default:
5346059Samurai	if (write(modem, &ch, n) < 0)
5356059Samurai	  fprintf(stderr, "err in write.\r\n");
5366059Samurai	break;
5376059Samurai      }
5386059Samurai      ttystate = 0;
5396059Samurai      break;
5406059Samurai    }
5416059Samurai  }
5426059Samurai}
5436059Samurai
5446059Samurai
5456059Samurai/*
5466059Samurai *  Here, we'll try to detect HDLC frame
5476059Samurai */
5486059Samurai
5496059Samuraistatic char *FrameHeaders[] = {
5506735Samurai  "\176\377\003\300\041",
5516735Samurai  "\176\377\175\043\300\041",
5526735Samurai  "\176\177\175\043\100\041",
5536735Samurai  "\176\175\337\175\043\300\041",
5546735Samurai  "\176\175\137\175\043\100\041",
5556059Samurai  NULL,
5566059Samurai};
5576059Samurai
5586059Samuraiu_char *
5596059SamuraiHdlcDetect(cp, n)
5606059Samuraiu_char *cp;
5616059Samuraiint n;
5626059Samurai{
5636735Samurai  char *ptr, *fp, **hp;
5646059Samurai
5656059Samurai  cp[n] = '\0';	/* be sure to null terminated */
5666059Samurai  ptr = NULL;
5676059Samurai  for (hp = FrameHeaders; *hp; hp++) {
5686735Samurai    fp = *hp;
5696735Samurai    if (DEV_IS_SYNC)
5706735Samurai      fp++;
57113389Sphk    ptr = strstr((char *)cp, fp);
57213389Sphk    if (ptr)
5736059Samurai      break;
5746059Samurai  }
5756059Samurai  return((u_char *)ptr);
5766059Samurai}
5776059Samurai
5786059Samuraistatic struct pppTimer RedialTimer;
5796059Samurai
5806059Samuraistatic void
5816059SamuraiRedialTimeout()
5826059Samurai{
5836059Samurai  StopTimer(&RedialTimer);
5846059Samurai  LogPrintf(LOG_PHASE, "Redialing timer expired.\n");
5856059Samurai}
5866059Samurai
5876059Samuraistatic void
5886059SamuraiStartRedialTimer()
5896059Samurai{
5906059Samurai  StopTimer(&RedialTimer);
59111336Samurai
59211336Samurai  if (VarRedialTimeout) {
59311336Samurai    LogPrintf(LOG_PHASE, "Enter pause for redialing.\n");
59411336Samurai    RedialTimer.state = TIMER_STOPPED;
59511336Samurai
59611336Samurai    if (VarRedialTimeout > 0)
59711336Samurai	RedialTimer.load = VarRedialTimeout * SECTICKS;
59811336Samurai    else
59911336Samurai	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
60011336Samurai
60111336Samurai    RedialTimer.func = RedialTimeout;
60211336Samurai    StartTimer(&RedialTimer);
60311336Samurai  }
6046059Samurai}
6056059Samurai
6066059Samurai
6076059Samuraistatic void
6086059SamuraiDoLoop()
6096059Samurai{
6106059Samurai  fd_set rfds, wfds, efds;
6116059Samurai  int pri, i, n, wfd;
6126059Samurai  struct sockaddr_in hisaddr;
6136059Samurai  struct timeval timeout, *tp;
6146059Samurai  int ssize = sizeof(hisaddr);
6156059Samurai  u_char *cp;
6166059Samurai  u_char rbuff[MAX_MRU];
6177001Samurai  int dial_up;
61811336Samurai  int tries;
6199448Samurai  int qlen;
62010528Samurai  pid_t pgroup;
6216059Samurai
62210528Samurai  pgroup = getpgrp();
62310528Samurai
6246059Samurai  if (mode & MODE_DIRECT) {
6256059Samurai    modem = OpenModem(mode);
6269448Samurai    LogPrintf(LOG_PHASE, "Packet mode enabled\n");
6276059Samurai    PacketMode();
6286059Samurai  } else if (mode & MODE_DEDICATED) {
6296059Samurai    if (!modem)
6306059Samurai      modem = OpenModem(mode);
6316059Samurai  }
6326059Samurai
6336059Samurai  fflush(stdout);
6346059Samurai
6357001Samurai  timeout.tv_sec = 0;
6366059Samurai  timeout.tv_usec = 0;
6376059Samurai
6387001Samurai  dial_up = FALSE;			/* XXXX */
63911336Samurai  tries = 0;
6406059Samurai  for (;;) {
6418857Srgrimes    if ( modem )
6427001Samurai	IpStartOutput();
6436059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
6447001Samurai
6457001Samurai   /*
6467001Samurai    * If Ip packet for output is enqueued and require dial up,
6477001Samurai    * Just do it!
6487001Samurai    */
6497001Samurai    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
6507001Samurai#ifdef DEBUG
6517001Samurai      logprintf("going to dial: modem = %d\n", modem);
6527001Samurai#endif
65311336Samurai      modem = OpenModem(mode);
65411336Samurai      if (modem < 0) {
65511336Samurai	modem = 0;	       /* Set intial value for next OpenModem */
65611336Samurai	StartRedialTimer();
65711336Samurai      } else {
65811336Samurai	tries++;
65911336Samurai	LogPrintf(LOG_CHAT, "Dial attempt %u\n", tries);
66011336Samurai	if (DialModem()) {
66111336Samurai	  sleep(1);	       /* little pause to allow peer starts */
66211336Samurai	  ModemTimeout();
66311336Samurai	  PacketMode();
66411336Samurai	  dial_up = FALSE;
66511336Samurai	  tries = 0;
66611336Samurai	} else {
66711336Samurai	  CloseModem();
66811336Samurai	  /* Dial failed. Keep quite during redial wait period. */
66911336Samurai	  StartRedialTimer();
67011336Samurai
67111336Samurai	  if (VarDialTries && tries >= VarDialTries) {
67211336Samurai	      dial_up = FALSE;
67311336Samurai	      tries = 0;
67411336Samurai	  }
67511336Samurai	}
67611336Samurai      }
6777001Samurai    }
6789448Samurai    qlen = ModemQlen();
6797001Samurai    if (modem) {
6807001Samurai      FD_SET(modem, &rfds);
6817001Samurai      FD_SET(modem, &efds);
6829448Samurai      if (qlen > 0) {
6837001Samurai	FD_SET(modem, &wfds);
6847001Samurai      }
6857001Samurai    }
6866059Samurai    if (server > 0) FD_SET(server, &rfds);
6876059Samurai
6886059Samurai    /*  *** IMPORTANT ***
6896059Samurai     *
6906059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
6916059Samurai     *	This value must be chosen with great care. If this values is
6926059Samurai     *  too big, it results loss of characters from modem and poor responce.
6936059Samurai     *  If this values is too small, ppp process eats many CPU time.
6946059Samurai     */
6956735Samurai#ifndef SIGALRM
6966059Samurai    usleep(TICKUNIT);
6976059Samurai    TimerService();
6986735Samurai#endif
69910877Sbde
70010877Sbde    /* If there are aren't many packets queued, look for some more. */
70110877Sbde    if (qlen < 20)
70210877Sbde      FD_SET(tun_in, &rfds);
70310877Sbde
7046059Samurai    if (netfd > -1) {
7056059Samurai      FD_SET(netfd, &rfds);
7066059Samurai      FD_SET(netfd, &efds);
7076059Samurai    }
7087001Samurai
7096735Samurai#ifndef SIGALRM
7106059Samurai    /*
7117001Samurai     *  Normally, select() will not block because modem is writable.
7127001Samurai     *  In AUTO mode, select will block until we find packet from tun
7136059Samurai     */
7146059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
7156059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7166735Samurai#else
7178857Srgrimes    /*
7187001Samurai     * When SIGALRM timer is running, a select function will be
7198857Srgrimes     * return -1 and EINTR after a Time Service signal hundler
72011336Samurai     * is done.  If the redial timer is not running and we are
72111336Samurai     * trying to dial, poll with a 0 value timer.
7227001Samurai     */
72311336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
72411336Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
7256735Samurai#endif
7267001Samurai    if ( i == 0 ) {
7277001Samurai        continue;
7286059Samurai    }
7296735Samurai
7307001Samurai    if ( i < 0 ) {
7317001Samurai       if ( errno == EINTR ) {
73211336Samurai          continue;            /* Got SIGALRM, Do check a queue for dialing */
7337001Samurai       }
7347001Samurai       perror("select");
7357001Samurai       break;
7368857Srgrimes    }
7377001Samurai
7386059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
7396059Samurai      logprintf("Exception detected.\n");
7406059Samurai      break;
7416059Samurai    }
7426059Samurai
7436059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
7446059Samurai#ifdef DEBUG
7456059Samurai      logprintf("connected to client.\n");
7466059Samurai#endif
7476059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
7486059Samurai      if (netfd > 0) {
7496059Samurai	write(wfd, "already in use.\n", 16);
7506059Samurai	close(wfd);
7516059Samurai	continue;
7526059Samurai      } else
7536059Samurai	netfd = wfd;
7546059Samurai      if (dup2(netfd, 1) < 0)
7556059Samurai	perror("dup2");
7566059Samurai      mode |= MODE_INTER;
7576059Samurai      Greetings();
7586764Samurai      switch ( LocalAuthInit() ) {
7596764Samurai         case NOT_FOUND:
7606764Samurai    	    fprintf(stdout,LAUTH_M1);
7616764Samurai    	    fprintf(stdout,LAUTH_M2);
7626764Samurai            fflush(stdout);
7636764Samurai	    /* Fall down */
7646764Samurai         case VALID:
7656764Samurai	    VarLocalAuth = LOCAL_AUTH;
7666764Samurai	    break;
7676764Samurai         default:
7686764Samurai	    break;
7696764Samurai      }
7706059Samurai      (void) IsInteractive();
7716059Samurai      Prompt(0);
7726059Samurai    }
7736059Samurai
77410528Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) &&
77510858Samurai	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
7766059Samurai      /* something to read from tty */
7776059Samurai      ReadTty();
7786059Samurai    }
7796059Samurai    if (modem) {
7806059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
7816059Samurai	 ModemStartOutput(modem);
7826059Samurai      }
7836059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
7846735Samurai	if (LcpFsm.state <= ST_CLOSED)
7856735Samurai	  usleep(10000);
7866059Samurai	n = read(modem, rbuff, sizeof(rbuff));
7876059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
7886059Samurai	  DownConnection();
7896059Samurai	} else
7906059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
7916059Samurai
7926059Samurai	if (LcpFsm.state <= ST_CLOSED) {
7936059Samurai	  /*
7946059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
7956059Samurai	   */
7966059Samurai	  if (!(mode & MODE_DEDICATED)) {
7976059Samurai	    cp = HdlcDetect(rbuff, n);
7986059Samurai	    if (cp) {
7996059Samurai	      /*
8006059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
8016059Samurai	       */
8026059Samurai	      if (cp != rbuff) {
8036059Samurai	        write(1, rbuff, cp - rbuff);
8046059Samurai	        write(1, "\r\n", 2);
8056059Samurai	      }
8066059Samurai	      PacketMode();
8076059Samurai#ifdef notdef
8086059Samurai	      AsyncInput(cp, n - (cp - rbuff));
8096059Samurai#endif
8106059Samurai	    } else
8116059Samurai	      write(1, rbuff, n);
8126059Samurai	  }
8136059Samurai	} else {
8146059Samurai	  if (n > 0)
8156059Samurai	    AsyncInput(rbuff, n);
8166059Samurai#ifdef notdef
8176059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
8186059Samurai#endif
8196059Samurai	}
8206059Samurai      }
8216059Samurai    }
8227001Samurai
8236059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
8246059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
8256059Samurai      if (n < 0) {
8266059Samurai	perror("read from tun");
8276059Samurai	continue;
8286059Samurai      }
8296059Samurai      /*
8306059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
8316059Samurai       *  device until IPCP is opened.
8326059Samurai       */
8336059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
8347001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
8356059Samurai	if (pri >= 0) {
8366059Samurai	  IpEnqueue(pri, rbuff, n);
8377001Samurai          dial_up = TRUE;		/* XXX */
8386059Samurai	}
8396059Samurai	continue;
8406059Samurai      }
8417001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
8426059Samurai      if (pri >= 0)
8436059Samurai	IpEnqueue(pri, rbuff, n);
8446059Samurai    }
8456059Samurai  }
8466059Samurai  logprintf("job done.\n");
8476059Samurai}
848