xref: /freebsd/usr.sbin/ppp/main.c (revision b7c5748e5ec02028a9b3c7c3937de36eac7c27d9)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *			User Process PPP
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
20b7c5748eSBrian Somers  * $Id: main.c,v 1.121.2.56 1998/05/06 18:50:09 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  */
242764b86aSBrian Somers 
251ae349f5Scvs2svn #include <sys/param.h>
26e43ebac1SBrian Somers #include <sys/socket.h>
271ae349f5Scvs2svn #include <netinet/in.h>
281ae349f5Scvs2svn #include <netinet/in_systm.h>
291ae349f5Scvs2svn #include <netinet/ip.h>
30565e35e5SBrian Somers #include <sys/un.h>
31e43ebac1SBrian Somers #include <net/if_tun.h>
321ae349f5Scvs2svn 
331ae349f5Scvs2svn #include <errno.h>
341ae349f5Scvs2svn #include <fcntl.h>
351ae349f5Scvs2svn #include <paths.h>
361ae349f5Scvs2svn #include <signal.h>
371ae349f5Scvs2svn #include <stdio.h>
381ae349f5Scvs2svn #include <string.h>
391ae349f5Scvs2svn #include <termios.h>
401ae349f5Scvs2svn #include <unistd.h>
411ae349f5Scvs2svn 
421ae349f5Scvs2svn #include "mbuf.h"
431ae349f5Scvs2svn #include "log.h"
441ae349f5Scvs2svn #include "defs.h"
451ae349f5Scvs2svn #include "id.h"
461ae349f5Scvs2svn #include "timer.h"
471ae349f5Scvs2svn #include "fsm.h"
48879ed6faSBrian Somers #include "lqr.h"
491ae349f5Scvs2svn #include "hdlc.h"
501ae349f5Scvs2svn #include "lcp.h"
511ae349f5Scvs2svn #include "ccp.h"
5229e275ceSBrian Somers #include "iplist.h"
5329e275ceSBrian Somers #include "throughput.h"
54eaa4df37SBrian Somers #include "slcompress.h"
551ae349f5Scvs2svn #include "ipcp.h"
565ca5389aSBrian Somers #include "filter.h"
572f786681SBrian Somers #include "descriptor.h"
583b0f8d2eSBrian Somers #include "link.h"
593b0f8d2eSBrian Somers #include "mp.h"
605828db6dSBrian Somers #include "bundle.h"
611ae349f5Scvs2svn #include "loadalias.h"
621ae349f5Scvs2svn #include "auth.h"
631ae349f5Scvs2svn #include "systems.h"
641ae349f5Scvs2svn #include "ip.h"
651ae349f5Scvs2svn #include "sig.h"
661ae349f5Scvs2svn #include "main.h"
671ae349f5Scvs2svn #include "tun.h"
6877ff88adSBrian Somers #include "server.h"
6985b542cfSBrian Somers #include "prompt.h"
70b6dec9f0SBrian Somers #include "chat.h"
71e2ebb036SBrian Somers #include "chap.h"
723006ec67SBrian Somers #include "datalink.h"
731ae349f5Scvs2svn 
741ae349f5Scvs2svn #ifndef O_NONBLOCK
751ae349f5Scvs2svn #ifdef O_NDELAY
761ae349f5Scvs2svn #define	O_NONBLOCK O_NDELAY
771ae349f5Scvs2svn #endif
781ae349f5Scvs2svn #endif
791ae349f5Scvs2svn 
801ae349f5Scvs2svn static char pid_filename[MAXPATHLEN];
811ae349f5Scvs2svn 
82b6217683SBrian Somers static void DoLoop(struct bundle *, struct prompt *);
831ae349f5Scvs2svn static void TerminalStop(int);
841ae349f5Scvs2svn static const char *ex_desc(int);
851ae349f5Scvs2svn 
8683d1af55SBrian Somers static struct bundle *SignalBundle;
87b6217683SBrian Somers static struct prompt *SignalPrompt;
887a6f8720SBrian Somers 
891ae349f5Scvs2svn void
901ae349f5Scvs2svn Cleanup(int excode)
911ae349f5Scvs2svn {
92a0cbd833SBrian Somers   SignalBundle->CleaningUp = 1;
933006ec67SBrian Somers   if (bundle_Phase(SignalBundle) != PHASE_DEAD)
943b0f8d2eSBrian Somers     bundle_Close(SignalBundle, NULL, 1);
951afedc4bSBrian Somers }
96455aabc3SBrian Somers 
971afedc4bSBrian Somers void
981afedc4bSBrian Somers AbortProgram(int excode)
991afedc4bSBrian Somers {
100dd7e2610SBrian Somers   server_Close(SignalBundle);
1011ae349f5Scvs2svn   ID0unlink(pid_filename);
102dd7e2610SBrian Somers   log_Printf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
103d345321bSBrian Somers   bundle_Close(SignalBundle, NULL, 1);
10468a0f0ccSBrian Somers   bundle_Destroy(SignalBundle);
105dd7e2610SBrian Somers   log_Close();
1061ae349f5Scvs2svn   exit(excode);
1071ae349f5Scvs2svn }
1081ae349f5Scvs2svn 
1091ae349f5Scvs2svn static void
1101ae349f5Scvs2svn CloseConnection(int signo)
1111ae349f5Scvs2svn {
1121ae349f5Scvs2svn   /* NOTE, these are manual, we've done a setsid() */
113dd7e2610SBrian Somers   sig_signal(SIGINT, SIG_IGN);
114dd7e2610SBrian Somers   log_Printf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo);
1151bc9b5baSBrian Somers   bundle_Down(SignalBundle);
116dd7e2610SBrian Somers   sig_signal(SIGINT, CloseConnection);
1171ae349f5Scvs2svn }
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn static void
1201ae349f5Scvs2svn CloseSession(int signo)
1211ae349f5Scvs2svn {
122dd7e2610SBrian Somers   log_Printf(LogPHASE, "Signal %d, terminate.\n", signo);
1231ae349f5Scvs2svn   Cleanup(EX_TERM);
1241ae349f5Scvs2svn }
1251ae349f5Scvs2svn 
12675b8d283SBrian Somers static pid_t BGPid = 0;
12775b8d283SBrian Somers 
12875b8d283SBrian Somers static void
12975b8d283SBrian Somers KillChild(int signo)
13075b8d283SBrian Somers {
131dd7e2610SBrian Somers   log_Printf(LogPHASE, "Parent: Signal %d\n", signo);
13275b8d283SBrian Somers   kill(BGPid, SIGINT);
13375b8d283SBrian Somers }
13475b8d283SBrian Somers 
1351ae349f5Scvs2svn static void
1361ae349f5Scvs2svn TerminalCont(int signo)
1371ae349f5Scvs2svn {
138f91ad6b0SBrian Somers   signal(SIGCONT, SIG_DFL);
139f91ad6b0SBrian Somers   prompt_Continue(SignalPrompt);
1401ae349f5Scvs2svn }
1411ae349f5Scvs2svn 
1421ae349f5Scvs2svn static void
1431ae349f5Scvs2svn TerminalStop(int signo)
1441ae349f5Scvs2svn {
145f91ad6b0SBrian Somers   prompt_Suspend(SignalPrompt);
146f91ad6b0SBrian Somers   signal(SIGCONT, TerminalCont);
147f91ad6b0SBrian Somers   raise(SIGSTOP);
1481ae349f5Scvs2svn }
1491ae349f5Scvs2svn 
150b6217683SBrian Somers #if 0 /* What's our passwd :-O */
1511ae349f5Scvs2svn static void
1521ae349f5Scvs2svn SetUpServer(int signo)
1531ae349f5Scvs2svn {
1541ae349f5Scvs2svn   int res;
1551ae349f5Scvs2svn 
1561ae349f5Scvs2svn   VarHaveLocalAuthKey = 0;
1571ae349f5Scvs2svn   LocalAuthInit();
158455aabc3SBrian Somers   if ((res = ServerTcpOpen(SERVER_PORT + SignalBundle->unit)) != 0)
159dd7e2610SBrian Somers     log_Printf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
160455aabc3SBrian Somers 	      res, SERVER_PORT + SignalBundle->unit);
1611ae349f5Scvs2svn }
162b6217683SBrian Somers #endif
1631ae349f5Scvs2svn 
1641ae349f5Scvs2svn static void
1651ae349f5Scvs2svn BringDownServer(int signo)
1661ae349f5Scvs2svn {
167b6217683SBrian Somers   /* Drops all child prompts too ! */
168dd7e2610SBrian Somers   server_Close(SignalBundle);
1691ae349f5Scvs2svn }
1701ae349f5Scvs2svn 
1711ae349f5Scvs2svn static const char *
1721ae349f5Scvs2svn ex_desc(int ex)
1731ae349f5Scvs2svn {
1741ae349f5Scvs2svn   static char num[12];
1751ae349f5Scvs2svn   static const char *desc[] = {
1761ae349f5Scvs2svn     "normal", "start", "sock", "modem", "dial", "dead", "done",
1771ae349f5Scvs2svn     "reboot", "errdead", "hangup", "term", "nodial", "nologin"
1781ae349f5Scvs2svn   };
1791ae349f5Scvs2svn 
1801ae349f5Scvs2svn   if (ex >= 0 && ex < sizeof desc / sizeof *desc)
1811ae349f5Scvs2svn     return desc[ex];
1821ae349f5Scvs2svn   snprintf(num, sizeof num, "%d", ex);
1831ae349f5Scvs2svn   return num;
1841ae349f5Scvs2svn }
1851ae349f5Scvs2svn 
1861ae349f5Scvs2svn static void
1871ae349f5Scvs2svn Usage(void)
1881ae349f5Scvs2svn {
1891ae349f5Scvs2svn   fprintf(stderr,
1901ae349f5Scvs2svn 	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]"
1911ae349f5Scvs2svn #ifndef NOALIAS
1921ae349f5Scvs2svn           " [ -alias ]"
1931ae349f5Scvs2svn #endif
1941ae349f5Scvs2svn           " [system]\n");
1951ae349f5Scvs2svn   exit(EX_START);
1961ae349f5Scvs2svn }
1971ae349f5Scvs2svn 
1981ae349f5Scvs2svn static char *
199565e35e5SBrian Somers ProcessArgs(int argc, char **argv, int *mode)
2001ae349f5Scvs2svn {
201565e35e5SBrian Somers   int optc, labelrequired;
2021ae349f5Scvs2svn   char *cp;
2031ae349f5Scvs2svn 
204565e35e5SBrian Somers   optc = labelrequired = 0;
205565e35e5SBrian Somers   *mode = PHYS_MANUAL;
2061ae349f5Scvs2svn   while (argc > 0 && **argv == '-') {
2071ae349f5Scvs2svn     cp = *argv + 1;
2081ae349f5Scvs2svn     if (strcmp(cp, "auto") == 0) {
209565e35e5SBrian Somers       *mode = PHYS_DEMAND;
210565e35e5SBrian Somers       labelrequired = 1;
2111ae349f5Scvs2svn     } else if (strcmp(cp, "background") == 0) {
212565e35e5SBrian Somers       *mode = PHYS_1OFF;
213565e35e5SBrian Somers       labelrequired = 1;
214565e35e5SBrian Somers     } else if (strcmp(cp, "direct") == 0)
2156f384573SBrian Somers       *mode = PHYS_DIRECT;
216565e35e5SBrian Somers     else if (strcmp(cp, "dedicated") == 0)
217565e35e5SBrian Somers       *mode = PHYS_DEDICATED;
218565e35e5SBrian Somers     else if (strcmp(cp, "ddial") == 0) {
219565e35e5SBrian Somers       *mode = PHYS_PERM;
220565e35e5SBrian Somers       labelrequired = 1;
2211ae349f5Scvs2svn     } else if (strcmp(cp, "alias") == 0) {
222565e35e5SBrian Somers #ifndef NOALIAS
223dd7e2610SBrian Somers       if (alias_Load() != 0)
224565e35e5SBrian Somers #endif
225dd7e2610SBrian Somers 	log_Printf(LogWARN, "Cannot load alias library\n");
2261ae349f5Scvs2svn       optc--;			/* this option isn't exclusive */
2271ae349f5Scvs2svn     } else
2281ae349f5Scvs2svn       Usage();
2291ae349f5Scvs2svn     optc++;
2301ae349f5Scvs2svn     argv++;
2311ae349f5Scvs2svn     argc--;
2321ae349f5Scvs2svn   }
2331ae349f5Scvs2svn   if (argc > 1) {
23485602e52SBrian Somers     fprintf(stderr, "You may specify only one system label.\n");
2351ae349f5Scvs2svn     exit(EX_START);
2361ae349f5Scvs2svn   }
2371ae349f5Scvs2svn 
2381ae349f5Scvs2svn   if (optc > 1) {
23985602e52SBrian Somers     fprintf(stderr, "You may specify only one mode.\n");
2401ae349f5Scvs2svn     exit(EX_START);
2411ae349f5Scvs2svn   }
2421ae349f5Scvs2svn 
243565e35e5SBrian Somers   if (labelrequired && argc != 1) {
244565e35e5SBrian Somers     fprintf(stderr, "Destination system must be specified in"
245565e35e5SBrian Somers             " auto, background or ddial mode.\n");
246565e35e5SBrian Somers     exit(EX_START);
247565e35e5SBrian Somers   }
248565e35e5SBrian Somers 
2491ae349f5Scvs2svn   return argc == 1 ? *argv : NULL;	/* Don't SetLabel yet ! */
2501ae349f5Scvs2svn }
2511ae349f5Scvs2svn 
2521ae349f5Scvs2svn int
2531ae349f5Scvs2svn main(int argc, char **argv)
2541ae349f5Scvs2svn {
2551ae349f5Scvs2svn   FILE *lockfile;
2561ae349f5Scvs2svn   char *name, *label;
257565e35e5SBrian Somers   int nfds, mode;
2587a6f8720SBrian Somers   struct bundle *bundle;
259b6217683SBrian Somers   struct prompt *prompt;
2601ae349f5Scvs2svn 
2611ae349f5Scvs2svn   nfds = getdtablesize();
2621ae349f5Scvs2svn   if (nfds >= FD_SETSIZE)
2631ae349f5Scvs2svn     /*
2641ae349f5Scvs2svn      * If we've got loads of file descriptors, make sure they're all
2651ae349f5Scvs2svn      * closed.  If they aren't, we may end up with a seg fault when our
2661ae349f5Scvs2svn      * `fd_set's get too big when select()ing !
2671ae349f5Scvs2svn      */
2681ae349f5Scvs2svn     while (--nfds > 2)
2691ae349f5Scvs2svn       close(nfds);
2701ae349f5Scvs2svn 
2711ae349f5Scvs2svn   name = strrchr(argv[0], '/');
272dd7e2610SBrian Somers   log_Open(name ? name + 1 : argv[0]);
2731ae349f5Scvs2svn 
2741ae349f5Scvs2svn   argc--;
2751ae349f5Scvs2svn   argv++;
276565e35e5SBrian Somers   label = ProcessArgs(argc, argv, &mode);
27785b542cfSBrian Somers 
27885b542cfSBrian Somers #ifdef __FreeBSD__
27985b542cfSBrian Somers   /*
28085b542cfSBrian Somers    * A FreeBSD hack to dodge a bug in the tty driver that drops output
28185b542cfSBrian Somers    * occasionally.... I must find the real reason some time.  To display
28285b542cfSBrian Somers    * the dodgy behaviour, comment out this bit, make yourself a large
28385b542cfSBrian Somers    * routing table and then run ppp in interactive mode.  The `show route'
28485b542cfSBrian Somers    * command will drop chunks of data !!!
28585b542cfSBrian Somers    */
286565e35e5SBrian Somers   if (mode == PHYS_MANUAL) {
28785b542cfSBrian Somers     close(STDIN_FILENO);
28885b542cfSBrian Somers     if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) {
28985b542cfSBrian Somers       fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY);
29085b542cfSBrian Somers       return 2;
29185b542cfSBrian Somers     }
29285b542cfSBrian Somers   }
29385b542cfSBrian Somers #endif
29485b542cfSBrian Somers 
295b6217683SBrian Somers   /* Allow output for the moment (except in direct mode) */
2966f384573SBrian Somers   if (mode == PHYS_DIRECT)
297b6217683SBrian Somers     prompt = NULL;
29885602e52SBrian Somers   else {
29985602e52SBrian Somers     const char *m;
30085602e52SBrian Somers 
301b6217683SBrian Somers     SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD);
302565e35e5SBrian Somers     if (mode == PHYS_PERM)
30385602e52SBrian Somers       m = "direct dial";
304565e35e5SBrian Somers     else if (mode & PHYS_1OFF)
30585602e52SBrian Somers       m = "background";
306565e35e5SBrian Somers     else if (mode & PHYS_DEMAND)
30785602e52SBrian Somers       m = "auto";
308565e35e5SBrian Somers     else if (mode & PHYS_DEDICATED)
30985602e52SBrian Somers       m = "dedicated";
310565e35e5SBrian Somers     else if (mode & PHYS_MANUAL)
31185602e52SBrian Somers       m = "interactive";
31285602e52SBrian Somers     else
31385602e52SBrian Somers       m = NULL;
31485602e52SBrian Somers 
31585602e52SBrian Somers     if (m)
31685602e52SBrian Somers       prompt_Printf(prompt, "Working in %s mode\n", m);
31785602e52SBrian Somers   }
3181ae349f5Scvs2svn 
3191ae349f5Scvs2svn   ID0init();
3201ae349f5Scvs2svn   if (ID0realuid() != 0) {
3211ae349f5Scvs2svn     char conf[200], *ptr;
3221ae349f5Scvs2svn 
3231ae349f5Scvs2svn     snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
3241ae349f5Scvs2svn     do {
3251ae349f5Scvs2svn       if (!access(conf, W_OK)) {
326dd7e2610SBrian Somers         log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
3271ae349f5Scvs2svn         return -1;
3281ae349f5Scvs2svn       }
3291ae349f5Scvs2svn       ptr = conf + strlen(conf)-2;
3301ae349f5Scvs2svn       while (ptr > conf && *ptr != '/')
3311ae349f5Scvs2svn         *ptr-- = '\0';
3321ae349f5Scvs2svn     } while (ptr >= conf);
3331ae349f5Scvs2svn   }
3341ae349f5Scvs2svn 
335dd7e2610SBrian Somers   if (!system_IsValid(label, prompt, mode)) {
3361ae349f5Scvs2svn     fprintf(stderr, "You may not use ppp in this mode with this label\n");
3376f384573SBrian Somers     if (mode == PHYS_DIRECT) {
3381ae349f5Scvs2svn       const char *l;
3391ae349f5Scvs2svn       l = label ? label : "default";
340dd7e2610SBrian Somers       log_Printf(LogWARN, "Label %s rejected -direct connection\n", l);
3411ae349f5Scvs2svn     }
342dd7e2610SBrian Somers     log_Close();
3431ae349f5Scvs2svn     return 1;
3441ae349f5Scvs2svn   }
3451ae349f5Scvs2svn 
346565e35e5SBrian Somers   if ((bundle = bundle_Create(TUN_PREFIX, prompt, mode)) == NULL) {
347dd7e2610SBrian Somers     log_Printf(LogWARN, "bundle_Create: %s\n", strerror(errno));
3481ae349f5Scvs2svn     return EX_START;
3491ae349f5Scvs2svn   }
35083d1af55SBrian Somers   SignalBundle = bundle;
3517a6f8720SBrian Somers 
352dd7e2610SBrian Somers   if (system_Select(bundle, "default", CONFFILE, prompt) < 0)
353565e35e5SBrian Somers     prompt_Printf(prompt, "Warning: No default entry found in config file.\n");
3541ae349f5Scvs2svn 
355dd7e2610SBrian Somers   sig_signal(SIGHUP, CloseSession);
356dd7e2610SBrian Somers   sig_signal(SIGTERM, CloseSession);
357dd7e2610SBrian Somers   sig_signal(SIGINT, CloseConnection);
358dd7e2610SBrian Somers   sig_signal(SIGQUIT, CloseSession);
359dd7e2610SBrian Somers   sig_signal(SIGALRM, SIG_IGN);
3601ae349f5Scvs2svn   signal(SIGPIPE, SIG_IGN);
361565e35e5SBrian Somers 
362565e35e5SBrian Somers   if (mode == PHYS_MANUAL)
363dd7e2610SBrian Somers     sig_signal(SIGTSTP, TerminalStop);
364f91ad6b0SBrian Somers 
365b6217683SBrian Somers #if 0 /* What's our passwd :-O */
366dd7e2610SBrian Somers   sig_signal(SIGUSR1, SetUpServer);
3671ae349f5Scvs2svn #endif
368dd7e2610SBrian Somers   sig_signal(SIGUSR2, BringDownServer);
3691ae349f5Scvs2svn 
3701ae349f5Scvs2svn   if (label) {
37149052c95SBrian Somers     /*
372dd7e2610SBrian Somers      * Set label both before and after system_Select !
373dd7e2610SBrian Somers      * This way, "set enddisc label" works during system_Select, and we
37449052c95SBrian Somers      * also end up with the correct label if we have embedded load
37549052c95SBrian Somers      * commands.
37649052c95SBrian Somers      */
37749052c95SBrian Somers     bundle_SetLabel(bundle, label);
378dd7e2610SBrian Somers     if (system_Select(bundle, label, CONFFILE, prompt) < 0) {
379b6217683SBrian Somers       prompt_Printf(prompt, "Destination system (%s) not found.\n", label);
3808390b576SBrian Somers       AbortProgram(EX_START);
3811ae349f5Scvs2svn     }
38249052c95SBrian Somers     bundle_SetLabel(bundle, label);
383565e35e5SBrian Somers     if (mode == PHYS_DEMAND &&
3845828db6dSBrian Somers 	bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
385565e35e5SBrian Somers       prompt_Printf(prompt, "You must \"set ifaddr\" with a peer address "
386565e35e5SBrian Somers                     "in label %s for auto mode.\n", label);
3878390b576SBrian Somers       AbortProgram(EX_START);
3881ae349f5Scvs2svn     }
3891ae349f5Scvs2svn   }
3901ae349f5Scvs2svn 
391565e35e5SBrian Somers   if (mode != PHYS_MANUAL) {
3926f384573SBrian Somers     if (mode != PHYS_DIRECT) {
3935cf4388bSBrian Somers       int bgpipe[2];
3945cf4388bSBrian Somers       pid_t bgpid;
3955cf4388bSBrian Somers 
396565e35e5SBrian Somers       if (mode == PHYS_1OFF && pipe(bgpipe)) {
397dd7e2610SBrian Somers         log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
3988390b576SBrian Somers 	AbortProgram(EX_SOCK);
3991ae349f5Scvs2svn       }
4001ae349f5Scvs2svn 
4011ae349f5Scvs2svn       bgpid = fork();
4021ae349f5Scvs2svn       if (bgpid == -1) {
403dd7e2610SBrian Somers 	log_Printf(LogERROR, "fork: %s\n", strerror(errno));
4048390b576SBrian Somers 	AbortProgram(EX_SOCK);
4051ae349f5Scvs2svn       }
4065cf4388bSBrian Somers 
4071ae349f5Scvs2svn       if (bgpid) {
4081ae349f5Scvs2svn 	char c = EX_NORMAL;
4091ae349f5Scvs2svn 
410565e35e5SBrian Somers 	if (mode == PHYS_1OFF) {
4115cf4388bSBrian Somers 	  close(bgpipe[1]);
41275b8d283SBrian Somers 	  BGPid = bgpid;
41375b8d283SBrian Somers           /* If we get a signal, kill the child */
41475b8d283SBrian Somers           signal(SIGHUP, KillChild);
41575b8d283SBrian Somers           signal(SIGTERM, KillChild);
41675b8d283SBrian Somers           signal(SIGINT, KillChild);
41775b8d283SBrian Somers           signal(SIGQUIT, KillChild);
41875b8d283SBrian Somers 
41975b8d283SBrian Somers 	  /* Wait for our child to close its pipe before we exit */
4205cf4388bSBrian Somers 	  if (read(bgpipe[0], &c, 1) != 1) {
421b6217683SBrian Somers 	    prompt_Printf(prompt, "Child exit, no status.\n");
422dd7e2610SBrian Somers 	    log_Printf(LogPHASE, "Parent: Child exit, no status.\n");
4231ae349f5Scvs2svn 	  } else if (c == EX_NORMAL) {
424b6217683SBrian Somers 	    prompt_Printf(prompt, "PPP enabled.\n");
425dd7e2610SBrian Somers 	    log_Printf(LogPHASE, "Parent: PPP enabled.\n");
4261ae349f5Scvs2svn 	  } else {
427b6217683SBrian Somers 	    prompt_Printf(prompt, "Child failed (%s).\n", ex_desc((int) c));
428dd7e2610SBrian Somers 	    log_Printf(LogPHASE, "Parent: Child failed (%s).\n",
4291ae349f5Scvs2svn 		      ex_desc((int) c));
4301ae349f5Scvs2svn 	  }
4315cf4388bSBrian Somers 	  close(bgpipe[0]);
4321ae349f5Scvs2svn 	}
4331ae349f5Scvs2svn 	return c;
434565e35e5SBrian Somers       } else if (mode == PHYS_1OFF) {
4355cf4388bSBrian Somers 	close(bgpipe[0]);
4365cf4388bSBrian Somers         bundle->notify.fd = bgpipe[1];
4375cf4388bSBrian Somers       }
4381ae349f5Scvs2svn 
439565e35e5SBrian Somers       /* -auto, -dedicated, -ddial & -background */
440b6217683SBrian Somers       prompt_Destroy(prompt, 0);
441b6217683SBrian Somers       close(STDOUT_FILENO);
442b6217683SBrian Somers       close(STDERR_FILENO);
4431ae349f5Scvs2svn       close(STDIN_FILENO);
444b6217683SBrian Somers       setsid();
445565e35e5SBrian Somers     } else {
446565e35e5SBrian Somers       /* -direct: STDIN_FILENO gets used by modem_Open */
447565e35e5SBrian Somers       prompt_TtyInit(NULL);
448565e35e5SBrian Somers       close(STDOUT_FILENO);
449565e35e5SBrian Somers       close(STDERR_FILENO);
4501ae349f5Scvs2svn     }
4511ae349f5Scvs2svn   } else {
452565e35e5SBrian Somers     /* Interactive mode */
4531ae349f5Scvs2svn     close(STDERR_FILENO);
454565e35e5SBrian Somers     prompt_TtyInit(prompt);
455b6217683SBrian Somers     prompt_TtyCommandMode(prompt);
456b6217683SBrian Somers     prompt_Required(prompt);
4571ae349f5Scvs2svn   }
4581ae349f5Scvs2svn 
4591ae349f5Scvs2svn   snprintf(pid_filename, sizeof pid_filename, "%stun%d.pid",
460455aabc3SBrian Somers            _PATH_VARRUN, bundle->unit);
4611ae349f5Scvs2svn   lockfile = ID0fopen(pid_filename, "w");
4621ae349f5Scvs2svn   if (lockfile != NULL) {
4631ae349f5Scvs2svn     fprintf(lockfile, "%d\n", (int) getpid());
4641ae349f5Scvs2svn     fclose(lockfile);
4651ae349f5Scvs2svn   }
4661ae349f5Scvs2svn #ifndef RELEASE_CRUNCH
4671ae349f5Scvs2svn   else
468dd7e2610SBrian Somers     log_Printf(LogALERT, "Warning: Can't create %s: %s\n",
4691ae349f5Scvs2svn               pid_filename, strerror(errno));
4701ae349f5Scvs2svn #endif
4711ae349f5Scvs2svn 
472dd7e2610SBrian Somers   log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(mode));
473b6217683SBrian Somers   DoLoop(bundle, prompt);
4741afedc4bSBrian Somers   AbortProgram(EX_NORMAL);
4751afedc4bSBrian Somers 
4761afedc4bSBrian Somers   return EX_NORMAL;
4771ae349f5Scvs2svn }
4781ae349f5Scvs2svn 
4791ae349f5Scvs2svn static void
480b6217683SBrian Somers DoLoop(struct bundle *bundle, struct prompt *prompt)
4811ae349f5Scvs2svn {
4821ae349f5Scvs2svn   fd_set rfds, wfds, efds;
483078c562eSBrian Somers   int i, nfds;
4841ae349f5Scvs2svn 
485565e35e5SBrian Somers   do {
4861ae349f5Scvs2svn     nfds = 0;
4871ae349f5Scvs2svn     FD_ZERO(&rfds);
4881ae349f5Scvs2svn     FD_ZERO(&wfds);
4891ae349f5Scvs2svn     FD_ZERO(&efds);
4901ae349f5Scvs2svn 
491dd7e2610SBrian Somers     sig_Handle();
492b6dec9f0SBrian Somers 
4931bc9b5baSBrian Somers     /* This may nuke a datalink */
4941fa665f5SBrian Somers     descriptor_UpdateSet(&bundle->ncp.mp.server.desc, &rfds, &wfds,
4951fa665f5SBrian Somers                          &efds, &nfds);
4966f384573SBrian Somers     descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds);
4976f384573SBrian Somers     descriptor_UpdateSet(&server.desc, &rfds, &wfds, &efds, &nfds);
4981ae349f5Scvs2svn 
4993b0f8d2eSBrian Somers     if (bundle_IsDead(bundle))
500f4768038SBrian Somers       /* Don't select - we'll be here forever */
501f4768038SBrian Somers       break;
502f4768038SBrian Somers 
5033006ec67SBrian Somers     i = select(nfds, &rfds, &wfds, &efds, NULL);
5041ae349f5Scvs2svn 
5053006ec67SBrian Somers     if (i == 0)
5061ae349f5Scvs2svn       continue;
507078c562eSBrian Somers     else if (i < 0) {
508078c562eSBrian Somers       if (errno == EINTR)
5091ae349f5Scvs2svn 	continue;
510dd7e2610SBrian Somers       log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
5111ae349f5Scvs2svn       break;
5121ae349f5Scvs2svn     }
51377ff88adSBrian Somers 
5143006ec67SBrian Somers     for (i = 0; i <= nfds; i++)
5153006ec67SBrian Somers       if (FD_ISSET(i, &efds)) {
516dd7e2610SBrian Somers         log_Printf(LogALERT, "Exception detected on descriptor %d\n", i);
5171ae349f5Scvs2svn         break;
5181ae349f5Scvs2svn       }
51977ff88adSBrian Somers 
520b7c5748eSBrian Somers     if (i <= nfds)
521b7c5748eSBrian Somers       break;
522b7c5748eSBrian Somers 
5231fa665f5SBrian Somers     if (descriptor_IsSet(&bundle->ncp.mp.server.desc, &rfds))
5241fa665f5SBrian Somers       descriptor_Read(&bundle->ncp.mp.server.desc, bundle, &rfds);
5251fa665f5SBrian Somers 
52677ff88adSBrian Somers     if (descriptor_IsSet(&server.desc, &rfds))
527b77776a7SBrian Somers       descriptor_Read(&server.desc, bundle, &rfds);
52842d4d396SBrian Somers 
5292f786681SBrian Somers     if (descriptor_IsSet(&bundle->desc, &wfds))
5302f786681SBrian Somers       descriptor_Write(&bundle->desc, bundle, &wfds);
5312f786681SBrian Somers 
5321bc9b5baSBrian Somers     /* This may add a datalink */
5332f786681SBrian Somers     if (descriptor_IsSet(&bundle->desc, &rfds))
5342f786681SBrian Somers       descriptor_Read(&bundle->desc, bundle, &rfds);
535565e35e5SBrian Somers   } while (bundle_CleanDatalinks(bundle), !bundle_IsDead(bundle));
536565e35e5SBrian Somers 
537dd7e2610SBrian Somers   log_Printf(LogDEBUG, "DoLoop done.\n");
5381ae349f5Scvs2svn }
539