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> 306b457978SBrian Somers #include <sys/socket.h> 316b457978SBrian Somers #include <net/route.h> 3275240ed1SBrian Somers 3375240ed1SBrian Somers #include <errno.h> 3475240ed1SBrian Somers #include <fcntl.h> 3575240ed1SBrian Somers #include <paths.h> 3675240ed1SBrian Somers #include <signal.h> 3775240ed1SBrian Somers #include <stdio.h> 38c0593e34SBrian Somers #include <stdlib.h> 3975240ed1SBrian Somers #include <string.h> 4075240ed1SBrian Somers #include <sys/time.h> 4175240ed1SBrian Somers #include <termios.h> 4275240ed1SBrian Somers #include <unistd.h> 431080ea25SBrian Somers #include <sys/stat.h> 4475240ed1SBrian Somers 4567b072f7SBrian Somers #ifndef NONAT 4610e629b9SBrian Somers #ifdef LOCALNAT 477884358fSBrian Somers #include "alias.h" 4810e629b9SBrian Somers #else 4910e629b9SBrian Somers #include <alias.h> 501595bacdSBrian Somers #endif 511595bacdSBrian Somers #endif 5210e629b9SBrian Somers 535d9e6103SBrian Somers #include "layer.h" 541af29a6eSBrian Somers #include "probe.h" 5575240ed1SBrian Somers #include "mbuf.h" 5675240ed1SBrian Somers #include "log.h" 5775240ed1SBrian Somers #include "defs.h" 585106c671SBrian Somers #include "id.h" 5975240ed1SBrian Somers #include "timer.h" 6075240ed1SBrian Somers #include "fsm.h" 61879ed6faSBrian Somers #include "lqr.h" 62af57ed9fSAtsushi Murai #include "hdlc.h" 63af57ed9fSAtsushi Murai #include "lcp.h" 640053cc58SBrian Somers #include "ccp.h" 6529e275ceSBrian Somers #include "iplist.h" 6629e275ceSBrian Somers #include "throughput.h" 67eaa4df37SBrian Somers #include "slcompress.h" 68af57ed9fSAtsushi Murai #include "ipcp.h" 6984b8a6ebSAtsushi Murai #include "filter.h" 702f786681SBrian Somers #include "descriptor.h" 713b0f8d2eSBrian Somers #include "link.h" 723b0f8d2eSBrian Somers #include "mp.h" 73972a1bcfSBrian Somers #ifndef NORADIUS 74972a1bcfSBrian Somers #include "radius.h" 75972a1bcfSBrian Somers #endif 765828db6dSBrian Somers #include "bundle.h" 771ae349f5Scvs2svn #include "auth.h" 78ed6a16c1SPoul-Henning Kamp #include "systems.h" 79f5ff0f7cSBrian Somers #include "sig.h" 8075240ed1SBrian Somers #include "main.h" 8177ff88adSBrian Somers #include "server.h" 8285b542cfSBrian Somers #include "prompt.h" 83b6dec9f0SBrian Somers #include "chat.h" 84e2ebb036SBrian Somers #include "chap.h" 8592b09558SBrian Somers #include "cbcp.h" 863006ec67SBrian Somers #include "datalink.h" 878fa6ebe4SBrian Somers #include "iface.h" 8853c9f6c0SAtsushi Murai 8953c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 9053c9f6c0SAtsushi Murai #ifdef O_NDELAY 9153c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 9253c9f6c0SAtsushi Murai #endif 9353c9f6c0SAtsushi Murai #endif 94af57ed9fSAtsushi Murai 950f78c7a7SBrian Somers static void DoLoop(struct bundle *); 9675240ed1SBrian Somers static void TerminalStop(int); 9775240ed1SBrian Somers 9883d1af55SBrian Somers static struct bundle *SignalBundle; 99b6217683SBrian Somers static struct prompt *SignalPrompt; 100c3899f8dSAtsushi Murai 101c3899f8dSAtsushi Murai void 102944f7098SBrian Somers Cleanup(int excode) 103af57ed9fSAtsushi Murai { 104a0cbd833SBrian Somers SignalBundle->CleaningUp = 1; 1059c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 1066e4959f0SBrian Somers } 107af57ed9fSAtsushi Murai 1081afedc4bSBrian Somers void 1091afedc4bSBrian Somers AbortProgram(int excode) 1101afedc4bSBrian Somers { 111dd7e2610SBrian Somers server_Close(SignalBundle); 112dd7e2610SBrian Somers log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 1139c81b87dSBrian Somers bundle_Close(SignalBundle, NULL, CLOSE_STAYDOWN); 11468a0f0ccSBrian Somers bundle_Destroy(SignalBundle); 115dd7e2610SBrian Somers log_Close(); 116af57ed9fSAtsushi Murai exit(excode); 117af57ed9fSAtsushi Murai } 118af57ed9fSAtsushi Murai 119af57ed9fSAtsushi Murai static void 120944f7098SBrian Somers CloseConnection(int signo) 121af57ed9fSAtsushi Murai { 122368aee2bSBrian Somers /* NOTE, these are manual, we've done a setsid() */ 123dd7e2610SBrian Somers sig_signal(SIGINT, SIG_IGN); 124dd7e2610SBrian Somers log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 125899011c4SBrian Somers bundle_Down(SignalBundle, CLOSE_STAYDOWN); 126dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 1276d14e2a8SJordan K. Hubbard } 128af57ed9fSAtsushi Murai 129af57ed9fSAtsushi Murai static void 130944f7098SBrian Somers CloseSession(int signo) 131af57ed9fSAtsushi Murai { 132dd7e2610SBrian Somers log_Printf(LogPHASE, "Signal %d, terminate.\n", signo); 133af57ed9fSAtsushi Murai Cleanup(EX_TERM); 134af57ed9fSAtsushi Murai } 135c3899f8dSAtsushi Murai 13675b8d283SBrian Somers static pid_t BGPid = 0; 13775b8d283SBrian Somers 13875b8d283SBrian Somers static void 13975b8d283SBrian Somers KillChild(int signo) 14075b8d283SBrian Somers { 141ac37ab22SBrian Somers signal(signo, SIG_IGN); 142dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Signal %d\n", signo); 14375b8d283SBrian Somers kill(BGPid, SIGINT); 14475b8d283SBrian Somers } 14575b8d283SBrian Somers 146c3899f8dSAtsushi Murai static void 147b6e82f33SBrian Somers TerminalCont(int signo) 148c3899f8dSAtsushi Murai { 149f91ad6b0SBrian Somers signal(SIGCONT, SIG_DFL); 150f91ad6b0SBrian Somers prompt_Continue(SignalPrompt); 151c3899f8dSAtsushi Murai } 152c3899f8dSAtsushi Murai 153c3899f8dSAtsushi Murai static void 154944f7098SBrian Somers TerminalStop(int signo) 155c3899f8dSAtsushi Murai { 156f91ad6b0SBrian Somers prompt_Suspend(SignalPrompt); 157f91ad6b0SBrian Somers signal(SIGCONT, TerminalCont); 158f91ad6b0SBrian Somers raise(SIGSTOP); 1594ef16f24SBrian Somers } 1604ef16f24SBrian Somers 1618ea8442cSBrian Somers static void 1628ea8442cSBrian Somers BringDownServer(int signo) 1638ea8442cSBrian Somers { 164b6217683SBrian Somers /* Drops all child prompts too ! */ 165dd7e2610SBrian Somers server_Close(SignalBundle); 1668ea8442cSBrian Somers } 1678ea8442cSBrian Somers 16875240ed1SBrian Somers static void 169b6e82f33SBrian Somers Usage(void) 170af57ed9fSAtsushi Murai { 171680026d6SNate Williams fprintf(stderr, 17267b072f7SBrian Somers "Usage: ppp [-auto | -foreground | -background | -direct | -dedicated | -ddial | -interactive]" 173b6e82f33SBrian Somers #ifndef NOALIAS 17467b072f7SBrian Somers " [-nat]" 175b6e82f33SBrian Somers #endif 176c0593e34SBrian Somers " [-quiet] [-unit N] [system ...]\n"); 177af57ed9fSAtsushi Murai exit(EX_START); 178af57ed9fSAtsushi Murai } 179af57ed9fSAtsushi Murai 180c0593e34SBrian Somers struct switches { 181c0593e34SBrian Somers unsigned nat : 1; 182c0593e34SBrian Somers unsigned fg : 1; 183c0593e34SBrian Somers unsigned quiet : 1; 184c0593e34SBrian Somers int mode; 185c0593e34SBrian Somers int unit; 186c0593e34SBrian Somers }; 187c0593e34SBrian Somers 1887cf368ebSBrian Somers static int 189c0593e34SBrian Somers ProcessArgs(int argc, char **argv, struct switches *sw) 190af57ed9fSAtsushi Murai { 1917cf368ebSBrian Somers int optc, newmode, arg; 192af57ed9fSAtsushi Murai char *cp; 193af57ed9fSAtsushi Murai 1947cf368ebSBrian Somers optc = 0; 195c0593e34SBrian Somers memset(sw, '\0', sizeof *sw); 196c0593e34SBrian Somers sw->mode = PHYS_INTERACTIVE; 197c0593e34SBrian Somers sw->unit = -1; 198c0593e34SBrian Somers 1997cf368ebSBrian Somers for (arg = 1; arg < argc && *argv[arg] == '-'; arg++, optc++) { 2007cf368ebSBrian Somers cp = argv[arg] + 1; 20181358fa3SBrian Somers newmode = Nam2mode(cp); 20281358fa3SBrian Somers switch (newmode) { 20381358fa3SBrian Somers case PHYS_NONE: 204c0593e34SBrian Somers if (strcmp(cp, "nat") == 0) { 20567b072f7SBrian Somers #ifdef NONAT 206c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 207615ad4f9SBrian Somers #else 208c0593e34SBrian Somers sw->nat = 1; 209615ad4f9SBrian Somers #endif 2101ae349f5Scvs2svn optc--; /* this option isn't exclusive */ 211c0593e34SBrian Somers } else if (strcmp(cp, "alias") == 0) { 212c0593e34SBrian Somers #ifdef NONAT 213c0593e34SBrian Somers log_Printf(LogWARN, "%s ignored: NAT is compiled out\n", argv[arg]); 214c0593e34SBrian Somers fprintf(stderr, "%s ignored: NAT is compiled out\n", argv[arg]); 215c0593e34SBrian Somers #else 216886530abSBrian Somers log_Printf(LogWARN, "%s is deprecated\n", argv[arg]); 217886530abSBrian Somers fprintf(stderr, "%s is deprecated\n", argv[arg]); 218c0593e34SBrian Somers sw->nat = 1; 219c0593e34SBrian Somers #endif 220c0593e34SBrian Somers optc--; /* this option isn't exclusive */ 221c0593e34SBrian Somers } else if (strncmp(cp, "unit", 4) == 0) { 2229d06928dSBrian Somers optc--; /* this option isn't exclusive */ 223c0593e34SBrian Somers if (cp[4] == '\0') { 2249d06928dSBrian Somers optc--; /* nor is the argument */ 225c0593e34SBrian Somers if (++arg == argc) { 226c0593e34SBrian Somers fprintf(stderr, "-unit: Expected unit number\n"); 227c0593e34SBrian Somers Usage(); 228c0593e34SBrian Somers } else 229c0593e34SBrian Somers sw->unit = atoi(argv[arg]); 230c0593e34SBrian Somers } else 231c0593e34SBrian Somers sw->unit = atoi(cp + 4); 23267b072f7SBrian Somers } else if (strcmp(cp, "quiet") == 0) { 233c0593e34SBrian Somers sw->quiet = 1; 23467b072f7SBrian Somers optc--; /* this option isn't exclusive */ 235944f7098SBrian Somers } else 236af57ed9fSAtsushi Murai Usage(); 23781358fa3SBrian Somers break; 23881358fa3SBrian Somers 23981358fa3SBrian Somers case PHYS_ALL: 24081358fa3SBrian Somers Usage(); 24181358fa3SBrian Somers break; 24281358fa3SBrian Somers 24381358fa3SBrian Somers default: 244c0593e34SBrian Somers sw->mode = newmode; 245f6a4e748SBrian Somers if (newmode == PHYS_FOREGROUND) 246f6a4e748SBrian Somers sw->fg = 1; 24781358fa3SBrian Somers } 248af57ed9fSAtsushi Murai } 249af57ed9fSAtsushi Murai 250af57ed9fSAtsushi Murai if (optc > 1) { 25185602e52SBrian Somers fprintf(stderr, "You may specify only one mode.\n"); 2521ae349f5Scvs2svn exit(EX_START); 2531ae349f5Scvs2svn } 2541ae349f5Scvs2svn 255c0593e34SBrian Somers if (sw->mode == PHYS_AUTO && arg == argc) { 2567cf368ebSBrian Somers fprintf(stderr, "A system must be specified in auto mode.\n"); 257af57ed9fSAtsushi Murai exit(EX_START); 258af57ed9fSAtsushi Murai } 25939f94eddSBrian Somers 2607cf368ebSBrian Somers return arg; /* Don't SetLabel yet ! */ 261af57ed9fSAtsushi Murai } 262af57ed9fSAtsushi Murai 2637cf368ebSBrian Somers static void 2647cf368ebSBrian Somers CheckLabel(const char *label, struct prompt *prompt, int mode) 2657cf368ebSBrian Somers { 2667cf368ebSBrian Somers const char *err; 2677cf368ebSBrian Somers 2687cf368ebSBrian Somers if ((err = system_IsValid(label, prompt, mode)) != NULL) { 2697cf368ebSBrian Somers fprintf(stderr, "%s: %s\n", label, err); 2707cf368ebSBrian Somers if (mode == PHYS_DIRECT) 2717cf368ebSBrian Somers log_Printf(LogWARN, "Label %s rejected -direct connection: %s\n", 2727cf368ebSBrian Somers label, err); 2737cf368ebSBrian Somers log_Close(); 2747cf368ebSBrian Somers exit(1); 2757cf368ebSBrian Somers } 2767cf368ebSBrian Somers } 2777cf368ebSBrian Somers 2787cf368ebSBrian Somers 2794ef16f24SBrian Somers int 280944f7098SBrian Somers main(int argc, char **argv) 281af57ed9fSAtsushi Murai { 2827cf368ebSBrian Somers char *name; 283756783fcSBrian Somers const char *lastlabel; 2848a52f3ecSBrian Somers int label, arg; 2857a6f8720SBrian Somers struct bundle *bundle; 286b6217683SBrian Somers struct prompt *prompt; 287c0593e34SBrian Somers struct switches sw; 288e3b4c400SBrian Somers 28975240ed1SBrian Somers name = strrchr(argv[0], '/'); 290dd7e2610SBrian Somers log_Open(name ? name + 1 : argv[0]); 2912a279fedSBrian Somers 29267b072f7SBrian Somers #ifndef NONAT 2932a630835SBrian Somers PacketAliasInit(); 2942a630835SBrian Somers #endif 295c0593e34SBrian Somers label = ProcessArgs(argc, argv, &sw); 29685b542cfSBrian Somers 29785b542cfSBrian Somers /* 298a611383fSBrian Somers * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops 299a611383fSBrian Somers * output occasionally.... I must find the real reason some time. To 300a611383fSBrian Somers * display the dodgy behaviour, comment out this bit, make yourself a large 30185b542cfSBrian Somers * routing table and then run ppp in interactive mode. The `show route' 30285b542cfSBrian Somers * command will drop chunks of data !!! 30385b542cfSBrian Somers */ 304c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) { 30585b542cfSBrian Somers close(STDIN_FILENO); 30685b542cfSBrian Somers if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 30785b542cfSBrian Somers fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 30885b542cfSBrian Somers return 2; 30985b542cfSBrian Somers } 31085b542cfSBrian Somers } 31185b542cfSBrian Somers 312b6217683SBrian Somers /* Allow output for the moment (except in direct mode) */ 313c0593e34SBrian Somers if (sw.mode == PHYS_DIRECT) 314b6217683SBrian Somers prompt = NULL; 315ed0e9269SBrian Somers else 316b6217683SBrian Somers SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); 31712ef29a8SBrian Somers 3185106c671SBrian Somers ID0init(); 3194562be74SBrian Somers if (ID0realuid() != 0) { 3204562be74SBrian Somers char conf[200], *ptr; 3214562be74SBrian Somers 3224562be74SBrian Somers snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 3234562be74SBrian Somers do { 3241080ea25SBrian Somers struct stat sb; 3251080ea25SBrian Somers 3261080ea25SBrian Somers if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { 327a33b2ef7SBrian Somers log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", 328a33b2ef7SBrian Somers conf); 3294562be74SBrian Somers return -1; 3304562be74SBrian Somers } 3314562be74SBrian Somers ptr = conf + strlen(conf)-2; 3324562be74SBrian Somers while (ptr > conf && *ptr != '/') 3334562be74SBrian Somers *ptr-- = '\0'; 3344562be74SBrian Somers } while (ptr >= conf); 3354562be74SBrian Somers } 3364562be74SBrian Somers 3377cf368ebSBrian Somers if (label < argc) 3387cf368ebSBrian Somers for (arg = label; arg < argc; arg++) 339c0593e34SBrian Somers CheckLabel(argv[arg], prompt, sw.mode); 3407cf368ebSBrian Somers else 341c0593e34SBrian Somers CheckLabel("default", prompt, sw.mode); 34212ef29a8SBrian Somers 343c0593e34SBrian Somers if (!sw.quiet) 344c0593e34SBrian Somers prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); 345ed0e9269SBrian Somers 346cf0a3940SBrian Somers if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) 3474ef16f24SBrian Somers return EX_START; 348756783fcSBrian Somers 349756783fcSBrian Somers /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ 350756783fcSBrian Somers 3510f2f3eb3SBrian Somers if (prompt) { 3520f2f3eb3SBrian Somers prompt->bundle = bundle; /* couldn't do it earlier */ 353c0593e34SBrian Somers if (!sw.quiet) 3548fa6ebe4SBrian Somers prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); 3550f2f3eb3SBrian Somers } 35683d1af55SBrian Somers SignalBundle = bundle; 357c0593e34SBrian Somers bundle->NatEnabled = sw.nat; 358c0593e34SBrian Somers if (sw.nat) 3598fa6ebe4SBrian Somers bundle->cfg.opt |= OPT_IFACEALIAS; 36012ef29a8SBrian Somers 36130291ffbSBrian Somers if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) 362565e35e5SBrian Somers prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); 3631ae349f5Scvs2svn 364dd7e2610SBrian Somers sig_signal(SIGHUP, CloseSession); 365dd7e2610SBrian Somers sig_signal(SIGTERM, CloseSession); 366dd7e2610SBrian Somers sig_signal(SIGINT, CloseConnection); 367dd7e2610SBrian Somers sig_signal(SIGQUIT, CloseSession); 368dd7e2610SBrian Somers sig_signal(SIGALRM, SIG_IGN); 369e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 370565e35e5SBrian Somers 371c0593e34SBrian Somers if (sw.mode == PHYS_INTERACTIVE) 372dd7e2610SBrian Somers sig_signal(SIGTSTP, TerminalStop); 373f91ad6b0SBrian Somers 374dd7e2610SBrian Somers sig_signal(SIGUSR2, BringDownServer); 375af57ed9fSAtsushi Murai 376cf0a3940SBrian Somers lastlabel = argv[argc - 1]; 3777cf368ebSBrian Somers for (arg = label; arg < argc; arg++) { 3787cf368ebSBrian Somers /* In case we use LABEL or ``set enddisc label'' */ 379756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 380cf0a3940SBrian Somers system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); 3811ae349f5Scvs2svn } 3827cf368ebSBrian Somers 3837cf368ebSBrian Somers if (label < argc) 3847cf368ebSBrian Somers /* In case the last label did a ``load'' */ 385756783fcSBrian Somers bundle_SetLabel(bundle, lastlabel); 3867cf368ebSBrian Somers 387c0593e34SBrian Somers if (sw.mode == PHYS_AUTO && 3885828db6dSBrian Somers bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 3897cf368ebSBrian Somers prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " 3907cf368ebSBrian Somers "in auto mode.\n"); 3918390b576SBrian Somers AbortProgram(EX_START); 392af57ed9fSAtsushi Murai } 3936efd9292SBrian Somers 394c0593e34SBrian Somers if (sw.mode != PHYS_INTERACTIVE) { 395c0593e34SBrian Somers if (sw.mode != PHYS_DIRECT) { 396c0593e34SBrian Somers if (!sw.fg) { 3975cf4388bSBrian Somers int bgpipe[2]; 3986d14e2a8SJordan K. Hubbard pid_t bgpid; 399a9c6b5dfSAtsushi Murai 400c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { 401dd7e2610SBrian Somers log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 4028390b576SBrian Somers AbortProgram(EX_SOCK); 4031ae349f5Scvs2svn } 4041ae349f5Scvs2svn 4056d14e2a8SJordan K. Hubbard bgpid = fork(); 4066d14e2a8SJordan K. Hubbard if (bgpid == -1) { 407dd7e2610SBrian Somers log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 4088390b576SBrian Somers AbortProgram(EX_SOCK); 4096d14e2a8SJordan K. Hubbard } 4105cf4388bSBrian Somers 4116d14e2a8SJordan K. Hubbard if (bgpid) { 4126d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 413b42135deSBrian Somers int ret; 414a9c6b5dfSAtsushi Murai 415c0593e34SBrian Somers if (sw.mode == PHYS_BACKGROUND) { 4165cf4388bSBrian Somers close(bgpipe[1]); 4176d14e2a8SJordan K. Hubbard BGPid = bgpid; 41875b8d283SBrian Somers /* If we get a signal, kill the child */ 41975b8d283SBrian Somers signal(SIGHUP, KillChild); 42075b8d283SBrian Somers signal(SIGTERM, KillChild); 42175b8d283SBrian Somers signal(SIGINT, KillChild); 42275b8d283SBrian Somers signal(SIGQUIT, KillChild); 42375b8d283SBrian Somers 42475b8d283SBrian Somers /* Wait for our child to close its pipe before we exit */ 425b42135deSBrian Somers while ((ret = read(bgpipe[0], &c, 1)) == 1) { 426b42135deSBrian Somers switch (c) { 427b42135deSBrian Somers case EX_NORMAL: 428b42135deSBrian Somers prompt_Printf(prompt, "PPP enabled\n"); 429b42135deSBrian Somers log_Printf(LogPHASE, "Parent: PPP enabled\n"); 4309bf01bcbSBrian Somers break; 431b42135deSBrian Somers case EX_REDIAL: 432b42135deSBrian Somers if (!sw.quiet) 433b42135deSBrian Somers prompt_Printf(prompt, "Attempting redial\n"); 434b42135deSBrian Somers continue; 435b42135deSBrian Somers case EX_RECONNECT: 436b42135deSBrian Somers if (!sw.quiet) 437b42135deSBrian Somers prompt_Printf(prompt, "Attempting reconnect\n"); 438b42135deSBrian Somers continue; 439b42135deSBrian Somers default: 440b42135deSBrian Somers prompt_Printf(prompt, "Child failed (%s)\n", 441b42135deSBrian Somers ex_desc((int)c)); 442b42135deSBrian Somers log_Printf(LogPHASE, "Parent: Child failed (%s)\n", 443b42135deSBrian Somers ex_desc((int) c)); 444b42135deSBrian Somers } 445b42135deSBrian Somers break; 446b42135deSBrian Somers } 447b42135deSBrian Somers if (ret != 1) { 448b6217683SBrian Somers prompt_Printf(prompt, "Child exit, no status.\n"); 449dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); 4506efd9292SBrian Somers } 4515cf4388bSBrian Somers close(bgpipe[0]); 4526d14e2a8SJordan K. Hubbard } 4534ef16f24SBrian Somers return c; 454c0593e34SBrian Somers } else if (sw.mode == PHYS_BACKGROUND) { 4555cf4388bSBrian Somers close(bgpipe[0]); 4565cf4388bSBrian Somers bundle->notify.fd = bgpipe[1]; 457aefd026aSBrian Somers } 458aefd026aSBrian Somers 45906b47306SBrian Somers bundle_ChangedPID(bundle); 460da66dd13SBrian Somers bundle_LockTun(bundle); /* we have a new pid */ 46167b072f7SBrian Somers } 462da66dd13SBrian Somers 46367b072f7SBrian Somers /* -auto, -dedicated, -ddial, -foreground & -background */ 464b6217683SBrian Somers prompt_Destroy(prompt, 0); 4652a279fedSBrian Somers close(STDOUT_FILENO); 4662a279fedSBrian Somers close(STDERR_FILENO); 4672a279fedSBrian Somers close(STDIN_FILENO); 468c0593e34SBrian Somers if (!sw.fg) 469b6217683SBrian Somers setsid(); 470565e35e5SBrian Somers } else { 47167b072f7SBrian Somers /* -direct - STDIN_FILENO gets used by physical_Open */ 472565e35e5SBrian Somers prompt_TtyInit(NULL); 473565e35e5SBrian Somers close(STDOUT_FILENO); 474565e35e5SBrian Somers close(STDERR_FILENO); 475d656a4c5SBrian Somers } 476af57ed9fSAtsushi Murai } else { 47767b072f7SBrian Somers /* -interactive */ 4782a279fedSBrian Somers close(STDERR_FILENO); 479565e35e5SBrian Somers prompt_TtyInit(prompt); 480b6217683SBrian Somers prompt_TtyCommandMode(prompt); 481b6217683SBrian Somers prompt_Required(prompt); 482af57ed9fSAtsushi Murai } 48335495becSBrian Somers 484c0593e34SBrian Somers log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); 4850f78c7a7SBrian Somers DoLoop(bundle); 4861afedc4bSBrian Somers AbortProgram(EX_NORMAL); 487af57ed9fSAtsushi Murai 4881afedc4bSBrian Somers return EX_NORMAL; 489af57ed9fSAtsushi Murai } 490af57ed9fSAtsushi Murai 491af57ed9fSAtsushi Murai static void 4920f78c7a7SBrian Somers DoLoop(struct bundle *bundle) 493af57ed9fSAtsushi Murai { 4948a52f3ecSBrian Somers fd_set *rfds, *wfds, *efds; 4951af29a6eSBrian Somers int i, nfds, nothing_done; 4961af29a6eSBrian Somers struct probe probe; 4971af29a6eSBrian Somers 4981af29a6eSBrian Somers probe_Init(&probe); 499c3899f8dSAtsushi Murai 5008a52f3ecSBrian Somers if ((rfds = mkfdset()) == NULL) { 5018a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5028a52f3ecSBrian Somers return; 5038a52f3ecSBrian Somers } 5048a52f3ecSBrian Somers 5058a52f3ecSBrian Somers if ((wfds = mkfdset()) == NULL) { 5068a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5078a52f3ecSBrian Somers free(rfds); 5088a52f3ecSBrian Somers return; 5098a52f3ecSBrian Somers } 5108a52f3ecSBrian Somers 5118a52f3ecSBrian Somers if ((efds = mkfdset()) == NULL) { 5128a52f3ecSBrian Somers log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); 5138a52f3ecSBrian Somers free(rfds); 5148a52f3ecSBrian Somers free(wfds); 5158a52f3ecSBrian Somers return; 5168a52f3ecSBrian Somers } 5178a52f3ecSBrian Somers 518da8b7034SBrian Somers for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { 519780700e5SAndrey A. Chernov nfds = 0; 5208a52f3ecSBrian Somers zerofdset(rfds); 5218a52f3ecSBrian Somers zerofdset(wfds); 5228a52f3ecSBrian Somers zerofdset(efds); 52384b8a6ebSAtsushi Murai 5240f2f3eb3SBrian Somers /* All our datalinks, the tun device and the MP socket */ 5258a52f3ecSBrian Somers descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); 5260f2f3eb3SBrian Somers 5270f2f3eb3SBrian Somers /* All our prompts and the diagnostic socket */ 5288a52f3ecSBrian Somers descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); 52907030d97SBrian Somers 5300cd8e902SBrian Somers bundle_CleanDatalinks(bundle); 5313b0f8d2eSBrian Somers if (bundle_IsDead(bundle)) 532f4768038SBrian Somers /* Don't select - we'll be here forever */ 533f4768038SBrian Somers break; 5340706ff38SBrian Somers 535486105bcSBrian Somers /* 536486105bcSBrian Somers * It's possible that we've had a signal since we last checked. If 537486105bcSBrian Somers * we don't check again before calling select(), we may end up stuck 538486105bcSBrian Somers * after having missed the event.... sig_Handle() tries to be as 539486105bcSBrian Somers * quick as possible if nothing is likely to have happened. 540486105bcSBrian Somers * This is only really likely if we block in open(... O_NONBLOCK) 541486105bcSBrian Somers * which will happen with a misconfigured device. 542486105bcSBrian Somers */ 543486105bcSBrian Somers if (sig_Handle()) 544486105bcSBrian Somers continue; 545486105bcSBrian Somers 5468a52f3ecSBrian Somers i = select(nfds, rfds, wfds, efds, NULL); 547712ae387SBrian Somers 54854cd8e13SBrian Somers if (i < 0 && errno != EINTR) { 549dd7e2610SBrian Somers log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 55024989c68SBrian Somers if (log_IsKept(LogTIMER)) { 55124989c68SBrian Somers struct timeval t; 55224989c68SBrian Somers 55324989c68SBrian Somers for (i = 0; i <= nfds; i++) { 5548a52f3ecSBrian Somers if (FD_ISSET(i, rfds)) { 55524989c68SBrian Somers log_Printf(LogTIMER, "Read set contains %d\n", i); 5568a52f3ecSBrian Somers FD_CLR(i, rfds); 55724989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 5588a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 55924989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 560af57ed9fSAtsushi Murai break; 561af57ed9fSAtsushi Murai } 56224989c68SBrian Somers } 5638a52f3ecSBrian Somers if (FD_ISSET(i, wfds)) { 56424989c68SBrian Somers log_Printf(LogTIMER, "Write set contains %d\n", i); 5658a52f3ecSBrian Somers FD_CLR(i, wfds); 56624989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 5678a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 56824989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 569af57ed9fSAtsushi Murai break; 570af57ed9fSAtsushi Murai } 571e0d3e233SAndrey A. Chernov } 5728a52f3ecSBrian Somers if (FD_ISSET(i, efds)) { 57324989c68SBrian Somers log_Printf(LogTIMER, "Error set contains %d\n", i); 5748a52f3ecSBrian Somers FD_CLR(i, efds); 57524989c68SBrian Somers t.tv_sec = t.tv_usec = 0; 5768a52f3ecSBrian Somers if (select(nfds, rfds, wfds, efds, &t) != -1) { 57724989c68SBrian Somers log_Printf(LogTIMER, "The culprit !\n"); 57858f264e1SBrian Somers break; 57958f264e1SBrian Somers } 58024989c68SBrian Somers } 58124989c68SBrian Somers } 58224989c68SBrian Somers } 58358f264e1SBrian Somers break; 584de451c68SBrian Somers } 585de451c68SBrian Somers 586f0cdd9c0SBrian Somers log_Printf(LogTIMER, "Select returns %d\n", i); 587f0cdd9c0SBrian Somers 58854cd8e13SBrian Somers sig_Handle(); 58954cd8e13SBrian Somers 59054cd8e13SBrian Somers if (i <= 0) 59154cd8e13SBrian Somers continue; 59254cd8e13SBrian Somers 5933006ec67SBrian Somers for (i = 0; i <= nfds; i++) 5948a52f3ecSBrian Somers if (FD_ISSET(i, efds)) { 5958e7bd08eSBrian Somers log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); 5968e7bd08eSBrian Somers /* We deal gracefully with link descriptor exceptions */ 597991c2a7bSBrian Somers if (!bundle_Exception(bundle, i)) { 598991c2a7bSBrian Somers log_Printf(LogERROR, "Exception cannot be handled !\n"); 5991ae349f5Scvs2svn break; 6001ae349f5Scvs2svn } 601991c2a7bSBrian Somers } 602c60f92caSBrian Somers 603b7c5748eSBrian Somers if (i <= nfds) 604b7c5748eSBrian Somers break; 605b7c5748eSBrian Somers 6061af29a6eSBrian Somers nothing_done = 1; 6071af29a6eSBrian Somers 6088a52f3ecSBrian Somers if (descriptor_IsSet(&server.desc, rfds)) { 6098a52f3ecSBrian Somers descriptor_Read(&server.desc, bundle, rfds); 6101af29a6eSBrian Somers nothing_done = 0; 6111af29a6eSBrian Somers } 6121af29a6eSBrian Somers 6138a52f3ecSBrian Somers if (descriptor_IsSet(&bundle->desc, rfds)) { 6148a52f3ecSBrian Somers descriptor_Read(&bundle->desc, bundle, rfds); 6151af29a6eSBrian Somers nothing_done = 0; 6161af29a6eSBrian Somers } 61742d4d396SBrian Somers 6188a52f3ecSBrian Somers if (descriptor_IsSet(&bundle->desc, wfds)) 6198a52f3ecSBrian Somers if (!descriptor_Write(&bundle->desc, bundle, wfds) && nothing_done) { 6201af29a6eSBrian Somers /* 6211af29a6eSBrian Somers * This is disasterous. The OS has told us that something is 6221af29a6eSBrian Somers * writable, and all our write()s have failed. Rather than 6231af29a6eSBrian Somers * going back immediately to do our UpdateSet()s and select(), 6241af29a6eSBrian Somers * we sleep for a bit to avoid gobbling up all cpu time. 6251af29a6eSBrian Somers */ 6261af29a6eSBrian Somers struct timeval t; 6272f786681SBrian Somers 6281af29a6eSBrian Somers t.tv_sec = 0; 6291af29a6eSBrian Somers t.tv_usec = 100000; 6301af29a6eSBrian Somers select(0, NULL, NULL, NULL, &t); 6311af29a6eSBrian Somers } 632da8b7034SBrian Somers } 633565e35e5SBrian Somers 634dd7e2610SBrian Somers log_Printf(LogDEBUG, "DoLoop done.\n"); 635af57ed9fSAtsushi Murai } 636