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 * 2039f94eddSBrian Somers * $Id: main.c,v 1.100 1997/11/17 00:42:40 brian Exp $ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai * o Add commands for traffic summary, version display, etc. 24af57ed9fSAtsushi Murai * o Add signal handler for misc controls. 25af57ed9fSAtsushi Murai */ 2675240ed1SBrian Somers #include <sys/param.h> 276a6b4bbbSBrian Somers #include <sys/time.h> 286a6b4bbbSBrian Somers #include <sys/select.h> 29af57ed9fSAtsushi Murai #include <sys/socket.h> 3075240ed1SBrian Somers #include <netinet/in.h> 31a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h> 32a9f484e5SJordan K. Hubbard #include <netinet/ip.h> 3375240ed1SBrian Somers #include <arpa/inet.h> 3475240ed1SBrian Somers #include <netdb.h> 356a6b4bbbSBrian Somers #include <net/if.h> 366a6b4bbbSBrian Somers #include <net/if_var.h> 376a6b4bbbSBrian Somers #include <net/if_tun.h> 3875240ed1SBrian Somers 3975240ed1SBrian Somers #include <errno.h> 4075240ed1SBrian Somers #include <fcntl.h> 4175240ed1SBrian Somers #include <paths.h> 4275240ed1SBrian Somers #include <signal.h> 4375240ed1SBrian Somers #include <stdio.h> 4475240ed1SBrian Somers #include <stdlib.h> 4575240ed1SBrian Somers #include <string.h> 4675240ed1SBrian Somers #include <sys/time.h> 4775240ed1SBrian Somers #include <sys/wait.h> 48683cef3cSBrian Somers #include <sysexits.h> 4975240ed1SBrian Somers #include <termios.h> 5075240ed1SBrian Somers #include <unistd.h> 5175240ed1SBrian Somers 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" 58af57ed9fSAtsushi Murai #include "modem.h" 59af57ed9fSAtsushi Murai #include "os.h" 60af57ed9fSAtsushi Murai #include "hdlc.h" 61ed6a16c1SPoul-Henning Kamp #include "ccp.h" 62af57ed9fSAtsushi Murai #include "lcp.h" 63af57ed9fSAtsushi Murai #include "ipcp.h" 646ed9fb2fSBrian Somers #include "loadalias.h" 6575240ed1SBrian Somers #include "command.h" 66af57ed9fSAtsushi Murai #include "vars.h" 6753c9f6c0SAtsushi Murai #include "auth.h" 6884b8a6ebSAtsushi Murai #include "filter.h" 69ed6a16c1SPoul-Henning Kamp #include "systems.h" 70ed6a16c1SPoul-Henning Kamp #include "ip.h" 71f5ff0f7cSBrian Somers #include "sig.h" 724ef16f24SBrian Somers #include "server.h" 73de451c68SBrian Somers #include "lcpproto.h" 7475240ed1SBrian Somers #include "main.h" 7575240ed1SBrian Somers #include "vjcomp.h" 7675240ed1SBrian Somers #include "async.h" 774562be74SBrian Somers #include "pathnames.h" 786a6b4bbbSBrian Somers #include "tun.h" 7953c9f6c0SAtsushi Murai 8053c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 8153c9f6c0SAtsushi Murai #ifdef O_NDELAY 8253c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 8353c9f6c0SAtsushi Murai #endif 8453c9f6c0SAtsushi Murai #endif 85af57ed9fSAtsushi Murai 8675240ed1SBrian Somers int TermMode = 0; 8775240ed1SBrian Somers int tunno = 0; 88af57ed9fSAtsushi Murai 89af57ed9fSAtsushi Murai static struct termios oldtio; /* Original tty mode */ 90af57ed9fSAtsushi Murai static struct termios comtio; /* Command level tty mode */ 916d14e2a8SJordan K. Hubbard static pid_t BGPid = 0; 9241c6c543SBrian Somers static char pid_filename[MAXPATHLEN]; 9376c5241dSBrian Somers static int dial_up; 94af57ed9fSAtsushi Murai 9575240ed1SBrian Somers static void DoLoop(void); 9675240ed1SBrian Somers static void TerminalStop(int); 9775240ed1SBrian Somers static char *ex_desc(int); 9875240ed1SBrian Somers 99af57ed9fSAtsushi Murai static void 100368aee2bSBrian Somers TtyInit(int DontWantInt) 101af57ed9fSAtsushi Murai { 102af57ed9fSAtsushi Murai struct termios newtio; 103af57ed9fSAtsushi Murai int stat; 104af57ed9fSAtsushi Murai 105af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 106274e766cSBrian Somers if (stat > 0) { 107af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 108274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 109274e766cSBrian Somers } 110af57ed9fSAtsushi Murai newtio = oldtio; 111af57ed9fSAtsushi Murai newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 112af57ed9fSAtsushi Murai newtio.c_iflag = 0; 113af57ed9fSAtsushi Murai newtio.c_oflag &= ~OPOST; 114af57ed9fSAtsushi Murai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 115368aee2bSBrian Somers if (DontWantInt) 116af57ed9fSAtsushi Murai newtio.c_cc[VINTR] = _POSIX_VDISABLE; 117af57ed9fSAtsushi Murai newtio.c_cc[VMIN] = 1; 118af57ed9fSAtsushi Murai newtio.c_cc[VTIME] = 0; 119af57ed9fSAtsushi Murai newtio.c_cflag |= CS8; 12053c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 121af57ed9fSAtsushi Murai comtio = newtio; 122af57ed9fSAtsushi Murai } 123af57ed9fSAtsushi Murai 124af57ed9fSAtsushi Murai /* 125af57ed9fSAtsushi Murai * Set tty into command mode. We allow canonical input and echo processing. 126af57ed9fSAtsushi Murai */ 127c3899f8dSAtsushi Murai void 128944f7098SBrian Somers TtyCommandMode(int prompt) 129af57ed9fSAtsushi Murai { 130af57ed9fSAtsushi Murai struct termios newtio; 131af57ed9fSAtsushi Murai int stat; 132af57ed9fSAtsushi Murai 133af57ed9fSAtsushi Murai if (!(mode & MODE_INTER)) 134af57ed9fSAtsushi Murai return; 13553c9f6c0SAtsushi Murai tcgetattr(0, &newtio); 136c3899f8dSAtsushi Murai newtio.c_lflag |= (ECHO | ISIG | ICANON); 137af57ed9fSAtsushi Murai newtio.c_iflag = oldtio.c_iflag; 138af57ed9fSAtsushi Murai newtio.c_oflag |= OPOST; 13953c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 140af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 141274e766cSBrian Somers if (stat > 0) { 142af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 143274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 144274e766cSBrian Somers } 145af57ed9fSAtsushi Murai TermMode = 0; 146944f7098SBrian Somers if (prompt) 147944f7098SBrian Somers Prompt(); 148af57ed9fSAtsushi Murai } 149af57ed9fSAtsushi Murai 150af57ed9fSAtsushi Murai /* 151af57ed9fSAtsushi Murai * Set tty into terminal mode which is used while we invoke term command. 152af57ed9fSAtsushi Murai */ 153af57ed9fSAtsushi Murai void 154af57ed9fSAtsushi Murai TtyTermMode() 155af57ed9fSAtsushi Murai { 156af57ed9fSAtsushi Murai int stat; 157af57ed9fSAtsushi Murai 15853c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &comtio); 159af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 160274e766cSBrian Somers if (stat > 0) { 161af57ed9fSAtsushi Murai stat &= ~O_NONBLOCK; 162274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 163274e766cSBrian Somers } 164af57ed9fSAtsushi Murai TermMode = 1; 165af57ed9fSAtsushi Murai } 166af57ed9fSAtsushi Murai 167af57ed9fSAtsushi Murai void 168c3899f8dSAtsushi Murai TtyOldMode() 169c3899f8dSAtsushi Murai { 170c3899f8dSAtsushi Murai int stat; 171c3899f8dSAtsushi Murai 172c3899f8dSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 173274e766cSBrian Somers if (stat > 0) { 174c3899f8dSAtsushi Murai stat &= ~O_NONBLOCK; 175274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 176274e766cSBrian Somers } 177c3899f8dSAtsushi Murai tcsetattr(0, TCSANOW, &oldtio); 178c3899f8dSAtsushi Murai } 179c3899f8dSAtsushi Murai 180c3899f8dSAtsushi Murai void 181944f7098SBrian Somers Cleanup(int excode) 182af57ed9fSAtsushi Murai { 1838ea8442cSBrian Somers ServerClose(); 1840fe7ca31SBrian Somers OsInterfaceDown(1); 1850fe7ca31SBrian Somers HangupModem(1); 1869a571ec7SBrian Somers nointr_sleep(1); 1876e4959f0SBrian Somers DeleteIfRoutes(1); 1885106c671SBrian Somers ID0unlink(pid_filename); 1896e4959f0SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 1906e4959f0SBrian Somers char c = EX_ERRDEAD; 191944f7098SBrian Somers 1926e4959f0SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 193927145beSBrian Somers LogPrintf(LogPHASE, "Parent notified of failure.\n"); 1946e4959f0SBrian Somers else 195927145beSBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); 1966e4959f0SBrian Somers close(BGFiledes[1]); 1976e4959f0SBrian Somers } 198927145beSBrian Somers LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 199c3899f8dSAtsushi Murai TtyOldMode(); 2005106c671SBrian Somers LogClose(); 201af57ed9fSAtsushi Murai 202af57ed9fSAtsushi Murai exit(excode); 203af57ed9fSAtsushi Murai } 204af57ed9fSAtsushi Murai 205af57ed9fSAtsushi Murai static void 206944f7098SBrian Somers CloseConnection(int signo) 207af57ed9fSAtsushi Murai { 208368aee2bSBrian Somers /* NOTE, these are manual, we've done a setsid() */ 20912ef29a8SBrian Somers pending_signal(SIGINT, SIG_IGN); 210873725ccSBrian Somers LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 211944f7098SBrian Somers reconnectState = RECON_FALSE; 212944f7098SBrian Somers reconnectCount = 0; 213368aee2bSBrian Somers DownConnection(); 21475240ed1SBrian Somers dial_up = 0; 21512ef29a8SBrian Somers pending_signal(SIGINT, CloseConnection); 2166d14e2a8SJordan K. Hubbard } 217af57ed9fSAtsushi Murai 218af57ed9fSAtsushi Murai static void 219944f7098SBrian Somers CloseSession(int signo) 220af57ed9fSAtsushi Murai { 2216d14e2a8SJordan K. Hubbard if (BGPid) { 2226d14e2a8SJordan K. Hubbard kill(BGPid, SIGINT); 2236d14e2a8SJordan K. Hubbard exit(EX_TERM); 2246d14e2a8SJordan K. Hubbard } 225927145beSBrian Somers LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 22625aa96acSBrian Somers reconnect(RECON_FALSE); 227af57ed9fSAtsushi Murai LcpClose(); 228af57ed9fSAtsushi Murai Cleanup(EX_TERM); 229af57ed9fSAtsushi Murai } 230c3899f8dSAtsushi Murai 231c3899f8dSAtsushi Murai static void 232c3899f8dSAtsushi Murai TerminalCont() 233c3899f8dSAtsushi Murai { 234f5ff0f7cSBrian Somers pending_signal(SIGCONT, SIG_DFL); 235f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 236c3899f8dSAtsushi Murai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 237c3899f8dSAtsushi Murai } 238c3899f8dSAtsushi Murai 239c3899f8dSAtsushi Murai static void 240944f7098SBrian Somers TerminalStop(int signo) 241c3899f8dSAtsushi Murai { 242f5ff0f7cSBrian Somers pending_signal(SIGCONT, TerminalCont); 243c3899f8dSAtsushi Murai TtyOldMode(); 244f5ff0f7cSBrian Somers pending_signal(SIGTSTP, SIG_DFL); 245c3899f8dSAtsushi Murai kill(getpid(), signo); 246c3899f8dSAtsushi Murai } 247c3899f8dSAtsushi Murai 2484ef16f24SBrian Somers static void 249944f7098SBrian Somers SetUpServer(int signo) 2504ef16f24SBrian Somers { 2514ef16f24SBrian Somers int res; 252944f7098SBrian Somers 2538ea8442cSBrian Somers VarHaveLocalAuthKey = 0; 2548ea8442cSBrian Somers LocalAuthInit(); 2554ef16f24SBrian Somers if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) 256683cef3cSBrian Somers LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 257683cef3cSBrian Somers res, SERVER_PORT + tunno); 2584ef16f24SBrian Somers } 2594ef16f24SBrian Somers 2608ea8442cSBrian Somers static void 2618ea8442cSBrian Somers BringDownServer(int signo) 2628ea8442cSBrian Somers { 2638ea8442cSBrian Somers VarHaveLocalAuthKey = 0; 2648ea8442cSBrian Somers LocalAuthInit(); 2658ea8442cSBrian Somers ServerClose(); 2668ea8442cSBrian Somers } 2678ea8442cSBrian Somers 2686efd9292SBrian Somers static char * 2696efd9292SBrian Somers ex_desc(int ex) 2706efd9292SBrian Somers { 2716efd9292SBrian Somers static char num[12]; 2726efd9292SBrian Somers static char *desc[] = {"normal", "start", "sock", 2736efd9292SBrian Somers "modem", "dial", "dead", "done", "reboot", "errdead", 2746efd9292SBrian Somers "hangup", "term", "nodial", "nologin"}; 2756efd9292SBrian Somers 2766efd9292SBrian Somers if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc)) 2776efd9292SBrian Somers return desc[ex]; 2786efd9292SBrian Somers snprintf(num, sizeof num, "%d", ex); 2796efd9292SBrian Somers return num; 2806efd9292SBrian Somers } 281c3899f8dSAtsushi Murai 28275240ed1SBrian Somers static void 283af57ed9fSAtsushi Murai Usage() 284af57ed9fSAtsushi Murai { 285680026d6SNate Williams fprintf(stderr, 2866d14e2a8SJordan K. Hubbard "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 287af57ed9fSAtsushi Murai exit(EX_START); 288af57ed9fSAtsushi Murai } 289af57ed9fSAtsushi Murai 29039f94eddSBrian Somers static char * 291af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv) 292af57ed9fSAtsushi Murai { 293af57ed9fSAtsushi Murai int optc; 294af57ed9fSAtsushi Murai char *cp; 295af57ed9fSAtsushi Murai 296af57ed9fSAtsushi Murai optc = 0; 29712ef29a8SBrian Somers mode = MODE_INTER; 298af57ed9fSAtsushi Murai while (argc > 0 && **argv == '-') { 299af57ed9fSAtsushi Murai cp = *argv + 1; 30012ef29a8SBrian Somers if (strcmp(cp, "auto") == 0) { 301af57ed9fSAtsushi Murai mode |= MODE_AUTO; 30212ef29a8SBrian Somers mode &= ~MODE_INTER; 30312ef29a8SBrian Somers } else if (strcmp(cp, "background") == 0) { 30412ef29a8SBrian Somers mode |= MODE_BACKGROUND; 30512ef29a8SBrian Somers mode &= ~MODE_INTER; 30612ef29a8SBrian Somers } else if (strcmp(cp, "direct") == 0) { 307af57ed9fSAtsushi Murai mode |= MODE_DIRECT; 30812ef29a8SBrian Somers mode &= ~MODE_INTER; 30912ef29a8SBrian Somers } else if (strcmp(cp, "dedicated") == 0) { 310af57ed9fSAtsushi Murai mode |= MODE_DEDICATED; 31112ef29a8SBrian Somers mode &= ~MODE_INTER; 31212ef29a8SBrian Somers } else if (strcmp(cp, "ddial") == 0) { 31312ef29a8SBrian Somers mode |= MODE_DDIAL; 31412ef29a8SBrian Somers mode &= ~MODE_INTER; 31512ef29a8SBrian Somers } else if (strcmp(cp, "alias") == 0) { 3166ed9fb2fSBrian Somers if (loadAliasHandlers(&VarAliasHandlers) == 0) 317a9f484e5SJordan K. Hubbard mode |= MODE_ALIAS; 3186ed9fb2fSBrian Somers else 319927145beSBrian Somers LogPrintf(LogWARN, "Cannot load alias library\n"); 320a9f484e5SJordan K. Hubbard optc--; /* this option isn't exclusive */ 321944f7098SBrian Somers } else 322af57ed9fSAtsushi Murai Usage(); 323af57ed9fSAtsushi Murai optc++; 324944f7098SBrian Somers argv++; 325944f7098SBrian Somers argc--; 326af57ed9fSAtsushi Murai } 327af57ed9fSAtsushi Murai if (argc > 1) { 328af57ed9fSAtsushi Murai fprintf(stderr, "specify only one system label.\n"); 329af57ed9fSAtsushi Murai exit(EX_START); 330af57ed9fSAtsushi Murai } 331af57ed9fSAtsushi Murai 332af57ed9fSAtsushi Murai if (optc > 1) { 333af57ed9fSAtsushi Murai fprintf(stderr, "specify only one mode.\n"); 334af57ed9fSAtsushi Murai exit(EX_START); 335af57ed9fSAtsushi Murai } 33639f94eddSBrian Somers 33739f94eddSBrian Somers return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ 338af57ed9fSAtsushi Murai } 339af57ed9fSAtsushi Murai 340af57ed9fSAtsushi Murai static void 341af57ed9fSAtsushi Murai Greetings() 342af57ed9fSAtsushi Murai { 343927145beSBrian Somers if (VarTerm) { 344927145beSBrian Somers fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 345927145beSBrian Somers fflush(VarTerm); 346927145beSBrian Somers } 347af57ed9fSAtsushi Murai } 348af57ed9fSAtsushi Murai 3494ef16f24SBrian Somers int 350944f7098SBrian Somers main(int argc, char **argv) 351af57ed9fSAtsushi Murai { 352aefd026aSBrian Somers FILE *lockfile; 35339f94eddSBrian Somers char *name, *label; 354af57ed9fSAtsushi Murai 3550706ff38SBrian Somers VarTerm = 0; 35675240ed1SBrian Somers name = strrchr(argv[0], '/'); 357927145beSBrian Somers LogOpen(name ? name + 1 : argv[0]); 358927145beSBrian Somers 359944f7098SBrian Somers argc--; 360944f7098SBrian Somers argv++; 36139f94eddSBrian Somers label = ProcessArgs(argc, argv); 36212ef29a8SBrian Somers if (!(mode & MODE_DIRECT)) 3630706ff38SBrian Somers VarTerm = stdout; 36412ef29a8SBrian Somers 3655106c671SBrian Somers ID0init(); 3664562be74SBrian Somers if (ID0realuid() != 0) { 3674562be74SBrian Somers char conf[200], *ptr; 3684562be74SBrian Somers 3694562be74SBrian Somers snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 3704562be74SBrian Somers do { 3714562be74SBrian Somers if (!access(conf, W_OK)) { 3724562be74SBrian Somers LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); 3734562be74SBrian Somers return -1; 3744562be74SBrian Somers } 3754562be74SBrian Somers ptr = conf + strlen(conf)-2; 3764562be74SBrian Somers while (ptr > conf && *ptr != '/') 3774562be74SBrian Somers *ptr-- = '\0'; 3784562be74SBrian Somers } while (ptr >= conf); 3794562be74SBrian Somers } 3804562be74SBrian Somers 38139f94eddSBrian Somers if (!ValidSystem(label)) { 38212ef29a8SBrian Somers fprintf(stderr, "You may not use ppp in this mode with this label\n"); 383815624cfSBrian Somers if (mode & MODE_DIRECT) { 384815624cfSBrian Somers const char *l; 38539f94eddSBrian Somers l = label ? label : "default"; 386815624cfSBrian Somers VarTerm = 0; 387815624cfSBrian Somers LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); 388815624cfSBrian Somers } 389815624cfSBrian Somers LogClose(); 39012ef29a8SBrian Somers return 1; 39112ef29a8SBrian Somers } 39212ef29a8SBrian Somers 393c7d4711fSBrian Somers if (!GetShortHost()) 394c7d4711fSBrian Somers return 1; 395af57ed9fSAtsushi Murai Greetings(); 396af57ed9fSAtsushi Murai IpcpDefAddress(); 397af57ed9fSAtsushi Murai 398927145beSBrian Somers if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 399927145beSBrian Somers fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 400af57ed9fSAtsushi Murai 401af57ed9fSAtsushi Murai if (OpenTunnel(&tunno) < 0) { 4024ef16f24SBrian Somers LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno)); 4034ef16f24SBrian Somers return EX_START; 404af57ed9fSAtsushi Murai } 405af57ed9fSAtsushi Murai if (mode & MODE_INTER) { 406927145beSBrian Somers fprintf(VarTerm, "Interactive mode\n"); 407cc39a98fSBrian Somers netfd = STDOUT_FILENO; 40812ef29a8SBrian Somers } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED)) 40939f94eddSBrian Somers if (label == NULL) { 410927145beSBrian Somers if (VarTerm) 411927145beSBrian Somers fprintf(VarTerm, "Destination system must be specified in" 4126efd9292SBrian Somers " auto, background or ddial mode.\n"); 4134ef16f24SBrian Somers return EX_START; 4146d14e2a8SJordan K. Hubbard } 41512ef29a8SBrian Somers 41653c9f6c0SAtsushi Murai tcgetattr(0, &oldtio); /* Save original tty mode */ 417af57ed9fSAtsushi Murai 418873725ccSBrian Somers pending_signal(SIGHUP, CloseSession); 419f5ff0f7cSBrian Somers pending_signal(SIGTERM, CloseSession); 420873725ccSBrian Somers pending_signal(SIGINT, CloseConnection); 421f5ff0f7cSBrian Somers pending_signal(SIGQUIT, CloseSession); 42253c9f6c0SAtsushi Murai #ifdef SIGPIPE 423e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 42453c9f6c0SAtsushi Murai #endif 42553c9f6c0SAtsushi Murai #ifdef SIGALRM 426f5ff0f7cSBrian Somers pending_signal(SIGALRM, SIG_IGN); 42753c9f6c0SAtsushi Murai #endif 4284ef16f24SBrian Somers if (mode & MODE_INTER) { 429c3899f8dSAtsushi Murai #ifdef SIGTSTP 430f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 431c3899f8dSAtsushi Murai #endif 432c3899f8dSAtsushi Murai #ifdef SIGTTIN 433f5ff0f7cSBrian Somers pending_signal(SIGTTIN, TerminalStop); 434c3899f8dSAtsushi Murai #endif 435c3899f8dSAtsushi Murai #ifdef SIGTTOU 436f5ff0f7cSBrian Somers pending_signal(SIGTTOU, SIG_IGN); 437c3899f8dSAtsushi Murai #endif 438c3899f8dSAtsushi Murai } 43912ef29a8SBrian Somers if (!(mode & MODE_INTER)) { 4404ef16f24SBrian Somers #ifdef SIGUSR1 4414ef16f24SBrian Somers pending_signal(SIGUSR1, SetUpServer); 4424ef16f24SBrian Somers #endif 4438ea8442cSBrian Somers #ifdef SIGUSR2 4448ea8442cSBrian Somers pending_signal(SIGUSR2, BringDownServer); 4458ea8442cSBrian Somers #endif 44612ef29a8SBrian Somers } 447af57ed9fSAtsushi Murai 44839f94eddSBrian Somers if (label) { 44939f94eddSBrian Somers if (SelectSystem(label, CONFFILE) < 0) { 450e4450123SBrian Somers LogPrintf(LogWARN, "Destination system %s not found in conf file.\n", 451e4450123SBrian Somers GetLabel()); 452af57ed9fSAtsushi Murai Cleanup(EX_START); 453af57ed9fSAtsushi Murai } 45439f94eddSBrian Somers /* 45539f94eddSBrian Somers * We don't SetLabel() 'till now in case SelectSystem() has an 45639f94eddSBrian Somers * embeded load "otherlabel" command. 45739f94eddSBrian Somers */ 45839f94eddSBrian Somers SetLabel(label); 45912ef29a8SBrian Somers if (mode & MODE_OUTGOING_DAEMON && 46012ef29a8SBrian Somers DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 461e4450123SBrian Somers LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for" 46239f94eddSBrian Somers " auto, background or ddial mode.\n", label); 463af57ed9fSAtsushi Murai Cleanup(EX_START); 464af57ed9fSAtsushi Murai } 465af57ed9fSAtsushi Murai } 4666efd9292SBrian Somers 46712ef29a8SBrian Somers if (mode & MODE_DAEMON) { 4686d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 4696d14e2a8SJordan K. Hubbard if (pipe(BGFiledes)) { 470afc7fa2cSBrian Somers LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 4716d14e2a8SJordan K. Hubbard Cleanup(EX_SOCK); 4726d14e2a8SJordan K. Hubbard } 4736d14e2a8SJordan K. Hubbard } 474af57ed9fSAtsushi Murai 475af57ed9fSAtsushi Murai if (!(mode & MODE_DIRECT)) { 4766d14e2a8SJordan K. Hubbard pid_t bgpid; 477a9c6b5dfSAtsushi Murai 4786d14e2a8SJordan K. Hubbard bgpid = fork(); 4796d14e2a8SJordan K. Hubbard if (bgpid == -1) { 480afc7fa2cSBrian Somers LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 4816d14e2a8SJordan K. Hubbard Cleanup(EX_SOCK); 4826d14e2a8SJordan K. Hubbard } 4836d14e2a8SJordan K. Hubbard if (bgpid) { 4846d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 485a9c6b5dfSAtsushi Murai 4866d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 4876d14e2a8SJordan K. Hubbard /* Wait for our child to close its pipe before we exit. */ 4886d14e2a8SJordan K. Hubbard BGPid = bgpid; 4896e4959f0SBrian Somers close(BGFiledes[1]); 4906efd9292SBrian Somers if (read(BGFiledes[0], &c, 1) != 1) { 491927145beSBrian Somers fprintf(VarTerm, "Child exit, no status.\n"); 492927145beSBrian Somers LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 4936efd9292SBrian Somers } else if (c == EX_NORMAL) { 494927145beSBrian Somers fprintf(VarTerm, "PPP enabled.\n"); 495927145beSBrian Somers LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 4966efd9292SBrian Somers } else { 497927145beSBrian Somers fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 498927145beSBrian Somers LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 49980e37c72SBrian Somers ex_desc((int) c)); 5006efd9292SBrian Somers } 5016e4959f0SBrian Somers close(BGFiledes[0]); 5026d14e2a8SJordan K. Hubbard } 5034ef16f24SBrian Somers return c; 5046e4959f0SBrian Somers } else if (mode & MODE_BACKGROUND) 5056e4959f0SBrian Somers close(BGFiledes[0]); 506aefd026aSBrian Somers } 507aefd026aSBrian Somers 508d656a4c5SBrian Somers VarTerm = 0; /* We know it's currently stdout */ 509fd2bc5ebSBrian Somers close(1); 510d656a4c5SBrian Somers close(2); 5110706ff38SBrian Somers 512d656a4c5SBrian Somers if (mode & MODE_DIRECT) 513368aee2bSBrian Somers TtyInit(1); 51412ef29a8SBrian Somers else if (mode & MODE_DAEMON) { 515d656a4c5SBrian Somers setsid(); 516fd2bc5ebSBrian Somers close(0); 517d656a4c5SBrian Somers } 518af57ed9fSAtsushi Murai } else { 519368aee2bSBrian Somers TtyInit(0); 520c3899f8dSAtsushi Murai TtyCommandMode(1); 521af57ed9fSAtsushi Murai } 52235495becSBrian Somers 52335495becSBrian Somers snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid", 52435495becSBrian Somers _PATH_VARRUN, tunno); 5255106c671SBrian Somers lockfile = ID0fopen(pid_filename, "w"); 5265106c671SBrian Somers if (lockfile != NULL) { 52735495becSBrian Somers fprintf(lockfile, "%d\n", (int) getpid()); 52835495becSBrian Somers fclose(lockfile); 52935495becSBrian Somers } else 53035495becSBrian Somers LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 53135495becSBrian Somers pid_filename, strerror(errno)); 53235495becSBrian Somers 533927145beSBrian Somers LogPrintf(LogPHASE, "PPP Started.\n"); 534af57ed9fSAtsushi Murai 535af57ed9fSAtsushi Murai 536af57ed9fSAtsushi Murai do 537af57ed9fSAtsushi Murai DoLoop(); 538af57ed9fSAtsushi Murai while (mode & MODE_DEDICATED); 539af57ed9fSAtsushi Murai 540af57ed9fSAtsushi Murai Cleanup(EX_DONE); 5414ef16f24SBrian Somers return 0; 542af57ed9fSAtsushi Murai } 543af57ed9fSAtsushi Murai 544af57ed9fSAtsushi Murai /* 5456d14e2a8SJordan K. Hubbard * Turn into packet mode, where we speak PPP. 546af57ed9fSAtsushi Murai */ 547af57ed9fSAtsushi Murai void 548af57ed9fSAtsushi Murai PacketMode() 549af57ed9fSAtsushi Murai { 5509780ef31SBrian Somers if (RawModem() < 0) { 551927145beSBrian Somers LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 552af57ed9fSAtsushi Murai return; 553af57ed9fSAtsushi Murai } 554af57ed9fSAtsushi Murai AsyncInit(); 55503604f35SBrian Somers VjInit(15); 556af57ed9fSAtsushi Murai LcpInit(); 557af57ed9fSAtsushi Murai IpcpInit(); 558af57ed9fSAtsushi Murai CcpInit(); 559af57ed9fSAtsushi Murai LcpUp(); 560af57ed9fSAtsushi Murai 561af57ed9fSAtsushi Murai LcpOpen(VarOpenMode); 56212ef29a8SBrian Somers if (mode & MODE_INTER) 563c3899f8dSAtsushi Murai TtyCommandMode(1); 564927145beSBrian Somers if (VarTerm) { 565927145beSBrian Somers fprintf(VarTerm, "Packet mode.\n"); 566b0cdb3ceSJordan K. Hubbard aft_cmd = 1; 567af57ed9fSAtsushi Murai } 568af57ed9fSAtsushi Murai } 569af57ed9fSAtsushi Murai 570af57ed9fSAtsushi Murai static void 571af57ed9fSAtsushi Murai ShowHelp() 572af57ed9fSAtsushi Murai { 573030d3ce6SBrian Somers fprintf(stderr, "The following commands are available:\r\n"); 574030d3ce6SBrian Somers fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 575030d3ce6SBrian Somers fprintf(stderr, " ~-\tDecrease log level\r\n"); 576030d3ce6SBrian Somers fprintf(stderr, " ~+\tIncrease log level\r\n"); 577030d3ce6SBrian Somers fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 578030d3ce6SBrian Somers fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 579030d3ce6SBrian Somers fprintf(stderr, " ~.\tTerminate program\r\n"); 580030d3ce6SBrian Somers fprintf(stderr, " ~?\tThis help\r\n"); 581af57ed9fSAtsushi Murai } 582af57ed9fSAtsushi Murai 583af57ed9fSAtsushi Murai static void 584af57ed9fSAtsushi Murai ReadTty() 585af57ed9fSAtsushi Murai { 586af57ed9fSAtsushi Murai int n; 587af57ed9fSAtsushi Murai char ch; 588af57ed9fSAtsushi Murai static int ttystate; 589927145beSBrian Somers FILE *oVarTerm; 59086e02934SBrian Somers char linebuff[LINE_LEN]; 591af57ed9fSAtsushi Murai 592927145beSBrian Somers LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 593927145beSBrian Somers TermMode, netfd, mode); 594af57ed9fSAtsushi Murai if (!TermMode) { 595af57ed9fSAtsushi Murai n = read(netfd, linebuff, sizeof(linebuff) - 1); 59653c9f6c0SAtsushi Murai if (n > 0) { 597927145beSBrian Somers aft_cmd = 1; 598a1e8f937SBrian Somers if (linebuff[n-1] == '\n') 599a1e8f937SBrian Somers linebuff[--n] = '\0'; 600d9181b05SBrian Somers if (n) 601d9181b05SBrian Somers DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client"); 602a1e8f937SBrian Somers Prompt(); 60353c9f6c0SAtsushi Murai } else { 604927145beSBrian Somers LogPrintf(LogPHASE, "client connection closed.\n"); 605927145beSBrian Somers oVarTerm = VarTerm; 606927145beSBrian Somers VarTerm = 0; 607927145beSBrian Somers if (oVarTerm && oVarTerm != stdout) 608927145beSBrian Somers fclose(oVarTerm); 609927145beSBrian Somers close(netfd); 610927145beSBrian Somers netfd = -1; 611af57ed9fSAtsushi Murai } 612af57ed9fSAtsushi Murai return; 613af57ed9fSAtsushi Murai } 614af57ed9fSAtsushi Murai 615af57ed9fSAtsushi Murai /* 616af57ed9fSAtsushi Murai * We are in terminal mode, decode special sequences 617af57ed9fSAtsushi Murai */ 618927145beSBrian Somers n = read(fileno(VarTerm), &ch, 1); 619afc7fa2cSBrian Somers LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 620af57ed9fSAtsushi Murai 621af57ed9fSAtsushi Murai if (n > 0) { 622af57ed9fSAtsushi Murai switch (ttystate) { 623af57ed9fSAtsushi Murai case 0: 624af57ed9fSAtsushi Murai if (ch == '~') 625af57ed9fSAtsushi Murai ttystate++; 626af57ed9fSAtsushi Murai else 627af57ed9fSAtsushi Murai write(modem, &ch, n); 628af57ed9fSAtsushi Murai break; 629af57ed9fSAtsushi Murai case 1: 630af57ed9fSAtsushi Murai switch (ch) { 631af57ed9fSAtsushi Murai case '?': 632af57ed9fSAtsushi Murai ShowHelp(); 633af57ed9fSAtsushi Murai break; 634af57ed9fSAtsushi Murai case 'p': 635944f7098SBrian Somers 636af57ed9fSAtsushi Murai /* 637af57ed9fSAtsushi Murai * XXX: Should check carrier. 638af57ed9fSAtsushi Murai */ 639af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 640af57ed9fSAtsushi Murai VarOpenMode = OPEN_ACTIVE; 641af57ed9fSAtsushi Murai PacketMode(); 642af57ed9fSAtsushi Murai } 643af57ed9fSAtsushi Murai break; 644af57ed9fSAtsushi Murai case '.': 645af57ed9fSAtsushi Murai TermMode = 1; 646927145beSBrian Somers aft_cmd = 1; 647c3899f8dSAtsushi Murai TtyCommandMode(1); 648af57ed9fSAtsushi Murai break; 649927145beSBrian Somers case 't': 650927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 651927145beSBrian Somers ShowTimers(); 652927145beSBrian Somers break; 653927145beSBrian Somers } 654927145beSBrian Somers case 'm': 655927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 656927145beSBrian Somers ShowMemMap(); 657927145beSBrian Somers break; 658927145beSBrian Somers } 659af57ed9fSAtsushi Murai default: 660af57ed9fSAtsushi Murai if (write(modem, &ch, n) < 0) 661927145beSBrian Somers LogPrintf(LogERROR, "error writing to modem.\n"); 662af57ed9fSAtsushi Murai break; 663af57ed9fSAtsushi Murai } 664af57ed9fSAtsushi Murai ttystate = 0; 665af57ed9fSAtsushi Murai break; 666af57ed9fSAtsushi Murai } 667af57ed9fSAtsushi Murai } 668af57ed9fSAtsushi Murai } 669af57ed9fSAtsushi Murai 670af57ed9fSAtsushi Murai 671af57ed9fSAtsushi Murai /* 672af57ed9fSAtsushi Murai * Here, we'll try to detect HDLC frame 673af57ed9fSAtsushi Murai */ 674af57ed9fSAtsushi Murai 675af57ed9fSAtsushi Murai static char *FrameHeaders[] = { 67653c9f6c0SAtsushi Murai "\176\377\003\300\041", 67753c9f6c0SAtsushi Murai "\176\377\175\043\300\041", 67853c9f6c0SAtsushi Murai "\176\177\175\043\100\041", 67953c9f6c0SAtsushi Murai "\176\175\337\175\043\300\041", 68053c9f6c0SAtsushi Murai "\176\175\137\175\043\100\041", 681af57ed9fSAtsushi Murai NULL, 682af57ed9fSAtsushi Murai }; 683af57ed9fSAtsushi Murai 68475240ed1SBrian Somers static u_char * 685944f7098SBrian Somers HdlcDetect(u_char * cp, int n) 686af57ed9fSAtsushi Murai { 68753c9f6c0SAtsushi Murai char *ptr, *fp, **hp; 688af57ed9fSAtsushi Murai 689af57ed9fSAtsushi Murai cp[n] = '\0'; /* be sure to null terminated */ 690af57ed9fSAtsushi Murai ptr = NULL; 691af57ed9fSAtsushi Murai for (hp = FrameHeaders; *hp; hp++) { 69253c9f6c0SAtsushi Murai fp = *hp; 69353c9f6c0SAtsushi Murai if (DEV_IS_SYNC) 69453c9f6c0SAtsushi Murai fp++; 695ed6a16c1SPoul-Henning Kamp ptr = strstr((char *) cp, fp); 696ed6a16c1SPoul-Henning Kamp if (ptr) 697af57ed9fSAtsushi Murai break; 698af57ed9fSAtsushi Murai } 699af57ed9fSAtsushi Murai return ((u_char *) ptr); 700af57ed9fSAtsushi Murai } 701af57ed9fSAtsushi Murai 702af57ed9fSAtsushi Murai static struct pppTimer RedialTimer; 703af57ed9fSAtsushi Murai 704af57ed9fSAtsushi Murai static void 705af57ed9fSAtsushi Murai RedialTimeout() 706af57ed9fSAtsushi Murai { 707af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 708927145beSBrian Somers LogPrintf(LogPHASE, "Redialing timer expired.\n"); 709af57ed9fSAtsushi Murai } 710af57ed9fSAtsushi Murai 711af57ed9fSAtsushi Murai static void 712944f7098SBrian Somers StartRedialTimer(int Timeout) 713af57ed9fSAtsushi Murai { 714af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 715a9c6b5dfSAtsushi Murai 71643ea9d19SBrian Somers if (Timeout) { 717af57ed9fSAtsushi Murai RedialTimer.state = TIMER_STOPPED; 718a9c6b5dfSAtsushi Murai 71943ea9d19SBrian Somers if (Timeout > 0) 72043ea9d19SBrian Somers RedialTimer.load = Timeout * SECTICKS; 721a9c6b5dfSAtsushi Murai else 722a9c6b5dfSAtsushi Murai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 723a9c6b5dfSAtsushi Murai 724927145beSBrian Somers LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 72543ea9d19SBrian Somers RedialTimer.load / SECTICKS); 72643ea9d19SBrian Somers 727af57ed9fSAtsushi Murai RedialTimer.func = RedialTimeout; 728af57ed9fSAtsushi Murai StartTimer(&RedialTimer); 729af57ed9fSAtsushi Murai } 730a9c6b5dfSAtsushi Murai } 731af57ed9fSAtsushi Murai 732af57ed9fSAtsushi Murai 733af57ed9fSAtsushi Murai static void 734af57ed9fSAtsushi Murai DoLoop() 735af57ed9fSAtsushi Murai { 736af57ed9fSAtsushi Murai fd_set rfds, wfds, efds; 737780700e5SAndrey A. Chernov int pri, i, n, wfd, nfds; 738af57ed9fSAtsushi Murai struct sockaddr_in hisaddr; 739af57ed9fSAtsushi Murai struct timeval timeout, *tp; 740af57ed9fSAtsushi Murai int ssize = sizeof(hisaddr); 741af57ed9fSAtsushi Murai u_char *cp; 742a9c6b5dfSAtsushi Murai int tries; 74360e218e4SAtsushi Murai int qlen; 744368aee2bSBrian Somers int res; 745c3899f8dSAtsushi Murai pid_t pgroup; 7466a6b4bbbSBrian Somers struct tun_data tun; 7476a6b4bbbSBrian Somers #define rbuff tun.data 748c3899f8dSAtsushi Murai 749c3899f8dSAtsushi Murai pgroup = getpgrp(); 750af57ed9fSAtsushi Murai 7516efd9292SBrian Somers if (mode & MODE_DIRECT) { 7520706ff38SBrian Somers LogPrintf(LogDEBUG, "Opening modem\n"); 7539780ef31SBrian Somers if (OpenModem() < 0) 754bc240299SBrian Somers return; 755927145beSBrian Somers LogPrintf(LogPHASE, "Packet mode enabled\n"); 756af57ed9fSAtsushi Murai PacketMode(); 757af57ed9fSAtsushi Murai } else if (mode & MODE_DEDICATED) { 758780700e5SAndrey A. Chernov if (modem < 0) 7599780ef31SBrian Somers while (OpenModem() < 0) 7609a571ec7SBrian Somers nointr_sleep(VarReconnectTimer); 761af57ed9fSAtsushi Murai } 762927145beSBrian Somers fflush(VarTerm); 763af57ed9fSAtsushi Murai 76484b8a6ebSAtsushi Murai timeout.tv_sec = 0; 765af57ed9fSAtsushi Murai timeout.tv_usec = 0; 76625aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 767af57ed9fSAtsushi Murai 7686e4959f0SBrian Somers if (mode & MODE_BACKGROUND) 76975240ed1SBrian Somers dial_up = 1; /* Bring the line up */ 7706e4959f0SBrian Somers else 77175240ed1SBrian Somers dial_up = 0; /* XXXX */ 772a9c6b5dfSAtsushi Murai tries = 0; 773af57ed9fSAtsushi Murai for (;;) { 774780700e5SAndrey A. Chernov nfds = 0; 775944f7098SBrian Somers FD_ZERO(&rfds); 776944f7098SBrian Somers FD_ZERO(&wfds); 777944f7098SBrian Somers FD_ZERO(&efds); 77884b8a6ebSAtsushi Murai 77984b8a6ebSAtsushi Murai /* 780944f7098SBrian Somers * If the link is down and we're in DDIAL mode, bring it back up. 781680026d6SNate Williams */ 782680026d6SNate Williams if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 78375240ed1SBrian Somers dial_up = 1; 784680026d6SNate Williams 785680026d6SNate Williams /* 786944f7098SBrian Somers * If we lost carrier and want to re-establish the connection due to the 787944f7098SBrian Somers * "set reconnect" value, we'd better bring the line back up. 78807030d97SBrian Somers */ 7896efd9292SBrian Somers if (LcpFsm.state <= ST_CLOSED) { 79075240ed1SBrian Somers if (!dial_up && reconnectState == RECON_TRUE) { 7916efd9292SBrian Somers if (++reconnectCount <= VarReconnectTries) { 792927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 7936efd9292SBrian Somers reconnectCount, VarReconnectTries); 79407030d97SBrian Somers StartRedialTimer(VarReconnectTimer); 79575240ed1SBrian Somers dial_up = 1; 796298091daSBrian Somers } else { 7976efd9292SBrian Somers if (VarReconnectTries) 798927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 799298091daSBrian Somers VarReconnectTries); 8006efd9292SBrian Somers reconnectCount = 0; 8016efd9292SBrian Somers if (mode & MODE_BACKGROUND) 8026efd9292SBrian Somers Cleanup(EX_DEAD); 8036efd9292SBrian Somers } 80425aa96acSBrian Somers reconnectState = RECON_ENVOKED; 80512ef29a8SBrian Somers } else if (mode & MODE_DEDICATED) 80612ef29a8SBrian Somers if (VarOpenMode == OPEN_ACTIVE) 80712ef29a8SBrian Somers PacketMode(); 80807030d97SBrian Somers } 80907030d97SBrian Somers 81007030d97SBrian Somers /* 811944f7098SBrian Somers * If Ip packet for output is enqueued and require dial up, Just do it! 81284b8a6ebSAtsushi Murai */ 81307030d97SBrian Somers if (dial_up && RedialTimer.state != TIMER_RUNNING) { 814927145beSBrian Somers LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 8159780ef31SBrian Somers if (OpenModem() < 0) { 8160706ff38SBrian Somers tries++; 817712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries) 8180706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 8190706ff38SBrian Somers tries, VarDialTries); 8200706ff38SBrian Somers else 8210706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 8220706ff38SBrian Somers 823712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 8240706ff38SBrian Somers if (mode & MODE_BACKGROUND) 8250706ff38SBrian Somers Cleanup(EX_DIAL); /* Can't get the modem */ 82675240ed1SBrian Somers dial_up = 0; 8270706ff38SBrian Somers reconnectState = RECON_UNKNOWN; 8280706ff38SBrian Somers reconnectCount = 0; 8290706ff38SBrian Somers tries = 0; 8300706ff38SBrian Somers } else 83143ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 83284b8a6ebSAtsushi Murai } else { 833944f7098SBrian Somers tries++; /* Tries are per number, not per list of 834944f7098SBrian Somers * numbers. */ 835712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries) 836712ae387SBrian Somers LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 837c0139fb2SBrian Somers else 838927145beSBrian Somers LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 839712ae387SBrian Somers 840368aee2bSBrian Somers if ((res = DialModem()) == EX_DONE) { 8419a571ec7SBrian Somers nointr_sleep(1); /* little pause to allow peer starts */ 84284b8a6ebSAtsushi Murai ModemTimeout(); 84384b8a6ebSAtsushi Murai PacketMode(); 84475240ed1SBrian Somers dial_up = 0; 84525aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 846a9c6b5dfSAtsushi Murai tries = 0; 84784b8a6ebSAtsushi Murai } else { 8484ed9958fSBrian Somers if (mode & MODE_BACKGROUND) { 849368aee2bSBrian Somers if (VarNextPhone == NULL || res == EX_SIG) 8504ed9958fSBrian Somers Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 8514ed9958fSBrian Somers else 85243ea9d19SBrian Somers /* Try all numbers in background mode */ 85343ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 854368aee2bSBrian Somers } else if (!(mode & MODE_DDIAL) && 855368aee2bSBrian Somers ((VarDialTries && tries >= VarDialTries) || 856368aee2bSBrian Somers res == EX_SIG)) { 857c0139fb2SBrian Somers /* I give up ! Can't get through :( */ 85843ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 85975240ed1SBrian Somers dial_up = 0; 86025aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 86125aa96acSBrian Somers reconnectCount = 0; 862a9c6b5dfSAtsushi Murai tries = 0; 863c0139fb2SBrian Somers } else if (VarNextPhone == NULL) 864c0139fb2SBrian Somers /* Dial failed. Keep quite during redial wait period. */ 86543ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 866c0139fb2SBrian Somers else 86743ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 86884b8a6ebSAtsushi Murai } 86984b8a6ebSAtsushi Murai } 87084b8a6ebSAtsushi Murai } 87160e218e4SAtsushi Murai qlen = ModemQlen(); 87276bd0c0aSDoug Rabson 87376bd0c0aSDoug Rabson if (qlen == 0) { 87476bd0c0aSDoug Rabson IpStartOutput(); 87576bd0c0aSDoug Rabson qlen = ModemQlen(); 87676bd0c0aSDoug Rabson } 877780700e5SAndrey A. Chernov if (modem >= 0) { 878780700e5SAndrey A. Chernov if (modem + 1 > nfds) 879780700e5SAndrey A. Chernov nfds = modem + 1; 88084b8a6ebSAtsushi Murai FD_SET(modem, &rfds); 88184b8a6ebSAtsushi Murai FD_SET(modem, &efds); 88260e218e4SAtsushi Murai if (qlen > 0) { 88384b8a6ebSAtsushi Murai FD_SET(modem, &wfds); 88484b8a6ebSAtsushi Murai } 88584b8a6ebSAtsushi Murai } 886780700e5SAndrey A. Chernov if (server >= 0) { 887780700e5SAndrey A. Chernov if (server + 1 > nfds) 888780700e5SAndrey A. Chernov nfds = server + 1; 889780700e5SAndrey A. Chernov FD_SET(server, &rfds); 890780700e5SAndrey A. Chernov } 891af57ed9fSAtsushi Murai 892944f7098SBrian Somers /* 893944f7098SBrian Somers * *** IMPORTANT *** 894af57ed9fSAtsushi Murai * 895944f7098SBrian Somers * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 896944f7098SBrian Somers * with great care. If this values is too big, it results loss of 897944f7098SBrian Somers * characters from modem and poor responce. If this values is too small, 898944f7098SBrian Somers * ppp process eats many CPU time. 899af57ed9fSAtsushi Murai */ 90053c9f6c0SAtsushi Murai #ifndef SIGALRM 9019a571ec7SBrian Somers nointr_usleep(TICKUNIT); 902af57ed9fSAtsushi Murai TimerService(); 903f5ff0f7cSBrian Somers #else 904f5ff0f7cSBrian Somers handle_signals(); 90553c9f6c0SAtsushi Murai #endif 90668d2b4d6SBruce Evans 90768d2b4d6SBruce Evans /* If there are aren't many packets queued, look for some more. */ 908780700e5SAndrey A. Chernov if (qlen < 20 && tun_in >= 0) { 909780700e5SAndrey A. Chernov if (tun_in + 1 > nfds) 910780700e5SAndrey A. Chernov nfds = tun_in + 1; 91184b8a6ebSAtsushi Murai FD_SET(tun_in, &rfds); 912780700e5SAndrey A. Chernov } 913780700e5SAndrey A. Chernov if (netfd >= 0) { 914780700e5SAndrey A. Chernov if (netfd + 1 > nfds) 915780700e5SAndrey A. Chernov nfds = netfd + 1; 916af57ed9fSAtsushi Murai FD_SET(netfd, &rfds); 917af57ed9fSAtsushi Murai FD_SET(netfd, &efds); 918af57ed9fSAtsushi Murai } 91953c9f6c0SAtsushi Murai #ifndef SIGALRM 920944f7098SBrian Somers 921af57ed9fSAtsushi Murai /* 922944f7098SBrian Somers * Normally, select() will not block because modem is writable. In AUTO 923944f7098SBrian Somers * mode, select will block until we find packet from tun 924af57ed9fSAtsushi Murai */ 925af57ed9fSAtsushi Murai tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 926780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 92753c9f6c0SAtsushi Murai #else 928944f7098SBrian Somers 92984b8a6ebSAtsushi Murai /* 930944f7098SBrian Somers * When SIGALRM timer is running, a select function will be return -1 and 931944f7098SBrian Somers * EINTR after a Time Service signal hundler is done. If the redial 932944f7098SBrian Somers * timer is not running and we are trying to dial, poll with a 0 value 933944f7098SBrian Somers * timer. 93484b8a6ebSAtsushi Murai */ 935a9c6b5dfSAtsushi Murai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 936780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 93753c9f6c0SAtsushi Murai #endif 9386b0b88d8SBrian Somers 939af57ed9fSAtsushi Murai if (i == 0) { 940af57ed9fSAtsushi Murai continue; 941af57ed9fSAtsushi Murai } 942534fe541SBrian Somers if (i < 0) { 943534fe541SBrian Somers if (errno == EINTR) { 944f5ff0f7cSBrian Somers handle_signals(); 945f5ff0f7cSBrian Somers continue; 94684b8a6ebSAtsushi Murai } 947afc7fa2cSBrian Somers LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 948af57ed9fSAtsushi Murai break; 949af57ed9fSAtsushi Murai } 950780700e5SAndrey A. Chernov if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 951927145beSBrian Somers LogPrintf(LogALERT, "Exception detected.\n"); 952af57ed9fSAtsushi Murai break; 953af57ed9fSAtsushi Murai } 954780700e5SAndrey A. Chernov if (server >= 0 && FD_ISSET(server, &rfds)) { 955927145beSBrian Somers LogPrintf(LogPHASE, "connected to client.\n"); 956af57ed9fSAtsushi Murai wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize); 957e0d3e233SAndrey A. Chernov if (wfd < 0) { 958afc7fa2cSBrian Somers LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 959e0d3e233SAndrey A. Chernov continue; 960e0d3e233SAndrey A. Chernov } 961780700e5SAndrey A. Chernov if (netfd >= 0) { 962af57ed9fSAtsushi Murai write(wfd, "already in use.\n", 16); 963af57ed9fSAtsushi Murai close(wfd); 964af57ed9fSAtsushi Murai continue; 965af57ed9fSAtsushi Murai } else 966af57ed9fSAtsushi Murai netfd = wfd; 967927145beSBrian Somers VarTerm = fdopen(netfd, "a+"); 9688ea8442cSBrian Somers LocalAuthInit(); 969af57ed9fSAtsushi Murai Greetings(); 970a1e8f937SBrian Somers IsInteractive(1); 971274e766cSBrian Somers Prompt(); 972af57ed9fSAtsushi Murai } 97312ef29a8SBrian Somers if (netfd >= 0 && FD_ISSET(netfd, &rfds) && 97412ef29a8SBrian Somers ((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) { 975af57ed9fSAtsushi Murai /* something to read from tty */ 976af57ed9fSAtsushi Murai ReadTty(); 977af57ed9fSAtsushi Murai } 978780700e5SAndrey A. Chernov if (modem >= 0) { 979af57ed9fSAtsushi Murai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 980af57ed9fSAtsushi Murai ModemStartOutput(modem); 981af57ed9fSAtsushi Murai } 982af57ed9fSAtsushi Murai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 98353c9f6c0SAtsushi Murai if (LcpFsm.state <= ST_CLOSED) 9849a571ec7SBrian Somers nointr_usleep(10000); 985af57ed9fSAtsushi Murai n = read(modem, rbuff, sizeof(rbuff)); 986af57ed9fSAtsushi Murai if ((mode & MODE_DIRECT) && n <= 0) { 987af57ed9fSAtsushi Murai DownConnection(); 988af57ed9fSAtsushi Murai } else 989927145beSBrian Somers LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 990af57ed9fSAtsushi Murai 991af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 992944f7098SBrian Somers 993af57ed9fSAtsushi Murai /* 994af57ed9fSAtsushi Murai * In dedicated mode, we just discard input until LCP is started. 995af57ed9fSAtsushi Murai */ 996af57ed9fSAtsushi Murai if (!(mode & MODE_DEDICATED)) { 997af57ed9fSAtsushi Murai cp = HdlcDetect(rbuff, n); 998af57ed9fSAtsushi Murai if (cp) { 999944f7098SBrian Somers 1000af57ed9fSAtsushi Murai /* 1001af57ed9fSAtsushi Murai * LCP packet is detected. Turn ourselves into packet mode. 1002af57ed9fSAtsushi Murai */ 1003af57ed9fSAtsushi Murai if (cp != rbuff) { 1004927145beSBrian Somers write(modem, rbuff, cp - rbuff); 1005927145beSBrian Somers write(modem, "\r\n", 2); 1006af57ed9fSAtsushi Murai } 1007af57ed9fSAtsushi Murai PacketMode(); 1008af57ed9fSAtsushi Murai } else 1009927145beSBrian Somers write(fileno(VarTerm), rbuff, n); 1010af57ed9fSAtsushi Murai } 1011af57ed9fSAtsushi Murai } else { 1012af57ed9fSAtsushi Murai if (n > 0) 1013af57ed9fSAtsushi Murai AsyncInput(rbuff, n); 1014af57ed9fSAtsushi Murai } 1015af57ed9fSAtsushi Murai } 1016af57ed9fSAtsushi Murai } 1017944f7098SBrian Somers if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 1018944f7098SBrian Somers * from tun */ 10196a6b4bbbSBrian Somers n = read(tun_in, &tun, sizeof(tun)); 1020af57ed9fSAtsushi Murai if (n < 0) { 1021afc7fa2cSBrian Somers LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 1022af57ed9fSAtsushi Murai continue; 1023af57ed9fSAtsushi Murai } 10246a6b4bbbSBrian Somers n -= sizeof(tun)-sizeof(tun.data); 10256a6b4bbbSBrian Somers if (n <= 0) { 10266a6b4bbbSBrian Somers LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n); 10276a6b4bbbSBrian Somers continue; 10286a6b4bbbSBrian Somers } 10296a6b4bbbSBrian Somers if (!tun_check_header(tun, AF_INET)) 10306a6b4bbbSBrian Somers continue; 1031de451c68SBrian Somers if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 1032de451c68SBrian Somers /* we've been asked to send something addressed *to* us :( */ 1033de451c68SBrian Somers if (VarLoopback) { 1034de451c68SBrian Somers pri = PacketCheck(rbuff, n, FL_IN); 1035de451c68SBrian Somers if (pri >= 0) { 1036de451c68SBrian Somers struct mbuf *bp; 1037944f7098SBrian Somers 1038de451c68SBrian Somers if (mode & MODE_ALIAS) { 1039de451c68SBrian Somers VarPacketAliasIn(rbuff, sizeof rbuff); 1040de451c68SBrian Somers n = ntohs(((struct ip *) rbuff)->ip_len); 1041de451c68SBrian Somers } 1042de451c68SBrian Somers bp = mballoc(n, MB_IPIN); 104375240ed1SBrian Somers memcpy(MBUF_CTOP(bp), rbuff, n); 1044de451c68SBrian Somers IpInput(bp); 1045de451c68SBrian Somers LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 1046de451c68SBrian Somers } 1047de451c68SBrian Somers continue; 1048de451c68SBrian Somers } else 1049de451c68SBrian Somers LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 1050de451c68SBrian Somers } 1051de451c68SBrian Somers 1052af57ed9fSAtsushi Murai /* 1053af57ed9fSAtsushi Murai * Process on-demand dialup. Output packets are queued within tunnel 1054af57ed9fSAtsushi Murai * device until IPCP is opened. 1055af57ed9fSAtsushi Murai */ 1056af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 105784b8a6ebSAtsushi Murai pri = PacketCheck(rbuff, n, FL_DIAL); 1058af57ed9fSAtsushi Murai if (pri >= 0) { 1059a9f484e5SJordan K. Hubbard if (mode & MODE_ALIAS) { 10606ed9fb2fSBrian Somers VarPacketAliasOut(rbuff, sizeof rbuff); 1061a9f484e5SJordan K. Hubbard n = ntohs(((struct ip *) rbuff)->ip_len); 1062a9f484e5SJordan K. Hubbard } 1063af57ed9fSAtsushi Murai IpEnqueue(pri, rbuff, n); 106475240ed1SBrian Somers dial_up = 1; /* XXX */ 1065af57ed9fSAtsushi Murai } 1066af57ed9fSAtsushi Murai continue; 1067af57ed9fSAtsushi Murai } 106884b8a6ebSAtsushi Murai pri = PacketCheck(rbuff, n, FL_OUT); 1069a9f484e5SJordan K. Hubbard if (pri >= 0) { 1070a9f484e5SJordan K. Hubbard if (mode & MODE_ALIAS) { 10716ed9fb2fSBrian Somers VarPacketAliasOut(rbuff, sizeof rbuff); 1072a9f484e5SJordan K. Hubbard n = ntohs(((struct ip *) rbuff)->ip_len); 1073a9f484e5SJordan K. Hubbard } 1074af57ed9fSAtsushi Murai IpEnqueue(pri, rbuff, n); 1075af57ed9fSAtsushi Murai } 1076af57ed9fSAtsushi Murai } 1077a9f484e5SJordan K. Hubbard } 1078927145beSBrian Somers LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1079af57ed9fSAtsushi Murai } 1080