main.c revision 102500
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 102500 2002-08-27 20:11:58Z 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 11236285SbrianCleanup(int excode) 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); 14628679Sbrian Cleanup(EX_TERM); 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 16036285SbrianTerminalCont(int signo) 16110528Samurai{ 16236285Sbrian signal(SIGCONT, SIG_DFL); 16336285Sbrian prompt_Continue(SignalPrompt); 16410528Samurai} 16510528Samurai 16626940Sbrianstatic void 16736285SbrianTerminalStop(int signo) 16826940Sbrian{ 16936285Sbrian prompt_Suspend(SignalPrompt); 17036285Sbrian signal(SIGCONT, TerminalCont); 17136285Sbrian raise(SIGSTOP); 17226940Sbrian} 17326940Sbrian 17431081Sbrianstatic void 17531081SbrianBringDownServer(int signo) 17631081Sbrian{ 17736285Sbrian /* Drops all child prompts too ! */ 17871657Sbrian if (server_Close(SignalBundle)) 17971657Sbrian log_Printf(LogPHASE, "Closed server socket\n"); 18031081Sbrian} 18131081Sbrian 18230715Sbrianstatic void 18371657SbrianRestartServer(int signo) 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; 30579173Sbrian int arg, f, holdfd[3], label; 30636285Sbrian struct bundle *bundle; 30736285Sbrian struct prompt *prompt; 30852396Sbrian struct switches sw; 30926516Sbrian 31081697Sbrian probe_Init(); 31181697Sbrian 31279173Sbrian /* 31379173Sbrian * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 31479173Sbrian * STDERR_FILENO are always open. These are closed before DoLoop(), 31579173Sbrian * but *after* we've avoided the possibility of erroneously closing 31679173Sbrian * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 31779173Sbrian */ 31879173Sbrian if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 31979173Sbrian fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 32079173Sbrian return 2; 32179173Sbrian } 32279173Sbrian for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 32379186Sbrian holdfd[f] = dup(holdfd[0]); 32479173Sbrian 32530715Sbrian name = strrchr(argv[0], '/'); 32636285Sbrian log_Open(name ? name + 1 : argv[0]); 32726516Sbrian 32850059Sbrian#ifndef NONAT 32938198Sbrian PacketAliasInit(); 33038198Sbrian#endif 33152396Sbrian label = ProcessArgs(argc, argv, &sw); 33231121Sbrian 33336285Sbrian /* 33444539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 33544539Sbrian * output occasionally.... I must find the real reason some time. To 33644539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 33736285Sbrian * routing table and then run ppp in interactive mode. The `show route' 33836285Sbrian * command will drop chunks of data !!! 33936285Sbrian */ 34052396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 34136285Sbrian close(STDIN_FILENO); 34236285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 34336285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 34436285Sbrian return 2; 34536285Sbrian } 34636285Sbrian } 34736285Sbrian 34836285Sbrian /* Allow output for the moment (except in direct mode) */ 34952396Sbrian if (sw.mode == PHYS_DIRECT) 35036285Sbrian prompt = NULL; 35143526Sbrian else 35236285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 35336285Sbrian 35431121Sbrian ID0init(); 35531158Sbrian if (ID0realuid() != 0) { 35631158Sbrian char conf[200], *ptr; 35731158Sbrian 35874687Sbrian snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 35931158Sbrian do { 36049581Sbrian struct stat sb; 36149581Sbrian 36249581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 36337019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 36437019Sbrian conf); 36531158Sbrian return -1; 36631158Sbrian } 36731158Sbrian ptr = conf + strlen(conf)-2; 36831158Sbrian while (ptr > conf && *ptr != '/') 36931158Sbrian *ptr-- = '\0'; 37031158Sbrian } while (ptr >= conf); 37131158Sbrian } 37231158Sbrian 37340797Sbrian if (label < argc) 37440797Sbrian for (arg = label; arg < argc; arg++) 37552396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 37640797Sbrian else 37752396Sbrian CheckLabel("default", prompt, sw.mode); 37831121Sbrian 37952396Sbrian if (!sw.quiet) 38052396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 38143526Sbrian 38253298Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 38326940Sbrian return EX_START; 38443187Sbrian 38543187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 38643187Sbrian 38736314Sbrian if (prompt) { 38836314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 38952396Sbrian if (!sw.quiet) 39050059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 39136314Sbrian } 39236285Sbrian SignalBundle = bundle; 39352396Sbrian bundle->NatEnabled = sw.nat; 39452396Sbrian if (sw.nat) 39540561Sbrian bundle->cfg.opt |= OPT_IFACEALIAS; 39631121Sbrian 39737008Sbrian if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 39836285Sbrian prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 39936285Sbrian 40036285Sbrian sig_signal(SIGHUP, CloseSession); 40136285Sbrian sig_signal(SIGTERM, CloseSession); 40236285Sbrian sig_signal(SIGINT, CloseConnection); 40336285Sbrian sig_signal(SIGQUIT, CloseSession); 40436285Sbrian sig_signal(SIGALRM, SIG_IGN); 40524753Sache signal(SIGPIPE, SIG_IGN); 4066059Samurai 40752396Sbrian if (sw.mode == PHYS_INTERACTIVE) 40836285Sbrian sig_signal(SIGTSTP, TerminalStop); 40936285Sbrian 41071657Sbrian sig_signal(SIGUSR1, RestartServer); 41136285Sbrian sig_signal(SIGUSR2, BringDownServer); 41236285Sbrian 41353298Sbrian lastlabel = argv[argc - 1]; 41440797Sbrian for (arg = label; arg < argc; arg++) { 41540797Sbrian /* In case we use LABEL or ``set enddisc label'' */ 41643187Sbrian bundle_SetLabel(bundle, lastlabel); 41753298Sbrian system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 4186059Samurai } 41926940Sbrian 42040797Sbrian if (label < argc) 42140797Sbrian /* In case the last label did a ``load'' */ 42243187Sbrian bundle_SetLabel(bundle, lastlabel); 42340797Sbrian 42452396Sbrian if (sw.mode == PHYS_AUTO && 42581634Sbrian ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { 42640797Sbrian prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 42740797Sbrian "in auto mode.\n"); 42840797Sbrian AbortProgram(EX_START); 42940797Sbrian } 43040797Sbrian 43152396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 43252396Sbrian if (sw.mode != PHYS_DIRECT) { 43352396Sbrian if (!sw.fg) { 43450059Sbrian int bgpipe[2]; 43550059Sbrian pid_t bgpid; 43636285Sbrian 43752396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 43850059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 43950059Sbrian AbortProgram(EX_SOCK); 44050059Sbrian } 4416059Samurai 44250059Sbrian bgpid = fork(); 44350059Sbrian if (bgpid == -1) { 44450059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 44550059Sbrian AbortProgram(EX_SOCK); 44650059Sbrian } 44736285Sbrian 44850059Sbrian if (bgpid) { 44950059Sbrian char c = EX_NORMAL; 45059084Sbrian int ret; 45111336Samurai 45252396Sbrian if (sw.mode == PHYS_BACKGROUND) { 45350059Sbrian close(bgpipe[1]); 45450059Sbrian BGPid = bgpid; 45550059Sbrian /* If we get a signal, kill the child */ 45650059Sbrian signal(SIGHUP, KillChild); 45750059Sbrian signal(SIGTERM, KillChild); 45850059Sbrian signal(SIGINT, KillChild); 45950059Sbrian signal(SIGQUIT, KillChild); 46036285Sbrian 46150059Sbrian /* Wait for our child to close its pipe before we exit */ 46259084Sbrian while ((ret = read(bgpipe[0], &c, 1)) == 1) { 46359084Sbrian switch (c) { 46459084Sbrian case EX_NORMAL: 46575120Sbrian if (!sw.quiet) { 46675120Sbrian prompt_Printf(prompt, "PPP enabled\n"); 46775120Sbrian log_Printf(LogPHASE, "Parent: PPP enabled\n"); 46875120Sbrian } 46959104Sbrian break; 47059084Sbrian case EX_REDIAL: 47159084Sbrian if (!sw.quiet) 47259084Sbrian prompt_Printf(prompt, "Attempting redial\n"); 47359084Sbrian continue; 47459084Sbrian case EX_RECONNECT: 47559084Sbrian if (!sw.quiet) 47659084Sbrian prompt_Printf(prompt, "Attempting reconnect\n"); 47759084Sbrian continue; 47859084Sbrian default: 47959084Sbrian prompt_Printf(prompt, "Child failed (%s)\n", 48059084Sbrian ex_desc((int)c)); 48159084Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 48259084Sbrian ex_desc((int) c)); 48359084Sbrian } 48459084Sbrian break; 48559084Sbrian } 48659084Sbrian if (ret != 1) { 48750059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 48850059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 48950059Sbrian } 49050059Sbrian close(bgpipe[0]); 49128679Sbrian } 49250059Sbrian return c; 49352396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 49436285Sbrian close(bgpipe[0]); 49550059Sbrian bundle->notify.fd = bgpipe[1]; 49650059Sbrian } 49750059Sbrian 49856350Sbrian bundle_ChangedPID(bundle); 49950059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 50036285Sbrian } 50120813Sjkh 50250059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 50336285Sbrian prompt_Destroy(prompt, 0); 50436285Sbrian close(STDOUT_FILENO); 50536285Sbrian close(STDERR_FILENO); 50636285Sbrian close(STDIN_FILENO); 50752396Sbrian if (!sw.fg) 50850059Sbrian setsid(); 50936285Sbrian } else { 51050059Sbrian /* -direct - STDIN_FILENO gets used by physical_Open */ 51136285Sbrian prompt_TtyInit(NULL); 51236285Sbrian close(STDOUT_FILENO); 51336285Sbrian close(STDERR_FILENO); 51426686Sbrian } 5156059Samurai } else { 51650059Sbrian /* -interactive */ 51732129Sbrian close(STDERR_FILENO); 51836285Sbrian prompt_TtyInit(prompt); 51936285Sbrian prompt_TtyCommandMode(prompt); 52036285Sbrian prompt_Required(prompt); 5216059Samurai } 52229696Sbrian 52379173Sbrian /* We can get rid of these now */ 52479173Sbrian for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 52579173Sbrian close(holdfd[f]); 52679173Sbrian 52752396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 52836431Sbrian DoLoop(bundle); 52936285Sbrian AbortProgram(EX_NORMAL); 5306059Samurai 53136285Sbrian return EX_NORMAL; 5326059Samurai} 5336059Samurai 5346059Samuraistatic void 53536431SbrianDoLoop(struct bundle *bundle) 5366059Samurai{ 53766898Sbrian fd_set *rfds, *wfds, *efds; 53837141Sbrian int i, nfds, nothing_done; 5396059Samurai 54066898Sbrian if ((rfds = mkfdset()) == NULL) { 54166898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54266898Sbrian return; 54366898Sbrian } 54466898Sbrian 54566898Sbrian if ((wfds = mkfdset()) == NULL) { 54666898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54766898Sbrian free(rfds); 54866898Sbrian return; 54966898Sbrian } 55066898Sbrian 55166898Sbrian if ((efds = mkfdset()) == NULL) { 55266898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55366898Sbrian free(rfds); 55466898Sbrian free(wfds); 55566898Sbrian return; 55666898Sbrian } 55766898Sbrian 55853070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 55923598Sache nfds = 0; 56066898Sbrian zerofdset(rfds); 56166898Sbrian zerofdset(wfds); 56266898Sbrian zerofdset(efds); 5637001Samurai 56436314Sbrian /* All our datalinks, the tun device and the MP socket */ 56566898Sbrian descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 56625067Sbrian 56736314Sbrian /* All our prompts and the diagnostic socket */ 56866898Sbrian descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 56936314Sbrian 57058453Sbrian bundle_CleanDatalinks(bundle); 57136285Sbrian if (bundle_IsDead(bundle)) 57236285Sbrian /* Don't select - we'll be here forever */ 57336285Sbrian break; 57426551Sbrian 57545126Sbrian /* 57645126Sbrian * It's possible that we've had a signal since we last checked. If 57745126Sbrian * we don't check again before calling select(), we may end up stuck 57845126Sbrian * after having missed the event.... sig_Handle() tries to be as 57945126Sbrian * quick as possible if nothing is likely to have happened. 58045126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 58145126Sbrian * which will happen with a misconfigured device. 58245126Sbrian */ 58345126Sbrian if (sig_Handle()) 58445126Sbrian continue; 58545126Sbrian 58666898Sbrian i = select(nfds, rfds, wfds, efds, NULL); 58726696Sbrian 58836345Sbrian if (i < 0 && errno != EINTR) { 58936285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 59036285Sbrian if (log_IsKept(LogTIMER)) { 59136285Sbrian struct timeval t; 59236285Sbrian 59336285Sbrian for (i = 0; i <= nfds; i++) { 59466898Sbrian if (FD_ISSET(i, rfds)) { 59536285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 59666898Sbrian FD_CLR(i, rfds); 59736285Sbrian t.tv_sec = t.tv_usec = 0; 59866898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 59936285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 60036285Sbrian break; 60136285Sbrian } 60236285Sbrian } 60366898Sbrian if (FD_ISSET(i, wfds)) { 60436285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 60566898Sbrian FD_CLR(i, wfds); 60636285Sbrian t.tv_sec = t.tv_usec = 0; 60766898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 60836285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 60936285Sbrian break; 61036285Sbrian } 61136285Sbrian } 61266898Sbrian if (FD_ISSET(i, efds)) { 61336285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 61466898Sbrian FD_CLR(i, efds); 61536285Sbrian t.tv_sec = t.tv_usec = 0; 61666898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 61736285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 61836285Sbrian break; 61936285Sbrian } 62036285Sbrian } 62136285Sbrian } 62228679Sbrian } 62328679Sbrian break; 6248857Srgrimes } 6256059Samurai 62643693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 62743693Sbrian 62836345Sbrian sig_Handle(); 62936345Sbrian 63036345Sbrian if (i <= 0) 63136345Sbrian continue; 63236345Sbrian 63336285Sbrian for (i = 0; i <= nfds; i++) 63466898Sbrian if (FD_ISSET(i, efds)) { 63558038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 63658038Sbrian /* We deal gracefully with link descriptor exceptions */ 63741654Sbrian if (!bundle_Exception(bundle, i)) { 63841654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 63941654Sbrian break; 64041654Sbrian } 6416059Samurai } 64228679Sbrian 64336285Sbrian if (i <= nfds) 64436285Sbrian break; 64528536Sbrian 64637141Sbrian nothing_done = 1; 64737141Sbrian 64866898Sbrian if (descriptor_IsSet(&server.desc, rfds)) { 64966898Sbrian descriptor_Read(&server.desc, bundle, rfds); 65037141Sbrian nothing_done = 0; 65137141Sbrian } 65232039Sbrian 65366898Sbrian if (descriptor_IsSet(&bundle->desc, rfds)) { 65466898Sbrian descriptor_Read(&bundle->desc, bundle, rfds); 65537141Sbrian nothing_done = 0; 65637141Sbrian } 65737141Sbrian 65866898Sbrian if (descriptor_IsSet(&bundle->desc, wfds)) 65993418Sbrian if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { 66037141Sbrian /* 66193418Sbrian * This is disastrous. The OS has told us that something is 66237141Sbrian * writable, and all our write()s have failed. Rather than 66337141Sbrian * going back immediately to do our UpdateSet()s and select(), 66437141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 66537141Sbrian */ 66637141Sbrian struct timeval t; 66736285Sbrian 66837141Sbrian t.tv_sec = 0; 66937141Sbrian t.tv_usec = 100000; 67037141Sbrian select(0, NULL, NULL, NULL, &t); 67137141Sbrian } 67253070Sbrian } 67336285Sbrian 67436285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6756059Samurai} 676