main.c revision 138198
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 138198 2004-11-29 17:11:15Z 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
112134789SbrianCleanup()
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);
146134789Sbrian  Cleanup();
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
160134789SbrianTerminalCont(int signo __unused)
16110528Samurai{
16236285Sbrian  signal(SIGCONT, SIG_DFL);
16336285Sbrian  prompt_Continue(SignalPrompt);
16410528Samurai}
16510528Samurai
16626940Sbrianstatic void
167134789SbrianTerminalStop(int signo __unused)
16826940Sbrian{
16936285Sbrian  prompt_Suspend(SignalPrompt);
17036285Sbrian  signal(SIGCONT, TerminalCont);
17136285Sbrian  raise(SIGSTOP);
17226940Sbrian}
17326940Sbrian
17431081Sbrianstatic void
175134789SbrianBringDownServer(int signo __unused)
17631081Sbrian{
17736285Sbrian  /* Drops all child prompts too ! */
17871657Sbrian  if (server_Close(SignalBundle))
17971657Sbrian    log_Printf(LogPHASE, "Closed server socket\n");
18031081Sbrian}
18131081Sbrian
18230715Sbrianstatic void
183134789SbrianRestartServer(int signo __unused)
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;
305134789Sbrian  int arg, holdfd[3], label;
306134789Sbrian  unsigned f;
30736285Sbrian  struct bundle *bundle;
30836285Sbrian  struct prompt *prompt;
30952396Sbrian  struct switches sw;
31026516Sbrian
31181697Sbrian  probe_Init();
31281697Sbrian
31379173Sbrian  /*
31479173Sbrian   * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and
31579173Sbrian   * STDERR_FILENO are always open.  These are closed before DoLoop(),
31679173Sbrian   * but *after* we've avoided the possibility of erroneously closing
31779173Sbrian   * an important descriptor with close(STD{IN,OUT,ERR}_FILENO).
31879173Sbrian   */
31979173Sbrian  if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) {
32079173Sbrian    fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL);
32179173Sbrian    return 2;
32279173Sbrian  }
32379173Sbrian  for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++)
32479186Sbrian    holdfd[f] = dup(holdfd[0]);
32579173Sbrian
32630715Sbrian  name = strrchr(argv[0], '/');
32736285Sbrian  log_Open(name ? name + 1 : argv[0]);
32826516Sbrian
32950059Sbrian#ifndef NONAT
33038198Sbrian  PacketAliasInit();
33138198Sbrian#endif
33252396Sbrian  label = ProcessArgs(argc, argv, &sw);
33331121Sbrian
33436285Sbrian  /*
33544539Sbrian   * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops
33644539Sbrian   * output occasionally.... I must find the real reason some time.  To
33744539Sbrian   * display the dodgy behaviour, comment out this bit, make yourself a large
33836285Sbrian   * routing table and then run ppp in interactive mode.  The `show route'
33936285Sbrian   * command will drop chunks of data !!!
34036285Sbrian   */
34152396Sbrian  if (sw.mode == PHYS_INTERACTIVE) {
34236285Sbrian    close(STDIN_FILENO);
34336285Sbrian    if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
34436285Sbrian      fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
34536285Sbrian      return 2;
34636285Sbrian    }
34736285Sbrian  }
34836285Sbrian
34936285Sbrian  /* Allow output for the moment (except in direct mode) */
35052396Sbrian  if (sw.mode == PHYS_DIRECT)
35136285Sbrian    prompt = NULL;
35243526Sbrian  else
35336285Sbrian    SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);
35436285Sbrian
35531121Sbrian  ID0init();
35631158Sbrian  if (ID0realuid() != 0) {
35731158Sbrian    char conf[200], *ptr;
35831158Sbrian
35974687Sbrian    snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE);
36031158Sbrian    do {
36149581Sbrian      struct stat sb;
36249581Sbrian
36349581Sbrian      if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) {
36437019Sbrian        log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n",
36537019Sbrian                   conf);
36631158Sbrian        return -1;
36731158Sbrian      }
36831158Sbrian      ptr = conf + strlen(conf)-2;
36931158Sbrian      while (ptr > conf && *ptr != '/')
37031158Sbrian        *ptr-- = '\0';
37131158Sbrian    } while (ptr >= conf);
37231158Sbrian  }
37331158Sbrian
37440797Sbrian  if (label < argc)
37540797Sbrian    for (arg = label; arg < argc; arg++)
37652396Sbrian      CheckLabel(argv[arg], prompt, sw.mode);
37740797Sbrian  else
37852396Sbrian    CheckLabel("default", prompt, sw.mode);
37931121Sbrian
38052396Sbrian  if (!sw.quiet)
38152396Sbrian    prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode));
38243526Sbrian
38353298Sbrian  if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL)
38426940Sbrian    return EX_START;
38543187Sbrian
38643187Sbrian  /* NOTE:  We may now have changed argv[1] via a ``set proctitle'' */
38743187Sbrian
38836314Sbrian  if (prompt) {
38936314Sbrian    prompt->bundle = bundle;	/* couldn't do it earlier */
39052396Sbrian    if (!sw.quiet)
39150059Sbrian      prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name);
39236314Sbrian  }
39336285Sbrian  SignalBundle = bundle;
39452396Sbrian  bundle->NatEnabled = sw.nat;
39552396Sbrian  if (sw.nat)
396138198Sbrian    opt_enable(bundle, OPT_IFACEALIAS);
39731121Sbrian
39837008Sbrian  if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0)
39936285Sbrian    prompt_Printf(prompt, "Warning: No default entry found in config file.\n");
40036285Sbrian
40136285Sbrian  sig_signal(SIGHUP, CloseSession);
40236285Sbrian  sig_signal(SIGTERM, CloseSession);
40336285Sbrian  sig_signal(SIGINT, CloseConnection);
40436285Sbrian  sig_signal(SIGQUIT, CloseSession);
40536285Sbrian  sig_signal(SIGALRM, SIG_IGN);
40624753Sache  signal(SIGPIPE, SIG_IGN);
4076059Samurai
40852396Sbrian  if (sw.mode == PHYS_INTERACTIVE)
40936285Sbrian    sig_signal(SIGTSTP, TerminalStop);
41036285Sbrian
41171657Sbrian  sig_signal(SIGUSR1, RestartServer);
41236285Sbrian  sig_signal(SIGUSR2, BringDownServer);
41336285Sbrian
41453298Sbrian  lastlabel = argv[argc - 1];
41540797Sbrian  for (arg = label; arg < argc; arg++) {
41640797Sbrian    /* In case we use LABEL or ``set enddisc label'' */
41743187Sbrian    bundle_SetLabel(bundle, lastlabel);
41853298Sbrian    system_Select(bundle, argv[arg], CONFFILE, prompt, NULL);
4196059Samurai  }
42026940Sbrian
42140797Sbrian  if (label < argc)
42240797Sbrian    /* In case the last label did a ``load'' */
42343187Sbrian    bundle_SetLabel(bundle, lastlabel);
42440797Sbrian
42552396Sbrian  if (sw.mode == PHYS_AUTO &&
42681634Sbrian      ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) {
42740797Sbrian    prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address "
42840797Sbrian                  "in auto mode.\n");
42940797Sbrian    AbortProgram(EX_START);
43040797Sbrian  }
43140797Sbrian
43252396Sbrian  if (sw.mode != PHYS_INTERACTIVE) {
43352396Sbrian    if (sw.mode != PHYS_DIRECT) {
43452396Sbrian      if (!sw.fg) {
43550059Sbrian        int bgpipe[2];
43650059Sbrian        pid_t bgpid;
43736285Sbrian
43852396Sbrian        if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) {
43950059Sbrian          log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
44050059Sbrian	  AbortProgram(EX_SOCK);
44150059Sbrian        }
4426059Samurai
44350059Sbrian        bgpid = fork();
44450059Sbrian        if (bgpid == -1) {
44550059Sbrian	  log_Printf(LogERROR, "fork: %s\n", strerror(errno));
44650059Sbrian	  AbortProgram(EX_SOCK);
44750059Sbrian        }
44836285Sbrian
44950059Sbrian        if (bgpid) {
45050059Sbrian	  char c = EX_NORMAL;
45159084Sbrian          int ret;
45211336Samurai
45352396Sbrian	  if (sw.mode == PHYS_BACKGROUND) {
45450059Sbrian	    close(bgpipe[1]);
45550059Sbrian	    BGPid = bgpid;
45650059Sbrian            /* If we get a signal, kill the child */
45750059Sbrian            signal(SIGHUP, KillChild);
45850059Sbrian            signal(SIGTERM, KillChild);
45950059Sbrian            signal(SIGINT, KillChild);
46050059Sbrian            signal(SIGQUIT, KillChild);
46136285Sbrian
46250059Sbrian	    /* Wait for our child to close its pipe before we exit */
46359084Sbrian            while ((ret = read(bgpipe[0], &c, 1)) == 1) {
46459084Sbrian              switch (c) {
46559084Sbrian                case EX_NORMAL:
46675120Sbrian                  if (!sw.quiet) {
46775120Sbrian	            prompt_Printf(prompt, "PPP enabled\n");
46875120Sbrian	            log_Printf(LogPHASE, "Parent: PPP enabled\n");
46975120Sbrian                  }
47059104Sbrian	          break;
47159084Sbrian                case EX_REDIAL:
47259084Sbrian                  if (!sw.quiet)
47359084Sbrian	            prompt_Printf(prompt, "Attempting redial\n");
47459084Sbrian                  continue;
47559084Sbrian                case EX_RECONNECT:
47659084Sbrian                  if (!sw.quiet)
47759084Sbrian	            prompt_Printf(prompt, "Attempting reconnect\n");
47859084Sbrian                  continue;
47959084Sbrian	        default:
48059084Sbrian	          prompt_Printf(prompt, "Child failed (%s)\n",
48159084Sbrian                                ex_desc((int)c));
48259084Sbrian	          log_Printf(LogPHASE, "Parent: Child failed (%s)\n",
48359084Sbrian		             ex_desc((int) c));
48459084Sbrian	      }
48559084Sbrian	      break;
48659084Sbrian            }
48759084Sbrian            if (ret != 1) {
48850059Sbrian	      prompt_Printf(prompt, "Child exit, no status.\n");
48950059Sbrian	      log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
49050059Sbrian	    }
49150059Sbrian	    close(bgpipe[0]);
49228679Sbrian	  }
49350059Sbrian	  return c;
49452396Sbrian        } else if (sw.mode == PHYS_BACKGROUND) {
49536285Sbrian	  close(bgpipe[0]);
49650059Sbrian          bundle->notify.fd = bgpipe[1];
49750059Sbrian        }
49850059Sbrian
49956350Sbrian        bundle_ChangedPID(bundle);
50050059Sbrian        bundle_LockTun(bundle);	/* we have a new pid */
50136285Sbrian      }
50220813Sjkh
50350059Sbrian      /* -auto, -dedicated, -ddial, -foreground & -background */
50436285Sbrian      prompt_Destroy(prompt, 0);
50536285Sbrian      close(STDOUT_FILENO);
50636285Sbrian      close(STDERR_FILENO);
50736285Sbrian      close(STDIN_FILENO);
50852396Sbrian      if (!sw.fg)
50950059Sbrian        setsid();
51036285Sbrian    } else {
51150059Sbrian      /* -direct - STDIN_FILENO gets used by physical_Open */
51236285Sbrian      prompt_TtyInit(NULL);
51336285Sbrian      close(STDOUT_FILENO);
51436285Sbrian      close(STDERR_FILENO);
51526686Sbrian    }
5166059Samurai  } else {
51750059Sbrian    /* -interactive */
51832129Sbrian    close(STDERR_FILENO);
51936285Sbrian    prompt_TtyInit(prompt);
52036285Sbrian    prompt_TtyCommandMode(prompt);
52136285Sbrian    prompt_Required(prompt);
5226059Samurai  }
52329696Sbrian
52479173Sbrian  /* We can get rid of these now */
52579173Sbrian  for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++)
52679173Sbrian    close(holdfd[f]);
52779173Sbrian
52852396Sbrian  log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode));
52936431Sbrian  DoLoop(bundle);
53036285Sbrian  AbortProgram(EX_NORMAL);
5316059Samurai
53236285Sbrian  return EX_NORMAL;
5336059Samurai}
5346059Samurai
5356059Samuraistatic void
53636431SbrianDoLoop(struct bundle *bundle)
5376059Samurai{
53866898Sbrian  fd_set *rfds, *wfds, *efds;
53937141Sbrian  int i, nfds, nothing_done;
5406059Samurai
54166898Sbrian  if ((rfds = mkfdset()) == NULL) {
54266898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54366898Sbrian    return;
54466898Sbrian  }
54566898Sbrian
54666898Sbrian  if ((wfds = mkfdset()) == NULL) {
54766898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
54866898Sbrian    free(rfds);
54966898Sbrian    return;
55066898Sbrian  }
55166898Sbrian
55266898Sbrian  if ((efds = mkfdset()) == NULL) {
55366898Sbrian    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
55466898Sbrian    free(rfds);
55566898Sbrian    free(wfds);
55666898Sbrian    return;
55766898Sbrian  }
55866898Sbrian
55953070Sbrian  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
56023598Sache    nfds = 0;
56166898Sbrian    zerofdset(rfds);
56266898Sbrian    zerofdset(wfds);
56366898Sbrian    zerofdset(efds);
5647001Samurai
56536314Sbrian    /* All our datalinks, the tun device and the MP socket */
56666898Sbrian    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);
56725067Sbrian
56836314Sbrian    /* All our prompts and the diagnostic socket */
56966898Sbrian    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);
57036314Sbrian
57158453Sbrian    bundle_CleanDatalinks(bundle);
57236285Sbrian    if (bundle_IsDead(bundle))
57336285Sbrian      /* Don't select - we'll be here forever */
57436285Sbrian      break;
57526551Sbrian
57645126Sbrian    /*
57745126Sbrian     * It's possible that we've had a signal since we last checked.  If
57845126Sbrian     * we don't check again before calling select(), we may end up stuck
57945126Sbrian     * after having missed the event.... sig_Handle() tries to be as
58045126Sbrian     * quick as possible if nothing is likely to have happened.
58145126Sbrian     * This is only really likely if we block in open(... O_NONBLOCK)
58245126Sbrian     * which will happen with a misconfigured device.
58345126Sbrian     */
58445126Sbrian    if (sig_Handle())
58545126Sbrian      continue;
58645126Sbrian
58766898Sbrian    i = select(nfds, rfds, wfds, efds, NULL);
58826696Sbrian
58936345Sbrian    if (i < 0 && errno != EINTR) {
59036285Sbrian      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
59136285Sbrian      if (log_IsKept(LogTIMER)) {
59236285Sbrian        struct timeval t;
59336285Sbrian
59436285Sbrian        for (i = 0; i <= nfds; i++) {
59566898Sbrian          if (FD_ISSET(i, rfds)) {
59636285Sbrian            log_Printf(LogTIMER, "Read set contains %d\n", i);
59766898Sbrian            FD_CLR(i, rfds);
59836285Sbrian            t.tv_sec = t.tv_usec = 0;
59966898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
60036285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
60136285Sbrian              break;
60236285Sbrian            }
60336285Sbrian          }
60466898Sbrian          if (FD_ISSET(i, wfds)) {
60536285Sbrian            log_Printf(LogTIMER, "Write set contains %d\n", i);
60666898Sbrian            FD_CLR(i, wfds);
60736285Sbrian            t.tv_sec = t.tv_usec = 0;
60866898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
60936285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
61036285Sbrian              break;
61136285Sbrian            }
61236285Sbrian          }
61366898Sbrian          if (FD_ISSET(i, efds)) {
61436285Sbrian            log_Printf(LogTIMER, "Error set contains %d\n", i);
61566898Sbrian            FD_CLR(i, efds);
61636285Sbrian            t.tv_sec = t.tv_usec = 0;
61766898Sbrian            if (select(nfds, rfds, wfds, efds, &t) != -1) {
61836285Sbrian              log_Printf(LogTIMER, "The culprit !\n");
61936285Sbrian              break;
62036285Sbrian            }
62136285Sbrian          }
62236285Sbrian        }
62328679Sbrian      }
62428679Sbrian      break;
6258857Srgrimes    }
6266059Samurai
62743693Sbrian    log_Printf(LogTIMER, "Select returns %d\n", i);
62843693Sbrian
62936345Sbrian    sig_Handle();
63036345Sbrian
63136345Sbrian    if (i <= 0)
63236345Sbrian      continue;
63336345Sbrian
63436285Sbrian    for (i = 0; i <= nfds; i++)
63566898Sbrian      if (FD_ISSET(i, efds)) {
63658038Sbrian        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
63758038Sbrian        /* We deal gracefully with link descriptor exceptions */
63841654Sbrian        if (!bundle_Exception(bundle, i)) {
63941654Sbrian          log_Printf(LogERROR, "Exception cannot be handled !\n");
64041654Sbrian          break;
64141654Sbrian        }
6426059Samurai      }
64328679Sbrian
64436285Sbrian    if (i <= nfds)
64536285Sbrian      break;
64628536Sbrian
64737141Sbrian    nothing_done = 1;
64837141Sbrian
64966898Sbrian    if (descriptor_IsSet(&server.desc, rfds)) {
65066898Sbrian      descriptor_Read(&server.desc, bundle, rfds);
65137141Sbrian      nothing_done = 0;
65237141Sbrian    }
65332039Sbrian
65466898Sbrian    if (descriptor_IsSet(&bundle->desc, rfds)) {
65566898Sbrian      descriptor_Read(&bundle->desc, bundle, rfds);
65637141Sbrian      nothing_done = 0;
65737141Sbrian    }
65837141Sbrian
65966898Sbrian    if (descriptor_IsSet(&bundle->desc, wfds))
66093418Sbrian      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
66137141Sbrian        /*
66293418Sbrian         * This is disastrous.  The OS has told us that something is
66337141Sbrian         * writable, and all our write()s have failed.  Rather than
66437141Sbrian         * going back immediately to do our UpdateSet()s and select(),
66537141Sbrian         * we sleep for a bit to avoid gobbling up all cpu time.
66637141Sbrian         */
66737141Sbrian        struct timeval t;
66836285Sbrian
66937141Sbrian        t.tv_sec = 0;
67037141Sbrian        t.tv_usec = 100000;
67137141Sbrian        select(0, NULL, NULL, NULL, &t);
67237141Sbrian      }
67353070Sbrian  }
67436285Sbrian
67536285Sbrian  log_Printf(LogDEBUG, "DoLoop done.\n");
6766059Samurai}
677