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$ 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; 110177100Spisostruct libalias *la; 1116059Samurai 11210528Samuraivoid 113134789SbrianCleanup() 1146059Samurai{ 11536285Sbrian SignalBundle->CleaningUp = 1; 11638008Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1176059Samurai} 1186059Samurai 1196059Samuraivoid 12036285SbrianAbortProgram(int excode) 1216059Samurai{ 12298970Sbrian if (SignalBundle) 12398970Sbrian server_Close(SignalBundle); 12436285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 12598970Sbrian if (SignalBundle) { 12698970Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 12798970Sbrian bundle_Destroy(SignalBundle); 12898970Sbrian } 12936285Sbrian log_Close(); 1306059Samurai exit(excode); 1316059Samurai} 1326059Samurai 1336059Samuraistatic void 13428679SbrianCloseConnection(int signo) 1356059Samurai{ 13626858Sbrian /* NOTE, these are manual, we've done a setsid() */ 13736285Sbrian sig_signal(SIGINT, SIG_IGN); 13836285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 13937018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 14036285Sbrian sig_signal(SIGINT, CloseConnection); 1416059Samurai} 1426059Samurai 1436059Samuraistatic void 14428679SbrianCloseSession(int signo) 1456059Samurai{ 14636285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 147134789Sbrian Cleanup(); 1486059Samurai} 1496059Samurai 15036285Sbrianstatic pid_t BGPid = 0; 15136285Sbrian 15210528Samuraistatic void 15336285SbrianKillChild(int signo) 15410528Samurai{ 15547119Sbrian signal(signo, SIG_IGN); 15636285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 15736285Sbrian kill(BGPid, SIGINT); 15810528Samurai} 15910528Samurai 16010528Samuraistatic void 161134789SbrianTerminalCont(int signo __unused) 16210528Samurai{ 16336285Sbrian signal(SIGCONT, SIG_DFL); 16436285Sbrian prompt_Continue(SignalPrompt); 16510528Samurai} 16610528Samurai 16726940Sbrianstatic void 168134789SbrianTerminalStop(int signo __unused) 16926940Sbrian{ 17036285Sbrian prompt_Suspend(SignalPrompt); 17136285Sbrian signal(SIGCONT, TerminalCont); 17236285Sbrian raise(SIGSTOP); 17326940Sbrian} 17426940Sbrian 17531081Sbrianstatic void 176134789SbrianBringDownServer(int signo __unused) 17731081Sbrian{ 17836285Sbrian /* Drops all child prompts too ! */ 17971657Sbrian if (server_Close(SignalBundle)) 18071657Sbrian log_Printf(LogPHASE, "Closed server socket\n"); 18131081Sbrian} 18231081Sbrian 18330715Sbrianstatic void 184134789SbrianRestartServer(int signo __unused) 18571657Sbrian{ 18671657Sbrian /* Drops all child prompts and re-opens the socket */ 18771657Sbrian server_Reopen(SignalBundle); 18871657Sbrian} 18971657Sbrian 19071657Sbrianstatic void 19131343SbrianUsage(void) 1926059Samurai{ 19395258Sdes fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |" 19467912Sbrian " -dedicated | -ddial | -interactive]" 195139116Sru#ifndef NONAT 19650059Sbrian " [-nat]" 19731343Sbrian#endif 19852396Sbrian " [-quiet] [-unit N] [system ...]\n"); 1996059Samurai exit(EX_START); 2006059Samurai} 2016059Samurai 20252396Sbrianstruct switches { 20352396Sbrian unsigned nat : 1; 20452396Sbrian unsigned fg : 1; 20552396Sbrian unsigned quiet : 1; 20652396Sbrian int mode; 20752396Sbrian int unit; 20852396Sbrian}; 20952396Sbrian 21040797Sbrianstatic int 21152396SbrianProcessArgs(int argc, char **argv, struct switches *sw) 2126059Samurai{ 21340797Sbrian int optc, newmode, arg; 2146059Samurai char *cp; 2156059Samurai 21640797Sbrian optc = 0; 21752396Sbrian memset(sw, '\0', sizeof *sw); 21852396Sbrian sw->mode = PHYS_INTERACTIVE; 21952396Sbrian sw->unit = -1; 22052396Sbrian 22140797Sbrian for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 22240797Sbrian cp = argv[arg] + 1; 22336465Sbrian newmode = Nam2mode(cp); 22436465Sbrian switch (newmode) { 22536465Sbrian case PHYS_NONE: 22652396Sbrian if (strcmp(cp, "nat") == 0) { 22750059Sbrian#ifdef NONAT 22852396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 22937191Sbrian#else 23052396Sbrian sw->nat = 1; 23136285Sbrian#endif 23236465Sbrian optc--; /* this option isn't exclusive */ 23352396Sbrian } else if (strcmp(cp, "alias") == 0) { 23452396Sbrian#ifdef NONAT 23552396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 23652396Sbrian fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 23752396Sbrian#else 23853889Sbrian log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 23953889Sbrian fprintf(stderr, "%s is deprecated\n", argv[arg]); 24052396Sbrian sw->nat = 1; 24152396Sbrian#endif 24252396Sbrian optc--; /* this option isn't exclusive */ 24352396Sbrian } else if (strncmp(cp, "unit", 4) == 0) { 24453067Sbrian optc--; /* this option isn't exclusive */ 24552396Sbrian if (cp[4] == '\0') { 24653067Sbrian optc--; /* nor is the argument */ 24752396Sbrian if (++arg == argc) { 24852396Sbrian fprintf(stderr, "-unit: Expected unit number\n"); 24952396Sbrian Usage(); 25052396Sbrian } else 25152396Sbrian sw->unit = atoi(argv[arg]); 25252396Sbrian } else 25352396Sbrian sw->unit = atoi(cp + 4); 25450059Sbrian } else if (strcmp(cp, "quiet") == 0) { 25552396Sbrian sw->quiet = 1; 25650059Sbrian optc--; /* this option isn't exclusive */ 25736465Sbrian } else 25836465Sbrian Usage(); 25936465Sbrian break; 26036465Sbrian 26136465Sbrian case PHYS_ALL: 26236465Sbrian Usage(); 26336465Sbrian break; 26436465Sbrian 26536465Sbrian default: 26652396Sbrian sw->mode = newmode; 26753830Sbrian if (newmode == PHYS_FOREGROUND) 26853830Sbrian sw->fg = 1; 26936465Sbrian } 2706059Samurai } 27136465Sbrian 2726059Samurai if (optc > 1) { 27336285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2746059Samurai exit(EX_START); 2756059Samurai } 27631197Sbrian 27752396Sbrian if (sw->mode == PHYS_AUTO && arg == argc) { 27840797Sbrian fprintf(stderr, "A system must be specified in auto mode.\n"); 27936285Sbrian exit(EX_START); 28036285Sbrian } 28136285Sbrian 28240797Sbrian return arg; /* Don't SetLabel yet ! */ 2836059Samurai} 2846059Samurai 28540797Sbrianstatic void 28640797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode) 28740797Sbrian{ 28840797Sbrian const char *err; 28940797Sbrian 29040797Sbrian if ((err = system_IsValid(label, prompt, mode)) != NULL) { 29140797Sbrian fprintf(stderr, "%s: %s\n", label, err); 29240797Sbrian if (mode == PHYS_DIRECT) 29340797Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 29440797Sbrian label, err); 29540797Sbrian log_Close(); 29640797Sbrian exit(1); 29740797Sbrian } 29840797Sbrian} 29940797Sbrian 30040797Sbrian 30126940Sbrianint 30228679Sbrianmain(int argc, char **argv) 3036059Samurai{ 30440797Sbrian char *name; 30543187Sbrian const char *lastlabel; 306134789Sbrian int arg, holdfd[3], label; 307134789Sbrian unsigned f; 30836285Sbrian struct bundle *bundle; 30936285Sbrian struct prompt *prompt; 31052396Sbrian struct switches sw; 31126516Sbrian 31281697Sbrian probe_Init(); 31381697Sbrian 31479173Sbrian /* 31579173Sbrian * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 31679173Sbrian * STDERR_FILENO are always open. These are closed before DoLoop(), 31779173Sbrian * but *after* we've avoided the possibility of erroneously closing 31879173Sbrian * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 31979173Sbrian */ 32079173Sbrian if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 32179173Sbrian fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 32279173Sbrian return 2; 32379173Sbrian } 32479173Sbrian for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 32579186Sbrian holdfd[f] = dup(holdfd[0]); 32679173Sbrian 32730715Sbrian name = strrchr(argv[0], '/'); 32836285Sbrian log_Open(name ? name + 1 : argv[0]); 32926516Sbrian 33050059Sbrian#ifndef NONAT 331177100Spiso la = LibAliasInit(NULL); 33238198Sbrian#endif 33352396Sbrian label = ProcessArgs(argc, argv, &sw); 33431121Sbrian 33536285Sbrian /* 33644539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 33744539Sbrian * output occasionally.... I must find the real reason some time. To 33844539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 33936285Sbrian * routing table and then run ppp in interactive mode. The `show route' 34036285Sbrian * command will drop chunks of data !!! 34136285Sbrian */ 34252396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 34336285Sbrian close(STDIN_FILENO); 34436285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 34536285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 34636285Sbrian return 2; 34736285Sbrian } 34836285Sbrian } 34936285Sbrian 35036285Sbrian /* Allow output for the moment (except in direct mode) */ 35152396Sbrian if (sw.mode == PHYS_DIRECT) 35236285Sbrian prompt = NULL; 35343526Sbrian else 35436285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 35536285Sbrian 35631121Sbrian ID0init(); 35731158Sbrian if (ID0realuid() != 0) { 35831158Sbrian char conf[200], *ptr; 35931158Sbrian 36074687Sbrian snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 36131158Sbrian do { 36249581Sbrian struct stat sb; 36349581Sbrian 36449581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 36537019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 36637019Sbrian conf); 36731158Sbrian return -1; 36831158Sbrian } 36931158Sbrian ptr = conf + strlen(conf)-2; 37031158Sbrian while (ptr > conf && *ptr != '/') 37131158Sbrian *ptr-- = '\0'; 37231158Sbrian } while (ptr >= conf); 37331158Sbrian } 37431158Sbrian 37540797Sbrian if (label < argc) 37640797Sbrian for (arg = label; arg < argc; arg++) 37752396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 37840797Sbrian else 37952396Sbrian CheckLabel("default", prompt, sw.mode); 38031121Sbrian 38152396Sbrian if (!sw.quiet) 38252396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 38343526Sbrian 38453298Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 38526940Sbrian return EX_START; 38643187Sbrian 38743187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 38843187Sbrian 38936285Sbrian SignalBundle = bundle; 39052396Sbrian bundle->NatEnabled = sw.nat; 39152396Sbrian if (sw.nat) 392138198Sbrian opt_enable(bundle, OPT_IFACEALIAS); 39331121Sbrian 39437008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 39536285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 39636285Sbrian 39736285Sbrian sig_signal(SIGHUP, CloseSession); 39836285Sbrian sig_signal(SIGTERM, CloseSession); 39936285Sbrian sig_signal(SIGINT, CloseConnection); 40036285Sbrian sig_signal(SIGQUIT, CloseSession); 40136285Sbrian sig_signal(SIGALRM, SIG_IGN); 40224753Sache signal(SIGPIPE, SIG_IGN); 4036059Samurai 40452396Sbrian if (sw.mode == PHYS_INTERACTIVE) 40536285Sbrian sig_signal(SIGTSTP, TerminalStop); 40636285Sbrian 40771657Sbrian sig_signal(SIGUSR1, RestartServer); 40836285Sbrian sig_signal(SIGUSR2, BringDownServer); 40936285Sbrian 41053298Sbrian lastlabel = argv[argc - 1]; 41140797Sbrian for (arg = label; arg < argc; arg++) { 41240797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 41343187Sbrian bundle_SetLabel(bundle, lastlabel); 41453298Sbrian system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 4156059Samurai } 41626940Sbrian 41740797Sbrian if (label < argc) 41840797Sbrian /* In case the last label did a ``load'' */ 41943187Sbrian bundle_SetLabel(bundle, lastlabel); 42040797Sbrian 42152396Sbrian if (sw.mode == PHYS_AUTO && 42281634Sbrian ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { 42340797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 42440797Sbrian "in auto mode.\n"); 42540797Sbrian AbortProgram(EX_START); 42640797Sbrian } 42740797Sbrian 428218397Sbrian if (prompt) { 429218397Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 430218397Sbrian if (!sw.quiet) 431218397Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 432218397Sbrian } 433218397Sbrian 43452396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 43552396Sbrian if (sw.mode != PHYS_DIRECT) { 43652396Sbrian if (!sw.fg) { 43750059Sbrian int bgpipe[2]; 43850059Sbrian pid_t bgpid; 43936285Sbrian 44052396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 44150059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 44250059Sbrian AbortProgram(EX_SOCK); 44350059Sbrian } 4446059Samurai 44550059Sbrian bgpid = fork(); 44650059Sbrian if (bgpid == -1) { 44750059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 44850059Sbrian AbortProgram(EX_SOCK); 44950059Sbrian } 45036285Sbrian 45150059Sbrian if (bgpid) { 45250059Sbrian char c = EX_NORMAL; 45359084Sbrian int ret; 45411336Samurai 45552396Sbrian if (sw.mode == PHYS_BACKGROUND) { 45650059Sbrian close(bgpipe[1]); 45750059Sbrian BGPid = bgpid; 45850059Sbrian /* If we get a signal, kill the child */ 45950059Sbrian signal(SIGHUP, KillChild); 46050059Sbrian signal(SIGTERM, KillChild); 46150059Sbrian signal(SIGINT, KillChild); 46250059Sbrian signal(SIGQUIT, KillChild); 46336285Sbrian 46450059Sbrian /* Wait for our child to close its pipe before we exit */ 46559084Sbrian while ((ret = read(bgpipe[0], &c, 1)) == 1) { 46659084Sbrian switch (c) { 46759084Sbrian case EX_NORMAL: 46875120Sbrian if (!sw.quiet) { 46975120Sbrian prompt_Printf(prompt, "PPP enabled\n"); 47075120Sbrian log_Printf(LogPHASE, "Parent: PPP enabled\n"); 47175120Sbrian } 47259104Sbrian break; 47359084Sbrian case EX_REDIAL: 47459084Sbrian if (!sw.quiet) 47559084Sbrian prompt_Printf(prompt, "Attempting redial\n"); 47659084Sbrian continue; 47759084Sbrian case EX_RECONNECT: 47859084Sbrian if (!sw.quiet) 47959084Sbrian prompt_Printf(prompt, "Attempting reconnect\n"); 48059084Sbrian continue; 48159084Sbrian default: 48259084Sbrian prompt_Printf(prompt, "Child failed (%s)\n", 48359084Sbrian ex_desc((int)c)); 48459084Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 48559084Sbrian ex_desc((int) c)); 48659084Sbrian } 48759084Sbrian break; 48859084Sbrian } 48959084Sbrian if (ret != 1) { 49050059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 49150059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 49250059Sbrian } 49350059Sbrian close(bgpipe[0]); 49428679Sbrian } 49550059Sbrian return c; 49652396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 49736285Sbrian close(bgpipe[0]); 49850059Sbrian bundle->notify.fd = bgpipe[1]; 49950059Sbrian } 50050059Sbrian 50156350Sbrian bundle_ChangedPID(bundle); 50250059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 50336285Sbrian } 50420813Sjkh 50550059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 50636285Sbrian prompt_Destroy(prompt, 0); 50736285Sbrian close(STDOUT_FILENO); 50836285Sbrian close(STDERR_FILENO); 50936285Sbrian close(STDIN_FILENO); 51052396Sbrian if (!sw.fg) 51150059Sbrian setsid(); 51236285Sbrian } else { 513196514Sbrian /* 514196514Sbrian * -direct - STDIN_FILENO gets used by physical_Open. STDOUT_FILENO 515196514Sbrian * *may* get used in exec/pipe mode. 516196514Sbrian */ 51736285Sbrian prompt_TtyInit(NULL); 51836285Sbrian close(STDERR_FILENO); 51926686Sbrian } 5206059Samurai } else { 52150059Sbrian /* -interactive */ 52232129Sbrian close(STDERR_FILENO); 52336285Sbrian prompt_TtyInit(prompt); 52436285Sbrian prompt_TtyCommandMode(prompt); 52536285Sbrian prompt_Required(prompt); 5266059Samurai } 52729696Sbrian 52879173Sbrian /* We can get rid of these now */ 52979173Sbrian for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 53079173Sbrian close(holdfd[f]); 53179173Sbrian 53252396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 53336431Sbrian DoLoop(bundle); 53436285Sbrian AbortProgram(EX_NORMAL); 5356059Samurai 53636285Sbrian return EX_NORMAL; 5376059Samurai} 5386059Samurai 5396059Samuraistatic void 54036431SbrianDoLoop(struct bundle *bundle) 5416059Samurai{ 54266898Sbrian fd_set *rfds, *wfds, *efds; 54337141Sbrian int i, nfds, nothing_done; 5446059Samurai 54566898Sbrian if ((rfds = mkfdset()) == NULL) { 54666898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54766898Sbrian return; 54866898Sbrian } 54966898Sbrian 55066898Sbrian if ((wfds = mkfdset()) == NULL) { 55166898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55266898Sbrian free(rfds); 55366898Sbrian return; 55466898Sbrian } 55566898Sbrian 55666898Sbrian if ((efds = mkfdset()) == NULL) { 55766898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55866898Sbrian free(rfds); 55966898Sbrian free(wfds); 56066898Sbrian return; 56166898Sbrian } 56266898Sbrian 56353070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 56423598Sache nfds = 0; 56566898Sbrian zerofdset(rfds); 56666898Sbrian zerofdset(wfds); 56766898Sbrian zerofdset(efds); 5687001Samurai 56936314Sbrian /* All our datalinks, the tun device and the MP socket */ 57066898Sbrian descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 57125067Sbrian 57236314Sbrian /* All our prompts and the diagnostic socket */ 57366898Sbrian descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 57436314Sbrian 57558453Sbrian bundle_CleanDatalinks(bundle); 57636285Sbrian if (bundle_IsDead(bundle)) 57736285Sbrian /* Don't select - we'll be here forever */ 57836285Sbrian break; 57926551Sbrian 58045126Sbrian /* 58145126Sbrian * It's possible that we've had a signal since we last checked. If 58245126Sbrian * we don't check again before calling select(), we may end up stuck 58345126Sbrian * after having missed the event.... sig_Handle() tries to be as 58445126Sbrian * quick as possible if nothing is likely to have happened. 58545126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 58645126Sbrian * which will happen with a misconfigured device. 58745126Sbrian */ 58845126Sbrian if (sig_Handle()) 58945126Sbrian continue; 59045126Sbrian 59166898Sbrian i = select(nfds, rfds, wfds, efds, NULL); 59226696Sbrian 59336345Sbrian if (i < 0 && errno != EINTR) { 59436285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 59536285Sbrian if (log_IsKept(LogTIMER)) { 59636285Sbrian struct timeval t; 59736285Sbrian 59836285Sbrian for (i = 0; i <= nfds; i++) { 59966898Sbrian if (FD_ISSET(i, rfds)) { 60036285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 60166898Sbrian FD_CLR(i, rfds); 60236285Sbrian t.tv_sec = t.tv_usec = 0; 60366898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 60436285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 60536285Sbrian break; 60636285Sbrian } 60736285Sbrian } 60866898Sbrian if (FD_ISSET(i, wfds)) { 60936285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 61066898Sbrian FD_CLR(i, wfds); 61136285Sbrian t.tv_sec = t.tv_usec = 0; 61266898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 61336285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 61436285Sbrian break; 61536285Sbrian } 61636285Sbrian } 61766898Sbrian if (FD_ISSET(i, efds)) { 61836285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 61966898Sbrian FD_CLR(i, efds); 62036285Sbrian t.tv_sec = t.tv_usec = 0; 62166898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 62236285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 62336285Sbrian break; 62436285Sbrian } 62536285Sbrian } 62636285Sbrian } 62728679Sbrian } 62828679Sbrian break; 6298857Srgrimes } 6306059Samurai 63143693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 63243693Sbrian 63336345Sbrian sig_Handle(); 63436345Sbrian 63536345Sbrian if (i <= 0) 63636345Sbrian continue; 63736345Sbrian 63836285Sbrian for (i = 0; i <= nfds; i++) 63966898Sbrian if (FD_ISSET(i, efds)) { 64058038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 64158038Sbrian /* We deal gracefully with link descriptor exceptions */ 64241654Sbrian if (!bundle_Exception(bundle, i)) { 64341654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 64441654Sbrian break; 64541654Sbrian } 6466059Samurai } 64728679Sbrian 64836285Sbrian if (i <= nfds) 64936285Sbrian break; 65028536Sbrian 65137141Sbrian nothing_done = 1; 65237141Sbrian 65366898Sbrian if (descriptor_IsSet(&server.desc, rfds)) { 65466898Sbrian descriptor_Read(&server.desc, bundle, rfds); 65537141Sbrian nothing_done = 0; 65637141Sbrian } 65732039Sbrian 65866898Sbrian if (descriptor_IsSet(&bundle->desc, rfds)) { 65966898Sbrian descriptor_Read(&bundle->desc, bundle, rfds); 66037141Sbrian nothing_done = 0; 66137141Sbrian } 66237141Sbrian 66366898Sbrian if (descriptor_IsSet(&bundle->desc, wfds)) 66493418Sbrian if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { 66537141Sbrian /* 66693418Sbrian * This is disastrous. The OS has told us that something is 66737141Sbrian * writable, and all our write()s have failed. Rather than 66837141Sbrian * going back immediately to do our UpdateSet()s and select(), 66937141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 67037141Sbrian */ 67137141Sbrian struct timeval t; 67236285Sbrian 67337141Sbrian t.tv_sec = 0; 67437141Sbrian t.tv_usec = 100000; 67537141Sbrian select(0, NULL, NULL, NULL, &t); 67637141Sbrian } 67753070Sbrian } 67836285Sbrian 67936285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6806059Samurai} 681