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 * 203b0f8d2eSBrian Somers * $Id: main.c,v 1.121.2.39 1998/03/25 18:38:59 brian Exp $ 211ae349f5Scvs2svn * 221ae349f5Scvs2svn * TODO: 231ae349f5Scvs2svn * o Add commands for traffic summary, version display, etc. 241ae349f5Scvs2svn * o Add signal handler for misc controls. 251ae349f5Scvs2svn */ 261ae349f5Scvs2svn #include <sys/param.h> 271ae349f5Scvs2svn #include <sys/time.h> 281ae349f5Scvs2svn #include <sys/select.h> 291ae349f5Scvs2svn #include <sys/socket.h> 301ae349f5Scvs2svn #include <net/if.h> 311ae349f5Scvs2svn #include <net/if_tun.h> 321ae349f5Scvs2svn #include <netinet/in.h> 331ae349f5Scvs2svn #include <netinet/in_systm.h> 341ae349f5Scvs2svn #include <netinet/ip.h> 351ae349f5Scvs2svn #include <arpa/inet.h> 361ae349f5Scvs2svn 371ae349f5Scvs2svn #include <errno.h> 381ae349f5Scvs2svn #include <fcntl.h> 391ae349f5Scvs2svn #include <paths.h> 401ae349f5Scvs2svn #include <signal.h> 411ae349f5Scvs2svn #include <stdio.h> 421ae349f5Scvs2svn #include <stdlib.h> 431ae349f5Scvs2svn #include <string.h> 441ae349f5Scvs2svn #include <sys/time.h> 451ae349f5Scvs2svn #include <sys/wait.h> 461ae349f5Scvs2svn #include <termios.h> 471ae349f5Scvs2svn #include <unistd.h> 481ae349f5Scvs2svn 491ae349f5Scvs2svn #include "command.h" 501ae349f5Scvs2svn #include "mbuf.h" 511ae349f5Scvs2svn #include "log.h" 521ae349f5Scvs2svn #include "defs.h" 531ae349f5Scvs2svn #include "id.h" 541ae349f5Scvs2svn #include "timer.h" 551ae349f5Scvs2svn #include "fsm.h" 561ae349f5Scvs2svn #include "modem.h" 57879ed6faSBrian Somers #include "lqr.h" 581ae349f5Scvs2svn #include "hdlc.h" 591ae349f5Scvs2svn #include "lcp.h" 601ae349f5Scvs2svn #include "ccp.h" 6129e275ceSBrian Somers #include "iplist.h" 6229e275ceSBrian Somers #include "throughput.h" 63eaa4df37SBrian Somers #include "slcompress.h" 641ae349f5Scvs2svn #include "ipcp.h" 655ca5389aSBrian Somers #include "filter.h" 662f786681SBrian Somers #include "descriptor.h" 673b0f8d2eSBrian Somers #include "link.h" 683b0f8d2eSBrian Somers #include "mp.h" 695828db6dSBrian Somers #include "bundle.h" 701ae349f5Scvs2svn #include "loadalias.h" 711ae349f5Scvs2svn #include "vars.h" 721ae349f5Scvs2svn #include "auth.h" 731ae349f5Scvs2svn #include "systems.h" 741ae349f5Scvs2svn #include "ip.h" 751ae349f5Scvs2svn #include "sig.h" 761ae349f5Scvs2svn #include "main.h" 771ae349f5Scvs2svn #include "vjcomp.h" 781ae349f5Scvs2svn #include "async.h" 791ae349f5Scvs2svn #include "pathnames.h" 801ae349f5Scvs2svn #include "tun.h" 811ae349f5Scvs2svn #include "route.h" 8263b73463SBrian Somers #include "physical.h" 8377ff88adSBrian Somers #include "server.h" 8485b542cfSBrian Somers #include "prompt.h" 85b6dec9f0SBrian Somers #include "chat.h" 86e2ebb036SBrian Somers #include "chap.h" 873006ec67SBrian Somers #include "datalink.h" 881ae349f5Scvs2svn 891ae349f5Scvs2svn #ifndef O_NONBLOCK 901ae349f5Scvs2svn #ifdef O_NDELAY 911ae349f5Scvs2svn #define O_NONBLOCK O_NDELAY 921ae349f5Scvs2svn #endif 931ae349f5Scvs2svn #endif 941ae349f5Scvs2svn 951ae349f5Scvs2svn static char pid_filename[MAXPATHLEN]; 961ae349f5Scvs2svn 977a6f8720SBrian Somers static void DoLoop(struct bundle *); 981ae349f5Scvs2svn static void TerminalStop(int); 991ae349f5Scvs2svn static const char *ex_desc(int); 1001ae349f5Scvs2svn 10183d1af55SBrian Somers static struct bundle *SignalBundle; 1027a6f8720SBrian Somers 1031ae349f5Scvs2svn void 1041ae349f5Scvs2svn Cleanup(int excode) 1051ae349f5Scvs2svn { 106a0cbd833SBrian Somers SignalBundle->CleaningUp = 1; 1073006ec67SBrian Somers if (bundle_Phase(SignalBundle) != PHASE_DEAD) 1083b0f8d2eSBrian Somers bundle_Close(SignalBundle, NULL, 1); 1091afedc4bSBrian Somers } 110455aabc3SBrian Somers 1111afedc4bSBrian Somers void 1121afedc4bSBrian Somers AbortProgram(int excode) 1131afedc4bSBrian Somers { 11485b542cfSBrian Somers prompt_Drop(&prompt, 1); 1151ae349f5Scvs2svn ServerClose(); 1161ae349f5Scvs2svn ID0unlink(pid_filename); 1171ae349f5Scvs2svn LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 11885b542cfSBrian Somers prompt_TtyOldMode(&prompt); 119d345321bSBrian Somers bundle_Close(SignalBundle, NULL, 1); 12068a0f0ccSBrian Somers bundle_Destroy(SignalBundle); 1213006ec67SBrian Somers LogClose(); 1221ae349f5Scvs2svn exit(excode); 1231ae349f5Scvs2svn } 1241ae349f5Scvs2svn 1251ae349f5Scvs2svn static void 1261ae349f5Scvs2svn CloseConnection(int signo) 1271ae349f5Scvs2svn { 1281ae349f5Scvs2svn /* NOTE, these are manual, we've done a setsid() */ 1293b0f8d2eSBrian Somers struct datalink *dl; 1303b0f8d2eSBrian Somers 1311ae349f5Scvs2svn pending_signal(SIGINT, SIG_IGN); 1323b0f8d2eSBrian Somers LogPrintf(LogPHASE, "Caught signal %d, abort connection(s)\n", signo); 1333b0f8d2eSBrian Somers for (dl = SignalBundle->links; dl; dl = dl->next) 1343b0f8d2eSBrian Somers datalink_Down(dl, 1); 1351ae349f5Scvs2svn pending_signal(SIGINT, CloseConnection); 1361ae349f5Scvs2svn } 1371ae349f5Scvs2svn 1381ae349f5Scvs2svn static void 1391ae349f5Scvs2svn CloseSession(int signo) 1401ae349f5Scvs2svn { 1411ae349f5Scvs2svn LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 1421ae349f5Scvs2svn Cleanup(EX_TERM); 1431ae349f5Scvs2svn } 1441ae349f5Scvs2svn 14575b8d283SBrian Somers static pid_t BGPid = 0; 14675b8d283SBrian Somers 14775b8d283SBrian Somers static void 14875b8d283SBrian Somers KillChild(int signo) 14975b8d283SBrian Somers { 15075b8d283SBrian Somers LogPrintf(LogPHASE, "Parent: Signal %d\n", signo); 15175b8d283SBrian Somers kill(BGPid, SIGINT); 15275b8d283SBrian Somers } 15375b8d283SBrian Somers 1541ae349f5Scvs2svn static void 1551ae349f5Scvs2svn TerminalCont(int signo) 1561ae349f5Scvs2svn { 1571ae349f5Scvs2svn pending_signal(SIGCONT, SIG_DFL); 1581ae349f5Scvs2svn pending_signal(SIGTSTP, TerminalStop); 15985b542cfSBrian Somers prompt_TtyCommandMode(&prompt); 16085b542cfSBrian Somers if (getpgrp() == prompt_pgrp(&prompt)) 16185b542cfSBrian Somers prompt_Display(&prompt, SignalBundle); 1621ae349f5Scvs2svn } 1631ae349f5Scvs2svn 1641ae349f5Scvs2svn static void 1651ae349f5Scvs2svn TerminalStop(int signo) 1661ae349f5Scvs2svn { 1671ae349f5Scvs2svn pending_signal(SIGCONT, TerminalCont); 16885b542cfSBrian Somers prompt_TtyOldMode(&prompt); 1691ae349f5Scvs2svn pending_signal(SIGTSTP, SIG_DFL); 1701ae349f5Scvs2svn kill(getpid(), signo); 1711ae349f5Scvs2svn } 1721ae349f5Scvs2svn 1731ae349f5Scvs2svn static void 1741ae349f5Scvs2svn SetUpServer(int signo) 1751ae349f5Scvs2svn { 1761ae349f5Scvs2svn int res; 1771ae349f5Scvs2svn 1781ae349f5Scvs2svn VarHaveLocalAuthKey = 0; 1791ae349f5Scvs2svn LocalAuthInit(); 180455aabc3SBrian Somers if ((res = ServerTcpOpen(SERVER_PORT + SignalBundle->unit)) != 0) 1811ae349f5Scvs2svn LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 182455aabc3SBrian Somers res, SERVER_PORT + SignalBundle->unit); 1831ae349f5Scvs2svn } 1841ae349f5Scvs2svn 1851ae349f5Scvs2svn static void 1861ae349f5Scvs2svn BringDownServer(int signo) 1871ae349f5Scvs2svn { 1881ae349f5Scvs2svn VarHaveLocalAuthKey = 0; 1891ae349f5Scvs2svn LocalAuthInit(); 1901ae349f5Scvs2svn ServerClose(); 1911ae349f5Scvs2svn } 1921ae349f5Scvs2svn 1931ae349f5Scvs2svn static const char * 1941ae349f5Scvs2svn ex_desc(int ex) 1951ae349f5Scvs2svn { 1961ae349f5Scvs2svn static char num[12]; 1971ae349f5Scvs2svn static const char *desc[] = { 1981ae349f5Scvs2svn "normal", "start", "sock", "modem", "dial", "dead", "done", 1991ae349f5Scvs2svn "reboot", "errdead", "hangup", "term", "nodial", "nologin" 2001ae349f5Scvs2svn }; 2011ae349f5Scvs2svn 2021ae349f5Scvs2svn if (ex >= 0 && ex < sizeof desc / sizeof *desc) 2031ae349f5Scvs2svn return desc[ex]; 2041ae349f5Scvs2svn snprintf(num, sizeof num, "%d", ex); 2051ae349f5Scvs2svn return num; 2061ae349f5Scvs2svn } 2071ae349f5Scvs2svn 2081ae349f5Scvs2svn static void 2091ae349f5Scvs2svn Usage(void) 2101ae349f5Scvs2svn { 2111ae349f5Scvs2svn fprintf(stderr, 2121ae349f5Scvs2svn "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 2131ae349f5Scvs2svn #ifndef NOALIAS 2141ae349f5Scvs2svn " [ -alias ]" 2151ae349f5Scvs2svn #endif 2161ae349f5Scvs2svn " [system]\n"); 2171ae349f5Scvs2svn exit(EX_START); 2181ae349f5Scvs2svn } 2191ae349f5Scvs2svn 2201ae349f5Scvs2svn static char * 2211ae349f5Scvs2svn ProcessArgs(int argc, char **argv) 2221ae349f5Scvs2svn { 2231ae349f5Scvs2svn int optc; 2241ae349f5Scvs2svn char *cp; 2251ae349f5Scvs2svn 2261ae349f5Scvs2svn optc = 0; 2271ae349f5Scvs2svn mode = MODE_INTER; 2281ae349f5Scvs2svn while (argc > 0 && **argv == '-') { 2291ae349f5Scvs2svn cp = *argv + 1; 2301ae349f5Scvs2svn if (strcmp(cp, "auto") == 0) { 2311ae349f5Scvs2svn mode |= MODE_AUTO; 2321ae349f5Scvs2svn mode &= ~MODE_INTER; 2331ae349f5Scvs2svn } else if (strcmp(cp, "background") == 0) { 2341ae349f5Scvs2svn mode |= MODE_BACKGROUND; 2351ae349f5Scvs2svn mode &= ~MODE_INTER; 2361ae349f5Scvs2svn } else if (strcmp(cp, "direct") == 0) { 2371ae349f5Scvs2svn mode |= MODE_DIRECT; 2381ae349f5Scvs2svn mode &= ~MODE_INTER; 2391ae349f5Scvs2svn } else if (strcmp(cp, "dedicated") == 0) { 2401ae349f5Scvs2svn mode |= MODE_DEDICATED; 2411ae349f5Scvs2svn mode &= ~MODE_INTER; 2421ae349f5Scvs2svn } else if (strcmp(cp, "ddial") == 0) { 2431ae349f5Scvs2svn mode |= MODE_DDIAL; 2441ae349f5Scvs2svn mode &= ~MODE_INTER; 2451ae349f5Scvs2svn #ifndef NOALIAS 2461ae349f5Scvs2svn } else if (strcmp(cp, "alias") == 0) { 2471ae349f5Scvs2svn if (loadAliasHandlers(&VarAliasHandlers) == 0) 2481ae349f5Scvs2svn mode |= MODE_ALIAS; 2491ae349f5Scvs2svn else 2501ae349f5Scvs2svn LogPrintf(LogWARN, "Cannot load alias library\n"); 2511ae349f5Scvs2svn optc--; /* this option isn't exclusive */ 2521ae349f5Scvs2svn #endif 2531ae349f5Scvs2svn } else 2541ae349f5Scvs2svn Usage(); 2551ae349f5Scvs2svn optc++; 2561ae349f5Scvs2svn argv++; 2571ae349f5Scvs2svn argc--; 2581ae349f5Scvs2svn } 2591ae349f5Scvs2svn if (argc > 1) { 2601ae349f5Scvs2svn fprintf(stderr, "specify only one system label.\n"); 2611ae349f5Scvs2svn exit(EX_START); 2621ae349f5Scvs2svn } 2631ae349f5Scvs2svn 2641ae349f5Scvs2svn if (optc > 1) { 2651ae349f5Scvs2svn fprintf(stderr, "specify only one mode.\n"); 2661ae349f5Scvs2svn exit(EX_START); 2671ae349f5Scvs2svn } 2681ae349f5Scvs2svn 2691ae349f5Scvs2svn return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ 2701ae349f5Scvs2svn } 2711ae349f5Scvs2svn 2721ae349f5Scvs2svn int 2731ae349f5Scvs2svn main(int argc, char **argv) 2741ae349f5Scvs2svn { 2751ae349f5Scvs2svn FILE *lockfile; 2761ae349f5Scvs2svn char *name, *label; 2771ae349f5Scvs2svn int nfds; 2787a6f8720SBrian Somers struct bundle *bundle; 2791ae349f5Scvs2svn 2801ae349f5Scvs2svn nfds = getdtablesize(); 2811ae349f5Scvs2svn if (nfds >= FD_SETSIZE) 2821ae349f5Scvs2svn /* 2831ae349f5Scvs2svn * If we've got loads of file descriptors, make sure they're all 2841ae349f5Scvs2svn * closed. If they aren't, we may end up with a seg fault when our 2851ae349f5Scvs2svn * `fd_set's get too big when select()ing ! 2861ae349f5Scvs2svn */ 2871ae349f5Scvs2svn while (--nfds > 2) 2881ae349f5Scvs2svn close(nfds); 2891ae349f5Scvs2svn 2901ae349f5Scvs2svn name = strrchr(argv[0], '/'); 2911ae349f5Scvs2svn LogOpen(name ? name + 1 : argv[0]); 2921ae349f5Scvs2svn 2931ae349f5Scvs2svn argc--; 2941ae349f5Scvs2svn argv++; 2951ae349f5Scvs2svn label = ProcessArgs(argc, argv); 29685b542cfSBrian Somers 29785b542cfSBrian Somers #ifdef __FreeBSD__ 29885b542cfSBrian Somers /* 29985b542cfSBrian Somers * A FreeBSD hack to dodge a bug in the tty driver that drops output 30085b542cfSBrian Somers * occasionally.... I must find the real reason some time. To display 30185b542cfSBrian Somers * the dodgy behaviour, comment out this bit, make yourself a large 30285b542cfSBrian Somers * routing table and then run ppp in interactive mode. The `show route' 30385b542cfSBrian Somers * command will drop chunks of data !!! 30485b542cfSBrian Somers */ 30585b542cfSBrian Somers if (mode & MODE_INTER) { 30685b542cfSBrian Somers close(STDIN_FILENO); 30785b542cfSBrian Somers if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { 30885b542cfSBrian Somers fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); 30985b542cfSBrian Somers return 2; 31085b542cfSBrian Somers } 31185b542cfSBrian Somers } 31285b542cfSBrian Somers #endif 31385b542cfSBrian Somers 31485b542cfSBrian Somers prompt_Init(&prompt, (mode & MODE_DIRECT) ? PROMPT_NONE : PROMPT_STD); 3151ae349f5Scvs2svn 3161ae349f5Scvs2svn ID0init(); 3171ae349f5Scvs2svn if (ID0realuid() != 0) { 3181ae349f5Scvs2svn char conf[200], *ptr; 3191ae349f5Scvs2svn 3201ae349f5Scvs2svn snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 3211ae349f5Scvs2svn do { 3221ae349f5Scvs2svn if (!access(conf, W_OK)) { 3231ae349f5Scvs2svn LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); 3241ae349f5Scvs2svn return -1; 3251ae349f5Scvs2svn } 3261ae349f5Scvs2svn ptr = conf + strlen(conf)-2; 3271ae349f5Scvs2svn while (ptr > conf && *ptr != '/') 3281ae349f5Scvs2svn *ptr-- = '\0'; 3291ae349f5Scvs2svn } while (ptr >= conf); 3301ae349f5Scvs2svn } 3311ae349f5Scvs2svn 3321ae349f5Scvs2svn if (!ValidSystem(label)) { 3331ae349f5Scvs2svn fprintf(stderr, "You may not use ppp in this mode with this label\n"); 3341ae349f5Scvs2svn if (mode & MODE_DIRECT) { 3351ae349f5Scvs2svn const char *l; 3361ae349f5Scvs2svn l = label ? label : "default"; 3371ae349f5Scvs2svn LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); 3381ae349f5Scvs2svn } 3391ae349f5Scvs2svn LogClose(); 3401ae349f5Scvs2svn return 1; 3411ae349f5Scvs2svn } 3421ae349f5Scvs2svn 3431ae349f5Scvs2svn if (mode & MODE_INTER) 3441ae349f5Scvs2svn VarLocalAuth = LOCAL_AUTH; 3451ae349f5Scvs2svn 3467a6f8720SBrian Somers if ((bundle = bundle_Create("/dev/tun")) == NULL) { 3477a6f8720SBrian Somers LogPrintf(LogWARN, "bundle_Create: %s\n", strerror(errno)); 3481ae349f5Scvs2svn return EX_START; 3491ae349f5Scvs2svn } 3507a6f8720SBrian Somers 3512289f246SBrian Somers if (!GetShortHost()) 3522289f246SBrian Somers return 1; 3532289f246SBrian Somers IsInteractive(1); 3542289f246SBrian Somers 35583d1af55SBrian Somers SignalBundle = bundle; 3567a6f8720SBrian Somers 35785b542cfSBrian Somers if (SelectSystem(bundle, "default", CONFFILE) < 0) 35885b542cfSBrian Somers prompt_Printf(&prompt, 35985b542cfSBrian Somers "Warning: No default entry is given in config file.\n"); 3607a6f8720SBrian Somers 3611ae349f5Scvs2svn if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED)) 3621ae349f5Scvs2svn if (label == NULL) { 36385b542cfSBrian Somers prompt_Printf(&prompt, "Destination system must be specified in" 3641ae349f5Scvs2svn " auto, background or ddial mode.\n"); 3651ae349f5Scvs2svn return EX_START; 3661ae349f5Scvs2svn } 3671ae349f5Scvs2svn 3681ae349f5Scvs2svn pending_signal(SIGHUP, CloseSession); 3691ae349f5Scvs2svn pending_signal(SIGTERM, CloseSession); 3701ae349f5Scvs2svn pending_signal(SIGINT, CloseConnection); 3711ae349f5Scvs2svn pending_signal(SIGQUIT, CloseSession); 3723b0f8d2eSBrian Somers pending_signal(SIGALRM, SIG_IGN); 3731ae349f5Scvs2svn #ifdef SIGPIPE 3741ae349f5Scvs2svn signal(SIGPIPE, SIG_IGN); 3751ae349f5Scvs2svn #endif 3761ae349f5Scvs2svn if (mode & MODE_INTER) { 3771ae349f5Scvs2svn #ifdef SIGTSTP 3781ae349f5Scvs2svn pending_signal(SIGTSTP, TerminalStop); 3791ae349f5Scvs2svn #endif 3801ae349f5Scvs2svn #ifdef SIGTTIN 3811ae349f5Scvs2svn pending_signal(SIGTTIN, TerminalStop); 3821ae349f5Scvs2svn #endif 3831ae349f5Scvs2svn #ifdef SIGTTOU 3841ae349f5Scvs2svn pending_signal(SIGTTOU, SIG_IGN); 3851ae349f5Scvs2svn #endif 3861ae349f5Scvs2svn } 3871ae349f5Scvs2svn if (!(mode & MODE_INTER)) { 3881ae349f5Scvs2svn #ifdef SIGUSR1 3891ae349f5Scvs2svn pending_signal(SIGUSR1, SetUpServer); 3901ae349f5Scvs2svn #endif 3911ae349f5Scvs2svn #ifdef SIGUSR2 3921ae349f5Scvs2svn pending_signal(SIGUSR2, BringDownServer); 3931ae349f5Scvs2svn #endif 3941ae349f5Scvs2svn } 3951ae349f5Scvs2svn 3961ae349f5Scvs2svn if (label) { 3977a6f8720SBrian Somers if (SelectSystem(bundle, label, CONFFILE) < 0) { 3981ae349f5Scvs2svn LogPrintf(LogWARN, "Destination system %s not found in conf file.\n", 3991ae349f5Scvs2svn GetLabel()); 4001ae349f5Scvs2svn Cleanup(EX_START); 4011ae349f5Scvs2svn } 4021ae349f5Scvs2svn /* 4031ae349f5Scvs2svn * We don't SetLabel() 'till now in case SelectSystem() has an 4041ae349f5Scvs2svn * embeded load "otherlabel" command. 4051ae349f5Scvs2svn */ 4061ae349f5Scvs2svn SetLabel(label); 407aad81d1eSBrian Somers if (mode & MODE_AUTO && 4085828db6dSBrian Somers bundle->ncp.ipcp.cfg.peer_range.ipaddr.s_addr == INADDR_ANY) { 409aad81d1eSBrian Somers LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for auto mode.\n", 410aad81d1eSBrian Somers label); 4111ae349f5Scvs2svn Cleanup(EX_START); 4121ae349f5Scvs2svn } 4131ae349f5Scvs2svn } 4141ae349f5Scvs2svn 4151ae349f5Scvs2svn if (mode & MODE_DAEMON) { 4165cf4388bSBrian Somers if (!(mode & MODE_DIRECT)) { 4175cf4388bSBrian Somers int bgpipe[2]; 4185cf4388bSBrian Somers pid_t bgpid; 4195cf4388bSBrian Somers 4205cf4388bSBrian Somers if (mode & MODE_BACKGROUND && pipe(bgpipe)) { 4211ae349f5Scvs2svn LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 4221ae349f5Scvs2svn Cleanup(EX_SOCK); 4231ae349f5Scvs2svn } 4241ae349f5Scvs2svn 4251ae349f5Scvs2svn bgpid = fork(); 4261ae349f5Scvs2svn if (bgpid == -1) { 4271ae349f5Scvs2svn LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 4281ae349f5Scvs2svn Cleanup(EX_SOCK); 4291ae349f5Scvs2svn } 4305cf4388bSBrian Somers 4311ae349f5Scvs2svn if (bgpid) { 4321ae349f5Scvs2svn char c = EX_NORMAL; 4331ae349f5Scvs2svn 4341ae349f5Scvs2svn if (mode & MODE_BACKGROUND) { 4355cf4388bSBrian Somers close(bgpipe[1]); 43675b8d283SBrian Somers BGPid = bgpid; 43775b8d283SBrian Somers /* If we get a signal, kill the child */ 43875b8d283SBrian Somers signal(SIGHUP, KillChild); 43975b8d283SBrian Somers signal(SIGTERM, KillChild); 44075b8d283SBrian Somers signal(SIGINT, KillChild); 44175b8d283SBrian Somers signal(SIGQUIT, KillChild); 44275b8d283SBrian Somers 44375b8d283SBrian Somers /* Wait for our child to close its pipe before we exit */ 4445cf4388bSBrian Somers if (read(bgpipe[0], &c, 1) != 1) { 44585b542cfSBrian Somers prompt_Printf(&prompt, "Child exit, no status.\n"); 4461ae349f5Scvs2svn LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 4471ae349f5Scvs2svn } else if (c == EX_NORMAL) { 44885b542cfSBrian Somers prompt_Printf(&prompt, "PPP enabled.\n"); 4491ae349f5Scvs2svn LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 4501ae349f5Scvs2svn } else { 45185b542cfSBrian Somers prompt_Printf(&prompt, "Child failed (%s).\n", ex_desc((int) c)); 4521ae349f5Scvs2svn LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 4531ae349f5Scvs2svn ex_desc((int) c)); 4541ae349f5Scvs2svn } 4555cf4388bSBrian Somers close(bgpipe[0]); 4561ae349f5Scvs2svn } 4571ae349f5Scvs2svn return c; 4585cf4388bSBrian Somers } else if (mode & MODE_BACKGROUND) { 4595cf4388bSBrian Somers close(bgpipe[0]); 4605cf4388bSBrian Somers bundle->notify.fd = bgpipe[1]; 4615cf4388bSBrian Somers } 4621ae349f5Scvs2svn } 4631ae349f5Scvs2svn 46485b542cfSBrian Somers prompt_Init(&prompt, PROMPT_NONE); 4651ae349f5Scvs2svn close(STDOUT_FILENO); 4661ae349f5Scvs2svn close(STDERR_FILENO); 4671ae349f5Scvs2svn 4681ae349f5Scvs2svn if (mode & MODE_DIRECT) 469ecd5172aSBrian Somers /* STDIN_FILENO gets used by modem_Open in DIRECT mode */ 47085b542cfSBrian Somers prompt_TtyInit(&prompt, PROMPT_DONT_WANT_INT); 4711ae349f5Scvs2svn else if (mode & MODE_DAEMON) { 4721ae349f5Scvs2svn setsid(); 4731ae349f5Scvs2svn close(STDIN_FILENO); 4741ae349f5Scvs2svn } 4751ae349f5Scvs2svn } else { 4761ae349f5Scvs2svn close(STDERR_FILENO); 47785b542cfSBrian Somers prompt_TtyInit(&prompt, PROMPT_WANT_INT); 47885b542cfSBrian Somers prompt_TtyCommandMode(&prompt); 47985b542cfSBrian Somers prompt_Display(&prompt, bundle); 4801ae349f5Scvs2svn } 4811ae349f5Scvs2svn 4821ae349f5Scvs2svn snprintf(pid_filename, sizeof pid_filename, "%stun%d.pid", 483455aabc3SBrian Somers _PATH_VARRUN, bundle->unit); 4841ae349f5Scvs2svn lockfile = ID0fopen(pid_filename, "w"); 4851ae349f5Scvs2svn if (lockfile != NULL) { 4861ae349f5Scvs2svn fprintf(lockfile, "%d\n", (int) getpid()); 4871ae349f5Scvs2svn fclose(lockfile); 4881ae349f5Scvs2svn } 4891ae349f5Scvs2svn #ifndef RELEASE_CRUNCH 4901ae349f5Scvs2svn else 4911ae349f5Scvs2svn LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 4921ae349f5Scvs2svn pid_filename, strerror(errno)); 4931ae349f5Scvs2svn #endif 4941ae349f5Scvs2svn 4951ae349f5Scvs2svn LogPrintf(LogPHASE, "PPP Started.\n"); 4961ae349f5Scvs2svn 4971ae349f5Scvs2svn 4981ae349f5Scvs2svn do 4997a6f8720SBrian Somers DoLoop(bundle); 5001ae349f5Scvs2svn while (mode & MODE_DEDICATED); 5011ae349f5Scvs2svn 5021afedc4bSBrian Somers AbortProgram(EX_NORMAL); 5031afedc4bSBrian Somers 5041afedc4bSBrian Somers return EX_NORMAL; 5051ae349f5Scvs2svn } 5061ae349f5Scvs2svn 5071ae349f5Scvs2svn static void 5087a6f8720SBrian Somers DoLoop(struct bundle *bundle) 5091ae349f5Scvs2svn { 5101ae349f5Scvs2svn fd_set rfds, wfds, efds; 5113006ec67SBrian Somers int pri, i, n, nfds; 5121ae349f5Scvs2svn int qlen; 5131ae349f5Scvs2svn struct tun_data tun; 5141ae349f5Scvs2svn 515c5a5a6caSBrian Somers if (mode & (MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND)) 5163006ec67SBrian Somers bundle_Open(bundle, NULL); 5173006ec67SBrian Somers 5183b0f8d2eSBrian Somers while (!bundle_IsDead(bundle)) { 5191ae349f5Scvs2svn nfds = 0; 5201ae349f5Scvs2svn FD_ZERO(&rfds); 5211ae349f5Scvs2svn FD_ZERO(&wfds); 5221ae349f5Scvs2svn FD_ZERO(&efds); 5231ae349f5Scvs2svn 5243006ec67SBrian Somers qlen = bundle_FillQueues(bundle); 525b6dec9f0SBrian Somers 526b6dec9f0SBrian Somers handle_signals(); 527b6dec9f0SBrian Somers 5282f786681SBrian Somers descriptor_UpdateSet(&bundle->desc, &rfds, &wfds, &efds, &nfds); 52977ff88adSBrian Somers descriptor_UpdateSet(&server.desc, &rfds, &wfds, &efds, &nfds); 5301ae349f5Scvs2svn 5311ae349f5Scvs2svn /* If there are aren't many packets queued, look for some more. */ 5327a6f8720SBrian Somers if (qlen < 20 && bundle->tun_fd >= 0) { 5337a6f8720SBrian Somers if (bundle->tun_fd + 1 > nfds) 5347a6f8720SBrian Somers nfds = bundle->tun_fd + 1; 5357a6f8720SBrian Somers FD_SET(bundle->tun_fd, &rfds); 5361ae349f5Scvs2svn } 53777ff88adSBrian Somers 53885b542cfSBrian Somers descriptor_UpdateSet(&prompt.desc, &rfds, &wfds, &efds, &nfds); 53977ff88adSBrian Somers 5403b0f8d2eSBrian Somers if (bundle_IsDead(bundle)) 541f4768038SBrian Somers /* Don't select - we'll be here forever */ 542f4768038SBrian Somers break; 543f4768038SBrian Somers 5443006ec67SBrian Somers i = select(nfds, &rfds, &wfds, &efds, NULL); 5451ae349f5Scvs2svn 5463006ec67SBrian Somers if (i == 0) 5471ae349f5Scvs2svn continue; 54877ff88adSBrian Somers 5491ae349f5Scvs2svn if (i < 0) { 5501ae349f5Scvs2svn if (errno == EINTR) { 5511ae349f5Scvs2svn handle_signals(); 5521ae349f5Scvs2svn continue; 5531ae349f5Scvs2svn } 5541ae349f5Scvs2svn LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 5551ae349f5Scvs2svn break; 5561ae349f5Scvs2svn } 55777ff88adSBrian Somers 5583006ec67SBrian Somers for (i = 0; i <= nfds; i++) 5593006ec67SBrian Somers if (FD_ISSET(i, &efds)) { 5603006ec67SBrian Somers LogPrintf(LogALERT, "Exception detected on descriptor %d\n", i); 5611ae349f5Scvs2svn break; 5621ae349f5Scvs2svn } 56377ff88adSBrian Somers 56477ff88adSBrian Somers if (descriptor_IsSet(&server.desc, &rfds)) 565b77776a7SBrian Somers descriptor_Read(&server.desc, bundle, &rfds); 56642d4d396SBrian Somers 56785b542cfSBrian Somers if (descriptor_IsSet(&prompt.desc, &rfds)) 56885b542cfSBrian Somers descriptor_Read(&prompt.desc, bundle, &rfds); 56942d4d396SBrian Somers 5702f786681SBrian Somers if (descriptor_IsSet(&bundle->desc, &wfds)) 5712f786681SBrian Somers descriptor_Write(&bundle->desc, bundle, &wfds); 5722f786681SBrian Somers 5732f786681SBrian Somers if (descriptor_IsSet(&bundle->desc, &rfds)) 5742f786681SBrian Somers descriptor_Read(&bundle->desc, bundle, &rfds); 57542d4d396SBrian Somers 5767a6f8720SBrian Somers if (bundle->tun_fd >= 0 && FD_ISSET(bundle->tun_fd, &rfds)) { 5777a6f8720SBrian Somers /* something to read from tun */ 5787a6f8720SBrian Somers n = read(bundle->tun_fd, &tun, sizeof tun); 5791ae349f5Scvs2svn if (n < 0) { 5801ae349f5Scvs2svn LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 5811ae349f5Scvs2svn continue; 5821ae349f5Scvs2svn } 5831ae349f5Scvs2svn n -= sizeof tun - sizeof tun.data; 5841ae349f5Scvs2svn if (n <= 0) { 5851ae349f5Scvs2svn LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n); 5861ae349f5Scvs2svn continue; 5871ae349f5Scvs2svn } 5881ae349f5Scvs2svn if (!tun_check_header(tun, AF_INET)) 5891ae349f5Scvs2svn continue; 5905828db6dSBrian Somers if (((struct ip *)tun.data)->ip_dst.s_addr == 5915828db6dSBrian Somers bundle->ncp.ipcp.my_ip.s_addr) { 5921ae349f5Scvs2svn /* we've been asked to send something addressed *to* us :( */ 5931ae349f5Scvs2svn if (VarLoopback) { 5945ca5389aSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); 5951ae349f5Scvs2svn if (pri >= 0) { 5961ae349f5Scvs2svn struct mbuf *bp; 5971ae349f5Scvs2svn 5981ae349f5Scvs2svn #ifndef NOALIAS 5991ae349f5Scvs2svn if (mode & MODE_ALIAS) { 600f4768038SBrian Somers VarPacketAliasIn(tun.data, sizeof tun.data); 601f4768038SBrian Somers n = ntohs(((struct ip *)tun.data)->ip_len); 6021ae349f5Scvs2svn } 6031ae349f5Scvs2svn #endif 6041ae349f5Scvs2svn bp = mballoc(n, MB_IPIN); 605f4768038SBrian Somers memcpy(MBUF_CTOP(bp), tun.data, n); 6067a6f8720SBrian Somers IpInput(bundle, bp); 6071ae349f5Scvs2svn LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 6081ae349f5Scvs2svn } 6091ae349f5Scvs2svn continue; 6101ae349f5Scvs2svn } else 6111ae349f5Scvs2svn LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 6121ae349f5Scvs2svn } 6131ae349f5Scvs2svn 6141ae349f5Scvs2svn /* 6151ae349f5Scvs2svn * Process on-demand dialup. Output packets are queued within tunnel 6161ae349f5Scvs2svn * device until IPCP is opened. 6171ae349f5Scvs2svn */ 6189e46ce35SBrian Somers if (bundle_Phase(bundle) == PHASE_DEAD && (mode & MODE_AUTO) && 6195ca5389aSBrian Somers (pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) 6203006ec67SBrian Somers bundle_Open(bundle, NULL); 6211ae349f5Scvs2svn 6225ca5389aSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); 6231ae349f5Scvs2svn if (pri >= 0) { 6241ae349f5Scvs2svn #ifndef NOALIAS 6251ae349f5Scvs2svn if (mode & MODE_ALIAS) { 626f4768038SBrian Somers VarPacketAliasOut(tun.data, sizeof tun.data); 627f4768038SBrian Somers n = ntohs(((struct ip *)tun.data)->ip_len); 6281ae349f5Scvs2svn } 6291ae349f5Scvs2svn #endif 630f4768038SBrian Somers IpEnqueue(pri, tun.data, n); 6311ae349f5Scvs2svn } 6321ae349f5Scvs2svn } 6331ae349f5Scvs2svn } 6343b0f8d2eSBrian Somers prompt_Printf(&prompt, "\n"); 6351ae349f5Scvs2svn LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 6361ae349f5Scvs2svn } 637