178189Sbrian/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
478189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
578189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
678189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
778189Sbrian * All rights reserved.
86059Samurai *
978189Sbrian * Redistribution and use in source and binary forms, with or without
1078189Sbrian * modification, are permitted provided that the following conditions
1178189Sbrian * are met:
1278189Sbrian * 1. Redistributions of source code must retain the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer.
1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1578189Sbrian *    notice, this list of conditions and the following disclaimer in the
1678189Sbrian *    documentation and/or other materials provided with the distribution.
176059Samurai *
1878189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1978189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2078189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2178189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2278189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2378189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2478189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2578189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2678189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2778189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2878189Sbrian * SUCH DAMAGE.
296059Samurai *
3050479Speter * $FreeBSD: stable/11/usr.sbin/ppp/main.c 330449 2018-03-05 07:26:05Z eadler $
316059Samurai */
3236285Sbrian
3343313Sbrian#include <sys/param.h>
3430715Sbrian#include <netinet/in.h>
3530715Sbrian#include <netinet/in_systm.h>
3630715Sbrian#include <netinet/ip.h>
3736285Sbrian#include <sys/un.h>
3858032Sbrian#include <sys/socket.h>
3958032Sbrian#include <net/route.h>
4030715Sbrian
4130715Sbrian#include <errno.h>
426059Samurai#include <fcntl.h>
4311336Samurai#include <paths.h>
4430715Sbrian#include <signal.h>
45102500Sbrian#include <stdarg.h>
4630715Sbrian#include <stdio.h>
4752396Sbrian#include <stdlib.h>
4830715Sbrian#include <string.h>
4997140Sbrian#include <sys/time.h>
506059Samurai#include <termios.h>
5118786Sjkh#include <unistd.h>
5249581Sbrian#include <sys/stat.h>
5330715Sbrian
5450059Sbrian#ifndef NONAT
5558037Sbrian#ifdef LOCALNAT
5658037Sbrian#include "alias.h"
5758037Sbrian#else
5846086Sbrian#include <alias.h>
5939395Sbrian#endif
6039395Sbrian#endif
6158037Sbrian
6246686Sbrian#include "layer.h"
6337141Sbrian#include "probe.h"
6430715Sbrian#include "mbuf.h"
6530715Sbrian#include "log.h"
6630715Sbrian#include "defs.h"
6731061Sbrian#include "id.h"
6830715Sbrian#include "timer.h"
6930715Sbrian#include "fsm.h"
7036285Sbrian#include "lqr.h"
716059Samurai#include "hdlc.h"
7231514Sbrian#include "lcp.h"
7313389Sphk#include "ccp.h"
7436285Sbrian#include "iplist.h"
7536285Sbrian#include "throughput.h"
7636285Sbrian#include "slcompress.h"
7781634Sbrian#include "ncpaddr.h"
786059Samurai#include "ipcp.h"
7936285Sbrian#include "filter.h"
8036285Sbrian#include "descriptor.h"
8136285Sbrian#include "link.h"
8236285Sbrian#include "mp.h"
8343313Sbrian#ifndef NORADIUS
8443313Sbrian#include "radius.h"
8543313Sbrian#endif
8681634Sbrian#include "ipv6cp.h"
8781634Sbrian#include "ncp.h"
8836285Sbrian#include "bundle.h"
896735Samurai#include "auth.h"
9013389Sphk#include "systems.h"
9123840Sbrian#include "sig.h"
9230715Sbrian#include "main.h"
9336285Sbrian#include "server.h"
9436285Sbrian#include "prompt.h"
9536285Sbrian#include "chat.h"
9636285Sbrian#include "chap.h"
9738174Sbrian#include "cbcp.h"
9836285Sbrian#include "datalink.h"
9940561Sbrian#include "iface.h"
1006059Samurai
1016735Samurai#ifndef O_NONBLOCK
1026735Samurai#ifdef O_NDELAY
1036735Samurai#define	O_NONBLOCK O_NDELAY
1046735Samurai#endif
1056735Samurai#endif
1066735Samurai
10736431Sbrianstatic void DoLoop(struct bundle *);
10830715Sbrianstatic void TerminalStop(int);
10930715Sbrian
11036285Sbrianstatic struct bundle *SignalBundle;
11136285Sbrianstatic struct prompt *SignalPrompt;
112177100Spisostruct libalias *la;
1136059Samurai
11410528Samuraivoid
115134789SbrianCleanup()
1166059Samurai{
11736285Sbrian  SignalBundle->CleaningUp = 1;
11838008Sbrian  bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
1196059Samurai}
1206059Samurai
1216059Samuraivoid
12236285SbrianAbortProgram(int excode)
1236059Samurai{
12498970Sbrian  if (SignalBundle)
12598970Sbrian    server_Close(SignalBundle);
12636285Sbrian  log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
12798970Sbrian  if (SignalBundle) {
12898970Sbrian    bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN);
12998970Sbrian    bundle_Destroy(SignalBundle);
13098970Sbrian  }
13136285Sbrian  log_Close();
1326059Samurai  exit(excode);
1336059Samurai}
1346059Samurai
1356059Samuraistatic void
13628679SbrianCloseConnection(int signo)
1376059Samurai{
13826858Sbrian  /* NOTE, these are manual, we've done a setsid() */
13936285Sbrian  sig_signal(SIGINT, SIG_IGN);
14036285Sbrian  log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo);
14137018Sbrian  bundle_Down(SignalBundle, CLOSE_STAYDOWN);
14236285Sbrian  sig_signal(SIGINT, CloseConnection);
1436059Samurai}
1446059Samurai
1456059Samuraistatic void
14628679SbrianCloseSession(int signo)
1476059Samurai{
14836285Sbrian  log_Printf(LogPHASE, "Signal %d, terminate.\n", signo);
149134789Sbrian  Cleanup();
1506059Samurai}
1516059Samurai
15236285Sbrianstatic pid_t BGPid = 0;
15336285Sbrian
15410528Samuraistatic void
15536285SbrianKillChild(int signo)
15610528Samurai{
15747119Sbrian  signal(signo, SIG_IGN);
15836285Sbrian  log_Printf(LogPHASE, "Parent: Signal %d\n", signo);
15936285Sbrian  kill(BGPid, SIGINT);
16010528Samurai}
16110528Samurai
16210528Samuraistatic void
163134789SbrianTerminalCont(int signo __unused)
16410528Samurai{
16536285Sbrian  signal(SIGCONT, SIG_DFL);
16636285Sbrian  prompt_Continue(SignalPrompt);
16710528Samurai}
16810528Samurai
16926940Sbrianstatic void
170134789SbrianTerminalStop(int signo __unused)
17126940Sbrian{
17236285Sbrian  prompt_Suspend(SignalPrompt);
17336285Sbrian  signal(SIGCONT, TerminalCont);
17436285Sbrian  raise(SIGSTOP);
17526940Sbrian}
17626940Sbrian
17731081Sbrianstatic void
178134789SbrianBringDownServer(int signo __unused)
17931081Sbrian{
18036285Sbrian  /* Drops all child prompts too ! */
18171657Sbrian  if (server_Close(SignalBundle))
18271657Sbrian    log_Printf(LogPHASE, "Closed server socket\n");
18331081Sbrian}
18431081Sbrian
18530715Sbrianstatic void
186134789SbrianRestartServer(int signo __unused)
18771657Sbrian{
18871657Sbrian  /* Drops all child prompts and re-opens the socket */
18971657Sbrian  server_Reopen(SignalBundle);
19071657Sbrian}
19171657Sbrian
19271657Sbrianstatic void
19331343SbrianUsage(void)
1946059Samurai{
19595258Sdes  fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |"
19667912Sbrian          " -dedicated | -ddial | -interactive]"
197139116Sru#ifndef NONAT
19850059Sbrian          " [-nat]"
19931343Sbrian#endif
20052396Sbrian          " [-quiet] [-unit N] [system ...]\n");
2016059Samurai  exit(EX_START);
2026059Samurai}
2036059Samurai
20452396Sbrianstruct switches {
20552396Sbrian  unsigned nat : 1;
20652396Sbrian  unsigned fg : 1;
20752396Sbrian  unsigned quiet : 1;
20852396Sbrian  int mode;
20952396Sbrian  int unit;
21052396Sbrian};
21152396Sbrian
21240797Sbrianstatic int
21352396SbrianProcessArgs(int argc, char **argv, struct switches *sw)
2146059Samurai{
21540797Sbrian  int optc, newmode, arg;
2166059Samurai  char *cp;
2176059Samurai
21840797Sbrian  optc = 0;
21952396Sbrian  memset(sw, '\0', sizeof *sw);
22052396Sbrian  sw->mode = PHYS_INTERACTIVE;
22152396Sbrian  sw->unit = -1;
22252396Sbrian
22340797Sbrian  for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) {
22440797Sbrian    cp = argv[arg] + 1;
22536465Sbrian    newmode = Nam2mode(cp);
22636465Sbrian    switch (newmode) {
22736465Sbrian      case PHYS_NONE:
22852396Sbrian        if (strcmp(cp, "nat") == 0) {
22950059Sbrian#ifdef NONAT
23052396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
23137191Sbrian#else
23252396Sbrian          sw->nat = 1;
23336285Sbrian#endif
23436465Sbrian          optc--;			/* this option isn't exclusive */
23552396Sbrian        } else if (strcmp(cp, "alias") == 0) {
23652396Sbrian#ifdef NONAT
23752396Sbrian          log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]);
23852396Sbrian          fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]);
23952396Sbrian#else
24053889Sbrian          log_Printf(LogWARN, "%s is deprecated\n", argv[arg]);
24153889Sbrian          fprintf(stderr, "%s is deprecated\n", argv[arg]);
24252396Sbrian          sw->nat = 1;
24352396Sbrian#endif
24452396Sbrian          optc--;			/* this option isn't exclusive */
24552396Sbrian        } else if (strncmp(cp, "unit", 4) == 0) {
24653067Sbrian          optc--;			/* this option isn't exclusive */
24752396Sbrian          if (cp[4] == '\0') {
24853067Sbrian            optc--;			/* nor is the argument */
24952396Sbrian            if (++arg == argc) {
25052396Sbrian              fprintf(stderr, "-unit: Expected unit number\n");
25152396Sbrian              Usage();
25252396Sbrian            } else
25352396Sbrian              sw->unit = atoi(argv[arg]);
25452396Sbrian          } else
25552396Sbrian            sw->unit = atoi(cp + 4);
25650059Sbrian        } else if (strcmp(cp, "quiet") == 0) {
25752396Sbrian          sw->quiet = 1;
25850059Sbrian          optc--;			/* this option isn't exclusive */
25936465Sbrian        } else
26036465Sbrian          Usage();
26136465Sbrian        break;
26236465Sbrian
26336465Sbrian      case PHYS_ALL:
26436465Sbrian        Usage();
26536465Sbrian        break;
26636465Sbrian
26736465Sbrian      default:
26852396Sbrian        sw->mode = newmode;
26953830Sbrian        if (newmode == PHYS_FOREGROUND)
27053830Sbrian          sw->fg = 1;
27136465Sbrian    }
2726059Samurai  }
27336465Sbrian
2746059Samurai  if (optc > 1) {
27536285Sbrian    fprintf(stderr, "You may specify only one mode.\n");
2766059Samurai    exit(EX_START);
2776059Samurai  }
27831197Sbrian
27952396Sbrian  if (sw->mode == PHYS_AUTO && arg == argc) {
28040797Sbrian    fprintf(stderr, "A system must be specified in auto mode.\n");
28136285Sbrian    exit(EX_START);
28236285Sbrian  }
28336285Sbrian
28440797Sbrian  return arg;		/* Don't SetLabel yet ! */
2856059Samurai}
2866059Samurai
28740797Sbrianstatic void
28840797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode)
28940797Sbrian{
29040797Sbrian  const char *err;
29140797Sbrian
29240797Sbrian  if ((err = system_IsValid(label, prompt, mode)) != NULL) {
29340797Sbrian    fprintf(stderr, "%s: %s\n", label, err);
29440797Sbrian    if (mode == PHYS_DIRECT)
29540797Sbrian      log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n",
29640797Sbrian                 label, err);
29740797Sbrian    log_Close();
29840797Sbrian    exit(1);
29940797Sbrian  }
30040797Sbrian}
30140797Sbrian
30240797Sbrian
30326940Sbrianint
30428679Sbrianmain(int argc, char **argv)
3056059Samurai{
30640797Sbrian  char *name;
30743187Sbrian  const char *lastlabel;
308134789Sbrian  int arg, holdfd[3], label;
309134789Sbrian  unsigned f;
31036285Sbrian  struct bundle *bundle;
31136285Sbrian  struct prompt *prompt;
31252396Sbrian  struct switches sw;
31326516Sbrian
31481697Sbrian  probe_Init();
31581697Sbrian
31679173Sbrian  /*
31779173Sbrian   * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and
31879173Sbrian   * STDERR_FILENO are always open.  These are closed before DoLoop(),
31979173Sbrian   * but *after* we've avoided the possibility of erroneously closing
32079173Sbrian   * an important descriptor with close(STD{IN,OUT,ERR}_FILENO).
32179173Sbrian   */
32279173Sbrian  if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) {
32379173Sbrian    fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL);
32479173Sbrian    return 2;
32579173Sbrian  }
32679173Sbrian  for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++)
32779186Sbrian    holdfd[f] = dup(holdfd[0]);
32879173Sbrian
32930715Sbrian  name = strrchr(argv[0], '/');
33036285Sbrian  log_Open(name ? name + 1 : argv[0]);
33126516Sbrian
33250059Sbrian#ifndef NONAT
333177100Spiso  la = LibAliasInit(NULL);
33438198Sbrian#endif
33552396Sbrian  label = ProcessArgs(argc, argv, &sw);
33631121Sbrian
33736285Sbrian  /*
33844539Sbrian   * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops
33944539Sbrian   * output occasionally.... I must find the real reason some time.  To
34044539Sbrian   * display the dodgy behaviour, comment out this bit, make yourself a large
34136285Sbrian   * routing table and then run ppp in interactive mode.  The `show route'
34236285Sbrian   * command will drop chunks of data !!!
34336285Sbrian   */
34452396Sbrian  if (sw.mode == PHYS_INTERACTIVE) {
34536285Sbrian    close(STDIN_FILENO);
34636285Sbrian    if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
34736285Sbrian      fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
34836285Sbrian      return 2;
34936285Sbrian    }
35036285Sbrian  }
35136285Sbrian
35236285Sbrian  /* Allow output for the moment (except in direct mode) */
35352396Sbrian  if (sw.mode == PHYS_DIRECT)
35436285Sbrian    prompt = NULL;
35543526Sbrian  else
35636285Sbrian    SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);
35736285Sbrian
35831121Sbrian  ID0init();
35931158Sbrian  if (ID0realuid() != 0) {
36031158Sbrian    char conf[200], *ptr;
36131158Sbrian
36274687Sbrian    snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE);
36331158Sbrian    do {
36449581Sbrian      struct stat sb;
36549581Sbrian
36649581Sbrian      if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) {
36737019Sbrian        log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n",
36837019Sbrian                   conf);
36931158Sbrian        return -1;
37031158Sbrian      }
37131158Sbrian      ptr = conf + strlen(conf)-2;
37231158Sbrian      while (ptr > conf && *ptr != '/')
37331158Sbrian        *ptr-- = '\0';
37431158Sbrian    } while (ptr >= conf);
37531158Sbrian  }
37631158Sbrian
37740797Sbrian  if (label < argc)
37840797Sbrian    for (arg = label; arg < argc; arg++)
37952396Sbrian      CheckLabel(argv[arg], prompt, sw.mode);
38040797Sbrian  else
38152396Sbrian    CheckLabel("default", prompt, sw.mode);
38231121Sbrian
38352396Sbrian  if (!sw.quiet)
38452396Sbrian    prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode));
38543526Sbrian
38653298Sbrian  if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL)
38726940Sbrian    return EX_START;
38843187Sbrian
38943187Sbrian  /* NOTE:  We may now have changed argv[1] via a ``set proctitle'' */
39043187Sbrian
39136285Sbrian  SignalBundle = bundle;
39252396Sbrian  bundle->NatEnabled = sw.nat;
39352396Sbrian  if (sw.nat)
394138198Sbrian    opt_enable(bundle, 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
430218397Sbrian  if (prompt) {
431218397Sbrian    prompt->bundle = bundle;	/* couldn't do it earlier */
432218397Sbrian    if (!sw.quiet)
433218397Sbrian      prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name);
434218397Sbrian  }
435218397Sbrian
43652396Sbrian  if (sw.mode != PHYS_INTERACTIVE) {
43752396Sbrian    if (sw.mode != PHYS_DIRECT) {
43852396Sbrian      if (!sw.fg) {
43950059Sbrian        int bgpipe[2];
44050059Sbrian        pid_t bgpid;
44136285Sbrian
44252396Sbrian        if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) {
44350059Sbrian          log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
44450059Sbrian	  AbortProgram(EX_SOCK);
44550059Sbrian        }
4466059Samurai
44750059Sbrian        bgpid = fork();
44850059Sbrian        if (bgpid == -1) {
44950059Sbrian	  log_Printf(LogERROR, "fork: %s\n", strerror(errno));
45050059Sbrian	  AbortProgram(EX_SOCK);
45150059Sbrian        }
45236285Sbrian
45350059Sbrian        if (bgpid) {
45450059Sbrian	  char c = EX_NORMAL;
45559084Sbrian          int ret;
45611336Samurai
45752396Sbrian	  if (sw.mode == PHYS_BACKGROUND) {
45850059Sbrian	    close(bgpipe[1]);
45950059Sbrian	    BGPid = bgpid;
46050059Sbrian            /* If we get a signal, kill the child */
46150059Sbrian            signal(SIGHUP, KillChild);
46250059Sbrian            signal(SIGTERM, KillChild);
46350059Sbrian            signal(SIGINT, KillChild);
46450059Sbrian            signal(SIGQUIT, KillChild);
46536285Sbrian
46650059Sbrian	    /* Wait for our child to close its pipe before we exit */
46759084Sbrian            while ((ret = read(bgpipe[0], &c, 1)) == 1) {
46859084Sbrian              switch (c) {
46959084Sbrian                case EX_NORMAL:
47075120Sbrian                  if (!sw.quiet) {
47175120Sbrian	            prompt_Printf(prompt, "PPP enabled\n");
47275120Sbrian	            log_Printf(LogPHASE, "Parent: PPP enabled\n");
47375120Sbrian                  }
47459104Sbrian	          break;
47559084Sbrian                case EX_REDIAL:
47659084Sbrian                  if (!sw.quiet)
47759084Sbrian	            prompt_Printf(prompt, "Attempting redial\n");
47859084Sbrian                  continue;
47959084Sbrian                case EX_RECONNECT:
48059084Sbrian                  if (!sw.quiet)
48159084Sbrian	            prompt_Printf(prompt, "Attempting reconnect\n");
48259084Sbrian                  continue;
48359084Sbrian	        default:
48459084Sbrian	          prompt_Printf(prompt, "Child failed (%s)\n",
48559084Sbrian                                ex_desc((int)c));
48659084Sbrian	          log_Printf(LogPHASE, "Parent: Child failed (%s)\n",
48759084Sbrian		             ex_desc((int) c));
48859084Sbrian	      }
48959084Sbrian	      break;
49059084Sbrian            }
49159084Sbrian            if (ret != 1) {
49250059Sbrian	      prompt_Printf(prompt, "Child exit, no status.\n");
49350059Sbrian	      log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
49450059Sbrian	    }
49550059Sbrian	    close(bgpipe[0]);
49628679Sbrian	  }
49750059Sbrian	  return c;
49852396Sbrian        } else if (sw.mode == PHYS_BACKGROUND) {
49936285Sbrian	  close(bgpipe[0]);
50050059Sbrian          bundle->notify.fd = bgpipe[1];
50150059Sbrian        }
50250059Sbrian
50356350Sbrian        bundle_ChangedPID(bundle);
50450059Sbrian        bundle_LockTun(bundle);	/* we have a new pid */
50536285Sbrian      }
50620813Sjkh
50750059Sbrian      /* -auto, -dedicated, -ddial, -foreground & -background */
50836285Sbrian      prompt_Destroy(prompt, 0);
50936285Sbrian      close(STDOUT_FILENO);
51036285Sbrian      close(STDERR_FILENO);
51136285Sbrian      close(STDIN_FILENO);
51252396Sbrian      if (!sw.fg)
51350059Sbrian        setsid();
51436285Sbrian    } else {
515196514Sbrian      /*
516196514Sbrian       * -direct - STDIN_FILENO gets used by physical_Open.  STDOUT_FILENO
517196514Sbrian       * *may* get used in exec/pipe mode.
518196514Sbrian       */
51936285Sbrian      prompt_TtyInit(NULL);
52036285Sbrian      close(STDERR_FILENO);
52126686Sbrian    }
5226059Samurai  } else {
52350059Sbrian    /* -interactive */
52432129Sbrian    close(STDERR_FILENO);
52536285Sbrian    prompt_TtyInit(prompt);
52636285Sbrian    prompt_TtyCommandMode(prompt);
52736285Sbrian    prompt_Required(prompt);
5286059Samurai  }
52929696Sbrian
53079173Sbrian  /* We can get rid of these now */
53179173Sbrian  for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++)
53279173Sbrian    close(holdfd[f]);
53379173Sbrian
53452396Sbrian  log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode));
53536431Sbrian  DoLoop(bundle);
53636285Sbrian  AbortProgram(EX_NORMAL);
5376059Samurai
53836285Sbrian  return EX_NORMAL;
5396059Samurai}
5406059Samurai
5416059Samuraistatic void
54236431SbrianDoLoop(struct bundle *bundle)
5436059Samurai{
54466898Sbrian  fd_set *rfds, *wfds, *efds;
54537141Sbrian  int i, nfds, nothing_done;
5466059Samurai
54766898Sbrian  if ((rfds = mkfdset()) == NULL) {
54866898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54966898Sbrian    return;
55066898Sbrian  }
55166898Sbrian
55266898Sbrian  if ((wfds = mkfdset()) == NULL) {
55366898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
55466898Sbrian    free(rfds);
55566898Sbrian    return;
55666898Sbrian  }
55766898Sbrian
55866898Sbrian  if ((efds = mkfdset()) == NULL) {
55966898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
56066898Sbrian    free(rfds);
56166898Sbrian    free(wfds);
56266898Sbrian    return;
56366898Sbrian  }
56466898Sbrian
56553070Sbrian  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
56623598Sache    nfds = 0;
56766898Sbrian    zerofdset(rfds);
56866898Sbrian    zerofdset(wfds);
56966898Sbrian    zerofdset(efds);
5707001Samurai
57136314Sbrian    /* All our datalinks, the tun device and the MP socket */
57266898Sbrian    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);
57325067Sbrian
57436314Sbrian    /* All our prompts and the diagnostic socket */
57566898Sbrian    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);
57636314Sbrian
57758453Sbrian    bundle_CleanDatalinks(bundle);
57836285Sbrian    if (bundle_IsDead(bundle))
57936285Sbrian      /* Don't select - we'll be here forever */
58036285Sbrian      break;
58126551Sbrian
58245126Sbrian    /*
58345126Sbrian     * It's possible that we've had a signal since we last checked.  If
58445126Sbrian     * we don't check again before calling select(), we may end up stuck
58545126Sbrian     * after having missed the event.... sig_Handle() tries to be as
58645126Sbrian     * quick as possible if nothing is likely to have happened.
58745126Sbrian     * This is only really likely if we block in open(... O_NONBLOCK)
58845126Sbrian     * which will happen with a misconfigured device.
58945126Sbrian     */
59045126Sbrian    if (sig_Handle())
59145126Sbrian      continue;
59245126Sbrian
59366898Sbrian    i = select(nfds, rfds, wfds, efds, NULL);
59426696Sbrian
59536345Sbrian    if (i < 0 && errno != EINTR) {
59636285Sbrian      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
59736285Sbrian      if (log_IsKept(LogTIMER)) {
59836285Sbrian        struct timeval t;
59936285Sbrian
60036285Sbrian        for (i = 0; i <= nfds; i++) {
60166898Sbrian          if (FD_ISSET(i, rfds)) {
60236285Sbrian            log_Printf(LogTIMER, "Read set contains %d\n", i);
60366898Sbrian            FD_CLR(i, rfds);
60436285Sbrian            t.tv_sec = t.tv_usec = 0;
60566898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
60636285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
60736285Sbrian              break;
60836285Sbrian            }
60936285Sbrian          }
61066898Sbrian          if (FD_ISSET(i, wfds)) {
61136285Sbrian            log_Printf(LogTIMER, "Write set contains %d\n", i);
61266898Sbrian            FD_CLR(i, wfds);
61336285Sbrian            t.tv_sec = t.tv_usec = 0;
61466898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
61536285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
61636285Sbrian              break;
61736285Sbrian            }
61836285Sbrian          }
61966898Sbrian          if (FD_ISSET(i, efds)) {
62036285Sbrian            log_Printf(LogTIMER, "Error set contains %d\n", i);
62166898Sbrian            FD_CLR(i, efds);
62236285Sbrian            t.tv_sec = t.tv_usec = 0;
62366898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
62436285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
62536285Sbrian              break;
62636285Sbrian            }
62736285Sbrian          }
62836285Sbrian        }
62928679Sbrian      }
63028679Sbrian      break;
6318857Srgrimes    }
6326059Samurai
63343693Sbrian    log_Printf(LogTIMER, "Select returns %d\n", i);
63443693Sbrian
63536345Sbrian    sig_Handle();
63636345Sbrian
63736345Sbrian    if (i <= 0)
63836345Sbrian      continue;
63936345Sbrian
64036285Sbrian    for (i = 0; i <= nfds; i++)
64166898Sbrian      if (FD_ISSET(i, efds)) {
64258038Sbrian        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
64358038Sbrian        /* We deal gracefully with link descriptor exceptions */
64441654Sbrian        if (!bundle_Exception(bundle, i)) {
64541654Sbrian          log_Printf(LogERROR, "Exception cannot be handled !\n");
64641654Sbrian          break;
64741654Sbrian        }
6486059Samurai      }
64928679Sbrian
65036285Sbrian    if (i <= nfds)
65136285Sbrian      break;
65228536Sbrian
65337141Sbrian    nothing_done = 1;
65437141Sbrian
65566898Sbrian    if (descriptor_IsSet(&server.desc, rfds)) {
65666898Sbrian      descriptor_Read(&server.desc, bundle, rfds);
65737141Sbrian      nothing_done = 0;
65837141Sbrian    }
65932039Sbrian
66066898Sbrian    if (descriptor_IsSet(&bundle->desc, rfds)) {
66166898Sbrian      descriptor_Read(&bundle->desc, bundle, rfds);
66237141Sbrian      nothing_done = 0;
66337141Sbrian    }
66437141Sbrian
66566898Sbrian    if (descriptor_IsSet(&bundle->desc, wfds))
66693418Sbrian      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
66737141Sbrian        /*
66893418Sbrian         * This is disastrous.  The OS has told us that something is
66937141Sbrian         * writable, and all our write()s have failed.  Rather than
67037141Sbrian         * going back immediately to do our UpdateSet()s and select(),
67137141Sbrian         * we sleep for a bit to avoid gobbling up all cpu time.
67237141Sbrian         */
67337141Sbrian        struct timeval t;
67436285Sbrian
67537141Sbrian        t.tv_sec = 0;
67637141Sbrian        t.tv_usec = 100000;
67737141Sbrian        select(0, NULL, NULL, NULL, &t);
67837141Sbrian      }
67953070Sbrian  }
68036285Sbrian
68136285Sbrian  log_Printf(LogDEBUG, "DoLoop done.\n");
6826059Samurai}
683