main.c revision 7001
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 *
207001Samurai * $Id: main.c,v 1.3 1995/02/27 10:57:50 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"
437001Samurai#include "filter.h"
446059Samurai
456764Samurai#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
466764Samurai#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in a world\n"
476764Samurai
486735Samurai#ifndef O_NONBLOCK
496735Samurai#ifdef O_NDELAY
506735Samurai#define	O_NONBLOCK O_NDELAY
516735Samurai#endif
526735Samurai#endif
536735Samurai
546059Samuraiextern void VjInit(), AsyncInit();
556059Samuraiextern void AsyncInput(), IpOutput();
566059Samuraiextern int  SelectSystem();
576059Samurai
586059Samuraiextern void DecodeCommand(), Prompt();
596059Samuraiextern int IsInteractive();
606059Samuraiextern struct in_addr ifnetmask;
616059Samuraistatic void DoLoop(void);
626059Samurai
636059Samuraistatic struct termios oldtio;		/* Original tty mode */
646059Samuraistatic struct termios comtio;		/* Command level tty mode */
656059Samuraistatic int TermMode;
666059Samuraistatic int server, update;
676059Samuraistruct sockaddr_in ifsin;
686059Samurai
696059Samuraistatic void
706059SamuraiTtyInit()
716059Samurai{
726059Samurai  struct termios newtio;
736059Samurai  int stat;
746059Samurai
756059Samurai  stat = fcntl(0, F_GETFL, 0);
766059Samurai  stat |= O_NONBLOCK;
776059Samurai  fcntl(0, F_SETFL, stat);
786059Samurai  newtio = oldtio;
796059Samurai  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
806059Samurai  newtio.c_iflag = 0;
816059Samurai  newtio.c_oflag &= ~OPOST;
826059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
836059Samurai  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
846059Samurai  newtio.c_cc[VMIN] = 1;
856059Samurai  newtio.c_cc[VTIME] = 0;
866059Samurai  newtio.c_cflag |= CS8;
876735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
886059Samurai  comtio = newtio;
896059Samurai}
906059Samurai
916059Samurai/*
926059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
936059Samurai */
946059Samuraistatic void
956059SamuraiTtyCommandMode()
966059Samurai{
976059Samurai  struct termios newtio;
986059Samurai  int stat;
996059Samurai
1006059Samurai  if (!(mode & MODE_INTER))
1016059Samurai    return;
1026735Samurai  tcgetattr(0, &newtio);
1036059Samurai  newtio.c_lflag |= (ECHO|ICANON);
1046059Samurai  newtio.c_iflag = oldtio.c_iflag;
1056059Samurai  newtio.c_oflag |= OPOST;
1066735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1076059Samurai  stat = fcntl(0, F_GETFL, 0);
1086059Samurai  stat |= O_NONBLOCK;
1096059Samurai  fcntl(0, F_SETFL, stat);
1106059Samurai  TermMode = 0;
1116059Samurai  Prompt(0);
1126059Samurai}
1136059Samurai
1146059Samurai/*
1156059Samurai * Set tty into terminal mode which is used while we invoke term command.
1166059Samurai */
1176059Samuraivoid
1186059SamuraiTtyTermMode()
1196059Samurai{
1206059Samurai  int stat;
1216059Samurai
1226735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1236059Samurai  stat = fcntl(0, F_GETFL, 0);
1246059Samurai  stat &= ~O_NONBLOCK;
1256059Samurai  fcntl(0, F_SETFL, stat);
1266059Samurai  TermMode = 1;
1276059Samurai}
1286059Samurai
1296059Samuraivoid
1306059SamuraiCleanup(excode)
1316059Samuraiint excode;
1326059Samurai{
1336059Samurai  int stat;
1346059Samurai
1356059Samurai  OsLinkdown();
1366735Samurai#ifdef notdef
1376059Samurai  stat = fcntl(0, F_GETFL, 0);
1386059Samurai  stat &= ~O_NONBLOCK;
1396059Samurai  fcntl(0, F_SETFL, stat);
1406735Samurai  tcsetattr(0, TCSANOW, &oldtio);
1416735Samurai#endif
1426059Samurai  OsCloseLink(1);
1436059Samurai  sleep(1);
1446059Samurai  if (mode & MODE_AUTO)
1456059Samurai    DeleteIfRoutes(1);
1466059Samurai  OsInterfaceDown(1);
1476059Samurai  LogPrintf(LOG_PHASE, "PPP Terminated.\n");
1486059Samurai  LogClose();
1496059Samurai  if (server > 0)
1506059Samurai    close(server);
1516735Samurai#ifndef notdef
1526735Samurai  stat = fcntl(0, F_GETFL, 0);
1536735Samurai  stat &= ~O_NONBLOCK;
1546735Samurai  fcntl(0, F_SETFL, stat);
1556735Samurai  tcsetattr(0, TCSANOW, &oldtio);
1566735Samurai#endif
1576059Samurai
1586059Samurai  exit(excode);
1596059Samurai}
1606059Samurai
1616059Samuraistatic void
1626059SamuraiHangup()
1636059Samurai{
1646059Samurai  LogPrintf(LOG_PHASE, "SIGHUP\n");
1656059Samurai  signal(SIGHUP, Hangup);
1666059Samurai  Cleanup(EX_HANGUP);
1676059Samurai}
1686059Samurai
1696059Samuraistatic void
1706059SamuraiCloseSession()
1716059Samurai{
1726059Samurai  LogPrintf(LOG_PHASE, "SIGTERM\n");
1736059Samurai  LcpClose();
1746059Samurai  Cleanup(EX_TERM);
1756059Samurai}
1766059Samurai
1776059Samuraivoid
1786059SamuraiUsage()
1796059Samurai{
1806059Samurai  fprintf(stderr, "Usage: ppp [-auto | -direct -dedicated] [system]\n");
1816059Samurai  exit(EX_START);
1826059Samurai}
1836059Samurai
1846059Samuraivoid
1856059SamuraiProcessArgs(int argc, char **argv)
1866059Samurai{
1876059Samurai  int optc;
1886059Samurai  char *cp;
1896059Samurai
1906059Samurai  optc = 0;
1916059Samurai  while (argc > 0 && **argv == '-') {
1926059Samurai    cp = *argv + 1;
1936059Samurai    if (strcmp(cp, "auto") == 0)
1946059Samurai      mode |= MODE_AUTO;
1956059Samurai    else if (strcmp(cp, "direct") == 0)
1966059Samurai      mode |= MODE_DIRECT;
1976059Samurai    else if (strcmp(cp, "dedicated") == 0)
1986059Samurai      mode |= MODE_DEDICATED;
1996059Samurai    else
2006059Samurai      Usage();
2016059Samurai    optc++;
2026059Samurai    argv++; argc--;
2036059Samurai  }
2046059Samurai  if (argc > 1) {
2056059Samurai    fprintf(stderr, "specify only one system label.\n");
2066059Samurai    exit(EX_START);
2076059Samurai  }
2086059Samurai  if (argc == 1) dstsystem = *argv;
2096059Samurai
2106059Samurai  if (optc > 1) {
2116059Samurai    fprintf(stderr, "specify only one mode.\n");
2126059Samurai    exit(EX_START);
2136059Samurai  }
2146059Samurai}
2156059Samurai
2166059Samuraistatic void
2176059SamuraiGreetings()
2186059Samurai{
2196059Samurai  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
2206059Samurai  fflush(stdout);
2216059Samurai}
2226059Samurai
2236059Samuraivoid
2246059Samuraimain(argc, argv)
2256059Samuraiint argc;
2266059Samuraichar **argv;
2276059Samurai{
2286059Samurai  int tunno;
2296059Samurai  int on = 1;
2306059Samurai
2316059Samurai  argc--; argv++;
2326059Samurai
2336059Samurai  mode = MODE_INTER;		/* default operation is interactive mode */
2346059Samurai  netfd = -1;
2356059Samurai  ProcessArgs(argc, argv);
2366059Samurai  Greetings();
2376059Samurai  GetUid();
2386059Samurai  IpcpDefAddress();
2396059Samurai
2406059Samurai  if (SelectSystem("default", CONFFILE) < 0) {
2416059Samurai    fprintf(stderr, "Warning: No default entry is given in config file.\n");
2426059Samurai  }
2436059Samurai
2446059Samurai  if (LogOpen())
2456059Samurai    exit(EX_START);
2466059Samurai
2476735Samurai  switch ( LocalAuthInit() ) {
2486735Samurai    case NOT_FOUND:
2496764Samurai    	fprintf(stderr,LAUTH_M1);
2506764Samurai    	fprintf(stderr,LAUTH_M2);
2516764Samurai	fflush (stderr);
2526764Samurai	/* Fall down */
2536764Samurai    case VALID:
2546735Samurai	VarLocalAuth = LOCAL_AUTH;
2556735Samurai	break;
2566735Samurai    default:
2576735Samurai	break;
2586735Samurai  }
2596735Samurai
2606059Samurai  if (OpenTunnel(&tunno) < 0) {
2616059Samurai    perror("open_tun");
2626059Samurai    exit(EX_START);
2636059Samurai  }
2646059Samurai
2656059Samurai  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
2666059Samurai    mode &= ~MODE_INTER;
2676059Samurai  if (mode & MODE_INTER) {
2686059Samurai    printf("Interactive mode\n");
2696059Samurai    netfd = 0;
2706059Samurai  } else if (mode & MODE_AUTO) {
2716059Samurai    printf("Automatic mode\n");
2726059Samurai    if (dstsystem == NULL) {
2736059Samurai      fprintf(stderr, "Destination system must be specified in auto mode.\n");
2746059Samurai      exit(EX_START);
2756059Samurai    }
2766059Samurai  }
2776059Samurai
2786735Samurai  tcgetattr(0, &oldtio);		/* Save original tty mode */
2796059Samurai
2806059Samurai  signal(SIGHUP, Hangup);
2816059Samurai  signal(SIGTERM, CloseSession);
2826059Samurai  signal(SIGINT, CloseSession);
2836735Samurai#ifdef SIGSEGV
2846059Samurai  signal(SIGSEGV, Hangup);
2856735Samurai#endif
2866735Samurai#ifdef SIGPIPE
2876735Samurai  signal(SIGPIPE, Hangup);
2886735Samurai#endif
2896735Samurai#ifdef SIGALRM
2906735Samurai  signal(SIGALRM, SIG_IGN);
2916735Samurai#endif
2926059Samurai
2936059Samurai  if (dstsystem) {
2946059Samurai    if (SelectSystem(dstsystem, CONFFILE) < 0) {
2956059Samurai      fprintf(stderr, "Destination system not found in conf file.\n");
2966059Samurai      Cleanup(EX_START);
2976059Samurai    }
2986059Samurai    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
2996059Samurai      fprintf(stderr, "Must specify dstaddr with auto mode.\n");
3006059Samurai      Cleanup(EX_START);
3016059Samurai    }
3026059Samurai  }
3036059Samurai  if (mode & MODE_DIRECT)
3046059Samurai    printf("Packet mode enabled.\n");
3056059Samurai
3066059Samurai#ifdef notdef
3076059Samurai  if (mode & MODE_AUTO) {
3086059Samurai    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
3096059Samurai  }
3106059Samurai#endif
3116059Samurai
3126059Samurai  if (!(mode & MODE_INTER)) {
3136059Samurai     int port = SERVER_PORT + tunno;
3146059Samurai    /*
3156059Samurai     *  Create server socket and listen at there.
3166059Samurai     */
3176059Samurai    server = socket(PF_INET, SOCK_STREAM, 0);
3186059Samurai    if (server < 0) {
3196059Samurai      perror("socket");
3206059Samurai      Cleanup(EX_SOCK);
3216059Samurai    }
3226059Samurai    ifsin.sin_family = AF_INET;
3236059Samurai    ifsin.sin_addr.s_addr = INADDR_ANY;
3246059Samurai    ifsin.sin_port = htons(port);
3256059Samurai    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
3266059Samurai      perror("bind");
3276059Samurai      if (errno == EADDRINUSE)
3286059Samurai	fprintf(stderr, "Wait for a while, then try again.\n");
3296059Samurai      Cleanup(EX_SOCK);
3306059Samurai    }
3316059Samurai    listen(server, 5);
3326059Samurai
3336059Samurai    DupLog();
3346059Samurai    if (!(mode & MODE_DIRECT)) {
3356059Samurai      if (fork())
3366059Samurai        exit(0);
3376059Samurai    }
3386059Samurai    LogPrintf(LOG_PHASE, "Listening at %d.\n", port);
3396059Samurai#ifdef DOTTYINIT
3406735Samurai    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
3416059Samurai#else
3426059Samurai    if (mode & MODE_DIRECT) {
3436059Samurai#endif
3446059Samurai      TtyInit();
3456059Samurai    } else {
3466059Samurai      setsid();			/* detach control tty */
3476059Samurai    }
3486059Samurai  } else {
3496059Samurai    server = -1;
3506059Samurai    TtyInit();
3516059Samurai    TtyCommandMode();
3526059Samurai  }
3536059Samurai  LogPrintf(LOG_PHASE, "PPP Started.\n");
3546059Samurai
3556059Samurai
3566059Samurai  do
3576059Samurai   DoLoop();
3586059Samurai  while (mode & MODE_DEDICATED);
3596059Samurai
3606059Samurai  Cleanup(EX_DONE);
3616059Samurai}
3626059Samurai
3636059Samurai/*
3646059Samurai *  Turn into packet mode, where we speek PPP.
3656059Samurai */
3666059Samuraivoid
3676059SamuraiPacketMode()
3686059Samurai{
3696059Samurai  if (RawModem(modem) < 0) {
3706059Samurai    fprintf(stderr, "Not connected.\r\n");
3716059Samurai    return;
3726059Samurai  }
3736059Samurai
3746059Samurai  AsyncInit();
3756059Samurai  VjInit();
3766059Samurai  LcpInit();
3776059Samurai  IpcpInit();
3786059Samurai  CcpInit();
3796059Samurai  LcpUp();
3806059Samurai
3816059Samurai  if (mode & (MODE_DIRECT|MODE_DEDICATED))
3826059Samurai    LcpOpen(OPEN_ACTIVE);
3836059Samurai  else
3846059Samurai    LcpOpen(VarOpenMode);
3856059Samurai  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
3866059Samurai    TtyCommandMode();
3876059Samurai    fprintf(stderr, "Packet mode.\r\n");
3886059Samurai  }
3896059Samurai}
3906059Samurai
3916059Samuraistatic void
3926059SamuraiShowHelp()
3936059Samurai{
3946059Samurai  fprintf(stderr, "Following commands are available\r\n");
3956059Samurai  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
3966059Samurai  fprintf(stderr, " ~.\tTerminate program\r\n");
3976059Samurai}
3986059Samurai
3996059Samuraistatic void
4006059SamuraiReadTty()
4016059Samurai{
4026059Samurai  int n;
4036059Samurai  char ch;
4046059Samurai  static int ttystate;
4056059Samurai#define MAXLINESIZE 200
4066059Samurai  char linebuff[MAXLINESIZE];
4076059Samurai
4086059Samurai#ifdef DEBUG
4096059Samurai  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
4106059Samurai#endif
4116059Samurai  if (!TermMode) {
4126059Samurai    n = read(netfd, linebuff, sizeof(linebuff)-1);
4136735Samurai    if (n > 0) {
4146059Samurai      DecodeCommand(linebuff, n, 1);
4156735Samurai    } else {
4166059Samurai#ifdef DEBUG
4176059Samurai      logprintf("connection closed.\n");
4186059Samurai#endif
4196059Samurai      close(netfd);
4206059Samurai      netfd = -1;
4216059Samurai      mode &= ~MODE_INTER;
4226059Samurai    }
4236059Samurai    return;
4246059Samurai  }
4256059Samurai
4266059Samurai  /*
4276059Samurai   *  We are in terminal mode, decode special sequences
4286059Samurai   */
4296059Samurai  n = read(0, &ch, 1);
4306059Samurai#ifdef DEBUG
4316059Samurai  logprintf("got %d bytes\n", n);
4326059Samurai#endif
4336059Samurai
4346059Samurai  if (n > 0) {
4356059Samurai    switch (ttystate) {
4366059Samurai    case 0:
4376059Samurai      if (ch == '~')
4386059Samurai	ttystate++;
4396059Samurai      else
4406059Samurai	write(modem, &ch, n);
4416059Samurai      break;
4426059Samurai    case 1:
4436059Samurai      switch (ch) {
4446059Samurai      case '?':
4456059Samurai	ShowHelp();
4466059Samurai	break;
4476059Samurai      case '-':
4486059Samurai	if (loglevel > 0) {
4496059Samurai	  loglevel--;
4506059Samurai	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
4516059Samurai	}
4526059Samurai	break;
4536059Samurai      case '+':
4546059Samurai	loglevel++;
4556059Samurai	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
4566059Samurai	break;
4576059Samurai#ifdef DEBUG
4586059Samurai      case 'm':
4596059Samurai	ShowMemMap();
4606059Samurai	break;
4616059Samurai#endif
4626059Samurai      case 'p':
4636059Samurai	/*
4646059Samurai	 * XXX: Should check carrier.
4656059Samurai	 */
4666059Samurai	if (LcpFsm.state <= ST_CLOSED) {
4676059Samurai	  VarOpenMode = OPEN_ACTIVE;
4686059Samurai	  PacketMode();
4696059Samurai	}
4706059Samurai	break;
4716059Samurai#ifdef DEBUG
4726059Samurai      case 't':
4736059Samurai	ShowTimers();
4746059Samurai	break;
4756059Samurai#endif
4766059Samurai      case '.':
4776059Samurai	TermMode = 1;
4786059Samurai	TtyCommandMode();
4796059Samurai	break;
4806059Samurai      default:
4816059Samurai	if (write(modem, &ch, n) < 0)
4826059Samurai	  fprintf(stderr, "err in write.\r\n");
4836059Samurai	break;
4846059Samurai      }
4856059Samurai      ttystate = 0;
4866059Samurai      break;
4876059Samurai    }
4886059Samurai  }
4896059Samurai}
4906059Samurai
4916059Samurai
4926059Samurai/*
4936059Samurai *  Here, we'll try to detect HDLC frame
4946059Samurai */
4956059Samurai
4966059Samuraistatic char *FrameHeaders[] = {
4976735Samurai  "\176\377\003\300\041",
4986735Samurai  "\176\377\175\043\300\041",
4996735Samurai  "\176\177\175\043\100\041",
5006735Samurai  "\176\175\337\175\043\300\041",
5016735Samurai  "\176\175\137\175\043\100\041",
5026059Samurai  NULL,
5036059Samurai};
5046059Samurai
5056059Samuraiu_char *
5066059SamuraiHdlcDetect(cp, n)
5076059Samuraiu_char *cp;
5086059Samuraiint n;
5096059Samurai{
5106735Samurai  char *ptr, *fp, **hp;
5116059Samurai
5126059Samurai  cp[n] = '\0';	/* be sure to null terminated */
5136059Samurai  ptr = NULL;
5146059Samurai  for (hp = FrameHeaders; *hp; hp++) {
5156735Samurai    fp = *hp;
5166735Samurai    if (DEV_IS_SYNC)
5176735Samurai      fp++;
5186735Samurai    if (ptr = strstr((char *)cp, fp))
5196059Samurai      break;
5206059Samurai  }
5216059Samurai  return((u_char *)ptr);
5226059Samurai}
5236059Samurai
5246059Samuraistatic struct pppTimer RedialTimer;
5256059Samurai
5266059Samuraistatic void
5276059SamuraiRedialTimeout()
5286059Samurai{
5296059Samurai  StopTimer(&RedialTimer);
5306059Samurai  LogPrintf(LOG_PHASE, "Redialing timer expired.\n");
5316059Samurai}
5326059Samurai
5336059Samuraistatic void
5346059SamuraiStartRedialTimer()
5356059Samurai{
5366059Samurai  LogPrintf(LOG_PHASE, "Enter pause for redialing.\n");
5376059Samurai  StopTimer(&RedialTimer);
5386059Samurai  RedialTimer.state = TIMER_STOPPED;
5396059Samurai  RedialTimer.load = REDIAL_PERIOD * SECTICKS;
5406059Samurai  RedialTimer.func = RedialTimeout;
5416059Samurai  StartTimer(&RedialTimer);
5426059Samurai}
5436059Samurai
5446059Samurai
5456059Samuraistatic void
5466059SamuraiDoLoop()
5476059Samurai{
5486059Samurai  fd_set rfds, wfds, efds;
5496059Samurai  int pri, i, n, wfd;
5506059Samurai  struct sockaddr_in hisaddr;
5516059Samurai  struct timeval timeout, *tp;
5526059Samurai  int ssize = sizeof(hisaddr);
5536059Samurai  u_char *cp;
5546059Samurai  u_char rbuff[MAX_MRU];
5557001Samurai  int dial_up;
5566059Samurai
5576059Samurai  if (mode & MODE_DIRECT) {
5586059Samurai    modem = OpenModem(mode);
5596059Samurai    fprintf(stderr, "Packet mode enabled\n");
5606059Samurai    PacketMode();
5616059Samurai  } else if (mode & MODE_DEDICATED) {
5626059Samurai    if (!modem)
5636059Samurai      modem = OpenModem(mode);
5646059Samurai  }
5656059Samurai
5666059Samurai  fflush(stdout);
5676059Samurai
5686735Samurai#ifdef SIGALRM
5697001Samurai  timeout.tv_sec = 0;
5706735Samurai#else
5716059Samurai  timeout.tv_usec = 0;
5726735Samurai#endif
5736059Samurai
5747001Samurai  dial_up = FALSE;			/* XXXX */
5756059Samurai  for (;;) {
5767001Samurai    if ( modem )
5777001Samurai	IpStartOutput();
5786059Samurai    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
5797001Samurai
5807001Samurai   /*
5817001Samurai    * If Ip packet for output is enqueued and require dial up,
5827001Samurai    * Just do it!
5837001Samurai    */
5847001Samurai    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
5857001Samurai#ifdef DEBUG
5867001Samurai      logprintf("going to dial: modem = %d\n", modem);
5877001Samurai#endif
5887001Samurai       modem = OpenModem(mode);
5897001Samurai       if (modem < 0) {
5907001Samurai         modem = 0;	       /* Set intial value for next OpenModem */
5917001Samurai         StartRedialTimer();
5927001Samurai       } else {
5937001Samurai         if (DialModem()) {
5947001Samurai           sleep(1);	       /* little pause to allow peer starts */
5957001Samurai           ModemTimeout();
5967001Samurai           PacketMode();
5977001Samurai           dial_up = FALSE;
5987001Samurai         } else {
5997001Samurai           CloseModem();
6007001Samurai           /* Dial failed. Keep quite during redial wait period. */
6017001Samurai           StartRedialTimer();
6027001Samurai         }
6037001Samurai       }
6047001Samurai    }
6057001Samurai    if (modem) {
6067001Samurai      FD_SET(modem, &rfds);
6077001Samurai      FD_SET(modem, &efds);
6087001Samurai      if (ModemQlen() > 0) {
6097001Samurai	FD_SET(modem, &wfds);
6107001Samurai      }
6117001Samurai    }
6126059Samurai    if (server > 0) FD_SET(server, &rfds);
6136059Samurai
6146059Samurai    /*  *** IMPORTANT ***
6156059Samurai     *
6166059Samurai     *  CPU is serviced every TICKUNIT micro seconds.
6176059Samurai     *	This value must be chosen with great care. If this values is
6186059Samurai     *  too big, it results loss of characters from modem and poor responce.
6196059Samurai     *  If this values is too small, ppp process eats many CPU time.
6206059Samurai     */
6216735Samurai#ifndef SIGALRM
6226059Samurai    usleep(TICKUNIT);
6236059Samurai    TimerService();
6246735Samurai#endif
6256059Samurai
6267001Samurai    FD_SET(tun_in, &rfds);
6276059Samurai    if (netfd > -1) {
6286059Samurai      FD_SET(netfd, &rfds);
6296059Samurai      FD_SET(netfd, &efds);
6306059Samurai    }
6317001Samurai
6327001Samurai
6336735Samurai#ifndef SIGALRM
6346059Samurai    /*
6357001Samurai     *  Normally, select() will not block because modem is writable.
6367001Samurai     *  In AUTO mode, select will block until we find packet from tun
6376059Samurai     */
6386059Samurai    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
6396059Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
6406735Samurai#else
6417001Samurai    /*
6427001Samurai     * When SIGALRM timer is running, a select function will be
6437001Samurai     * return -1 and EINTR after a Time Service signal hundler
6447001Samurai     * is done.
6457001Samurai     */
6466735Samurai    i = select(tun_in+10, &rfds, &wfds, &efds, NULL);
6476735Samurai#endif
6487001Samurai    if ( i == 0 ) {
6497001Samurai        continue;
6506059Samurai    }
6516735Samurai
6527001Samurai    if ( i < 0 ) {
6537001Samurai       if ( errno == EINTR ) {
6547001Samurai          continue;            /* Got SIGALRM, Do check a queue for dailing */
6557001Samurai       }
6567001Samurai       perror("select");
6577001Samurai       break;
6587001Samurai    }
6597001Samurai
6606059Samurai    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
6616059Samurai      logprintf("Exception detected.\n");
6626059Samurai      break;
6636059Samurai    }
6646059Samurai
6656059Samurai    if (server > 0 && FD_ISSET(server, &rfds)) {
6666059Samurai#ifdef DEBUG
6676059Samurai      logprintf("connected to client.\n");
6686059Samurai#endif
6696059Samurai      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
6706059Samurai      if (netfd > 0) {
6716059Samurai	write(wfd, "already in use.\n", 16);
6726059Samurai	close(wfd);
6736059Samurai	continue;
6746059Samurai      } else
6756059Samurai	netfd = wfd;
6766059Samurai      if (dup2(netfd, 1) < 0)
6776059Samurai	perror("dup2");
6786059Samurai      mode |= MODE_INTER;
6796059Samurai      Greetings();
6806764Samurai      switch ( LocalAuthInit() ) {
6816764Samurai         case NOT_FOUND:
6826764Samurai    	    fprintf(stdout,LAUTH_M1);
6836764Samurai    	    fprintf(stdout,LAUTH_M2);
6846764Samurai            fflush(stdout);
6856764Samurai	    /* Fall down */
6866764Samurai         case VALID:
6876764Samurai	    VarLocalAuth = LOCAL_AUTH;
6886764Samurai	    break;
6896764Samurai         default:
6906764Samurai	    break;
6916764Samurai      }
6926059Samurai      (void) IsInteractive();
6936059Samurai      Prompt(0);
6946059Samurai    }
6956059Samurai
6966059Samurai    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds)) {
6976059Samurai      /* something to read from tty */
6986059Samurai      ReadTty();
6996059Samurai    }
7006059Samurai    if (modem) {
7016059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
7026059Samurai	 ModemStartOutput(modem);
7036059Samurai      }
7046059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
7056735Samurai	if (LcpFsm.state <= ST_CLOSED)
7066735Samurai	  usleep(10000);
7076059Samurai	n = read(modem, rbuff, sizeof(rbuff));
7086059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
7096059Samurai	  DownConnection();
7106059Samurai	} else
7116059Samurai          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
7126059Samurai
7136059Samurai	if (LcpFsm.state <= ST_CLOSED) {
7146059Samurai	  /*
7156059Samurai	   *  In dedicated mode, we just discard input until LCP is started.
7166059Samurai	   */
7176059Samurai	  if (!(mode & MODE_DEDICATED)) {
7186059Samurai	    cp = HdlcDetect(rbuff, n);
7196059Samurai	    if (cp) {
7206059Samurai	      /*
7216059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
7226059Samurai	       */
7236059Samurai	      if (cp != rbuff) {
7246059Samurai	        write(1, rbuff, cp - rbuff);
7256059Samurai	        write(1, "\r\n", 2);
7266059Samurai	      }
7276059Samurai	      PacketMode();
7286059Samurai#ifdef notdef
7296059Samurai	      AsyncInput(cp, n - (cp - rbuff));
7306059Samurai#endif
7316059Samurai	    } else
7326059Samurai	      write(1, rbuff, n);
7336059Samurai	  }
7346059Samurai	} else {
7356059Samurai	  if (n > 0)
7366059Samurai	    AsyncInput(rbuff, n);
7376059Samurai#ifdef notdef
7386059Samurai	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
7396059Samurai#endif
7406059Samurai	}
7416059Samurai      }
7426059Samurai    }
7437001Samurai
7446059Samurai    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
7456059Samurai      /*
7466059Samurai       *  If there are many packets queued, wait until they are drained.
7476059Samurai       */
7486059Samurai      if (ModemQlen() > 5)
7496059Samurai	continue;
7507001Samurai
7516059Samurai      n = read(tun_in, rbuff, sizeof(rbuff));
7526059Samurai      if (n < 0) {
7536059Samurai	perror("read from tun");
7546059Samurai	continue;
7556059Samurai      }
7566059Samurai      /*
7576059Samurai       *  Process on-demand dialup. Output packets are queued within tunnel
7586059Samurai       *  device until IPCP is opened.
7596059Samurai       */
7606059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
7617001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
7626059Samurai	if (pri >= 0) {
7636059Samurai	  IpEnqueue(pri, rbuff, n);
7647001Samurai          dial_up = TRUE;		/* XXX */
7656059Samurai	}
7666059Samurai	continue;
7676059Samurai      }
7687001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
7696059Samurai      if (pri >= 0)
7706059Samurai	IpEnqueue(pri, rbuff, n);
7716059Samurai    }
7726059Samurai  }
7736059Samurai  logprintf("job done.\n");
7746059Samurai}
775