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