main.c revision 102500
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 102500 2002-08-27 20:11:58Z 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>
43102500Sbrian#include <stdarg.h>
4430715Sbrian#include <stdio.h>
4552396Sbrian#include <stdlib.h>
4630715Sbrian#include <string.h>
4797140Sbrian#include <sys/time.h>
486059Samurai#include <termios.h>
4918786Sjkh#include <unistd.h>
5049581Sbrian#include <sys/stat.h>
5130715Sbrian
5250059Sbrian#ifndef NONAT
5358037Sbrian#ifdef LOCALNAT
5458037Sbrian#include "alias.h"
5558037Sbrian#else
5646086Sbrian#include <alias.h>
5739395Sbrian#endif
5839395Sbrian#endif
5958037Sbrian
6046686Sbrian#include "layer.h"
6137141Sbrian#include "probe.h"
6230715Sbrian#include "mbuf.h"
6330715Sbrian#include "log.h"
6430715Sbrian#include "defs.h"
6531061Sbrian#include "id.h"
6630715Sbrian#include "timer.h"
6730715Sbrian#include "fsm.h"
6836285Sbrian#include "lqr.h"
696059Samurai#include "hdlc.h"
7031514Sbrian#include "lcp.h"
7113389Sphk#include "ccp.h"
7236285Sbrian#include "iplist.h"
7336285Sbrian#include "throughput.h"
7436285Sbrian#include "slcompress.h"
7581634Sbrian#include "ncpaddr.h"
766059Samurai#include "ipcp.h"
7736285Sbrian#include "filter.h"
7836285Sbrian#include "descriptor.h"
7936285Sbrian#include "link.h"
8036285Sbrian#include "mp.h"
8143313Sbrian#ifndef NORADIUS
8243313Sbrian#include "radius.h"
8343313Sbrian#endif
8481634Sbrian#include "ipv6cp.h"
8581634Sbrian#include "ncp.h"
8636285Sbrian#include "bundle.h"
876735Samurai#include "auth.h"
8813389Sphk#include "systems.h"
8923840Sbrian#include "sig.h"
9030715Sbrian#include "main.h"
9136285Sbrian#include "server.h"
9236285Sbrian#include "prompt.h"
9336285Sbrian#include "chat.h"
9436285Sbrian#include "chap.h"
9538174Sbrian#include "cbcp.h"
9636285Sbrian#include "datalink.h"
9740561Sbrian#include "iface.h"
986059Samurai
996735Samurai#ifndef O_NONBLOCK
1006735Samurai#ifdef O_NDELAY
1016735Samurai#define	O_NONBLOCK O_NDELAY
1026735Samurai#endif
1036735Samurai#endif
1046735Samurai
10536431Sbrianstatic void DoLoop(struct bundle *);
10630715Sbrianstatic void TerminalStop(int);
10730715Sbrian
10836285Sbrianstatic struct bundle *SignalBundle;
10936285Sbrianstatic struct prompt *SignalPrompt;
1106059Samurai
11110528Samuraivoid
11236285SbrianCleanup(int excode)
1136059Samurai{
11436285Sbrian  SignalBundle->CleaningUp = 1;
11538008Sbrian  bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
1166059Samurai}
1176059Samurai
1186059Samuraivoid
11936285SbrianAbortProgram(int excode)
1206059Samurai{
12198970Sbrian  if (SignalBundle)
12298970Sbrian    server_Close(SignalBundle);
12336285Sbrian  log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
12498970Sbrian  if (SignalBundle) {
12598970Sbrian    bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
12698970Sbrian    bundle_Destroy(SignalBundle);
12798970Sbrian  }
12836285Sbrian  log_Close();
1296059Samurai  exit(excode);
1306059Samurai}
1316059Samurai
1326059Samuraistatic void
13328679SbrianCloseConnection(int signo)
1346059Samurai{
13526858Sbrian  /* NOTE, these are manual, we've done a setsid() */
13636285Sbrian  sig_signal(SIGINT, SIG_IGN);
13736285Sbrian  log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo);
13837018Sbrian  bundle_Down(SignalBundle, CLOSE_STAYDOWN);
13936285Sbrian  sig_signal(SIGINT, CloseConnection);
1406059Samurai}
1416059Samurai
1426059Samuraistatic void
14328679SbrianCloseSession(int signo)
1446059Samurai{
14536285Sbrian  log_Printf(LogPHASE, "Signal %d, terminate.\n", signo);
14628679Sbrian  Cleanup(EX_TERM);
1476059Samurai}
1486059Samurai
14936285Sbrianstatic pid_t BGPid = 0;
15036285Sbrian
15110528Samuraistatic void
15236285SbrianKillChild(int signo)
15310528Samurai{
15447119Sbrian  signal(signo, SIG_IGN);
15536285Sbrian  log_Printf(LogPHASE, "Parent: Signal %d\n", signo);
15636285Sbrian  kill(BGPid, SIGINT);
15710528Samurai}
15810528Samurai
15910528Samuraistatic void
16036285SbrianTerminalCont(int signo)
16110528Samurai{
16236285Sbrian  signal(SIGCONT, SIG_DFL);
16336285Sbrian  prompt_Continue(SignalPrompt);
16410528Samurai}
16510528Samurai
16626940Sbrianstatic void
16736285SbrianTerminalStop(int signo)
16826940Sbrian{
16936285Sbrian  prompt_Suspend(SignalPrompt);
17036285Sbrian  signal(SIGCONT, TerminalCont);
17136285Sbrian  raise(SIGSTOP);
17226940Sbrian}
17326940Sbrian
17431081Sbrianstatic void
17531081SbrianBringDownServer(int signo)
17631081Sbrian{
17736285Sbrian  /* Drops all child prompts too ! */
17871657Sbrian  if (server_Close(SignalBundle))
17971657Sbrian    log_Printf(LogPHASE, "Closed server socket\n");
18031081Sbrian}
18131081Sbrian
18230715Sbrianstatic void
18371657SbrianRestartServer(int signo)
18471657Sbrian{
18571657Sbrian  /* Drops all child prompts and re-opens the socket */
18671657Sbrian  server_Reopen(SignalBundle);
18771657Sbrian}
18871657Sbrian
18971657Sbrianstatic void
19031343SbrianUsage(void)
1916059Samurai{
19295258Sdes  fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |"
19367912Sbrian          " -dedicated | -ddial | -interactive]"
19431343Sbrian#ifndef NOALIAS
19550059Sbrian          " [-nat]"
19631343Sbrian#endif
19752396Sbrian          " [-quiet] [-unit N] [system ...]\n");
1986059Samurai  exit(EX_START);
1996059Samurai}
2006059Samurai
20152396Sbrianstruct switches {
20252396Sbrian  unsigned nat : 1;
20352396Sbrian  unsigned fg : 1;
20452396Sbrian  unsigned quiet : 1;
20552396Sbrian  int mode;
20652396Sbrian  int unit;
20752396Sbrian};
20852396Sbrian
20940797Sbrianstatic int
21052396SbrianProcessArgs(int argc, char **argv, struct switches *sw)
2116059Samurai{
21240797Sbrian  int optc, newmode, arg;
2136059Samurai  char *cp;
2146059Samurai
21540797Sbrian  optc = 0;
21652396Sbrian  memset(sw, '\0', sizeof *sw);
21752396Sbrian  sw->mode = PHYS_INTERACTIVE;
21852396Sbrian  sw->unit = -1;
21952396Sbrian
22040797Sbrian  for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) {
22140797Sbrian    cp = argv[arg] + 1;
22236465Sbrian    newmode = Nam2mode(cp);
22336465Sbrian    switch (newmode) {
22436465Sbrian      case PHYS_NONE:
22552396Sbrian        if (strcmp(cp, "nat") == 0) {
22650059Sbrian#ifdef NONAT
22752396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
22837191Sbrian#else
22952396Sbrian          sw->nat = 1;
23036285Sbrian#endif
23136465Sbrian          optc--;			/* this option isn't exclusive */
23252396Sbrian        } else if (strcmp(cp, "alias") == 0) {
23352396Sbrian#ifdef NONAT
23452396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
23552396Sbrian          fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]);
23652396Sbrian#else
23753889Sbrian          log_Printf(LogWARN, "%s is deprecated\n", argv[arg]);
23853889Sbrian          fprintf(stderr, "%s is deprecated\n", argv[arg]);
23952396Sbrian          sw->nat = 1;
24052396Sbrian#endif
24152396Sbrian          optc--;			/* this option isn't exclusive */
24252396Sbrian        } else if (strncmp(cp, "unit", 4) == 0) {
24353067Sbrian          optc--;			/* this option isn't exclusive */
24452396Sbrian          if (cp[4] == '\0') {
24553067Sbrian            optc--;			/* nor is the argument */
24652396Sbrian            if (++arg == argc) {
24752396Sbrian              fprintf(stderr, "-unit: Expected unit number\n");
24852396Sbrian              Usage();
24952396Sbrian            } else
25052396Sbrian              sw->unit = atoi(argv[arg]);
25152396Sbrian          } else
25252396Sbrian            sw->unit = atoi(cp + 4);
25350059Sbrian        } else if (strcmp(cp, "quiet") == 0) {
25452396Sbrian          sw->quiet = 1;
25550059Sbrian          optc--;			/* this option isn't exclusive */
25636465Sbrian        } else
25736465Sbrian          Usage();
25836465Sbrian        break;
25936465Sbrian
26036465Sbrian      case PHYS_ALL:
26136465Sbrian        Usage();
26236465Sbrian        break;
26336465Sbrian
26436465Sbrian      default:
26552396Sbrian        sw->mode = newmode;
26653830Sbrian        if (newmode == PHYS_FOREGROUND)
26753830Sbrian          sw->fg = 1;
26836465Sbrian    }
2696059Samurai  }
27036465Sbrian
2716059Samurai  if (optc > 1) {
27236285Sbrian    fprintf(stderr, "You may specify only one mode.\n");
2736059Samurai    exit(EX_START);
2746059Samurai  }
27531197Sbrian
27652396Sbrian  if (sw->mode == PHYS_AUTO && arg == argc) {
27740797Sbrian    fprintf(stderr, "A system must be specified in auto mode.\n");
27836285Sbrian    exit(EX_START);
27936285Sbrian  }
28036285Sbrian
28140797Sbrian  return arg;		/* Don't SetLabel yet ! */
2826059Samurai}
2836059Samurai
28440797Sbrianstatic void
28540797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode)
28640797Sbrian{
28740797Sbrian  const char *err;
28840797Sbrian
28940797Sbrian  if ((err = system_IsValid(label, prompt, mode)) != NULL) {
29040797Sbrian    fprintf(stderr, "%s: %s\n", label, err);
29140797Sbrian    if (mode == PHYS_DIRECT)
29240797Sbrian      log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n",
29340797Sbrian                 label, err);
29440797Sbrian    log_Close();
29540797Sbrian    exit(1);
29640797Sbrian  }
29740797Sbrian}
29840797Sbrian
29940797Sbrian
30026940Sbrianint
30128679Sbrianmain(int argc, char **argv)
3026059Samurai{
30340797Sbrian  char *name;
30443187Sbrian  const char *lastlabel;
30579173Sbrian  int arg, f, holdfd[3], label;
30636285Sbrian  struct bundle *bundle;
30736285Sbrian  struct prompt *prompt;
30852396Sbrian  struct switches sw;
30926516Sbrian
31081697Sbrian  probe_Init();
31181697Sbrian
31279173Sbrian  /*
31379173Sbrian   * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and
31479173Sbrian   * STDERR_FILENO are always open.  These are closed before DoLoop(),
31579173Sbrian   * but *after* we've avoided the possibility of erroneously closing
31679173Sbrian   * an important descriptor with close(STD{IN,OUT,ERR}_FILENO).
31779173Sbrian   */
31879173Sbrian  if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) {
31979173Sbrian    fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL);
32079173Sbrian    return 2;
32179173Sbrian  }
32279173Sbrian  for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++)
32379186Sbrian    holdfd[f] = dup(holdfd[0]);
32479173Sbrian
32530715Sbrian  name = strrchr(argv[0], '/');
32636285Sbrian  log_Open(name ? name + 1 : argv[0]);
32726516Sbrian
32850059Sbrian#ifndef NONAT
32938198Sbrian  PacketAliasInit();
33038198Sbrian#endif
33152396Sbrian  label = ProcessArgs(argc, argv, &sw);
33231121Sbrian
33336285Sbrian  /*
33444539Sbrian   * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops
33544539Sbrian   * output occasionally.... I must find the real reason some time.  To
33644539Sbrian   * display the dodgy behaviour, comment out this bit, make yourself a large
33736285Sbrian   * routing table and then run ppp in interactive mode.  The `show route'
33836285Sbrian   * command will drop chunks of data !!!
33936285Sbrian   */
34052396Sbrian  if (sw.mode == PHYS_INTERACTIVE) {
34136285Sbrian    close(STDIN_FILENO);
34236285Sbrian    if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
34336285Sbrian      fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
34436285Sbrian      return 2;
34536285Sbrian    }
34636285Sbrian  }
34736285Sbrian
34836285Sbrian  /* Allow output for the moment (except in direct mode) */
34952396Sbrian  if (sw.mode == PHYS_DIRECT)
35036285Sbrian    prompt = NULL;
35143526Sbrian  else
35236285Sbrian    SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);
35336285Sbrian
35431121Sbrian  ID0init();
35531158Sbrian  if (ID0realuid() != 0) {
35631158Sbrian    char conf[200], *ptr;
35731158Sbrian
35874687Sbrian    snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE);
35931158Sbrian    do {
36049581Sbrian      struct stat sb;
36149581Sbrian
36249581Sbrian      if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) {
36337019Sbrian        log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n",
36437019Sbrian                   conf);
36531158Sbrian        return -1;
36631158Sbrian      }
36731158Sbrian      ptr = conf + strlen(conf)-2;
36831158Sbrian      while (ptr > conf && *ptr != '/')
36931158Sbrian        *ptr-- = '\0';
37031158Sbrian    } while (ptr >= conf);
37131158Sbrian  }
37231158Sbrian
37340797Sbrian  if (label < argc)
37440797Sbrian    for (arg = label; arg < argc; arg++)
37552396Sbrian      CheckLabel(argv[arg], prompt, sw.mode);
37640797Sbrian  else
37752396Sbrian    CheckLabel("default", prompt, sw.mode);
37831121Sbrian
37952396Sbrian  if (!sw.quiet)
38052396Sbrian    prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode));
38143526Sbrian
38253298Sbrian  if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL)
38326940Sbrian    return EX_START;
38443187Sbrian
38543187Sbrian  /* NOTE:  We may now have changed argv[1] via a ``set proctitle'' */
38643187Sbrian
38736314Sbrian  if (prompt) {
38836314Sbrian    prompt->bundle = bundle;	/* couldn't do it earlier */
38952396Sbrian    if (!sw.quiet)
39050059Sbrian      prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name);
39136314Sbrian  }
39236285Sbrian  SignalBundle = bundle;
39352396Sbrian  bundle->NatEnabled = sw.nat;
39452396Sbrian  if (sw.nat)
39540561Sbrian    bundle->cfg.opt |= OPT_IFACEALIAS;
39631121Sbrian
39737008Sbrian  if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0)
39836285Sbrian    prompt_Printf(prompt, "Warning: No default entry found in config file.\n");
39936285Sbrian
40036285Sbrian  sig_signal(SIGHUP, CloseSession);
40136285Sbrian  sig_signal(SIGTERM, CloseSession);
40236285Sbrian  sig_signal(SIGINT, CloseConnection);
40336285Sbrian  sig_signal(SIGQUIT, CloseSession);
40436285Sbrian  sig_signal(SIGALRM, SIG_IGN);
40524753Sache  signal(SIGPIPE, SIG_IGN);
4066059Samurai
40752396Sbrian  if (sw.mode == PHYS_INTERACTIVE)
40836285Sbrian    sig_signal(SIGTSTP, TerminalStop);
40936285Sbrian
41071657Sbrian  sig_signal(SIGUSR1, RestartServer);
41136285Sbrian  sig_signal(SIGUSR2, BringDownServer);
41236285Sbrian
41353298Sbrian  lastlabel = argv[argc - 1];
41440797Sbrian  for (arg = label; arg < argc; arg++) {
41540797Sbrian    /* In case we use LABEL or ``set enddisc label'' */
41643187Sbrian    bundle_SetLabel(bundle, lastlabel);
41753298Sbrian    system_Select(bundle, argv[arg], CONFFILE, prompt, NULL);
4186059Samurai  }
41926940Sbrian
42040797Sbrian  if (label < argc)
42140797Sbrian    /* In case the last label did a ``load'' */
42243187Sbrian    bundle_SetLabel(bundle, lastlabel);
42340797Sbrian
42452396Sbrian  if (sw.mode == PHYS_AUTO &&
42581634Sbrian      ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) {
42640797Sbrian    prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address "
42740797Sbrian                  "in auto mode.\n");
42840797Sbrian    AbortProgram(EX_START);
42940797Sbrian  }
43040797Sbrian
43152396Sbrian  if (sw.mode != PHYS_INTERACTIVE) {
43252396Sbrian    if (sw.mode != PHYS_DIRECT) {
43352396Sbrian      if (!sw.fg) {
43450059Sbrian        int bgpipe[2];
43550059Sbrian        pid_t bgpid;
43636285Sbrian
43752396Sbrian        if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) {
43850059Sbrian          log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
43950059Sbrian	  AbortProgram(EX_SOCK);
44050059Sbrian        }
4416059Samurai
44250059Sbrian        bgpid = fork();
44350059Sbrian        if (bgpid == -1) {
44450059Sbrian	  log_Printf(LogERROR, "fork: %s\n", strerror(errno));
44550059Sbrian	  AbortProgram(EX_SOCK);
44650059Sbrian        }
44736285Sbrian
44850059Sbrian        if (bgpid) {
44950059Sbrian	  char c = EX_NORMAL;
45059084Sbrian          int ret;
45111336Samurai
45252396Sbrian	  if (sw.mode == PHYS_BACKGROUND) {
45350059Sbrian	    close(bgpipe[1]);
45450059Sbrian	    BGPid = bgpid;
45550059Sbrian            /* If we get a signal, kill the child */
45650059Sbrian            signal(SIGHUP, KillChild);
45750059Sbrian            signal(SIGTERM, KillChild);
45850059Sbrian            signal(SIGINT, KillChild);
45950059Sbrian            signal(SIGQUIT, KillChild);
46036285Sbrian
46150059Sbrian	    /* Wait for our child to close its pipe before we exit */
46259084Sbrian            while ((ret = read(bgpipe[0], &c, 1)) == 1) {
46359084Sbrian              switch (c) {
46459084Sbrian                case EX_NORMAL:
46575120Sbrian                  if (!sw.quiet) {
46675120Sbrian	            prompt_Printf(prompt, "PPP enabled\n");
46775120Sbrian	            log_Printf(LogPHASE, "Parent: PPP enabled\n");
46875120Sbrian                  }
46959104Sbrian	          break;
47059084Sbrian                case EX_REDIAL:
47159084Sbrian                  if (!sw.quiet)
47259084Sbrian	            prompt_Printf(prompt, "Attempting redial\n");
47359084Sbrian                  continue;
47459084Sbrian                case EX_RECONNECT:
47559084Sbrian                  if (!sw.quiet)
47659084Sbrian	            prompt_Printf(prompt, "Attempting reconnect\n");
47759084Sbrian                  continue;
47859084Sbrian	        default:
47959084Sbrian	          prompt_Printf(prompt, "Child failed (%s)\n",
48059084Sbrian                                ex_desc((int)c));
48159084Sbrian	          log_Printf(LogPHASE, "Parent: Child failed (%s)\n",
48259084Sbrian		             ex_desc((int) c));
48359084Sbrian	      }
48459084Sbrian	      break;
48559084Sbrian            }
48659084Sbrian            if (ret != 1) {
48750059Sbrian	      prompt_Printf(prompt, "Child exit, no status.\n");
48850059Sbrian	      log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
48950059Sbrian	    }
49050059Sbrian	    close(bgpipe[0]);
49128679Sbrian	  }
49250059Sbrian	  return c;
49352396Sbrian        } else if (sw.mode == PHYS_BACKGROUND) {
49436285Sbrian	  close(bgpipe[0]);
49550059Sbrian          bundle->notify.fd = bgpipe[1];
49650059Sbrian        }
49750059Sbrian
49856350Sbrian        bundle_ChangedPID(bundle);
49950059Sbrian        bundle_LockTun(bundle);	/* we have a new pid */
50036285Sbrian      }
50120813Sjkh
50250059Sbrian      /* -auto, -dedicated, -ddial, -foreground & -background */
50336285Sbrian      prompt_Destroy(prompt, 0);
50436285Sbrian      close(STDOUT_FILENO);
50536285Sbrian      close(STDERR_FILENO);
50636285Sbrian      close(STDIN_FILENO);
50752396Sbrian      if (!sw.fg)
50850059Sbrian        setsid();
50936285Sbrian    } else {
51050059Sbrian      /* -direct - STDIN_FILENO gets used by physical_Open */
51136285Sbrian      prompt_TtyInit(NULL);
51236285Sbrian      close(STDOUT_FILENO);
51336285Sbrian      close(STDERR_FILENO);
51426686Sbrian    }
5156059Samurai  } else {
51650059Sbrian    /* -interactive */
51732129Sbrian    close(STDERR_FILENO);
51836285Sbrian    prompt_TtyInit(prompt);
51936285Sbrian    prompt_TtyCommandMode(prompt);
52036285Sbrian    prompt_Required(prompt);
5216059Samurai  }
52229696Sbrian
52379173Sbrian  /* We can get rid of these now */
52479173Sbrian  for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++)
52579173Sbrian    close(holdfd[f]);
52679173Sbrian
52752396Sbrian  log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode));
52836431Sbrian  DoLoop(bundle);
52936285Sbrian  AbortProgram(EX_NORMAL);
5306059Samurai
53136285Sbrian  return EX_NORMAL;
5326059Samurai}
5336059Samurai
5346059Samuraistatic void
53536431SbrianDoLoop(struct bundle *bundle)
5366059Samurai{
53766898Sbrian  fd_set *rfds, *wfds, *efds;
53837141Sbrian  int i, nfds, nothing_done;
5396059Samurai
54066898Sbrian  if ((rfds = mkfdset()) == NULL) {
54166898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54266898Sbrian    return;
54366898Sbrian  }
54466898Sbrian
54566898Sbrian  if ((wfds = mkfdset()) == NULL) {
54666898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54766898Sbrian    free(rfds);
54866898Sbrian    return;
54966898Sbrian  }
55066898Sbrian
55166898Sbrian  if ((efds = mkfdset()) == NULL) {
55266898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
55366898Sbrian    free(rfds);
55466898Sbrian    free(wfds);
55566898Sbrian    return;
55666898Sbrian  }
55766898Sbrian
55853070Sbrian  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
55923598Sache    nfds = 0;
56066898Sbrian    zerofdset(rfds);
56166898Sbrian    zerofdset(wfds);
56266898Sbrian    zerofdset(efds);
5637001Samurai
56436314Sbrian    /* All our datalinks, the tun device and the MP socket */
56566898Sbrian    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);
56625067Sbrian
56736314Sbrian    /* All our prompts and the diagnostic socket */
56866898Sbrian    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);
56936314Sbrian
57058453Sbrian    bundle_CleanDatalinks(bundle);
57136285Sbrian    if (bundle_IsDead(bundle))
57236285Sbrian      /* Don't select - we'll be here forever */
57336285Sbrian      break;
57426551Sbrian
57545126Sbrian    /*
57645126Sbrian     * It's possible that we've had a signal since we last checked.  If
57745126Sbrian     * we don't check again before calling select(), we may end up stuck
57845126Sbrian     * after having missed the event.... sig_Handle() tries to be as
57945126Sbrian     * quick as possible if nothing is likely to have happened.
58045126Sbrian     * This is only really likely if we block in open(... O_NONBLOCK)
58145126Sbrian     * which will happen with a misconfigured device.
58245126Sbrian     */
58345126Sbrian    if (sig_Handle())
58445126Sbrian      continue;
58545126Sbrian
58666898Sbrian    i = select(nfds, rfds, wfds, efds, NULL);
58726696Sbrian
58836345Sbrian    if (i < 0 && errno != EINTR) {
58936285Sbrian      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
59036285Sbrian      if (log_IsKept(LogTIMER)) {
59136285Sbrian        struct timeval t;
59236285Sbrian
59336285Sbrian        for (i = 0; i <= nfds; i++) {
59466898Sbrian          if (FD_ISSET(i, rfds)) {
59536285Sbrian            log_Printf(LogTIMER, "Read set contains %d\n", i);
59666898Sbrian            FD_CLR(i, rfds);
59736285Sbrian            t.tv_sec = t.tv_usec = 0;
59866898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
59936285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
60036285Sbrian              break;
60136285Sbrian            }
60236285Sbrian          }
60366898Sbrian          if (FD_ISSET(i, wfds)) {
60436285Sbrian            log_Printf(LogTIMER, "Write set contains %d\n", i);
60566898Sbrian            FD_CLR(i, wfds);
60636285Sbrian            t.tv_sec = t.tv_usec = 0;
60766898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
60836285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
60936285Sbrian              break;
61036285Sbrian            }
61136285Sbrian          }
61266898Sbrian          if (FD_ISSET(i, efds)) {
61336285Sbrian            log_Printf(LogTIMER, "Error set contains %d\n", i);
61466898Sbrian            FD_CLR(i, efds);
61536285Sbrian            t.tv_sec = t.tv_usec = 0;
61666898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
61736285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
61836285Sbrian              break;
61936285Sbrian            }
62036285Sbrian          }
62136285Sbrian        }
62228679Sbrian      }
62328679Sbrian      break;
6248857Srgrimes    }
6256059Samurai
62643693Sbrian    log_Printf(LogTIMER, "Select returns %d\n", i);
62743693Sbrian
62836345Sbrian    sig_Handle();
62936345Sbrian
63036345Sbrian    if (i <= 0)
63136345Sbrian      continue;
63236345Sbrian
63336285Sbrian    for (i = 0; i <= nfds; i++)
63466898Sbrian      if (FD_ISSET(i, efds)) {
63558038Sbrian        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
63658038Sbrian        /* We deal gracefully with link descriptor exceptions */
63741654Sbrian        if (!bundle_Exception(bundle, i)) {
63841654Sbrian          log_Printf(LogERROR, "Exception cannot be handled !\n");
63941654Sbrian          break;
64041654Sbrian        }
6416059Samurai      }
64228679Sbrian
64336285Sbrian    if (i <= nfds)
64436285Sbrian      break;
64528536Sbrian
64637141Sbrian    nothing_done = 1;
64737141Sbrian
64866898Sbrian    if (descriptor_IsSet(&server.desc, rfds)) {
64966898Sbrian      descriptor_Read(&server.desc, bundle, rfds);
65037141Sbrian      nothing_done = 0;
65137141Sbrian    }
65232039Sbrian
65366898Sbrian    if (descriptor_IsSet(&bundle->desc, rfds)) {
65466898Sbrian      descriptor_Read(&bundle->desc, bundle, rfds);
65537141Sbrian      nothing_done = 0;
65637141Sbrian    }
65737141Sbrian
65866898Sbrian    if (descriptor_IsSet(&bundle->desc, wfds))
65993418Sbrian      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
66037141Sbrian        /*
66193418Sbrian         * This is disastrous.  The OS has told us that something is
66237141Sbrian         * writable, and all our write()s have failed.  Rather than
66337141Sbrian         * going back immediately to do our UpdateSet()s and select(),
66437141Sbrian         * we sleep for a bit to avoid gobbling up all cpu time.
66537141Sbrian         */
66637141Sbrian        struct timeval t;
66736285Sbrian
66837141Sbrian        t.tv_sec = 0;
66937141Sbrian        t.tv_usec = 100000;
67037141Sbrian        select(0, NULL, NULL, NULL, &t);
67137141Sbrian      }
67253070Sbrian  }
67336285Sbrian
67436285Sbrian  log_Printf(LogDEBUG, "DoLoop done.\n");
6756059Samurai}
676