1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * User Process PPP 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan, Inc. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 2097d92980SPeter Wemm * $FreeBSD$ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai */ 242764b86aSBrian Somers 25972a1bcfSBrian Somers #include <sys/param.h> 2675240ed1SBrian Somers #include <netinet/in.h> 27a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h> 28a9f484e5SJordan K. Hubbard #include <netinet/ip.h> 29565e35e5SBrian Somers #include <sys/un.h> 3075240ed1SBrian Somers 3175240ed1SBrian Somers #include <errno.h> 3275240ed1SBrian Somers #include <fcntl.h> 3375240ed1SBrian Somers #include <paths.h> 3475240ed1SBrian Somers #include <signal.h> 3575240ed1SBrian Somers #include <stdio.h> 36c0593e34SBrian Somers #include <stdlib.h> 3775240ed1SBrian Somers #include <string.h> 3875240ed1SBrian Somers #include <sys/time.h> 3975240ed1SBrian Somers #include <termios.h> 4075240ed1SBrian Somers #include <unistd.h> 411080ea25SBrian Somers #include <sys/stat.h> 4275240ed1SBrian Somers 4367b072f7SBrian Somers #ifndef NONAT 447884358fSBrian Somers #ifdef __FreeBSD__ 451595bacdSBrian Somers #include <alias.h> 467884358fSBrian Somers #else 477884358fSBrian Somers #include "alias.h" 481595bacdSBrian Somers #endif 491595bacdSBrian Somers #endif 505d9e6103SBrian Somers #include "layer.h" 511af29a6eSBrian Somers #include "probe.h" 5275240ed1SBrian Somers #include "mbuf.h" 5375240ed1SBrian Somers #include "log.h" 5475240ed1SBrian Somers #include "defs.h" 555106c671SBrian Somers #include "id.h" 5675240ed1SBrian Somers #include "timer.h" 5775240ed1SBrian Somers #include "fsm.h" 58879ed6faSBrian Somers #include "lqr.h" 59af57ed9fSAtsushi Murai #include "hdlc.h" 60af57ed9fSAtsushi Murai #include "lcp.h" 610053cc58SBrian Somers #include "ccp.h" 6229e275ceSBrian Somers #include "iplist.h" 6329e275ceSBrian Somers #include "throughput.h" 64eaa4df37SBrian Somers #include "slcompress.h" 65af57ed9fSAtsushi Murai #include "ipcp.h" 6684b8a6ebSAtsushi Murai #include "filter.h" 672f786681SBrian Somers #include "descriptor.h" 683b0f8d2eSBrian Somers #include "link.h" 693b0f8d2eSBrian Somers #include "mp.h" 70972a1bcfSBrian Somers #ifndef NORADIUS 71972a1bcfSBrian Somers #include "radius.h" 72972a1bcfSBrian Somers #endif 735828db6dSBrian Somers #include "bundle.h" 741ae349f5Scvs2svn #include "auth.h" 75ed6a16c1SPoul-Henning Kamp #include "systems.h" 76f5ff0f7cSBrian Somers #include "sig.h" 7775240ed1SBrian Somers #include "main.h" 7877ff88adSBrian Somers #include "server.h" 7985b542cfSBrian Somers #include "prompt.h" 80b6dec9f0SBrian Somers #include "chat.h" 81e2ebb036SBrian Somers #include "chap.h" 8292b09558SBrian Somers #include "cbcp.h" 833006ec67SBrian Somers #include "datalink.h" 848fa6ebe4SBrian Somers #include "iface.h" 8553c9f6c0SAtsushi Murai 8653c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 8753c9f6c0SAtsushi Murai #ifdef O_NDELAY 8853c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 8953c9f6c0SAtsushi Murai #endif 9053c9f6c0SAtsushi Murai #endif 91af57ed9fSAtsushi Murai 920f78c7a7SBrian Somers static void DoLoop(struct bundle *); 9375240ed1SBrian Somers static void TerminalStop(int); 94b6e82f33SBrian Somers static const char *ex_desc(int); 9575240ed1SBrian Somers 9683d1af55SBrian Somers static struct bundle *SignalBundle; 97b6217683SBrian Somers static struct prompt *SignalPrompt; 98c3899f8dSAtsushi Murai 99c3899f8dSAtsushi Murai void 100944f7098SBrian Somers Cleanup(int excode) 101af57ed9fSAtsushi Murai { 102a0cbd833SBrian Somers SignalBundle->CleaningUp = 1; 1039c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1046e4959f0SBrian Somers } 105af57ed9fSAtsushi Murai 1061afedc4bSBrian Somers void 1071afedc4bSBrian Somers AbortProgram(int excode) 1081afedc4bSBrian Somers { 109dd7e2610SBrian Somers server_Close(SignalBundle); 110dd7e2610SBrian Somers log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 1119c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 11268a0f0ccSBrian Somers bundle_Destroy(SignalBundle); 113dd7e2610SBrian Somers log_Close(); 114af57ed9fSAtsushi Murai exit(excode); 115af57ed9fSAtsushi Murai } 116af57ed9fSAtsushi Murai 117af57ed9fSAtsushi Murai static void 118944f7098SBrian Somers CloseConnection(int signo) 119af57ed9fSAtsushi Murai { 120368aee2bSBrian Somers /* NOTE, these are manual, we've done a setsid() */ 121dd7e2610SBrian Somers sig_signal(SIGINT, SIG_IGN); 122dd7e2610SBrian Somers log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 123899011c4SBrian Somers bundle_Down(SignalBundle, CLOSE_STAYDOWN); 124dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 1256d14e2a8SJordan K. Hubbard } 126af57ed9fSAtsushi Murai 127af57ed9fSAtsushi Murai static void 128944f7098SBrian Somers CloseSession(int signo) 129af57ed9fSAtsushi Murai { 130dd7e2610SBrian Somers log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 131af57ed9fSAtsushi Murai Cleanup(EX_TERM); 132af57ed9fSAtsushi Murai } 133c3899f8dSAtsushi Murai 13475b8d283SBrian Somers static pid_t BGPid = 0; 13575b8d283SBrian Somers 13675b8d283SBrian Somers static void 13775b8d283SBrian Somers KillChild(int signo) 13875b8d283SBrian Somers { 139ac37ab22SBrian Somers signal(signo, SIG_IGN); 140dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14175b8d283SBrian Somers kill(BGPid, SIGINT); 14275b8d283SBrian Somers } 14375b8d283SBrian Somers 144c3899f8dSAtsushi Murai static void 145b6e82f33SBrian Somers TerminalCont(int signo) 146c3899f8dSAtsushi Murai { 147f91ad6b0SBrian Somers signal(SIGCONT, SIG_DFL); 148f91ad6b0SBrian Somers prompt_Continue(SignalPrompt); 149c3899f8dSAtsushi Murai } 150c3899f8dSAtsushi Murai 151c3899f8dSAtsushi Murai static void 152944f7098SBrian Somers TerminalStop(int signo) 153c3899f8dSAtsushi Murai { 154f91ad6b0SBrian Somers prompt_Suspend(SignalPrompt); 155f91ad6b0SBrian Somers signal(SIGCONT, TerminalCont); 156f91ad6b0SBrian Somers raise(SIGSTOP); 1574ef16f24SBrian Somers } 1584ef16f24SBrian Somers 1598ea8442cSBrian Somers static void 1608ea8442cSBrian Somers BringDownServer(int signo) 1618ea8442cSBrian Somers { 162b6217683SBrian Somers /* Drops all child prompts too ! */ 163dd7e2610SBrian Somers server_Close(SignalBundle); 1648ea8442cSBrian Somers } 1658ea8442cSBrian Somers 166b6e82f33SBrian Somers static const char * 1676efd9292SBrian Somers ex_desc(int ex) 1686efd9292SBrian Somers { 169d93d3a9cSBrian Somers static char num[12]; /* Used immediately if returned */ 170b6e82f33SBrian Somers static const char *desc[] = { 171b6e82f33SBrian Somers "normal", "start", "sock", "modem", "dial", "dead", "done", 172b6e82f33SBrian Somers "reboot", "errdead", "hangup", "term", "nodial", "nologin" 173b6e82f33SBrian Somers }; 1746efd9292SBrian Somers 17570ee81ffSBrian Somers if (ex >= 0 && ex < sizeof desc / sizeof *desc) 1766efd9292SBrian Somers return desc[ex]; 1776efd9292SBrian Somers snprintf(num, sizeof num, "%d", ex); 1786efd9292SBrian Somers return num; 1796efd9292SBrian Somers } 180c3899f8dSAtsushi Murai 18175240ed1SBrian Somers static void 182b6e82f33SBrian Somers Usage(void) 183af57ed9fSAtsushi Murai { 184680026d6SNate Williams fprintf(stderr, 18567b072f7SBrian Somers "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 186b6e82f33SBrian Somers #ifndef NOALIAS 18767b072f7SBrian Somers " [-nat]" 188b6e82f33SBrian Somers #endif 189c0593e34SBrian Somers " [-quiet] [-unit N] [system ...]\n"); 190af57ed9fSAtsushi Murai exit(EX_START); 191af57ed9fSAtsushi Murai } 192af57ed9fSAtsushi Murai 193c0593e34SBrian Somers struct switches { 194c0593e34SBrian Somers unsigned nat : 1; 195c0593e34SBrian Somers unsigned fg : 1; 196c0593e34SBrian Somers unsigned quiet : 1; 197c0593e34SBrian Somers int mode; 198c0593e34SBrian Somers int unit; 199c0593e34SBrian Somers }; 200c0593e34SBrian Somers 2017cf368ebSBrian Somers static int 202c0593e34SBrian Somers ProcessArgs(int argc, char **argv, struct switches *sw) 203af57ed9fSAtsushi Murai { 2047cf368ebSBrian Somers int optc, newmode, arg; 205af57ed9fSAtsushi Murai char *cp; 206af57ed9fSAtsushi Murai 2077cf368ebSBrian Somers optc = 0; 208c0593e34SBrian Somers memset(sw, '\0', sizeof *sw); 209c0593e34SBrian Somers sw->mode = PHYS_INTERACTIVE; 210c0593e34SBrian Somers sw->unit = -1; 211c0593e34SBrian Somers 2127cf368ebSBrian Somers for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 2137cf368ebSBrian Somers cp = argv[arg] + 1; 21481358fa3SBrian Somers newmode = Nam2mode(cp); 21581358fa3SBrian Somers switch (newmode) { 21681358fa3SBrian Somers case PHYS_NONE: 217c0593e34SBrian Somers if (strcmp(cp, "nat") == 0) { 21867b072f7SBrian Somers #ifdef NONAT 219c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 220615ad4f9SBrian Somers #else 221c0593e34SBrian Somers sw->nat = 1; 222615ad4f9SBrian Somers #endif 2231ae349f5Scvs2svn optc--; /* this option isn't exclusive */ 224c0593e34SBrian Somers } else if (strcmp(cp, "alias") == 0) { 225c0593e34SBrian Somers #ifdef NONAT 226c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 227c0593e34SBrian Somers fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 228c0593e34SBrian Somers #else 229c0593e34SBrian Somers log_Printf(LogWARN, "%s is depricated\n", argv[arg]); 230c0593e34SBrian Somers fprintf(stderr, "%s is depricated\n", argv[arg]); 231c0593e34SBrian Somers sw->nat = 1; 232c0593e34SBrian Somers #endif 233c0593e34SBrian Somers optc--; /* this option isn't exclusive */ 234c0593e34SBrian Somers } else if (strncmp(cp, "unit", 4) == 0) { 2359d06928dSBrian Somers optc--; /* this option isn't exclusive */ 236c0593e34SBrian Somers if (cp[4] == '\0') { 2379d06928dSBrian Somers optc--; /* nor is the argument */ 238c0593e34SBrian Somers if (++arg == argc) { 239c0593e34SBrian Somers fprintf(stderr, "-unit: Expected unit number\n"); 240c0593e34SBrian Somers Usage(); 241c0593e34SBrian Somers } else 242c0593e34SBrian Somers sw->unit = atoi(argv[arg]); 243c0593e34SBrian Somers } else 244c0593e34SBrian Somers sw->unit = atoi(cp + 4); 24567b072f7SBrian Somers } else if (strcmp(cp, "quiet") == 0) { 246c0593e34SBrian Somers sw->quiet = 1; 24767b072f7SBrian Somers optc--; /* this option isn't exclusive */ 24867b072f7SBrian Somers } else if (strcmp(cp, "foreground") == 0) { 249c0593e34SBrian Somers sw->mode = PHYS_BACKGROUND; /* Kinda like background mode */ 250c0593e34SBrian Somers sw->fg = 1; 251944f7098SBrian Somers } else 252af57ed9fSAtsushi Murai Usage(); 25381358fa3SBrian Somers break; 25481358fa3SBrian Somers 25581358fa3SBrian Somers case PHYS_ALL: 25681358fa3SBrian Somers Usage(); 25781358fa3SBrian Somers break; 25881358fa3SBrian Somers 25981358fa3SBrian Somers default: 260c0593e34SBrian Somers sw->mode = newmode; 26181358fa3SBrian Somers } 262af57ed9fSAtsushi Murai } 263af57ed9fSAtsushi Murai 264af57ed9fSAtsushi Murai if (optc > 1) { 26585602e52SBrian Somers fprintf(stderr, "You may specify only one mode.\n"); 2661ae349f5Scvs2svn exit(EX_START); 2671ae349f5Scvs2svn } 2681ae349f5Scvs2svn 269c0593e34SBrian Somers if (sw->mode == PHYS_AUTO && arg == argc) { 2707cf368ebSBrian Somers fprintf(stderr, "A system must be specified in auto mode.\n"); 271af57ed9fSAtsushi Murai exit(EX_START); 272af57ed9fSAtsushi Murai } 27339f94eddSBrian Somers 2747cf368ebSBrian Somers return arg; /* Don't SetLabel yet ! */ 275af57ed9fSAtsushi Murai } 276af57ed9fSAtsushi Murai 2777cf368ebSBrian Somers static void 2787cf368ebSBrian Somers CheckLabel(const char *label, struct prompt *prompt, int mode) 2797cf368ebSBrian Somers { 2807cf368ebSBrian Somers const char *err; 2817cf368ebSBrian Somers 2827cf368ebSBrian Somers if ((err = system_IsValid(label, prompt, mode)) != NULL) { 2837cf368ebSBrian Somers fprintf(stderr, "%s: %s\n", label, err); 2847cf368ebSBrian Somers if (mode == PHYS_DIRECT) 2857cf368ebSBrian Somers log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 2867cf368ebSBrian Somers label, err); 2877cf368ebSBrian Somers log_Close(); 2887cf368ebSBrian Somers exit(1); 2897cf368ebSBrian Somers } 2907cf368ebSBrian Somers } 2917cf368ebSBrian Somers 2927cf368ebSBrian Somers 2934ef16f24SBrian Somers int 294944f7098SBrian Somers main(int argc, char **argv) 295af57ed9fSAtsushi Murai { 2967cf368ebSBrian Somers char *name; 297756783fcSBrian Somers const char *lastlabel; 298c0593e34SBrian Somers int nfds, label, arg; 2997a6f8720SBrian Somers struct bundle *bundle; 300b6217683SBrian Somers struct prompt *prompt; 301c0593e34SBrian Somers struct switches sw; 302e3b4c400SBrian Somers 303e3b4c400SBrian Somers nfds = getdtablesize(); 304e3b4c400SBrian Somers if (nfds >= FD_SETSIZE) 305e3b4c400SBrian Somers /* 306e3b4c400SBrian Somers * If we've got loads of file descriptors, make sure they're all 307e3b4c400SBrian Somers * closed. If they aren't, we may end up with a seg fault when our 308e3b4c400SBrian Somers * `fd_set's get too big when select()ing ! 309e3b4c400SBrian Somers */ 310e3b4c400SBrian Somers while (--nfds > 2) 311e3b4c400SBrian Somers close(nfds); 312af57ed9fSAtsushi Murai 31375240ed1SBrian Somers name = strrchr(argv[0], '/'); 314dd7e2610SBrian Somers log_Open(name ? name + 1 : argv[0]); 3152a279fedSBrian Somers 31667b072f7SBrian Somers #ifndef NONAT 3172a630835SBrian Somers PacketAliasInit(); 3182a630835SBrian Somers #endif 319c0593e34SBrian Somers label = ProcessArgs(argc, argv, &sw); 32085b542cfSBrian Somers 32185b542cfSBrian Somers /* 322a611383fSBrian Somers * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 323a611383fSBrian Somers * output occasionally.... I must find the real reason some time. To 324a611383fSBrian Somers * display the dodgy behaviour, comment out this bit, make yourself a large 32585b542cfSBrian Somers * routing table and then run ppp in interactive mode. The `show route' 32685b542cfSBrian Somers * command will drop chunks of data !!! 32785b542cfSBrian Somers */ 328c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) { 32985b542cfSBrian Somers close(STDIN_FILENO); 33085b542cfSBrian Somers if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 33185b542cfSBrian Somers fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 33285b542cfSBrian Somers return 2; 33385b542cfSBrian Somers } 33485b542cfSBrian Somers } 33585b542cfSBrian Somers 336b6217683SBrian Somers /* Allow output for the moment (except in direct mode) */ 337c0593e34SBrian Somers if (sw.mode == PHYS_DIRECT) 338b6217683SBrian Somers prompt = NULL; 339ed0e9269SBrian Somers else 340b6217683SBrian Somers SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 34112ef29a8SBrian Somers 3425106c671SBrian Somers ID0init(); 3434562be74SBrian Somers if (ID0realuid() != 0) { 3444562be74SBrian Somers char conf[200], *ptr; 3454562be74SBrian Somers 3464562be74SBrian Somers snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 3474562be74SBrian Somers do { 3481080ea25SBrian Somers struct stat sb; 3491080ea25SBrian Somers 3501080ea25SBrian Somers if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 351a33b2ef7SBrian Somers log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 352a33b2ef7SBrian Somers conf); 3534562be74SBrian Somers return -1; 3544562be74SBrian Somers } 3554562be74SBrian Somers ptr = conf + strlen(conf)-2; 3564562be74SBrian Somers while (ptr > conf && *ptr != '/') 3574562be74SBrian Somers *ptr-- = '\0'; 3584562be74SBrian Somers } while (ptr >= conf); 3594562be74SBrian Somers } 3604562be74SBrian Somers 3617cf368ebSBrian Somers if (label < argc) 3627cf368ebSBrian Somers for (arg = label; arg < argc; arg++) 363c0593e34SBrian Somers CheckLabel(argv[arg], prompt, sw.mode); 3647cf368ebSBrian Somers else 365c0593e34SBrian Somers CheckLabel("default", prompt, sw.mode); 36612ef29a8SBrian Somers 367c0593e34SBrian Somers if (!sw.quiet) 368c0593e34SBrian Somers prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 369ed0e9269SBrian Somers 370c0593e34SBrian Somers if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit, 371c0593e34SBrian Somers (const char **)argv)) == NULL) 3724ef16f24SBrian Somers return EX_START; 373756783fcSBrian Somers 374756783fcSBrian Somers /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 375756783fcSBrian Somers 3760f2f3eb3SBrian Somers if (prompt) { 3770f2f3eb3SBrian Somers prompt->bundle = bundle; /* couldn't do it earlier */ 378c0593e34SBrian Somers if (!sw.quiet) 3798fa6ebe4SBrian Somers prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 3800f2f3eb3SBrian Somers } 38183d1af55SBrian Somers SignalBundle = bundle; 382c0593e34SBrian Somers bundle->NatEnabled = sw.nat; 383c0593e34SBrian Somers if (sw.nat) 3848fa6ebe4SBrian Somers bundle->cfg.opt |= OPT_IFACEALIAS; 38512ef29a8SBrian Somers 38630291ffbSBrian Somers if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 387565e35e5SBrian Somers prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 3881ae349f5Scvs2svn 389dd7e2610SBrian Somers sig_signal(SIGHUP, CloseSession); 390dd7e2610SBrian Somers sig_signal(SIGTERM, CloseSession); 391dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 392dd7e2610SBrian Somers sig_signal(SIGQUIT, CloseSession); 393dd7e2610SBrian Somers sig_signal(SIGALRM, SIG_IGN); 394e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 395565e35e5SBrian Somers 396c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) 397dd7e2610SBrian Somers sig_signal(SIGTSTP, TerminalStop); 398f91ad6b0SBrian Somers 399dd7e2610SBrian Somers sig_signal(SIGUSR2, BringDownServer); 400af57ed9fSAtsushi Murai 401756783fcSBrian Somers lastlabel = argc == 2 ? bundle->argv1 : argv[argc - 1]; 4027cf368ebSBrian Somers for (arg = label; arg < argc; arg++) { 4037cf368ebSBrian Somers /* In case we use LABEL or ``set enddisc label'' */ 404756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 405756783fcSBrian Somers system_Select(bundle, arg == 1 ? bundle->argv1 : argv[arg], 406756783fcSBrian Somers CONFFILE, prompt, NULL); 4071ae349f5Scvs2svn } 4087cf368ebSBrian Somers 4097cf368ebSBrian Somers if (label < argc) 4107cf368ebSBrian Somers /* In case the last label did a ``load'' */ 411756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 4127cf368ebSBrian Somers 413c0593e34SBrian Somers if (sw.mode == PHYS_AUTO && 4145828db6dSBrian Somers bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 4157cf368ebSBrian Somers prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 4167cf368ebSBrian Somers "in auto mode.\n"); 4178390b576SBrian Somers AbortProgram(EX_START); 418af57ed9fSAtsushi Murai } 4196efd9292SBrian Somers 420c0593e34SBrian Somers if (sw.mode != PHYS_INTERACTIVE) { 421c0593e34SBrian Somers if (sw.mode != PHYS_DIRECT) { 422c0593e34SBrian Somers if (!sw.fg) { 4235cf4388bSBrian Somers int bgpipe[2]; 4246d14e2a8SJordan K. Hubbard pid_t bgpid; 425a9c6b5dfSAtsushi Murai 426c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 427dd7e2610SBrian Somers log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 4288390b576SBrian Somers AbortProgram(EX_SOCK); 4291ae349f5Scvs2svn } 4301ae349f5Scvs2svn 4316d14e2a8SJordan K. Hubbard bgpid = fork(); 4326d14e2a8SJordan K. Hubbard if (bgpid == -1) { 433dd7e2610SBrian Somers log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 4348390b576SBrian Somers AbortProgram(EX_SOCK); 4356d14e2a8SJordan K. Hubbard } 4365cf4388bSBrian Somers 4376d14e2a8SJordan K. Hubbard if (bgpid) { 4386d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 439a9c6b5dfSAtsushi Murai 440c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND) { 4415cf4388bSBrian Somers close(bgpipe[1]); 4426d14e2a8SJordan K. Hubbard BGPid = bgpid; 44375b8d283SBrian Somers /* If we get a signal, kill the child */ 44475b8d283SBrian Somers signal(SIGHUP, KillChild); 44575b8d283SBrian Somers signal(SIGTERM, KillChild); 44675b8d283SBrian Somers signal(SIGINT, KillChild); 44775b8d283SBrian Somers signal(SIGQUIT, KillChild); 44875b8d283SBrian Somers 44975b8d283SBrian Somers /* Wait for our child to close its pipe before we exit */ 4505cf4388bSBrian Somers if (read(bgpipe[0], &c, 1) != 1) { 451b6217683SBrian Somers prompt_Printf(prompt, "Child exit, no status.\n"); 452dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 4536efd9292SBrian Somers } else if (c == EX_NORMAL) { 454b6217683SBrian Somers prompt_Printf(prompt, "PPP enabled.\n"); 455dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: PPP enabled.\n"); 4566efd9292SBrian Somers } else { 457b6217683SBrian Somers prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c)); 458dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Child failed (%s).\n", 45980e37c72SBrian Somers ex_desc((int) c)); 4606efd9292SBrian Somers } 4615cf4388bSBrian Somers close(bgpipe[0]); 4626d14e2a8SJordan K. Hubbard } 4634ef16f24SBrian Somers return c; 464c0593e34SBrian Somers } else if (sw.mode == PHYS_BACKGROUND) { 4655cf4388bSBrian Somers close(bgpipe[0]); 4665cf4388bSBrian Somers bundle->notify.fd = bgpipe[1]; 467aefd026aSBrian Somers } 468aefd026aSBrian Somers 469da66dd13SBrian Somers bundle_LockTun(bundle); /* we have a new pid */ 47067b072f7SBrian Somers } 471da66dd13SBrian Somers 47267b072f7SBrian Somers /* -auto, -dedicated, -ddial, -foreground & -background */ 473b6217683SBrian Somers prompt_Destroy(prompt, 0); 4742a279fedSBrian Somers close(STDOUT_FILENO); 4752a279fedSBrian Somers close(STDERR_FILENO); 4762a279fedSBrian Somers close(STDIN_FILENO); 477c0593e34SBrian Somers if (!sw.fg) 478b6217683SBrian Somers setsid(); 479565e35e5SBrian Somers } else { 48067b072f7SBrian Somers /* -direct - STDIN_FILENO gets used by physical_Open */ 481565e35e5SBrian Somers prompt_TtyInit(NULL); 482565e35e5SBrian Somers close(STDOUT_FILENO); 483565e35e5SBrian Somers close(STDERR_FILENO); 484d656a4c5SBrian Somers } 485af57ed9fSAtsushi Murai } else { 48667b072f7SBrian Somers /* -interactive */ 4872a279fedSBrian Somers close(STDERR_FILENO); 488565e35e5SBrian Somers prompt_TtyInit(prompt); 489b6217683SBrian Somers prompt_TtyCommandMode(prompt); 490b6217683SBrian Somers prompt_Required(prompt); 491af57ed9fSAtsushi Murai } 49235495becSBrian Somers 493c0593e34SBrian Somers log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 4940f78c7a7SBrian Somers DoLoop(bundle); 4951afedc4bSBrian Somers AbortProgram(EX_NORMAL); 496af57ed9fSAtsushi Murai 4971afedc4bSBrian Somers return EX_NORMAL; 498af57ed9fSAtsushi Murai } 499af57ed9fSAtsushi Murai 500af57ed9fSAtsushi Murai static void 5010f78c7a7SBrian Somers DoLoop(struct bundle *bundle) 502af57ed9fSAtsushi Murai { 503af57ed9fSAtsushi Murai fd_set rfds, wfds, efds; 5041af29a6eSBrian Somers int i, nfds, nothing_done; 5051af29a6eSBrian Somers struct probe probe; 5061af29a6eSBrian Somers 5071af29a6eSBrian Somers probe_Init(&probe); 508c3899f8dSAtsushi Murai 509565e35e5SBrian Somers do { 510780700e5SAndrey A. Chernov nfds = 0; 511944f7098SBrian Somers FD_ZERO(&rfds); 512944f7098SBrian Somers FD_ZERO(&wfds); 513944f7098SBrian Somers FD_ZERO(&efds); 51484b8a6ebSAtsushi Murai 5150f2f3eb3SBrian Somers /* All our datalinks, the tun device and the MP socket */ 5166f384573SBrian Somers descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 5170f2f3eb3SBrian Somers 5180f2f3eb3SBrian Somers /* All our prompts and the diagnostic socket */ 5190f2f3eb3SBrian Somers descriptor_UpdateSet(&server.desc, &rfds, NULL, NULL, &nfds); 52007030d97SBrian Somers 5213b0f8d2eSBrian Somers if (bundle_IsDead(bundle)) 522f4768038SBrian Somers /* Don't select - we'll be here forever */ 523f4768038SBrian Somers break; 5240706ff38SBrian Somers 525486105bcSBrian Somers /* 526486105bcSBrian Somers * It's possible that we've had a signal since we last checked. If 527486105bcSBrian Somers * we don't check again before calling select(), we may end up stuck 528486105bcSBrian Somers * after having missed the event.... sig_Handle() tries to be as 529486105bcSBrian Somers * quick as possible if nothing is likely to have happened. 530486105bcSBrian Somers * This is only really likely if we block in open(... O_NONBLOCK) 531486105bcSBrian Somers * which will happen with a misconfigured device. 532486105bcSBrian Somers */ 533486105bcSBrian Somers if (sig_Handle()) 534486105bcSBrian Somers continue; 535486105bcSBrian Somers 5363006ec67SBrian Somers i = select(nfds, &rfds, &wfds, &efds, NULL); 537712ae387SBrian Somers 53854cd8e13SBrian Somers if (i < 0 && errno != EINTR) { 539dd7e2610SBrian Somers log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 54024989c68SBrian Somers if (log_IsKept(LogTIMER)) { 54124989c68SBrian Somers struct timeval t; 54224989c68SBrian Somers 54324989c68SBrian Somers for (i = 0; i <= nfds; i++) { 54424989c68SBrian Somers if (FD_ISSET(i, &rfds)) { 54524989c68SBrian Somers log_Printf(LogTIMER, "Read set contains %d\n", i); 54624989c68SBrian Somers FD_CLR(i, &rfds); 54724989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 54824989c68SBrian Somers if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 54924989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 550af57ed9fSAtsushi Murai break; 551af57ed9fSAtsushi Murai } 55224989c68SBrian Somers } 55324989c68SBrian Somers if (FD_ISSET(i, &wfds)) { 55424989c68SBrian Somers log_Printf(LogTIMER, "Write set contains %d\n", i); 55524989c68SBrian Somers FD_CLR(i, &wfds); 55624989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 55724989c68SBrian Somers if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 55824989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 559af57ed9fSAtsushi Murai break; 560af57ed9fSAtsushi Murai } 561e0d3e233SAndrey A. Chernov } 56224989c68SBrian Somers if (FD_ISSET(i, &efds)) { 56324989c68SBrian Somers log_Printf(LogTIMER, "Error set contains %d\n", i); 56424989c68SBrian Somers FD_CLR(i, &efds); 56524989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 56624989c68SBrian Somers if (select(nfds, &rfds, &wfds, &efds, &t) != -1) { 56724989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 56858f264e1SBrian Somers break; 56958f264e1SBrian Somers } 57024989c68SBrian Somers } 57124989c68SBrian Somers } 57224989c68SBrian Somers } 57358f264e1SBrian Somers break; 574de451c68SBrian Somers } 575de451c68SBrian Somers 576f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Select returns %d\n", i); 577f0cdd9c0SBrian Somers 57854cd8e13SBrian Somers sig_Handle(); 57954cd8e13SBrian Somers 58054cd8e13SBrian Somers if (i <= 0) 58154cd8e13SBrian Somers continue; 58254cd8e13SBrian Somers 5833006ec67SBrian Somers for (i = 0; i <= nfds; i++) 5843006ec67SBrian Somers if (FD_ISSET(i, &efds)) { 585991c2a7bSBrian Somers log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 586991c2a7bSBrian Somers /* We deal gracefully with link descriptor exceptions */ 587991c2a7bSBrian Somers if (!bundle_Exception(bundle, i)) { 588991c2a7bSBrian Somers log_Printf(LogERROR, "Exception cannot be handled !\n"); 5891ae349f5Scvs2svn break; 5901ae349f5Scvs2svn } 591991c2a7bSBrian Somers } 592c60f92caSBrian Somers 593b7c5748eSBrian Somers if (i <= nfds) 594b7c5748eSBrian Somers break; 595b7c5748eSBrian Somers 5961af29a6eSBrian Somers nothing_done = 1; 5971af29a6eSBrian Somers 5981af29a6eSBrian Somers if (descriptor_IsSet(&server.desc, &rfds)) { 599b77776a7SBrian Somers descriptor_Read(&server.desc, bundle, &rfds); 6001af29a6eSBrian Somers nothing_done = 0; 6011af29a6eSBrian Somers } 6021af29a6eSBrian Somers 6031af29a6eSBrian Somers if (descriptor_IsSet(&bundle->desc, &rfds)) { 6041af29a6eSBrian Somers descriptor_Read(&bundle->desc, bundle, &rfds); 6051af29a6eSBrian Somers nothing_done = 0; 6061af29a6eSBrian Somers } 60742d4d396SBrian Somers 6082f786681SBrian Somers if (descriptor_IsSet(&bundle->desc, &wfds)) 6091af29a6eSBrian Somers if (!descriptor_Write(&bundle->desc, bundle, &wfds) && nothing_done) { 6101af29a6eSBrian Somers /* 6111af29a6eSBrian Somers * This is disasterous. The OS has told us that something is 6121af29a6eSBrian Somers * writable, and all our write()s have failed. Rather than 6131af29a6eSBrian Somers * going back immediately to do our UpdateSet()s and select(), 6141af29a6eSBrian Somers * we sleep for a bit to avoid gobbling up all cpu time. 6151af29a6eSBrian Somers */ 6161af29a6eSBrian Somers struct timeval t; 6172f786681SBrian Somers 6181af29a6eSBrian Somers t.tv_sec = 0; 6191af29a6eSBrian Somers t.tv_usec = 100000; 6201af29a6eSBrian Somers select(0, NULL, NULL, NULL, &t); 6211af29a6eSBrian Somers } 622565e35e5SBrian Somers } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle)); 623565e35e5SBrian Somers 624dd7e2610SBrian Somers log_Printf(LogDEBUG, "DoLoop done.\n"); 625af57ed9fSAtsushi Murai } 626