main.c revision 6764
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 *
206764Samurai * $Id: main.c,v 1.2 1995/02/26 12:17:41 amurai Exp $
216735Samurai *
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>
286059Samurai#include <sys/time.h>
296059Samurai#include <termios.h>
306059Samurai#include <signal.h>
316059Samurai#include <sys/wait.h>
326059Samurai#include <errno.h>
336059Samurai#include <netdb.h>
346059Samurai#include <sys/socket.h>
356059Samurai#include <arpa/inet.h>
366059Samurai#include "modem.h"
376059Samurai#include "os.h"
386059Samurai#include "hdlc.h"
396059Samurai#include "lcp.h"
406059Samurai#include "ipcp.h"
416059Samurai#include "vars.h"
426735Samurai#include "auth.h"
436059Samurai
446764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
456764Samurai#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in a world\n"
466764Samurai
476735Samurai#ifndef O_NONBLOCK
486735Samurai#ifdef O_NDELAY
496735Samurai#define	O_NONBLOCK O_NDELAY
506735Samurai#endif
516735Samurai#endif
526735Samurai
536059Samuraiextern void VjInit(), AsyncInit();
546059Samuraiextern void AsyncInput(), IpOutput();
556059Samuraiextern int  SelectSystem();
566059Samurai
576059Samuraiextern void DecodeCommand(), Prompt();
586059Samuraiextern int IsInteractive();
596059Samuraiextern struct in_addr ifnetmask;
606059Samuraistatic void DoLoop(void);
616059Samurai
626059Samuraistatic struct termios oldtio;		/* Original tty mode */
636059Samuraistatic struct termios comtio;		/* Command level tty mode */
646059Samuraistatic int TermMode;
656059Samuraistatic int server, update;
666059Samuraistruct sockaddr_in ifsin;
676059Samurai
686059Samuraistatic void
696059SamuraiTtyInit()
706059Samurai{
716059Samurai  struct termios newtio;
726059Samurai  int stat;
736059Samurai
746059Samurai  stat = fcntl(0, F_GETFL, 0);
756059Samurai  stat |= O_NONBLOCK;
766059Samurai  fcntl(0, F_SETFL, stat);
776059Samurai  newtio = oldtio;
786059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
796059Samurai  newtio.c_iflag = 0;
806059Samurai  newtio.c_oflag &= ~OPOST;
816059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
826059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
836059Samurai  newtio.c_cc[VMIN] = 1;
846059Samurai  newtio.c_cc[VTIME] = 0;
856059Samurai  newtio.c_cflag |= CS8;
866735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
876059Samurai  comtio = newtio;
886059Samurai}
896059Samurai
906059Samurai/*
916059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
926059Samurai */
936059Samuraistatic void
946059SamuraiTtyCommandMode()
956059Samurai{
966059Samurai  struct termios newtio;
976059Samurai  int stat;
986059Samurai
996059Samurai  if (!(mode & MODE_INTER))
1006059Samurai    return;
1016735Samurai  tcgetattr(0, &newtio);
1026059Samurai  newtio.c_lflag |= (ECHO|ICANON);
1036059Samurai  newtio.c_iflag = oldtio.c_iflag;
1046059Samurai  newtio.c_oflag |= OPOST;
1056735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1066059Samurai  stat = fcntl(0, F_GETFL, 0);
1076059Samurai  stat |= O_NONBLOCK;
1086059Samurai  fcntl(0, F_SETFL, stat);
1096059Samurai  TermMode = 0;
1106059Samurai  Prompt(0);
1116059Samurai}
1126059Samurai
1136059Samurai/*
1146059Samurai * Set tty into terminal mode which is used while we invoke term command.
1156059Samurai */
1166059Samuraivoid
1176059SamuraiTtyTermMode()
1186059Samurai{
1196059Samurai  int stat;
1206059Samurai
1216735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1226059Samurai  stat = fcntl(0, F_GETFL, 0);
1236059Samurai  stat &= ~O_NONBLOCK;
1246059Samurai  fcntl(0, F_SETFL, stat);
1256059Samurai  TermMode = 1;
1266059Samurai}
1276059Samurai
1286059Samuraivoid
1296059SamuraiCleanup(excode)
1306059Samuraiint excode;
1316059Samurai{
1326059Samurai  int stat;
1336059Samurai
1346059Samurai  OsLinkdown();
1356735Samurai#ifdef notdef
1366059Samurai  stat = fcntl(0, F_GETFL, 0);
1376059Samurai  stat &= ~O_NONBLOCK;
1386059Samurai  fcntl(0, F_SETFL, stat);
1396735Samurai  tcsetattr(0, TCSANOW, &oldtio);
1406735Samurai#endif
1416059Samurai  OsCloseLink(1);
1426059Samurai  sleep(1);
1436059Samurai  if (mode & MODE_AUTO)
1446059Samurai    DeleteIfRoutes(1);
1456059Samurai  OsInterfaceDown(1);
1466059Samurai  LogPrintf(LOG_PHASE, "PPP Terminated.\n");
1476059Samurai  LogClose();
1486059Samurai  if (server > 0)
1496059Samurai    close(server);
1506735Samurai#ifndef notdef
1516735Samurai  stat = fcntl(0, F_GETFL, 0);
1526735Samurai  stat &= ~O_NONBLOCK;
1536735Samurai  fcntl(0, F_SETFL, stat);
1546735Samurai  tcsetattr(0, TCSANOW, &oldtio);
1556735Samurai#endif
1566059Samurai
1576059Samurai  exit(excode);
1586059Samurai}
1596059Samurai
1606059Samuraistatic void
1616059SamuraiHangup()
1626059Samurai{
1636059Samurai  LogPrintf(LOG_PHASE, "SIGHUP\n");
1646059Samurai  signal(SIGHUP, Hangup);
1656059Samurai  Cleanup(EX_HANGUP);
1666059Samurai}
1676059Samurai
1686059Samuraistatic void
1696059SamuraiCloseSession()
1706059Samurai{
1716059Samurai  LogPrintf(LOG_PHASE, "SIGTERM\n");
1726059Samurai  LcpClose();
1736059Samurai  Cleanup(EX_TERM);
1746059Samurai}
1756059Samurai
1766059Samuraivoid
1776059SamuraiUsage()
1786059Samurai{
1796059Samurai  fprintf(stderr, "Usage: ppp [-auto | -direct -dedicated] [system]\n");
1806059Samurai  exit(EX_START);
1816059Samurai}
1826059Samurai
1836059Samuraivoid
1846059SamuraiProcessArgs(int argc, char **argv)
1856059Samurai{
1866059Samurai  int optc;
1876059Samurai  char *cp;
1886059Samurai
1896059Samurai  optc = 0;
1906059Samurai  while (argc > 0 && **argv == '-') {
1916059Samurai    cp = *argv + 1;
1926059Samurai    if (strcmp(cp, "auto") == 0)
1936059Samurai      mode |= MODE_AUTO;
1946059Samurai    else if (strcmp(cp, "direct") == 0)
1956059Samurai      mode |= MODE_DIRECT;
1966059Samurai    else if (strcmp(cp, "dedicated") == 0)
1976059Samurai      mode |= MODE_DEDICATED;
1986059Samurai    else
1996059Samurai      Usage();
2006059Samurai    optc++;
2016059Samurai    argv++; argc--;
2026059Samurai  }
2036059Samurai  if (argc > 1) {
2046059Samurai    fprintf(stderr, "specify only one system label.\n");
2056059Samurai    exit(EX_START);
2066059Samurai  }
2076059Samurai  if (argc == 1) dstsystem = *argv;
2086059Samurai
2096059Samurai  if (optc > 1) {
2106059Samurai    fprintf(stderr, "specify only one mode.\n");
2116059Samurai    exit(EX_START);
2126059Samurai  }
2136059Samurai}
2146059Samurai
2156059Samuraistatic void
2166059SamuraiGreetings()
2176059Samurai{
2186059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2196059Samurai  fflush(stdout);
2206059Samurai}
2216059Samurai
2226059Samuraivoid
2236059Samuraimain(argc, argv)
2246059Samuraiint argc;
2256059Samuraichar **argv;
2266059Samurai{
2276059Samurai  int tunno;
2286059Samurai  int on = 1;
2296059Samurai
2306059Samurai  argc--; argv++;
2316059Samurai
2326059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2336059Samurai  netfd = -1;
2346059Samurai  ProcessArgs(argc, argv);
2356059Samurai  Greetings();
2366059Samurai  GetUid();
2376059Samurai  IpcpDefAddress();
2386059Samurai
2396059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
2406059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
2416059Samurai  }
2426059Samurai
2436059Samurai  if (LogOpen())
2446059Samurai    exit(EX_START);
2456059Samurai
2466735Samurai  switch ( LocalAuthInit() ) {
2476735Samurai    case NOT_FOUND:
2486764Samurai    	fprintf(stderr,LAUTH_M1);
2496764Samurai    	fprintf(stderr,LAUTH_M2);
2506764Samurai	fflush (stderr);
2516764Samurai	/* Fall down */
2526764Samurai    case VALID:
2536735Samurai	VarLocalAuth = LOCAL_AUTH;
2546735Samurai	break;
2556735Samurai    default:
2566735Samurai	break;
2576735Samurai  }
2586735Samurai
2596059Samurai  if (OpenTunnel(&tunno) < 0) {
2606059Samurai    perror("open_tun");
2616059Samurai    exit(EX_START);
2626059Samurai  }
2636059Samurai
2646059Samurai  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
2656059Samurai    mode &= ~MODE_INTER;
2666059Samurai  if (mode & MODE_INTER) {
2676059Samurai    printf("Interactive mode\n");
2686059Samurai    netfd = 0;
2696059Samurai  } else if (mode & MODE_AUTO) {
2706059Samurai    printf("Automatic mode\n");
2716059Samurai    if (dstsystem == NULL) {
2726059Samurai      fprintf(stderr, "Destination system must be specified in auto mode.\n");
2736059Samurai      exit(EX_START);
2746059Samurai    }
2756059Samurai  }
2766059Samurai
2776735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
2786059Samurai
2796059Samurai  signal(SIGHUP, Hangup);
2806059Samurai  signal(SIGTERM, CloseSession);
2816059Samurai  signal(SIGINT, CloseSession);
2826735Samurai#ifdef SIGSEGV
2836059Samurai  signal(SIGSEGV, Hangup);
2846735Samurai#endif
2856735Samurai#ifdef SIGPIPE
2866735Samurai  signal(SIGPIPE, Hangup);
2876735Samurai#endif
2886735Samurai#ifdef SIGALRM
2896735Samurai  signal(SIGALRM, SIG_IGN);
2906735Samurai#endif
2916059Samurai
2926059Samurai  if (dstsystem) {
2936059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
2946059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
2956059Samurai      Cleanup(EX_START);
2966059Samurai    }
2976059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
2986059Samurai      fprintf(stderr, "Must specify dstaddr with auto mode.\n");
2996059Samurai      Cleanup(EX_START);
3006059Samurai    }
3016059Samurai  }
3026059Samurai  if (mode & MODE_DIRECT)
3036059Samurai    printf("Packet mode enabled.\n");
3046059Samurai
3056059Samurai#ifdef notdef
3066059Samurai  if (mode & MODE_AUTO) {
3076059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3086059Samurai  }
3096059Samurai#endif
3106059Samurai
3116059Samurai  if (!(mode & MODE_INTER)) {
3126059Samurai     int port = SERVER_PORT + tunno;
3136059Samurai    /*
3146059Samurai     *  Create server socket and listen at there.
3156059Samurai     */
3166059Samurai    server = socket(PF_INET, SOCK_STREAM, 0);
3176059Samurai    if (server < 0) {
3186059Samurai      perror("socket");
3196059Samurai      Cleanup(EX_SOCK);
3206059Samurai    }
3216059Samurai    ifsin.sin_family = AF_INET;
3226059Samurai    ifsin.sin_addr.s_addr = INADDR_ANY;
3236059Samurai    ifsin.sin_port = htons(port);
3246059Samurai    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
3256059Samurai      perror("bind");
3266059Samurai      if (errno == EADDRINUSE)
3276059Samurai	fprintf(stderr, "Wait for a while, then try again.\n");
3286059Samurai      Cleanup(EX_SOCK);
3296059Samurai    }
3306059Samurai    listen(server, 5);
3316059Samurai
3326059Samurai    DupLog();
3336059Samurai    if (!(mode & MODE_DIRECT)) {
3346059Samurai      if (fork())
3356059Samurai        exit(0);
3366059Samurai    }
3376059Samurai    LogPrintf(LOG_PHASE, "Listening at %d.\n", port);
3386059Samurai#ifdef DOTTYINIT
3396735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
3406059Samurai#else
3416059Samurai    if (mode & MODE_DIRECT) {
3426059Samurai#endif
3436059Samurai      TtyInit();
3446059Samurai    } else {
3456059Samurai      setsid();			/* detach control tty */
3466059Samurai    }
3476059Samurai  } else {
3486059Samurai    server = -1;
3496059Samurai    TtyInit();
3506059Samurai    TtyCommandMode();
3516059Samurai  }
3526059Samurai  LogPrintf(LOG_PHASE, "PPP Started.\n");
3536059Samurai
3546059Samurai
3556059Samurai  do
3566059Samurai   DoLoop();
3576059Samurai  while (mode & MODE_DEDICATED);
3586059Samurai
3596059Samurai  Cleanup(EX_DONE);
3606059Samurai}
3616059Samurai
3626059Samurai/*
3636059Samurai *  Turn into packet mode, where we speek PPP.
3646059Samurai */
3656059Samuraivoid
3666059SamuraiPacketMode()
3676059Samurai{
3686059Samurai  if (RawModem(modem) < 0) {
3696059Samurai    fprintf(stderr, "Not connected.\r\n");
3706059Samurai    return;
3716059Samurai  }
3726059Samurai
3736059Samurai  AsyncInit();
3746059Samurai  VjInit();
3756059Samurai  LcpInit();
3766059Samurai  IpcpInit();
3776059Samurai  CcpInit();
3786059Samurai  LcpUp();
3796059Samurai
3806059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
3816059Samurai    LcpOpen(OPEN_ACTIVE);
3826059Samurai  else
3836059Samurai    LcpOpen(VarOpenMode);
3846059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
3856059Samurai    TtyCommandMode();
3866059Samurai    fprintf(stderr, "Packet mode.\r\n");
3876059Samurai  }
3886059Samurai}
3896059Samurai
3906059Samuraistatic void
3916059SamuraiShowHelp()
3926059Samurai{
3936059Samurai  fprintf(stderr, "Following commands are available\r\n");
3946059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
3956059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
3966059Samurai}
3976059Samurai
3986059Samuraistatic void
3996059SamuraiReadTty()
4006059Samurai{
4016059Samurai  int n;
4026059Samurai  char ch;
4036059Samurai  static int ttystate;
4046059Samurai#define MAXLINESIZE 200
4056059Samurai  char linebuff[MAXLINESIZE];
4066059Samurai
4076059Samurai#ifdef DEBUG
4086059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
4096059Samurai#endif
4106059Samurai  if (!TermMode) {
4116059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
4126735Samurai    if (n > 0) {
4136059Samurai      DecodeCommand(linebuff, n, 1);
4146735Samurai    } else {
4156059Samurai#ifdef DEBUG
4166059Samurai      logprintf("connection closed.\n");
4176059Samurai#endif
4186059Samurai      close(netfd);
4196059Samurai      netfd = -1;
4206059Samurai      mode &= ~MODE_INTER;
4216059Samurai    }
4226059Samurai    return;
4236059Samurai  }
4246059Samurai
4256059Samurai  /*
4266059Samurai   *  We are in terminal mode, decode special sequences
4276059Samurai   */
4286059Samurai  n = read(0, &ch, 1);
4296059Samurai#ifdef DEBUG
4306059Samurai  logprintf("got %d bytes\n", n);
4316059Samurai#endif
4326059Samurai
4336059Samurai  if (n > 0) {
4346059Samurai    switch (ttystate) {
4356059Samurai    case 0:
4366059Samurai      if (ch == '~')
4376059Samurai	ttystate++;
4386059Samurai      else
4396059Samurai	write(modem, &ch, n);
4406059Samurai      break;
4416059Samurai    case 1:
4426059Samurai      switch (ch) {
4436059Samurai      case '?':
4446059Samurai	ShowHelp();
4456059Samurai	break;
4466059Samurai      case '-':
4476059Samurai	if (loglevel > 0) {
4486059Samurai	  loglevel--;
4496059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
4506059Samurai	}
4516059Samurai	break;
4526059Samurai      case '+':
4536059Samurai	loglevel++;
4546059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
4556059Samurai	break;
4566059Samurai#ifdef DEBUG
4576059Samurai      case 'm':
4586059Samurai	ShowMemMap();
4596059Samurai	break;
4606059Samurai#endif
4616059Samurai      case 'p':
4626059Samurai	/*
4636059Samurai	 * XXX: Should check carrier.
4646059Samurai	 */
4656059Samurai	if (LcpFsm.state <= ST_CLOSED) {
4666059Samurai	  VarOpenMode = OPEN_ACTIVE;
4676059Samurai	  PacketMode();
4686059Samurai	}
4696059Samurai	break;
4706059Samurai#ifdef DEBUG
4716059Samurai      case 't':
4726059Samurai	ShowTimers();
4736059Samurai	break;
4746059Samurai#endif
4756059Samurai      case '.':
4766059Samurai	TermMode = 1;
4776059Samurai	TtyCommandMode();
4786059Samurai	break;
4796059Samurai      default:
4806059Samurai	if (write(modem, &ch, n) < 0)
4816059Samurai	  fprintf(stderr, "err in write.\r\n");
4826059Samurai	break;
4836059Samurai      }
4846059Samurai      ttystate = 0;
4856059Samurai      break;
4866059Samurai    }
4876059Samurai  }
4886059Samurai}
4896059Samurai
4906059Samurai
4916059Samurai/*
4926059Samurai *  Here, we'll try to detect HDLC frame
4936059Samurai */
4946059Samurai
4956059Samuraistatic char *FrameHeaders[] = {
4966735Samurai  "\176\377\003\300\041",
4976735Samurai  "\176\377\175\043\300\041",
4986735Samurai  "\176\177\175\043\100\041",
4996735Samurai  "\176\175\337\175\043\300\041",
5006735Samurai  "\176\175\137\175\043\100\041",
5016059Samurai  NULL,
5026059Samurai};
5036059Samurai
5046059Samuraiu_char *
5056059SamuraiHdlcDetect(cp, n)
5066059Samuraiu_char *cp;
5076059Samuraiint n;
5086059Samurai{
5096735Samurai  char *ptr, *fp, **hp;
5106059Samurai
5116059Samurai  cp[n] = '\0';	/* be sure to null terminated */
5126059Samurai  ptr = NULL;
5136059Samurai  for (hp = FrameHeaders; *hp; hp++) {
5146735Samurai    fp = *hp;
5156735Samurai    if (DEV_IS_SYNC)
5166735Samurai      fp++;
5176735Samurai    if (ptr = strstr((char *)cp, fp))
5186059Samurai      break;
5196059Samurai  }
5206059Samurai  return((u_char *)ptr);
5216059Samurai}
5226059Samurai
5236059Samuraistatic struct pppTimer RedialTimer;
5246059Samurai
5256059Samuraistatic void
5266059SamuraiRedialTimeout()
5276059Samurai{
5286059Samurai  StopTimer(&RedialTimer);
5296059Samurai  LogPrintf(LOG_PHASE, "Redialing timer expired.\n");
5306059Samurai}
5316059Samurai
5326059Samuraistatic void
5336059SamuraiStartRedialTimer()
5346059Samurai{
5356059Samurai  LogPrintf(LOG_PHASE, "Enter pause for redialing.\n");
5366059Samurai  StopTimer(&RedialTimer);
5376059Samurai  RedialTimer.state = TIMER_STOPPED;
5386059Samurai  RedialTimer.load = REDIAL_PERIOD * SECTICKS;
5396059Samurai  RedialTimer.func = RedialTimeout;
5406059Samurai  StartTimer(&RedialTimer);
5416059Samurai}
5426059Samurai
5436059Samurai
5446059Samuraistatic void
5456059SamuraiDoLoop()
5466059Samurai{
5476059Samurai  fd_set rfds, wfds, efds;
5486059Samurai  int pri, i, n, wfd;
5496059Samurai  struct sockaddr_in hisaddr;
5506059Samurai  struct timeval timeout, *tp;
5516059Samurai  int ssize = sizeof(hisaddr);
5526059Samurai  u_char *cp;
5536059Samurai  u_char rbuff[MAX_MRU];
5546735Samurai  struct itimerval itimer;
5556059Samurai
5566059Samurai  if (mode & MODE_DIRECT) {
5576059Samurai    modem = OpenModem(mode);
5586059Samurai    fprintf(stderr, "Packet mode enabled\n");
5596059Samurai    PacketMode();
5606059Samurai  } else if (mode & MODE_DEDICATED) {
5616059Samurai    if (!modem)
5626059Samurai      modem = OpenModem(mode);
5636059Samurai  }
5646059Samurai
5656059Samurai  fflush(stdout);
5666059Samurai
5676059Samurai  timeout.tv_sec = 0;;
5686735Samurai#ifdef SIGALRM
5696735Samurai  signal(SIGALRM, (void (*)(int))TimerService);
5706735Samurai  itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
5716735Samurai  itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
5726735Samurai  setitimer(ITIMER_REAL, &itimer, NULL);
5736735Samurai#else
5746059Samurai  timeout.tv_usec = 0;
5756735Samurai#endif
5766059Samurai
5776059Samurai  for (;;) {
5786059Samurai    IpStartOutput();
5796059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
5806059Samurai    FD_SET(tun_in, &rfds);
5816059Samurai    if (server > 0) FD_SET(server, &rfds);
5826059Samurai
5836059Samurai    /*  *** IMPORTANT ***
5846059Samurai     *
5856059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
5866059Samurai     *	This value must be chosen with great care. If this values is
5876059Samurai     *  too big, it results loss of characters from modem and poor responce.
5886059Samurai     *  If this values is too small, ppp process eats many CPU time.
5896059Samurai     */
5906735Samurai#ifndef SIGALRM
5916059Samurai    usleep(TICKUNIT);
5926059Samurai    TimerService();
5936735Samurai#endif
5946059Samurai
5956059Samurai    if (modem) {
5966059Samurai      FD_SET(modem, &rfds);
5976059Samurai      FD_SET(modem, &efds);
5986735Samurai      if (ModemQlen() > 0) {
5996735Samurai	FD_SET(modem, &wfds);
6006735Samurai      }
6016059Samurai    }
6026059Samurai    if (netfd > -1) {
6036059Samurai      FD_SET(netfd, &rfds);
6046059Samurai      FD_SET(netfd, &efds);
6056059Samurai    }
6066735Samurai#ifndef SIGALRM
6076059Samurai    /*
6086059Samurai     *  Normally, slect() will not block because modem is writable.
6096059Samurai     *  In AUTO mode, select will block until we find packet from tun.
6106059Samurai     *  However, we have to run ourselves while we are in redial wait state.
6116059Samurai     */
6126059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
6136059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
6146735Samurai#else
6156735Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, NULL);
6166735Samurai#endif
6176059Samurai    if (i == 0) {
6186059Samurai      continue;
6196059Samurai    }
6206735Samurai
6216059Samurai    if (i < 0) {
6226735Samurai      if (errno == EINTR)
6236735Samurai	continue;
6246059Samurai      perror("select");
6256059Samurai      break;
6266059Samurai    }
6276059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
6286059Samurai      logprintf("Exception detected.\n");
6296059Samurai      break;
6306059Samurai    }
6316059Samurai
6326059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
6336059Samurai#ifdef DEBUG
6346059Samurai      logprintf("connected to client.\n");
6356059Samurai#endif
6366059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
6376059Samurai      if (netfd > 0) {
6386059Samurai	write(wfd, "already in use.\n", 16);
6396059Samurai	close(wfd);
6406059Samurai	continue;
6416059Samurai      } else
6426059Samurai	netfd = wfd;
6436059Samurai      if (dup2(netfd, 1) < 0)
6446059Samurai	perror("dup2");
6456059Samurai      mode |= MODE_INTER;
6466059Samurai      Greetings();
6476764Samurai      switch ( LocalAuthInit() ) {
6486764Samurai         case NOT_FOUND:
6496764Samurai    	    fprintf(stdout,LAUTH_M1);
6506764Samurai    	    fprintf(stdout,LAUTH_M2);
6516764Samurai            fflush(stdout);
6526764Samurai	    /* Fall down */
6536764Samurai         case VALID:
6546764Samurai	    VarLocalAuth = LOCAL_AUTH;
6556764Samurai	    break;
6566764Samurai         default:
6576764Samurai	    break;
6586764Samurai      }
6596059Samurai      (void) IsInteractive();
6606059Samurai      Prompt(0);
6616059Samurai    }
6626059Samurai
6636059Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds)) {
6646059Samurai      /* something to read from tty */
6656059Samurai      ReadTty();
6666059Samurai    }
6676059Samurai    if (modem) {
6686059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
6696059Samurai	 ModemStartOutput(modem);
6706059Samurai      }
6716059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
6726735Samurai	if (LcpFsm.state <= ST_CLOSED)
6736735Samurai	  usleep(10000);
6746059Samurai	n = read(modem, rbuff, sizeof(rbuff));
6756059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
6766059Samurai	  DownConnection();
6776059Samurai	} else
6786059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
6796059Samurai
6806059Samurai	if (LcpFsm.state <= ST_CLOSED) {
6816059Samurai	  /*
6826059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
6836059Samurai	   */
6846059Samurai	  if (!(mode & MODE_DEDICATED)) {
6856059Samurai	    cp = HdlcDetect(rbuff, n);
6866059Samurai	    if (cp) {
6876059Samurai	      /*
6886059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
6896059Samurai	       */
6906059Samurai	      if (cp != rbuff) {
6916059Samurai	        write(1, rbuff, cp - rbuff);
6926059Samurai	        write(1, "\r\n", 2);
6936059Samurai	      }
6946059Samurai	      PacketMode();
6956059Samurai#ifdef notdef
6966059Samurai	      AsyncInput(cp, n - (cp - rbuff));
6976059Samurai#endif
6986059Samurai	    } else
6996059Samurai	      write(1, rbuff, n);
7006059Samurai	  }
7016059Samurai	} else {
7026059Samurai	  if (n > 0)
7036059Samurai	    AsyncInput(rbuff, n);
7046059Samurai#ifdef notdef
7056059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
7066059Samurai#endif
7076059Samurai	}
7086059Samurai      }
7096059Samurai    }
7106059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
7116059Samurai      /*
7126059Samurai       *  If there are many packets queued, wait until they are drained.
7136059Samurai       */
7146059Samurai      if (ModemQlen() > 5)
7156059Samurai	continue;
7166059Samurai
7176059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
7186059Samurai      if (n < 0) {
7196059Samurai	perror("read from tun");
7206059Samurai	continue;
7216059Samurai      }
7226059Samurai      /*
7236059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
7246059Samurai       *  device until IPCP is opened.
7256059Samurai       */
7266059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
7276059Samurai	pri = PacketCheck(rbuff, n, 2);
7286059Samurai	if (pri >= 0) {
7296059Samurai	  if (RedialTimer.state == TIMER_RUNNING) {
7306059Samurai	    /*
7316059Samurai	     * We are in redial wait state. Ignore packet.
7326059Samurai	     */
7336059Samurai	    continue;
7346059Samurai	  }
7356059Samurai	  modem = OpenModem(mode);
7366059Samurai#ifdef DEBUG
7376059Samurai	  logprintf("going to dial: modem = %d\n", modem);
7386059Samurai#endif
7396059Samurai	  if (modem < 0) {
7406059Samurai	    printf("failed to open modem.\n");
7416059Samurai	    Cleanup(EX_MODEM);
7426059Samurai	  }
7436059Samurai
7446059Samurai	  if (DialModem()) {
7456059Samurai	    sleep(1);		/* little pause to allow peer starts */
7466735Samurai 	    ModemTimeout();
7476059Samurai	    PacketMode();
7486059Samurai	  } else {
7496059Samurai	    CloseModem();
7506059Samurai	    /* Dial failed. Keep quite during redial wait period. */
7516059Samurai	    /* XXX: We shoud implement re-dial */
7526059Samurai	    StartRedialTimer();
7536059Samurai	    continue;
7546059Samurai	  }
7556059Samurai	  IpEnqueue(pri, rbuff, n);
7566059Samurai	}
7576059Samurai	continue;
7586059Samurai      }
7596059Samurai      pri = PacketCheck(rbuff, n, 1);
7606059Samurai      if (pri >= 0)
7616059Samurai	IpEnqueue(pri, rbuff, n);
7626059Samurai    }
7636059Samurai  }
7646735Samurai#ifdef SIGALRM
7656735Samurai  itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
7666735Samurai  setitimer(ITIMER_REAL, &itimer, NULL);
7676735Samurai  signal(SIGALRM, SIG_DFL);
7686735Samurai#endif
7696059Samurai  logprintf("job done.\n");
7706059Samurai}
771