main.c revision 196514
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 196514 2009-08-24 17:19:45Z 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; 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 38936314Sbrian if (prompt) { 39036314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 39152396Sbrian if (!sw.quiet) 39250059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 39336314Sbrian } 39436285Sbrian SignalBundle = bundle; 39552396Sbrian bundle->NatEnabled = sw.nat; 39652396Sbrian if (sw.nat) 397138198Sbrian opt_enable(bundle, OPT_IFACEALIAS); 39831121Sbrian 39937008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 40036285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 40136285Sbrian 40236285Sbrian sig_signal(SIGHUP, CloseSession); 40336285Sbrian sig_signal(SIGTERM, CloseSession); 40436285Sbrian sig_signal(SIGINT, CloseConnection); 40536285Sbrian sig_signal(SIGQUIT, CloseSession); 40636285Sbrian sig_signal(SIGALRM, SIG_IGN); 40724753Sache signal(SIGPIPE, SIG_IGN); 4086059Samurai 40952396Sbrian if (sw.mode == PHYS_INTERACTIVE) 41036285Sbrian sig_signal(SIGTSTP, TerminalStop); 41136285Sbrian 41271657Sbrian sig_signal(SIGUSR1, RestartServer); 41336285Sbrian sig_signal(SIGUSR2, BringDownServer); 41436285Sbrian 41553298Sbrian lastlabel = argv[argc - 1]; 41640797Sbrian for (arg = label; arg < argc; arg++) { 41740797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 41843187Sbrian bundle_SetLabel(bundle, lastlabel); 41953298Sbrian system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 4206059Samurai } 42126940Sbrian 42240797Sbrian if (label < argc) 42340797Sbrian /* In case the last label did a ``load'' */ 42443187Sbrian bundle_SetLabel(bundle, lastlabel); 42540797Sbrian 42652396Sbrian if (sw.mode == PHYS_AUTO && 42781634Sbrian ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { 42840797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 42940797Sbrian "in auto mode.\n"); 43040797Sbrian AbortProgram(EX_START); 43140797Sbrian } 43240797Sbrian 43352396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 43452396Sbrian if (sw.mode != PHYS_DIRECT) { 43552396Sbrian if (!sw.fg) { 43650059Sbrian int bgpipe[2]; 43750059Sbrian pid_t bgpid; 43836285Sbrian 43952396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 44050059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 44150059Sbrian AbortProgram(EX_SOCK); 44250059Sbrian } 4436059Samurai 44450059Sbrian bgpid = fork(); 44550059Sbrian if (bgpid == -1) { 44650059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 44750059Sbrian AbortProgram(EX_SOCK); 44850059Sbrian } 44936285Sbrian 45050059Sbrian if (bgpid) { 45150059Sbrian char c = EX_NORMAL; 45259084Sbrian int ret; 45311336Samurai 45452396Sbrian if (sw.mode == PHYS_BACKGROUND) { 45550059Sbrian close(bgpipe[1]); 45650059Sbrian BGPid = bgpid; 45750059Sbrian /* If we get a signal, kill the child */ 45850059Sbrian signal(SIGHUP, KillChild); 45950059Sbrian signal(SIGTERM, KillChild); 46050059Sbrian signal(SIGINT, KillChild); 46150059Sbrian signal(SIGQUIT, KillChild); 46236285Sbrian 46350059Sbrian /* Wait for our child to close its pipe before we exit */ 46459084Sbrian while ((ret = read(bgpipe[0], &c, 1)) == 1) { 46559084Sbrian switch (c) { 46659084Sbrian case EX_NORMAL: 46775120Sbrian if (!sw.quiet) { 46875120Sbrian prompt_Printf(prompt, "PPP enabled\n"); 46975120Sbrian log_Printf(LogPHASE, "Parent: PPP enabled\n"); 47075120Sbrian } 47159104Sbrian break; 47259084Sbrian case EX_REDIAL: 47359084Sbrian if (!sw.quiet) 47459084Sbrian prompt_Printf(prompt, "Attempting redial\n"); 47559084Sbrian continue; 47659084Sbrian case EX_RECONNECT: 47759084Sbrian if (!sw.quiet) 47859084Sbrian prompt_Printf(prompt, "Attempting reconnect\n"); 47959084Sbrian continue; 48059084Sbrian default: 48159084Sbrian prompt_Printf(prompt, "Child failed (%s)\n", 48259084Sbrian ex_desc((int)c)); 48359084Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 48459084Sbrian ex_desc((int) c)); 48559084Sbrian } 48659084Sbrian break; 48759084Sbrian } 48859084Sbrian if (ret != 1) { 48950059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 49050059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 49150059Sbrian } 49250059Sbrian close(bgpipe[0]); 49328679Sbrian } 49450059Sbrian return c; 49552396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 49636285Sbrian close(bgpipe[0]); 49750059Sbrian bundle->notify.fd = bgpipe[1]; 49850059Sbrian } 49950059Sbrian 50056350Sbrian bundle_ChangedPID(bundle); 50150059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 50236285Sbrian } 50320813Sjkh 50450059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 50536285Sbrian prompt_Destroy(prompt, 0); 50636285Sbrian close(STDOUT_FILENO); 50736285Sbrian close(STDERR_FILENO); 50836285Sbrian close(STDIN_FILENO); 50952396Sbrian if (!sw.fg) 51050059Sbrian setsid(); 51136285Sbrian } else { 512196514Sbrian /* 513196514Sbrian * -direct - STDIN_FILENO gets used by physical_Open. STDOUT_FILENO 514196514Sbrian * *may* get used in exec/pipe mode. 515196514Sbrian */ 51636285Sbrian prompt_TtyInit(NULL); 51736285Sbrian close(STDERR_FILENO); 51826686Sbrian } 5196059Samurai } else { 52050059Sbrian /* -interactive */ 52132129Sbrian close(STDERR_FILENO); 52236285Sbrian prompt_TtyInit(prompt); 52336285Sbrian prompt_TtyCommandMode(prompt); 52436285Sbrian prompt_Required(prompt); 5256059Samurai } 52629696Sbrian 52779173Sbrian /* We can get rid of these now */ 52879173Sbrian for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 52979173Sbrian close(holdfd[f]); 53079173Sbrian 53152396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 53236431Sbrian DoLoop(bundle); 53336285Sbrian AbortProgram(EX_NORMAL); 5346059Samurai 53536285Sbrian return EX_NORMAL; 5366059Samurai} 5376059Samurai 5386059Samuraistatic void 53936431SbrianDoLoop(struct bundle *bundle) 5406059Samurai{ 54166898Sbrian fd_set *rfds, *wfds, *efds; 54237141Sbrian int i, nfds, nothing_done; 5436059Samurai 54466898Sbrian if ((rfds = mkfdset()) == NULL) { 54566898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54666898Sbrian return; 54766898Sbrian } 54866898Sbrian 54966898Sbrian if ((wfds = mkfdset()) == NULL) { 55066898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55166898Sbrian free(rfds); 55266898Sbrian return; 55366898Sbrian } 55466898Sbrian 55566898Sbrian if ((efds = mkfdset()) == NULL) { 55666898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55766898Sbrian free(rfds); 55866898Sbrian free(wfds); 55966898Sbrian return; 56066898Sbrian } 56166898Sbrian 56253070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 56323598Sache nfds = 0; 56466898Sbrian zerofdset(rfds); 56566898Sbrian zerofdset(wfds); 56666898Sbrian zerofdset(efds); 5677001Samurai 56836314Sbrian /* All our datalinks, the tun device and the MP socket */ 56966898Sbrian descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 57025067Sbrian 57136314Sbrian /* All our prompts and the diagnostic socket */ 57266898Sbrian descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 57336314Sbrian 57458453Sbrian bundle_CleanDatalinks(bundle); 57536285Sbrian if (bundle_IsDead(bundle)) 57636285Sbrian /* Don't select - we'll be here forever */ 57736285Sbrian break; 57826551Sbrian 57945126Sbrian /* 58045126Sbrian * It's possible that we've had a signal since we last checked. If 58145126Sbrian * we don't check again before calling select(), we may end up stuck 58245126Sbrian * after having missed the event.... sig_Handle() tries to be as 58345126Sbrian * quick as possible if nothing is likely to have happened. 58445126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 58545126Sbrian * which will happen with a misconfigured device. 58645126Sbrian */ 58745126Sbrian if (sig_Handle()) 58845126Sbrian continue; 58945126Sbrian 59066898Sbrian i = select(nfds, rfds, wfds, efds, NULL); 59126696Sbrian 59236345Sbrian if (i < 0 && errno != EINTR) { 59336285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 59436285Sbrian if (log_IsKept(LogTIMER)) { 59536285Sbrian struct timeval t; 59636285Sbrian 59736285Sbrian for (i = 0; i <= nfds; i++) { 59866898Sbrian if (FD_ISSET(i, rfds)) { 59936285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 60066898Sbrian FD_CLR(i, rfds); 60136285Sbrian t.tv_sec = t.tv_usec = 0; 60266898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 60336285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 60436285Sbrian break; 60536285Sbrian } 60636285Sbrian } 60766898Sbrian if (FD_ISSET(i, wfds)) { 60836285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 60966898Sbrian FD_CLR(i, wfds); 61036285Sbrian t.tv_sec = t.tv_usec = 0; 61166898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 61236285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 61336285Sbrian break; 61436285Sbrian } 61536285Sbrian } 61666898Sbrian if (FD_ISSET(i, efds)) { 61736285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 61866898Sbrian FD_CLR(i, efds); 61936285Sbrian t.tv_sec = t.tv_usec = 0; 62066898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 62136285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 62236285Sbrian break; 62336285Sbrian } 62436285Sbrian } 62536285Sbrian } 62628679Sbrian } 62728679Sbrian break; 6288857Srgrimes } 6296059Samurai 63043693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 63143693Sbrian 63236345Sbrian sig_Handle(); 63336345Sbrian 63436345Sbrian if (i <= 0) 63536345Sbrian continue; 63636345Sbrian 63736285Sbrian for (i = 0; i <= nfds; i++) 63866898Sbrian if (FD_ISSET(i, efds)) { 63958038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 64058038Sbrian /* We deal gracefully with link descriptor exceptions */ 64141654Sbrian if (!bundle_Exception(bundle, i)) { 64241654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 64341654Sbrian break; 64441654Sbrian } 6456059Samurai } 64628679Sbrian 64736285Sbrian if (i <= nfds) 64836285Sbrian break; 64928536Sbrian 65037141Sbrian nothing_done = 1; 65137141Sbrian 65266898Sbrian if (descriptor_IsSet(&server.desc, rfds)) { 65366898Sbrian descriptor_Read(&server.desc, bundle, rfds); 65437141Sbrian nothing_done = 0; 65537141Sbrian } 65632039Sbrian 65766898Sbrian if (descriptor_IsSet(&bundle->desc, rfds)) { 65866898Sbrian descriptor_Read(&bundle->desc, bundle, rfds); 65937141Sbrian nothing_done = 0; 66037141Sbrian } 66137141Sbrian 66266898Sbrian if (descriptor_IsSet(&bundle->desc, wfds)) 66393418Sbrian if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { 66437141Sbrian /* 66593418Sbrian * This is disastrous. The OS has told us that something is 66637141Sbrian * writable, and all our write()s have failed. Rather than 66737141Sbrian * going back immediately to do our UpdateSet()s and select(), 66837141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 66937141Sbrian */ 67037141Sbrian struct timeval t; 67136285Sbrian 67237141Sbrian t.tv_sec = 0; 67337141Sbrian t.tv_usec = 100000; 67437141Sbrian select(0, NULL, NULL, NULL, &t); 67537141Sbrian } 67653070Sbrian } 67736285Sbrian 67836285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6796059Samurai} 680