main.c revision 98970
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/main.c 98970 2002-06-28 09:33:25Z brian $
296059Samurai */
3036285Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in.h>
3330715Sbrian#include <netinet/in_systm.h>
3430715Sbrian#include <netinet/ip.h>
3536285Sbrian#include <sys/un.h>
3658032Sbrian#include <sys/socket.h>
3758032Sbrian#include <net/route.h>
3830715Sbrian
3930715Sbrian#include <errno.h>
406059Samurai#include <fcntl.h>
4111336Samurai#include <paths.h>
4230715Sbrian#include <signal.h>
4330715Sbrian#include <stdio.h>
4452396Sbrian#include <stdlib.h>
4530715Sbrian#include <string.h>
4697140Sbrian#include <sys/time.h>
476059Samurai#include <termios.h>
4818786Sjkh#include <unistd.h>
4949581Sbrian#include <sys/stat.h>
5030715Sbrian
5150059Sbrian#ifndef NONAT
5258037Sbrian#ifdef LOCALNAT
5358037Sbrian#include "alias.h"
5458037Sbrian#else
5546086Sbrian#include <alias.h>
5639395Sbrian#endif
5739395Sbrian#endif
5858037Sbrian
5946686Sbrian#include "layer.h"
6037141Sbrian#include "probe.h"
6130715Sbrian#include "mbuf.h"
6230715Sbrian#include "log.h"
6330715Sbrian#include "defs.h"
6431061Sbrian#include "id.h"
6530715Sbrian#include "timer.h"
6630715Sbrian#include "fsm.h"
6736285Sbrian#include "lqr.h"
686059Samurai#include "hdlc.h"
6931514Sbrian#include "lcp.h"
7013389Sphk#include "ccp.h"
7136285Sbrian#include "iplist.h"
7236285Sbrian#include "throughput.h"
7336285Sbrian#include "slcompress.h"
7481634Sbrian#include "ncpaddr.h"
756059Samurai#include "ipcp.h"
7636285Sbrian#include "filter.h"
7736285Sbrian#include "descriptor.h"
7836285Sbrian#include "link.h"
7936285Sbrian#include "mp.h"
8043313Sbrian#ifndef NORADIUS
8143313Sbrian#include "radius.h"
8243313Sbrian#endif
8381634Sbrian#include "ipv6cp.h"
8481634Sbrian#include "ncp.h"
8536285Sbrian#include "bundle.h"
866735Samurai#include "auth.h"
8713389Sphk#include "systems.h"
8823840Sbrian#include "sig.h"
8930715Sbrian#include "main.h"
9036285Sbrian#include "server.h"
9136285Sbrian#include "prompt.h"
9236285Sbrian#include "chat.h"
9336285Sbrian#include "chap.h"
9438174Sbrian#include "cbcp.h"
9536285Sbrian#include "datalink.h"
9640561Sbrian#include "iface.h"
976059Samurai
986735Samurai#ifndef O_NONBLOCK
996735Samurai#ifdef O_NDELAY
1006735Samurai#define	O_NONBLOCK O_NDELAY
1016735Samurai#endif
1026735Samurai#endif
1036735Samurai
10436431Sbrianstatic void DoLoop(struct bundle *);
10530715Sbrianstatic void TerminalStop(int);
10630715Sbrian
10736285Sbrianstatic struct bundle *SignalBundle;
10836285Sbrianstatic struct prompt *SignalPrompt;
1096059Samurai
11010528Samuraivoid
11136285SbrianCleanup(int excode)
1126059Samurai{
11336285Sbrian  SignalBundle->CleaningUp = 1;
11438008Sbrian  bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
1156059Samurai}
1166059Samurai
1176059Samuraivoid
11836285SbrianAbortProgram(int excode)
1196059Samurai{
12098970Sbrian  if (SignalBundle)
12198970Sbrian    server_Close(SignalBundle);
12236285Sbrian  log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
12398970Sbrian  if (SignalBundle) {
12498970Sbrian    bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
12598970Sbrian    bundle_Destroy(SignalBundle);
12698970Sbrian  }
12736285Sbrian  log_Close();
1286059Samurai  exit(excode);
1296059Samurai}
1306059Samurai
1316059Samuraistatic void
13228679SbrianCloseConnection(int signo)
1336059Samurai{
13426858Sbrian  /* NOTE, these are manual, we've done a setsid() */
13536285Sbrian  sig_signal(SIGINT, SIG_IGN);
13636285Sbrian  log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo);
13737018Sbrian  bundle_Down(SignalBundle, CLOSE_STAYDOWN);
13836285Sbrian  sig_signal(SIGINT, CloseConnection);
1396059Samurai}
1406059Samurai
1416059Samuraistatic void
14228679SbrianCloseSession(int signo)
1436059Samurai{
14436285Sbrian  log_Printf(LogPHASE, "Signal %d, terminate.\n", signo);
14528679Sbrian  Cleanup(EX_TERM);
1466059Samurai}
1476059Samurai
14836285Sbrianstatic pid_t BGPid = 0;
14936285Sbrian
15010528Samuraistatic void
15136285SbrianKillChild(int signo)
15210528Samurai{
15347119Sbrian  signal(signo, SIG_IGN);
15436285Sbrian  log_Printf(LogPHASE, "Parent: Signal %d\n", signo);
15536285Sbrian  kill(BGPid, SIGINT);
15610528Samurai}
15710528Samurai
15810528Samuraistatic void
15936285SbrianTerminalCont(int signo)
16010528Samurai{
16136285Sbrian  signal(SIGCONT, SIG_DFL);
16236285Sbrian  prompt_Continue(SignalPrompt);
16310528Samurai}
16410528Samurai
16526940Sbrianstatic void
16636285SbrianTerminalStop(int signo)
16726940Sbrian{
16836285Sbrian  prompt_Suspend(SignalPrompt);
16936285Sbrian  signal(SIGCONT, TerminalCont);
17036285Sbrian  raise(SIGSTOP);
17126940Sbrian}
17226940Sbrian
17331081Sbrianstatic void
17431081SbrianBringDownServer(int signo)
17531081Sbrian{
17636285Sbrian  /* Drops all child prompts too ! */
17771657Sbrian  if (server_Close(SignalBundle))
17871657Sbrian    log_Printf(LogPHASE, "Closed server socket\n");
17931081Sbrian}
18031081Sbrian
18130715Sbrianstatic void
18271657SbrianRestartServer(int signo)
18371657Sbrian{
18471657Sbrian  /* Drops all child prompts and re-opens the socket */
18571657Sbrian  server_Reopen(SignalBundle);
18671657Sbrian}
18771657Sbrian
18871657Sbrianstatic void
18931343SbrianUsage(void)
1906059Samurai{
19195258Sdes  fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |"
19267912Sbrian          " -dedicated | -ddial | -interactive]"
19331343Sbrian#ifndef NOALIAS
19450059Sbrian          " [-nat]"
19531343Sbrian#endif
19652396Sbrian          " [-quiet] [-unit N] [system ...]\n");
1976059Samurai  exit(EX_START);
1986059Samurai}
1996059Samurai
20052396Sbrianstruct switches {
20152396Sbrian  unsigned nat : 1;
20252396Sbrian  unsigned fg : 1;
20352396Sbrian  unsigned quiet : 1;
20452396Sbrian  int mode;
20552396Sbrian  int unit;
20652396Sbrian};
20752396Sbrian
20840797Sbrianstatic int
20952396SbrianProcessArgs(int argc, char **argv, struct switches *sw)
2106059Samurai{
21140797Sbrian  int optc, newmode, arg;
2126059Samurai  char *cp;
2136059Samurai
21440797Sbrian  optc = 0;
21552396Sbrian  memset(sw, '\0', sizeof *sw);
21652396Sbrian  sw->mode = PHYS_INTERACTIVE;
21752396Sbrian  sw->unit = -1;
21852396Sbrian
21940797Sbrian  for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) {
22040797Sbrian    cp = argv[arg] + 1;
22136465Sbrian    newmode = Nam2mode(cp);
22236465Sbrian    switch (newmode) {
22336465Sbrian      case PHYS_NONE:
22452396Sbrian        if (strcmp(cp, "nat") == 0) {
22550059Sbrian#ifdef NONAT
22652396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
22737191Sbrian#else
22852396Sbrian          sw->nat = 1;
22936285Sbrian#endif
23036465Sbrian          optc--;			/* this option isn't exclusive */
23152396Sbrian        } else if (strcmp(cp, "alias") == 0) {
23252396Sbrian#ifdef NONAT
23352396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
23452396Sbrian          fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]);
23552396Sbrian#else
23653889Sbrian          log_Printf(LogWARN, "%s is deprecated\n", argv[arg]);
23753889Sbrian          fprintf(stderr, "%s is deprecated\n", argv[arg]);
23852396Sbrian          sw->nat = 1;
23952396Sbrian#endif
24052396Sbrian          optc--;			/* this option isn't exclusive */
24152396Sbrian        } else if (strncmp(cp, "unit", 4) == 0) {
24253067Sbrian          optc--;			/* this option isn't exclusive */
24352396Sbrian          if (cp[4] == '\0') {
24453067Sbrian            optc--;			/* nor is the argument */
24552396Sbrian            if (++arg == argc) {
24652396Sbrian              fprintf(stderr, "-unit: Expected unit number\n");
24752396Sbrian              Usage();
24852396Sbrian            } else
24952396Sbrian              sw->unit = atoi(argv[arg]);
25052396Sbrian          } else
25152396Sbrian            sw->unit = atoi(cp + 4);
25250059Sbrian        } else if (strcmp(cp, "quiet") == 0) {
25352396Sbrian          sw->quiet = 1;
25450059Sbrian          optc--;			/* this option isn't exclusive */
25536465Sbrian        } else
25636465Sbrian          Usage();
25736465Sbrian        break;
25836465Sbrian
25936465Sbrian      case PHYS_ALL:
26036465Sbrian        Usage();
26136465Sbrian        break;
26236465Sbrian
26336465Sbrian      default:
26452396Sbrian        sw->mode = newmode;
26553830Sbrian        if (newmode == PHYS_FOREGROUND)
26653830Sbrian          sw->fg = 1;
26736465Sbrian    }
2686059Samurai  }
26936465Sbrian
2706059Samurai  if (optc > 1) {
27136285Sbrian    fprintf(stderr, "You may specify only one mode.\n");
2726059Samurai    exit(EX_START);
2736059Samurai  }
27431197Sbrian
27552396Sbrian  if (sw->mode == PHYS_AUTO && arg == argc) {
27640797Sbrian    fprintf(stderr, "A system must be specified in auto mode.\n");
27736285Sbrian    exit(EX_START);
27836285Sbrian  }
27936285Sbrian
28040797Sbrian  return arg;		/* Don't SetLabel yet ! */
2816059Samurai}
2826059Samurai
28340797Sbrianstatic void
28440797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode)
28540797Sbrian{
28640797Sbrian  const char *err;
28740797Sbrian
28840797Sbrian  if ((err = system_IsValid(label, prompt, mode)) != NULL) {
28940797Sbrian    fprintf(stderr, "%s: %s\n", label, err);
29040797Sbrian    if (mode == PHYS_DIRECT)
29140797Sbrian      log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n",
29240797Sbrian                 label, err);
29340797Sbrian    log_Close();
29440797Sbrian    exit(1);
29540797Sbrian  }
29640797Sbrian}
29740797Sbrian
29840797Sbrian
29926940Sbrianint
30028679Sbrianmain(int argc, char **argv)
3016059Samurai{
30240797Sbrian  char *name;
30343187Sbrian  const char *lastlabel;
30479173Sbrian  int arg, f, holdfd[3], label;
30536285Sbrian  struct bundle *bundle;
30636285Sbrian  struct prompt *prompt;
30752396Sbrian  struct switches sw;
30826516Sbrian
30981697Sbrian  probe_Init();
31081697Sbrian
31179173Sbrian  /*
31279173Sbrian   * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and
31379173Sbrian   * STDERR_FILENO are always open.  These are closed before DoLoop(),
31479173Sbrian   * but *after* we've avoided the possibility of erroneously closing
31579173Sbrian   * an important descriptor with close(STD{IN,OUT,ERR}_FILENO).
31679173Sbrian   */
31779173Sbrian  if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) {
31879173Sbrian    fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL);
31979173Sbrian    return 2;
32079173Sbrian  }
32179173Sbrian  for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++)
32279186Sbrian    holdfd[f] = dup(holdfd[0]);
32379173Sbrian
32430715Sbrian  name = strrchr(argv[0], '/');
32536285Sbrian  log_Open(name ? name + 1 : argv[0]);
32626516Sbrian
32750059Sbrian#ifndef NONAT
32838198Sbrian  PacketAliasInit();
32938198Sbrian#endif
33052396Sbrian  label = ProcessArgs(argc, argv, &sw);
33131121Sbrian
33236285Sbrian  /*
33344539Sbrian   * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops
33444539Sbrian   * output occasionally.... I must find the real reason some time.  To
33544539Sbrian   * display the dodgy behaviour, comment out this bit, make yourself a large
33636285Sbrian   * routing table and then run ppp in interactive mode.  The `show route'
33736285Sbrian   * command will drop chunks of data !!!
33836285Sbrian   */
33952396Sbrian  if (sw.mode == PHYS_INTERACTIVE) {
34036285Sbrian    close(STDIN_FILENO);
34136285Sbrian    if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
34236285Sbrian      fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
34336285Sbrian      return 2;
34436285Sbrian    }
34536285Sbrian  }
34636285Sbrian
34736285Sbrian  /* Allow output for the moment (except in direct mode) */
34852396Sbrian  if (sw.mode == PHYS_DIRECT)
34936285Sbrian    prompt = NULL;
35043526Sbrian  else
35136285Sbrian    SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);
35236285Sbrian
35331121Sbrian  ID0init();
35431158Sbrian  if (ID0realuid() != 0) {
35531158Sbrian    char conf[200], *ptr;
35631158Sbrian
35774687Sbrian    snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE);
35831158Sbrian    do {
35949581Sbrian      struct stat sb;
36049581Sbrian
36149581Sbrian      if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) {
36237019Sbrian        log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n",
36337019Sbrian                   conf);
36431158Sbrian        return -1;
36531158Sbrian      }
36631158Sbrian      ptr = conf + strlen(conf)-2;
36731158Sbrian      while (ptr > conf && *ptr != '/')
36831158Sbrian        *ptr-- = '\0';
36931158Sbrian    } while (ptr >= conf);
37031158Sbrian  }
37131158Sbrian
37240797Sbrian  if (label < argc)
37340797Sbrian    for (arg = label; arg < argc; arg++)
37452396Sbrian      CheckLabel(argv[arg], prompt, sw.mode);
37540797Sbrian  else
37652396Sbrian    CheckLabel("default", prompt, sw.mode);
37731121Sbrian
37852396Sbrian  if (!sw.quiet)
37952396Sbrian    prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode));
38043526Sbrian
38153298Sbrian  if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL)
38226940Sbrian    return EX_START;
38343187Sbrian
38443187Sbrian  /* NOTE:  We may now have changed argv[1] via a ``set proctitle'' */
38543187Sbrian
38636314Sbrian  if (prompt) {
38736314Sbrian    prompt->bundle = bundle;	/* couldn't do it earlier */
38852396Sbrian    if (!sw.quiet)
38950059Sbrian      prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name);
39036314Sbrian  }
39136285Sbrian  SignalBundle = bundle;
39252396Sbrian  bundle->NatEnabled = sw.nat;
39352396Sbrian  if (sw.nat)
39440561Sbrian    bundle->cfg.opt |= OPT_IFACEALIAS;
39531121Sbrian
39637008Sbrian  if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0)
39736285Sbrian    prompt_Printf(prompt, "Warning: No default entry found in config file.\n");
39836285Sbrian
39936285Sbrian  sig_signal(SIGHUP, CloseSession);
40036285Sbrian  sig_signal(SIGTERM, CloseSession);
40136285Sbrian  sig_signal(SIGINT, CloseConnection);
40236285Sbrian  sig_signal(SIGQUIT, CloseSession);
40336285Sbrian  sig_signal(SIGALRM, SIG_IGN);
40424753Sache  signal(SIGPIPE, SIG_IGN);
4056059Samurai
40652396Sbrian  if (sw.mode == PHYS_INTERACTIVE)
40736285Sbrian    sig_signal(SIGTSTP, TerminalStop);
40836285Sbrian
40971657Sbrian  sig_signal(SIGUSR1, RestartServer);
41036285Sbrian  sig_signal(SIGUSR2, BringDownServer);
41136285Sbrian
41253298Sbrian  lastlabel = argv[argc - 1];
41340797Sbrian  for (arg = label; arg < argc; arg++) {
41440797Sbrian    /* In case we use LABEL or ``set enddisc label'' */
41543187Sbrian    bundle_SetLabel(bundle, lastlabel);
41653298Sbrian    system_Select(bundle, argv[arg], CONFFILE, prompt, NULL);
4176059Samurai  }
41826940Sbrian
41940797Sbrian  if (label < argc)
42040797Sbrian    /* In case the last label did a ``load'' */
42143187Sbrian    bundle_SetLabel(bundle, lastlabel);
42240797Sbrian
42352396Sbrian  if (sw.mode == PHYS_AUTO &&
42481634Sbrian      ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) {
42540797Sbrian    prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address "
42640797Sbrian                  "in auto mode.\n");
42740797Sbrian    AbortProgram(EX_START);
42840797Sbrian  }
42940797Sbrian
43052396Sbrian  if (sw.mode != PHYS_INTERACTIVE) {
43152396Sbrian    if (sw.mode != PHYS_DIRECT) {
43252396Sbrian      if (!sw.fg) {
43350059Sbrian        int bgpipe[2];
43450059Sbrian        pid_t bgpid;
43536285Sbrian
43652396Sbrian        if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) {
43750059Sbrian          log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
43850059Sbrian	  AbortProgram(EX_SOCK);
43950059Sbrian        }
4406059Samurai
44150059Sbrian        bgpid = fork();
44250059Sbrian        if (bgpid == -1) {
44350059Sbrian	  log_Printf(LogERROR, "fork: %s\n", strerror(errno));
44450059Sbrian	  AbortProgram(EX_SOCK);
44550059Sbrian        }
44636285Sbrian
44750059Sbrian        if (bgpid) {
44850059Sbrian	  char c = EX_NORMAL;
44959084Sbrian          int ret;
45011336Samurai
45152396Sbrian	  if (sw.mode == PHYS_BACKGROUND) {
45250059Sbrian	    close(bgpipe[1]);
45350059Sbrian	    BGPid = bgpid;
45450059Sbrian            /* If we get a signal, kill the child */
45550059Sbrian            signal(SIGHUP, KillChild);
45650059Sbrian            signal(SIGTERM, KillChild);
45750059Sbrian            signal(SIGINT, KillChild);
45850059Sbrian            signal(SIGQUIT, KillChild);
45936285Sbrian
46050059Sbrian	    /* Wait for our child to close its pipe before we exit */
46159084Sbrian            while ((ret = read(bgpipe[0], &c, 1)) == 1) {
46259084Sbrian              switch (c) {
46359084Sbrian                case EX_NORMAL:
46475120Sbrian                  if (!sw.quiet) {
46575120Sbrian	            prompt_Printf(prompt, "PPP enabled\n");
46675120Sbrian	            log_Printf(LogPHASE, "Parent: PPP enabled\n");
46775120Sbrian                  }
46859104Sbrian	          break;
46959084Sbrian                case EX_REDIAL:
47059084Sbrian                  if (!sw.quiet)
47159084Sbrian	            prompt_Printf(prompt, "Attempting redial\n");
47259084Sbrian                  continue;
47359084Sbrian                case EX_RECONNECT:
47459084Sbrian                  if (!sw.quiet)
47559084Sbrian	            prompt_Printf(prompt, "Attempting reconnect\n");
47659084Sbrian                  continue;
47759084Sbrian	        default:
47859084Sbrian	          prompt_Printf(prompt, "Child failed (%s)\n",
47959084Sbrian                                ex_desc((int)c));
48059084Sbrian	          log_Printf(LogPHASE, "Parent: Child failed (%s)\n",
48159084Sbrian		             ex_desc((int) c));
48259084Sbrian	      }
48359084Sbrian	      break;
48459084Sbrian            }
48559084Sbrian            if (ret != 1) {
48650059Sbrian	      prompt_Printf(prompt, "Child exit, no status.\n");
48750059Sbrian	      log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
48850059Sbrian	    }
48950059Sbrian	    close(bgpipe[0]);
49028679Sbrian	  }
49150059Sbrian	  return c;
49252396Sbrian        } else if (sw.mode == PHYS_BACKGROUND) {
49336285Sbrian	  close(bgpipe[0]);
49450059Sbrian          bundle->notify.fd = bgpipe[1];
49550059Sbrian        }
49650059Sbrian
49756350Sbrian        bundle_ChangedPID(bundle);
49850059Sbrian        bundle_LockTun(bundle);	/* we have a new pid */
49936285Sbrian      }
50020813Sjkh
50150059Sbrian      /* -auto, -dedicated, -ddial, -foreground & -background */
50236285Sbrian      prompt_Destroy(prompt, 0);
50336285Sbrian      close(STDOUT_FILENO);
50436285Sbrian      close(STDERR_FILENO);
50536285Sbrian      close(STDIN_FILENO);
50652396Sbrian      if (!sw.fg)
50750059Sbrian        setsid();
50836285Sbrian    } else {
50950059Sbrian      /* -direct - STDIN_FILENO gets used by physical_Open */
51036285Sbrian      prompt_TtyInit(NULL);
51136285Sbrian      close(STDOUT_FILENO);
51236285Sbrian      close(STDERR_FILENO);
51326686Sbrian    }
5146059Samurai  } else {
51550059Sbrian    /* -interactive */
51632129Sbrian    close(STDERR_FILENO);
51736285Sbrian    prompt_TtyInit(prompt);
51836285Sbrian    prompt_TtyCommandMode(prompt);
51936285Sbrian    prompt_Required(prompt);
5206059Samurai  }
52129696Sbrian
52279173Sbrian  /* We can get rid of these now */
52379173Sbrian  for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++)
52479173Sbrian    close(holdfd[f]);
52579173Sbrian
52652396Sbrian  log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode));
52736431Sbrian  DoLoop(bundle);
52836285Sbrian  AbortProgram(EX_NORMAL);
5296059Samurai
53036285Sbrian  return EX_NORMAL;
5316059Samurai}
5326059Samurai
5336059Samuraistatic void
53436431SbrianDoLoop(struct bundle *bundle)
5356059Samurai{
53666898Sbrian  fd_set *rfds, *wfds, *efds;
53737141Sbrian  int i, nfds, nothing_done;
5386059Samurai
53966898Sbrian  if ((rfds = mkfdset()) == NULL) {
54066898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54166898Sbrian    return;
54266898Sbrian  }
54366898Sbrian
54466898Sbrian  if ((wfds = mkfdset()) == NULL) {
54566898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54666898Sbrian    free(rfds);
54766898Sbrian    return;
54866898Sbrian  }
54966898Sbrian
55066898Sbrian  if ((efds = mkfdset()) == NULL) {
55166898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
55266898Sbrian    free(rfds);
55366898Sbrian    free(wfds);
55466898Sbrian    return;
55566898Sbrian  }
55666898Sbrian
55753070Sbrian  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
55823598Sache    nfds = 0;
55966898Sbrian    zerofdset(rfds);
56066898Sbrian    zerofdset(wfds);
56166898Sbrian    zerofdset(efds);
5627001Samurai
56336314Sbrian    /* All our datalinks, the tun device and the MP socket */
56466898Sbrian    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);
56525067Sbrian
56636314Sbrian    /* All our prompts and the diagnostic socket */
56766898Sbrian    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);
56836314Sbrian
56958453Sbrian    bundle_CleanDatalinks(bundle);
57036285Sbrian    if (bundle_IsDead(bundle))
57136285Sbrian      /* Don't select - we'll be here forever */
57236285Sbrian      break;
57326551Sbrian
57445126Sbrian    /*
57545126Sbrian     * It's possible that we've had a signal since we last checked.  If
57645126Sbrian     * we don't check again before calling select(), we may end up stuck
57745126Sbrian     * after having missed the event.... sig_Handle() tries to be as
57845126Sbrian     * quick as possible if nothing is likely to have happened.
57945126Sbrian     * This is only really likely if we block in open(... O_NONBLOCK)
58045126Sbrian     * which will happen with a misconfigured device.
58145126Sbrian     */
58245126Sbrian    if (sig_Handle())
58345126Sbrian      continue;
58445126Sbrian
58566898Sbrian    i = select(nfds, rfds, wfds, efds, NULL);
58626696Sbrian
58736345Sbrian    if (i < 0 && errno != EINTR) {
58836285Sbrian      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
58936285Sbrian      if (log_IsKept(LogTIMER)) {
59036285Sbrian        struct timeval t;
59136285Sbrian
59236285Sbrian        for (i = 0; i <= nfds; i++) {
59366898Sbrian          if (FD_ISSET(i, rfds)) {
59436285Sbrian            log_Printf(LogTIMER, "Read set contains %d\n", i);
59566898Sbrian            FD_CLR(i, rfds);
59636285Sbrian            t.tv_sec = t.tv_usec = 0;
59766898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
59836285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
59936285Sbrian              break;
60036285Sbrian            }
60136285Sbrian          }
60266898Sbrian          if (FD_ISSET(i, wfds)) {
60336285Sbrian            log_Printf(LogTIMER, "Write set contains %d\n", i);
60466898Sbrian            FD_CLR(i, wfds);
60536285Sbrian            t.tv_sec = t.tv_usec = 0;
60666898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
60736285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
60836285Sbrian              break;
60936285Sbrian            }
61036285Sbrian          }
61166898Sbrian          if (FD_ISSET(i, efds)) {
61236285Sbrian            log_Printf(LogTIMER, "Error set contains %d\n", i);
61366898Sbrian            FD_CLR(i, efds);
61436285Sbrian            t.tv_sec = t.tv_usec = 0;
61566898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
61636285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
61736285Sbrian              break;
61836285Sbrian            }
61936285Sbrian          }
62036285Sbrian        }
62128679Sbrian      }
62228679Sbrian      break;
6238857Srgrimes    }
6246059Samurai
62543693Sbrian    log_Printf(LogTIMER, "Select returns %d\n", i);
62643693Sbrian
62736345Sbrian    sig_Handle();
62836345Sbrian
62936345Sbrian    if (i <= 0)
63036345Sbrian      continue;
63136345Sbrian
63236285Sbrian    for (i = 0; i <= nfds; i++)
63366898Sbrian      if (FD_ISSET(i, efds)) {
63458038Sbrian        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
63558038Sbrian        /* We deal gracefully with link descriptor exceptions */
63641654Sbrian        if (!bundle_Exception(bundle, i)) {
63741654Sbrian          log_Printf(LogERROR, "Exception cannot be handled !\n");
63841654Sbrian          break;
63941654Sbrian        }
6406059Samurai      }
64128679Sbrian
64236285Sbrian    if (i <= nfds)
64336285Sbrian      break;
64428536Sbrian
64537141Sbrian    nothing_done = 1;
64637141Sbrian
64766898Sbrian    if (descriptor_IsSet(&server.desc, rfds)) {
64866898Sbrian      descriptor_Read(&server.desc, bundle, rfds);
64937141Sbrian      nothing_done = 0;
65037141Sbrian    }
65132039Sbrian
65266898Sbrian    if (descriptor_IsSet(&bundle->desc, rfds)) {
65366898Sbrian      descriptor_Read(&bundle->desc, bundle, rfds);
65437141Sbrian      nothing_done = 0;
65537141Sbrian    }
65637141Sbrian
65766898Sbrian    if (descriptor_IsSet(&bundle->desc, wfds))
65893418Sbrian      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
65937141Sbrian        /*
66093418Sbrian         * This is disastrous.  The OS has told us that something is
66137141Sbrian         * writable, and all our write()s have failed.  Rather than
66237141Sbrian         * going back immediately to do our UpdateSet()s and select(),
66337141Sbrian         * we sleep for a bit to avoid gobbling up all cpu time.
66437141Sbrian         */
66537141Sbrian        struct timeval t;
66636285Sbrian
66737141Sbrian        t.tv_sec = 0;
66837141Sbrian        t.tv_usec = 100000;
66937141Sbrian        select(0, NULL, NULL, NULL, &t);
67037141Sbrian      }
67153070Sbrian  }
67236285Sbrian
67336285Sbrian  log_Printf(LogDEBUG, "DoLoop done.\n");
6746059Samurai}
675