main.c revision 98970
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 98970 2002-06-28 09:33:25Z 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> 4330715Sbrian#include <stdio.h> 4452396Sbrian#include <stdlib.h> 4530715Sbrian#include <string.h> 4697140Sbrian#include <sys/time.h> 476059Samurai#include <termios.h> 4818786Sjkh#include <unistd.h> 4949581Sbrian#include <sys/stat.h> 5030715Sbrian 5150059Sbrian#ifndef NONAT 5258037Sbrian#ifdef LOCALNAT 5358037Sbrian#include "alias.h" 5458037Sbrian#else 5546086Sbrian#include <alias.h> 5639395Sbrian#endif 5739395Sbrian#endif 5858037Sbrian 5946686Sbrian#include "layer.h" 6037141Sbrian#include "probe.h" 6130715Sbrian#include "mbuf.h" 6230715Sbrian#include "log.h" 6330715Sbrian#include "defs.h" 6431061Sbrian#include "id.h" 6530715Sbrian#include "timer.h" 6630715Sbrian#include "fsm.h" 6736285Sbrian#include "lqr.h" 686059Samurai#include "hdlc.h" 6931514Sbrian#include "lcp.h" 7013389Sphk#include "ccp.h" 7136285Sbrian#include "iplist.h" 7236285Sbrian#include "throughput.h" 7336285Sbrian#include "slcompress.h" 7481634Sbrian#include "ncpaddr.h" 756059Samurai#include "ipcp.h" 7636285Sbrian#include "filter.h" 7736285Sbrian#include "descriptor.h" 7836285Sbrian#include "link.h" 7936285Sbrian#include "mp.h" 8043313Sbrian#ifndef NORADIUS 8143313Sbrian#include "radius.h" 8243313Sbrian#endif 8381634Sbrian#include "ipv6cp.h" 8481634Sbrian#include "ncp.h" 8536285Sbrian#include "bundle.h" 866735Samurai#include "auth.h" 8713389Sphk#include "systems.h" 8823840Sbrian#include "sig.h" 8930715Sbrian#include "main.h" 9036285Sbrian#include "server.h" 9136285Sbrian#include "prompt.h" 9236285Sbrian#include "chat.h" 9336285Sbrian#include "chap.h" 9438174Sbrian#include "cbcp.h" 9536285Sbrian#include "datalink.h" 9640561Sbrian#include "iface.h" 976059Samurai 986735Samurai#ifndef O_NONBLOCK 996735Samurai#ifdef O_NDELAY 1006735Samurai#define O_NONBLOCK O_NDELAY 1016735Samurai#endif 1026735Samurai#endif 1036735Samurai 10436431Sbrianstatic void DoLoop(struct bundle *); 10530715Sbrianstatic void TerminalStop(int); 10630715Sbrian 10736285Sbrianstatic struct bundle *SignalBundle; 10836285Sbrianstatic struct prompt *SignalPrompt; 1096059Samurai 11010528Samuraivoid 11136285SbrianCleanup(int excode) 1126059Samurai{ 11336285Sbrian SignalBundle->CleaningUp = 1; 11438008Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1156059Samurai} 1166059Samurai 1176059Samuraivoid 11836285SbrianAbortProgram(int excode) 1196059Samurai{ 12098970Sbrian if (SignalBundle) 12198970Sbrian server_Close(SignalBundle); 12236285Sbrian log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 12398970Sbrian if (SignalBundle) { 12498970Sbrian bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 12598970Sbrian bundle_Destroy(SignalBundle); 12698970Sbrian } 12736285Sbrian log_Close(); 1286059Samurai exit(excode); 1296059Samurai} 1306059Samurai 1316059Samuraistatic void 13228679SbrianCloseConnection(int signo) 1336059Samurai{ 13426858Sbrian /* NOTE, these are manual, we've done a setsid() */ 13536285Sbrian sig_signal(SIGINT, SIG_IGN); 13636285Sbrian log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 13737018Sbrian bundle_Down(SignalBundle, CLOSE_STAYDOWN); 13836285Sbrian sig_signal(SIGINT, CloseConnection); 1396059Samurai} 1406059Samurai 1416059Samuraistatic void 14228679SbrianCloseSession(int signo) 1436059Samurai{ 14436285Sbrian log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 14528679Sbrian Cleanup(EX_TERM); 1466059Samurai} 1476059Samurai 14836285Sbrianstatic pid_t BGPid = 0; 14936285Sbrian 15010528Samuraistatic void 15136285SbrianKillChild(int signo) 15210528Samurai{ 15347119Sbrian signal(signo, SIG_IGN); 15436285Sbrian log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 15536285Sbrian kill(BGPid, SIGINT); 15610528Samurai} 15710528Samurai 15810528Samuraistatic void 15936285SbrianTerminalCont(int signo) 16010528Samurai{ 16136285Sbrian signal(SIGCONT, SIG_DFL); 16236285Sbrian prompt_Continue(SignalPrompt); 16310528Samurai} 16410528Samurai 16526940Sbrianstatic void 16636285SbrianTerminalStop(int signo) 16726940Sbrian{ 16836285Sbrian prompt_Suspend(SignalPrompt); 16936285Sbrian signal(SIGCONT, TerminalCont); 17036285Sbrian raise(SIGSTOP); 17126940Sbrian} 17226940Sbrian 17331081Sbrianstatic void 17431081SbrianBringDownServer(int signo) 17531081Sbrian{ 17636285Sbrian /* Drops all child prompts too ! */ 17771657Sbrian if (server_Close(SignalBundle)) 17871657Sbrian log_Printf(LogPHASE, "Closed server socket\n"); 17931081Sbrian} 18031081Sbrian 18130715Sbrianstatic void 18271657SbrianRestartServer(int signo) 18371657Sbrian{ 18471657Sbrian /* Drops all child prompts and re-opens the socket */ 18571657Sbrian server_Reopen(SignalBundle); 18671657Sbrian} 18771657Sbrian 18871657Sbrianstatic void 18931343SbrianUsage(void) 1906059Samurai{ 19195258Sdes fprintf(stderr, "usage: ppp [-auto | -foreground | -background | -direct |" 19267912Sbrian " -dedicated | -ddial | -interactive]" 19331343Sbrian#ifndef NOALIAS 19450059Sbrian " [-nat]" 19531343Sbrian#endif 19652396Sbrian " [-quiet] [-unit N] [system ...]\n"); 1976059Samurai exit(EX_START); 1986059Samurai} 1996059Samurai 20052396Sbrianstruct switches { 20152396Sbrian unsigned nat : 1; 20252396Sbrian unsigned fg : 1; 20352396Sbrian unsigned quiet : 1; 20452396Sbrian int mode; 20552396Sbrian int unit; 20652396Sbrian}; 20752396Sbrian 20840797Sbrianstatic int 20952396SbrianProcessArgs(int argc, char **argv, struct switches *sw) 2106059Samurai{ 21140797Sbrian int optc, newmode, arg; 2126059Samurai char *cp; 2136059Samurai 21440797Sbrian optc = 0; 21552396Sbrian memset(sw, '\0', sizeof *sw); 21652396Sbrian sw->mode = PHYS_INTERACTIVE; 21752396Sbrian sw->unit = -1; 21852396Sbrian 21940797Sbrian for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 22040797Sbrian cp = argv[arg] + 1; 22136465Sbrian newmode = Nam2mode(cp); 22236465Sbrian switch (newmode) { 22336465Sbrian case PHYS_NONE: 22452396Sbrian if (strcmp(cp, "nat") == 0) { 22550059Sbrian#ifdef NONAT 22652396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 22737191Sbrian#else 22852396Sbrian sw->nat = 1; 22936285Sbrian#endif 23036465Sbrian optc--; /* this option isn't exclusive */ 23152396Sbrian } else if (strcmp(cp, "alias") == 0) { 23252396Sbrian#ifdef NONAT 23352396Sbrian log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 23452396Sbrian fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 23552396Sbrian#else 23653889Sbrian log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 23753889Sbrian fprintf(stderr, "%s is deprecated\n", argv[arg]); 23852396Sbrian sw->nat = 1; 23952396Sbrian#endif 24052396Sbrian optc--; /* this option isn't exclusive */ 24152396Sbrian } else if (strncmp(cp, "unit", 4) == 0) { 24253067Sbrian optc--; /* this option isn't exclusive */ 24352396Sbrian if (cp[4] == '\0') { 24453067Sbrian optc--; /* nor is the argument */ 24552396Sbrian if (++arg == argc) { 24652396Sbrian fprintf(stderr, "-unit: Expected unit number\n"); 24752396Sbrian Usage(); 24852396Sbrian } else 24952396Sbrian sw->unit = atoi(argv[arg]); 25052396Sbrian } else 25152396Sbrian sw->unit = atoi(cp + 4); 25250059Sbrian } else if (strcmp(cp, "quiet") == 0) { 25352396Sbrian sw->quiet = 1; 25450059Sbrian optc--; /* this option isn't exclusive */ 25536465Sbrian } else 25636465Sbrian Usage(); 25736465Sbrian break; 25836465Sbrian 25936465Sbrian case PHYS_ALL: 26036465Sbrian Usage(); 26136465Sbrian break; 26236465Sbrian 26336465Sbrian default: 26452396Sbrian sw->mode = newmode; 26553830Sbrian if (newmode == PHYS_FOREGROUND) 26653830Sbrian sw->fg = 1; 26736465Sbrian } 2686059Samurai } 26936465Sbrian 2706059Samurai if (optc > 1) { 27136285Sbrian fprintf(stderr, "You may specify only one mode.\n"); 2726059Samurai exit(EX_START); 2736059Samurai } 27431197Sbrian 27552396Sbrian if (sw->mode == PHYS_AUTO && arg == argc) { 27640797Sbrian fprintf(stderr, "A system must be specified in auto mode.\n"); 27736285Sbrian exit(EX_START); 27836285Sbrian } 27936285Sbrian 28040797Sbrian return arg; /* Don't SetLabel yet ! */ 2816059Samurai} 2826059Samurai 28340797Sbrianstatic void 28440797SbrianCheckLabel(const char *label, struct prompt *prompt, int mode) 28540797Sbrian{ 28640797Sbrian const char *err; 28740797Sbrian 28840797Sbrian if ((err = system_IsValid(label, prompt, mode)) != NULL) { 28940797Sbrian fprintf(stderr, "%s: %s\n", label, err); 29040797Sbrian if (mode == PHYS_DIRECT) 29140797Sbrian log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 29240797Sbrian label, err); 29340797Sbrian log_Close(); 29440797Sbrian exit(1); 29540797Sbrian } 29640797Sbrian} 29740797Sbrian 29840797Sbrian 29926940Sbrianint 30028679Sbrianmain(int argc, char **argv) 3016059Samurai{ 30240797Sbrian char *name; 30343187Sbrian const char *lastlabel; 30479173Sbrian int arg, f, holdfd[3], label; 30536285Sbrian struct bundle *bundle; 30636285Sbrian struct prompt *prompt; 30752396Sbrian struct switches sw; 30826516Sbrian 30981697Sbrian probe_Init(); 31081697Sbrian 31179173Sbrian /* 31279173Sbrian * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and 31379173Sbrian * STDERR_FILENO are always open. These are closed before DoLoop(), 31479173Sbrian * but *after* we've avoided the possibility of erroneously closing 31579173Sbrian * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). 31679173Sbrian */ 31779173Sbrian if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { 31879173Sbrian fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); 31979173Sbrian return 2; 32079173Sbrian } 32179173Sbrian for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) 32279186Sbrian holdfd[f] = dup(holdfd[0]); 32379173Sbrian 32430715Sbrian name = strrchr(argv[0], '/'); 32536285Sbrian log_Open(name ? name + 1 : argv[0]); 32626516Sbrian 32750059Sbrian#ifndef NONAT 32838198Sbrian PacketAliasInit(); 32938198Sbrian#endif 33052396Sbrian label = ProcessArgs(argc, argv, &sw); 33131121Sbrian 33236285Sbrian /* 33344539Sbrian * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 33444539Sbrian * output occasionally.... I must find the real reason some time. To 33544539Sbrian * display the dodgy behaviour, comment out this bit, make yourself a large 33636285Sbrian * routing table and then run ppp in interactive mode. The `show route' 33736285Sbrian * command will drop chunks of data !!! 33836285Sbrian */ 33952396Sbrian if (sw.mode == PHYS_INTERACTIVE) { 34036285Sbrian close(STDIN_FILENO); 34136285Sbrian if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 34236285Sbrian fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 34336285Sbrian return 2; 34436285Sbrian } 34536285Sbrian } 34636285Sbrian 34736285Sbrian /* Allow output for the moment (except in direct mode) */ 34852396Sbrian if (sw.mode == PHYS_DIRECT) 34936285Sbrian prompt = NULL; 35043526Sbrian else 35136285Sbrian SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 35236285Sbrian 35331121Sbrian ID0init(); 35431158Sbrian if (ID0realuid() != 0) { 35531158Sbrian char conf[200], *ptr; 35631158Sbrian 35774687Sbrian snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); 35831158Sbrian do { 35949581Sbrian struct stat sb; 36049581Sbrian 36149581Sbrian if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 36237019Sbrian log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 36337019Sbrian conf); 36431158Sbrian return -1; 36531158Sbrian } 36631158Sbrian ptr = conf + strlen(conf)-2; 36731158Sbrian while (ptr > conf && *ptr != '/') 36831158Sbrian *ptr-- = '\0'; 36931158Sbrian } while (ptr >= conf); 37031158Sbrian } 37131158Sbrian 37240797Sbrian if (label < argc) 37340797Sbrian for (arg = label; arg < argc; arg++) 37452396Sbrian CheckLabel(argv[arg], prompt, sw.mode); 37540797Sbrian else 37652396Sbrian CheckLabel("default", prompt, sw.mode); 37731121Sbrian 37852396Sbrian if (!sw.quiet) 37952396Sbrian prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 38043526Sbrian 38153298Sbrian if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 38226940Sbrian return EX_START; 38343187Sbrian 38443187Sbrian /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 38543187Sbrian 38636314Sbrian if (prompt) { 38736314Sbrian prompt->bundle = bundle; /* couldn't do it earlier */ 38852396Sbrian if (!sw.quiet) 38950059Sbrian prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 39036314Sbrian } 39136285Sbrian SignalBundle = bundle; 39252396Sbrian bundle->NatEnabled = sw.nat; 39352396Sbrian if (sw.nat) 39440561Sbrian bundle->cfg.opt |= 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 43052396Sbrian if (sw.mode != PHYS_INTERACTIVE) { 43152396Sbrian if (sw.mode != PHYS_DIRECT) { 43252396Sbrian if (!sw.fg) { 43350059Sbrian int bgpipe[2]; 43450059Sbrian pid_t bgpid; 43536285Sbrian 43652396Sbrian if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 43750059Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 43850059Sbrian AbortProgram(EX_SOCK); 43950059Sbrian } 4406059Samurai 44150059Sbrian bgpid = fork(); 44250059Sbrian if (bgpid == -1) { 44350059Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 44450059Sbrian AbortProgram(EX_SOCK); 44550059Sbrian } 44636285Sbrian 44750059Sbrian if (bgpid) { 44850059Sbrian char c = EX_NORMAL; 44959084Sbrian int ret; 45011336Samurai 45152396Sbrian if (sw.mode == PHYS_BACKGROUND) { 45250059Sbrian close(bgpipe[1]); 45350059Sbrian BGPid = bgpid; 45450059Sbrian /* If we get a signal, kill the child */ 45550059Sbrian signal(SIGHUP, KillChild); 45650059Sbrian signal(SIGTERM, KillChild); 45750059Sbrian signal(SIGINT, KillChild); 45850059Sbrian signal(SIGQUIT, KillChild); 45936285Sbrian 46050059Sbrian /* Wait for our child to close its pipe before we exit */ 46159084Sbrian while ((ret = read(bgpipe[0], &c, 1)) == 1) { 46259084Sbrian switch (c) { 46359084Sbrian case EX_NORMAL: 46475120Sbrian if (!sw.quiet) { 46575120Sbrian prompt_Printf(prompt, "PPP enabled\n"); 46675120Sbrian log_Printf(LogPHASE, "Parent: PPP enabled\n"); 46775120Sbrian } 46859104Sbrian break; 46959084Sbrian case EX_REDIAL: 47059084Sbrian if (!sw.quiet) 47159084Sbrian prompt_Printf(prompt, "Attempting redial\n"); 47259084Sbrian continue; 47359084Sbrian case EX_RECONNECT: 47459084Sbrian if (!sw.quiet) 47559084Sbrian prompt_Printf(prompt, "Attempting reconnect\n"); 47659084Sbrian continue; 47759084Sbrian default: 47859084Sbrian prompt_Printf(prompt, "Child failed (%s)\n", 47959084Sbrian ex_desc((int)c)); 48059084Sbrian log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 48159084Sbrian ex_desc((int) c)); 48259084Sbrian } 48359084Sbrian break; 48459084Sbrian } 48559084Sbrian if (ret != 1) { 48650059Sbrian prompt_Printf(prompt, "Child exit, no status.\n"); 48750059Sbrian log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 48850059Sbrian } 48950059Sbrian close(bgpipe[0]); 49028679Sbrian } 49150059Sbrian return c; 49252396Sbrian } else if (sw.mode == PHYS_BACKGROUND) { 49336285Sbrian close(bgpipe[0]); 49450059Sbrian bundle->notify.fd = bgpipe[1]; 49550059Sbrian } 49650059Sbrian 49756350Sbrian bundle_ChangedPID(bundle); 49850059Sbrian bundle_LockTun(bundle); /* we have a new pid */ 49936285Sbrian } 50020813Sjkh 50150059Sbrian /* -auto, -dedicated, -ddial, -foreground & -background */ 50236285Sbrian prompt_Destroy(prompt, 0); 50336285Sbrian close(STDOUT_FILENO); 50436285Sbrian close(STDERR_FILENO); 50536285Sbrian close(STDIN_FILENO); 50652396Sbrian if (!sw.fg) 50750059Sbrian setsid(); 50836285Sbrian } else { 50950059Sbrian /* -direct - STDIN_FILENO gets used by physical_Open */ 51036285Sbrian prompt_TtyInit(NULL); 51136285Sbrian close(STDOUT_FILENO); 51236285Sbrian close(STDERR_FILENO); 51326686Sbrian } 5146059Samurai } else { 51550059Sbrian /* -interactive */ 51632129Sbrian close(STDERR_FILENO); 51736285Sbrian prompt_TtyInit(prompt); 51836285Sbrian prompt_TtyCommandMode(prompt); 51936285Sbrian prompt_Required(prompt); 5206059Samurai } 52129696Sbrian 52279173Sbrian /* We can get rid of these now */ 52379173Sbrian for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) 52479173Sbrian close(holdfd[f]); 52579173Sbrian 52652396Sbrian log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 52736431Sbrian DoLoop(bundle); 52836285Sbrian AbortProgram(EX_NORMAL); 5296059Samurai 53036285Sbrian return EX_NORMAL; 5316059Samurai} 5326059Samurai 5336059Samuraistatic void 53436431SbrianDoLoop(struct bundle *bundle) 5356059Samurai{ 53666898Sbrian fd_set *rfds, *wfds, *efds; 53737141Sbrian int i, nfds, nothing_done; 5386059Samurai 53966898Sbrian if ((rfds = mkfdset()) == NULL) { 54066898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54166898Sbrian return; 54266898Sbrian } 54366898Sbrian 54466898Sbrian if ((wfds = mkfdset()) == NULL) { 54566898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 54666898Sbrian free(rfds); 54766898Sbrian return; 54866898Sbrian } 54966898Sbrian 55066898Sbrian if ((efds = mkfdset()) == NULL) { 55166898Sbrian log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 55266898Sbrian free(rfds); 55366898Sbrian free(wfds); 55466898Sbrian return; 55566898Sbrian } 55666898Sbrian 55753070Sbrian for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 55823598Sache nfds = 0; 55966898Sbrian zerofdset(rfds); 56066898Sbrian zerofdset(wfds); 56166898Sbrian zerofdset(efds); 5627001Samurai 56336314Sbrian /* All our datalinks, the tun device and the MP socket */ 56466898Sbrian descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 56525067Sbrian 56636314Sbrian /* All our prompts and the diagnostic socket */ 56766898Sbrian descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 56836314Sbrian 56958453Sbrian bundle_CleanDatalinks(bundle); 57036285Sbrian if (bundle_IsDead(bundle)) 57136285Sbrian /* Don't select - we'll be here forever */ 57236285Sbrian break; 57326551Sbrian 57445126Sbrian /* 57545126Sbrian * It's possible that we've had a signal since we last checked. If 57645126Sbrian * we don't check again before calling select(), we may end up stuck 57745126Sbrian * after having missed the event.... sig_Handle() tries to be as 57845126Sbrian * quick as possible if nothing is likely to have happened. 57945126Sbrian * This is only really likely if we block in open(... O_NONBLOCK) 58045126Sbrian * which will happen with a misconfigured device. 58145126Sbrian */ 58245126Sbrian if (sig_Handle()) 58345126Sbrian continue; 58445126Sbrian 58566898Sbrian i = select(nfds, rfds, wfds, efds, NULL); 58626696Sbrian 58736345Sbrian if (i < 0 && errno != EINTR) { 58836285Sbrian log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 58936285Sbrian if (log_IsKept(LogTIMER)) { 59036285Sbrian struct timeval t; 59136285Sbrian 59236285Sbrian for (i = 0; i <= nfds; i++) { 59366898Sbrian if (FD_ISSET(i, rfds)) { 59436285Sbrian log_Printf(LogTIMER, "Read set contains %d\n", i); 59566898Sbrian FD_CLR(i, rfds); 59636285Sbrian t.tv_sec = t.tv_usec = 0; 59766898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 59836285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 59936285Sbrian break; 60036285Sbrian } 60136285Sbrian } 60266898Sbrian if (FD_ISSET(i, wfds)) { 60336285Sbrian log_Printf(LogTIMER, "Write set contains %d\n", i); 60466898Sbrian FD_CLR(i, wfds); 60536285Sbrian t.tv_sec = t.tv_usec = 0; 60666898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 60736285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 60836285Sbrian break; 60936285Sbrian } 61036285Sbrian } 61166898Sbrian if (FD_ISSET(i, efds)) { 61236285Sbrian log_Printf(LogTIMER, "Error set contains %d\n", i); 61366898Sbrian FD_CLR(i, efds); 61436285Sbrian t.tv_sec = t.tv_usec = 0; 61566898Sbrian if (select(nfds, rfds, wfds, efds, &t) != -1) { 61636285Sbrian log_Printf(LogTIMER, "The culprit !\n"); 61736285Sbrian break; 61836285Sbrian } 61936285Sbrian } 62036285Sbrian } 62128679Sbrian } 62228679Sbrian break; 6238857Srgrimes } 6246059Samurai 62543693Sbrian log_Printf(LogTIMER, "Select returns %d\n", i); 62643693Sbrian 62736345Sbrian sig_Handle(); 62836345Sbrian 62936345Sbrian if (i <= 0) 63036345Sbrian continue; 63136345Sbrian 63236285Sbrian for (i = 0; i <= nfds; i++) 63366898Sbrian if (FD_ISSET(i, efds)) { 63458038Sbrian log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 63558038Sbrian /* We deal gracefully with link descriptor exceptions */ 63641654Sbrian if (!bundle_Exception(bundle, i)) { 63741654Sbrian log_Printf(LogERROR, "Exception cannot be handled !\n"); 63841654Sbrian break; 63941654Sbrian } 6406059Samurai } 64128679Sbrian 64236285Sbrian if (i <= nfds) 64336285Sbrian break; 64428536Sbrian 64537141Sbrian nothing_done = 1; 64637141Sbrian 64766898Sbrian if (descriptor_IsSet(&server.desc, rfds)) { 64866898Sbrian descriptor_Read(&server.desc, bundle, rfds); 64937141Sbrian nothing_done = 0; 65037141Sbrian } 65132039Sbrian 65266898Sbrian if (descriptor_IsSet(&bundle->desc, rfds)) { 65366898Sbrian descriptor_Read(&bundle->desc, bundle, rfds); 65437141Sbrian nothing_done = 0; 65537141Sbrian } 65637141Sbrian 65766898Sbrian if (descriptor_IsSet(&bundle->desc, wfds)) 65893418Sbrian if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { 65937141Sbrian /* 66093418Sbrian * This is disastrous. The OS has told us that something is 66137141Sbrian * writable, and all our write()s have failed. Rather than 66237141Sbrian * going back immediately to do our UpdateSet()s and select(), 66337141Sbrian * we sleep for a bit to avoid gobbling up all cpu time. 66437141Sbrian */ 66537141Sbrian struct timeval t; 66636285Sbrian 66737141Sbrian t.tv_sec = 0; 66837141Sbrian t.tv_usec = 100000; 66937141Sbrian select(0, NULL, NULL, NULL, &t); 67037141Sbrian } 67153070Sbrian } 67236285Sbrian 67336285Sbrian log_Printf(LogDEBUG, "DoLoop done.\n"); 6746059Samurai} 675