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 * 20c60f92caSBrian Somers * $Id: main.c,v 1.112 1997/12/27 13:45:53 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> 36b6e82f33SBrian Somers #ifdef __FreeBSD__ 376a6b4bbbSBrian Somers #include <net/if_var.h> 38b6e82f33SBrian Somers #endif 396a6b4bbbSBrian Somers #include <net/if_tun.h> 4075240ed1SBrian Somers 4175240ed1SBrian Somers #include <errno.h> 4275240ed1SBrian Somers #include <fcntl.h> 4375240ed1SBrian Somers #include <paths.h> 4475240ed1SBrian Somers #include <signal.h> 4575240ed1SBrian Somers #include <stdio.h> 4675240ed1SBrian Somers #include <stdlib.h> 4775240ed1SBrian Somers #include <string.h> 4875240ed1SBrian Somers #include <sys/time.h> 4975240ed1SBrian Somers #include <sys/wait.h> 50683cef3cSBrian Somers #include <sysexits.h> 5175240ed1SBrian Somers #include <termios.h> 5275240ed1SBrian Somers #include <unistd.h> 5375240ed1SBrian Somers 54b6e82f33SBrian Somers #include "command.h" 5575240ed1SBrian Somers #include "mbuf.h" 5675240ed1SBrian Somers #include "log.h" 5775240ed1SBrian Somers #include "defs.h" 585106c671SBrian Somers #include "id.h" 5975240ed1SBrian Somers #include "timer.h" 6075240ed1SBrian Somers #include "fsm.h" 61af57ed9fSAtsushi Murai #include "modem.h" 62af57ed9fSAtsushi Murai #include "os.h" 63af57ed9fSAtsushi Murai #include "hdlc.h" 64af57ed9fSAtsushi Murai #include "lcp.h" 650053cc58SBrian Somers #include "ccp.h" 66af57ed9fSAtsushi Murai #include "ipcp.h" 676ed9fb2fSBrian Somers #include "loadalias.h" 68af57ed9fSAtsushi Murai #include "vars.h" 6953c9f6c0SAtsushi Murai #include "auth.h" 7084b8a6ebSAtsushi Murai #include "filter.h" 71ed6a16c1SPoul-Henning Kamp #include "systems.h" 72ed6a16c1SPoul-Henning Kamp #include "ip.h" 73f5ff0f7cSBrian Somers #include "sig.h" 744ef16f24SBrian Somers #include "server.h" 75de451c68SBrian Somers #include "lcpproto.h" 7675240ed1SBrian Somers #include "main.h" 7775240ed1SBrian Somers #include "vjcomp.h" 7875240ed1SBrian Somers #include "async.h" 794562be74SBrian Somers #include "pathnames.h" 806a6b4bbbSBrian Somers #include "tun.h" 81b6e82f33SBrian Somers #include "route.h" 8253c9f6c0SAtsushi Murai 8353c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 8453c9f6c0SAtsushi Murai #ifdef O_NDELAY 8553c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 8653c9f6c0SAtsushi Murai #endif 8753c9f6c0SAtsushi Murai #endif 88af57ed9fSAtsushi Murai 8975240ed1SBrian Somers int TermMode = 0; 9075240ed1SBrian Somers int tunno = 0; 91af57ed9fSAtsushi Murai 92af57ed9fSAtsushi Murai static struct termios oldtio; /* Original tty mode */ 93af57ed9fSAtsushi Murai static struct termios comtio; /* Command level tty mode */ 946d14e2a8SJordan K. Hubbard static pid_t BGPid = 0; 9541c6c543SBrian Somers static char pid_filename[MAXPATHLEN]; 9676c5241dSBrian Somers static int dial_up; 97af57ed9fSAtsushi Murai 9875240ed1SBrian Somers static void DoLoop(void); 9975240ed1SBrian Somers static void TerminalStop(int); 100b6e82f33SBrian Somers static const char *ex_desc(int); 10175240ed1SBrian Somers 102af57ed9fSAtsushi Murai static void 103368aee2bSBrian Somers TtyInit(int DontWantInt) 104af57ed9fSAtsushi Murai { 105af57ed9fSAtsushi Murai struct termios newtio; 106af57ed9fSAtsushi Murai int stat; 107af57ed9fSAtsushi Murai 108af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 109274e766cSBrian Somers if (stat > 0) { 110af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 111274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 112274e766cSBrian Somers } 113af57ed9fSAtsushi Murai newtio = oldtio; 114af57ed9fSAtsushi Murai newtio.c_lflag &= ~(ECHO | ISIG | ICANON); 115af57ed9fSAtsushi Murai newtio.c_iflag = 0; 116af57ed9fSAtsushi Murai newtio.c_oflag &= ~OPOST; 117af57ed9fSAtsushi Murai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 118368aee2bSBrian Somers if (DontWantInt) 119af57ed9fSAtsushi Murai newtio.c_cc[VINTR] = _POSIX_VDISABLE; 120af57ed9fSAtsushi Murai newtio.c_cc[VMIN] = 1; 121af57ed9fSAtsushi Murai newtio.c_cc[VTIME] = 0; 122af57ed9fSAtsushi Murai newtio.c_cflag |= CS8; 12353c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 124af57ed9fSAtsushi Murai comtio = newtio; 125af57ed9fSAtsushi Murai } 126af57ed9fSAtsushi Murai 127af57ed9fSAtsushi Murai /* 128af57ed9fSAtsushi Murai * Set tty into command mode. We allow canonical input and echo processing. 129af57ed9fSAtsushi Murai */ 130c3899f8dSAtsushi Murai void 131944f7098SBrian Somers TtyCommandMode(int prompt) 132af57ed9fSAtsushi Murai { 133af57ed9fSAtsushi Murai struct termios newtio; 134af57ed9fSAtsushi Murai int stat; 135af57ed9fSAtsushi Murai 136af57ed9fSAtsushi Murai if (!(mode & MODE_INTER)) 137af57ed9fSAtsushi Murai return; 13853c9f6c0SAtsushi Murai tcgetattr(0, &newtio); 139c3899f8dSAtsushi Murai newtio.c_lflag |= (ECHO | ISIG | ICANON); 140af57ed9fSAtsushi Murai newtio.c_iflag = oldtio.c_iflag; 141af57ed9fSAtsushi Murai newtio.c_oflag |= OPOST; 14253c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 143af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 144274e766cSBrian Somers if (stat > 0) { 145af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 146274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 147274e766cSBrian Somers } 148af57ed9fSAtsushi Murai TermMode = 0; 149944f7098SBrian Somers if (prompt) 150944f7098SBrian Somers Prompt(); 151af57ed9fSAtsushi Murai } 152af57ed9fSAtsushi Murai 153af57ed9fSAtsushi Murai /* 154af57ed9fSAtsushi Murai * Set tty into terminal mode which is used while we invoke term command. 155af57ed9fSAtsushi Murai */ 156af57ed9fSAtsushi Murai void 157af57ed9fSAtsushi Murai TtyTermMode() 158af57ed9fSAtsushi Murai { 159af57ed9fSAtsushi Murai int stat; 160af57ed9fSAtsushi Murai 16153c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &comtio); 162af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 163274e766cSBrian Somers if (stat > 0) { 164af57ed9fSAtsushi Murai stat &= ~O_NONBLOCK; 165274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 166274e766cSBrian Somers } 167af57ed9fSAtsushi Murai TermMode = 1; 168af57ed9fSAtsushi Murai } 169af57ed9fSAtsushi Murai 170af57ed9fSAtsushi Murai void 171c3899f8dSAtsushi Murai TtyOldMode() 172c3899f8dSAtsushi Murai { 173c3899f8dSAtsushi Murai int stat; 174c3899f8dSAtsushi Murai 175c3899f8dSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 176274e766cSBrian Somers if (stat > 0) { 177c3899f8dSAtsushi Murai stat &= ~O_NONBLOCK; 178274e766cSBrian Somers (void) fcntl(0, F_SETFL, stat); 179274e766cSBrian Somers } 180c3899f8dSAtsushi Murai tcsetattr(0, TCSANOW, &oldtio); 181c3899f8dSAtsushi Murai } 182c3899f8dSAtsushi Murai 183c3899f8dSAtsushi Murai void 184944f7098SBrian Somers Cleanup(int excode) 185af57ed9fSAtsushi Murai { 186e7250038SBrian Somers DropClient(1); 1878ea8442cSBrian Somers ServerClose(); 1880fe7ca31SBrian Somers OsInterfaceDown(1); 1890fe7ca31SBrian Somers HangupModem(1); 1909a571ec7SBrian Somers nointr_sleep(1); 1916e4959f0SBrian Somers DeleteIfRoutes(1); 1925106c671SBrian Somers ID0unlink(pid_filename); 1936e4959f0SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 1946e4959f0SBrian Somers char c = EX_ERRDEAD; 195944f7098SBrian Somers 1966e4959f0SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 197927145beSBrian Somers LogPrintf(LogPHASE, "Parent notified of failure.\n"); 1986e4959f0SBrian Somers else 199927145beSBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of failure.\n"); 2006e4959f0SBrian Somers close(BGFiledes[1]); 2016e4959f0SBrian Somers } 202927145beSBrian Somers LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode)); 203c3899f8dSAtsushi Murai TtyOldMode(); 2045106c671SBrian Somers LogClose(); 205af57ed9fSAtsushi Murai 206af57ed9fSAtsushi Murai exit(excode); 207af57ed9fSAtsushi Murai } 208af57ed9fSAtsushi Murai 209af57ed9fSAtsushi Murai static void 210944f7098SBrian Somers CloseConnection(int signo) 211af57ed9fSAtsushi Murai { 212368aee2bSBrian Somers /* NOTE, these are manual, we've done a setsid() */ 21312ef29a8SBrian Somers pending_signal(SIGINT, SIG_IGN); 214873725ccSBrian Somers LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo); 215944f7098SBrian Somers reconnectState = RECON_FALSE; 216944f7098SBrian Somers reconnectCount = 0; 217368aee2bSBrian Somers DownConnection(); 21875240ed1SBrian Somers dial_up = 0; 21912ef29a8SBrian Somers pending_signal(SIGINT, CloseConnection); 2206d14e2a8SJordan K. Hubbard } 221af57ed9fSAtsushi Murai 222af57ed9fSAtsushi Murai static void 223944f7098SBrian Somers CloseSession(int signo) 224af57ed9fSAtsushi Murai { 2256d14e2a8SJordan K. Hubbard if (BGPid) { 2266d14e2a8SJordan K. Hubbard kill(BGPid, SIGINT); 2276d14e2a8SJordan K. Hubbard exit(EX_TERM); 2286d14e2a8SJordan K. Hubbard } 229927145beSBrian Somers LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 23025aa96acSBrian Somers reconnect(RECON_FALSE); 231af57ed9fSAtsushi Murai LcpClose(); 232af57ed9fSAtsushi Murai Cleanup(EX_TERM); 233af57ed9fSAtsushi Murai } 234c3899f8dSAtsushi Murai 235c3899f8dSAtsushi Murai static void 236b6e82f33SBrian Somers TerminalCont(int signo) 237c3899f8dSAtsushi Murai { 238f5ff0f7cSBrian Somers pending_signal(SIGCONT, SIG_DFL); 239f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 240c3899f8dSAtsushi Murai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 241c3899f8dSAtsushi Murai } 242c3899f8dSAtsushi Murai 243c3899f8dSAtsushi Murai static void 244944f7098SBrian Somers TerminalStop(int signo) 245c3899f8dSAtsushi Murai { 246f5ff0f7cSBrian Somers pending_signal(SIGCONT, TerminalCont); 247c3899f8dSAtsushi Murai TtyOldMode(); 248f5ff0f7cSBrian Somers pending_signal(SIGTSTP, SIG_DFL); 249c3899f8dSAtsushi Murai kill(getpid(), signo); 250c3899f8dSAtsushi Murai } 251c3899f8dSAtsushi Murai 2524ef16f24SBrian Somers static void 253944f7098SBrian Somers SetUpServer(int signo) 2544ef16f24SBrian Somers { 2554ef16f24SBrian Somers int res; 256944f7098SBrian Somers 2578ea8442cSBrian Somers VarHaveLocalAuthKey = 0; 2588ea8442cSBrian Somers LocalAuthInit(); 2594ef16f24SBrian Somers if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0) 260683cef3cSBrian Somers LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n", 261683cef3cSBrian Somers res, SERVER_PORT + tunno); 2624ef16f24SBrian Somers } 2634ef16f24SBrian Somers 2648ea8442cSBrian Somers static void 2658ea8442cSBrian Somers BringDownServer(int signo) 2668ea8442cSBrian Somers { 2678ea8442cSBrian Somers VarHaveLocalAuthKey = 0; 2688ea8442cSBrian Somers LocalAuthInit(); 2698ea8442cSBrian Somers ServerClose(); 2708ea8442cSBrian Somers } 2718ea8442cSBrian Somers 272b6e82f33SBrian Somers static const char * 2736efd9292SBrian Somers ex_desc(int ex) 2746efd9292SBrian Somers { 2756efd9292SBrian Somers static char num[12]; 276b6e82f33SBrian Somers static const char *desc[] = { 277b6e82f33SBrian Somers "normal", "start", "sock", "modem", "dial", "dead", "done", 278b6e82f33SBrian Somers "reboot", "errdead", "hangup", "term", "nodial", "nologin" 279b6e82f33SBrian Somers }; 2806efd9292SBrian Somers 28170ee81ffSBrian Somers if (ex >= 0 && ex < sizeof desc / sizeof *desc) 2826efd9292SBrian Somers return desc[ex]; 2836efd9292SBrian Somers snprintf(num, sizeof num, "%d", ex); 2846efd9292SBrian Somers return num; 2856efd9292SBrian Somers } 286c3899f8dSAtsushi Murai 28775240ed1SBrian Somers static void 288b6e82f33SBrian Somers Usage(void) 289af57ed9fSAtsushi Murai { 290680026d6SNate Williams fprintf(stderr, 291b6e82f33SBrian Somers "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]" 292b6e82f33SBrian Somers #ifndef NOALIAS 293b6e82f33SBrian Somers " [ -alias ]" 294b6e82f33SBrian Somers #endif 295b6e82f33SBrian Somers " [system]\n"); 296af57ed9fSAtsushi Murai exit(EX_START); 297af57ed9fSAtsushi Murai } 298af57ed9fSAtsushi Murai 29939f94eddSBrian Somers static char * 300af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv) 301af57ed9fSAtsushi Murai { 302af57ed9fSAtsushi Murai int optc; 303af57ed9fSAtsushi Murai char *cp; 304af57ed9fSAtsushi Murai 305af57ed9fSAtsushi Murai optc = 0; 30612ef29a8SBrian Somers mode = MODE_INTER; 307af57ed9fSAtsushi Murai while (argc > 0 && **argv == '-') { 308af57ed9fSAtsushi Murai cp = *argv + 1; 30912ef29a8SBrian Somers if (strcmp(cp, "auto") == 0) { 310af57ed9fSAtsushi Murai mode |= MODE_AUTO; 31112ef29a8SBrian Somers mode &= ~MODE_INTER; 31212ef29a8SBrian Somers } else if (strcmp(cp, "background") == 0) { 31312ef29a8SBrian Somers mode |= MODE_BACKGROUND; 31412ef29a8SBrian Somers mode &= ~MODE_INTER; 31512ef29a8SBrian Somers } else if (strcmp(cp, "direct") == 0) { 316af57ed9fSAtsushi Murai mode |= MODE_DIRECT; 31712ef29a8SBrian Somers mode &= ~MODE_INTER; 31812ef29a8SBrian Somers } else if (strcmp(cp, "dedicated") == 0) { 319af57ed9fSAtsushi Murai mode |= MODE_DEDICATED; 32012ef29a8SBrian Somers mode &= ~MODE_INTER; 32112ef29a8SBrian Somers } else if (strcmp(cp, "ddial") == 0) { 32212ef29a8SBrian Somers mode |= MODE_DDIAL; 32312ef29a8SBrian Somers mode &= ~MODE_INTER; 324b6e82f33SBrian Somers #ifndef NOALIAS 32512ef29a8SBrian Somers } else if (strcmp(cp, "alias") == 0) { 3266ed9fb2fSBrian Somers if (loadAliasHandlers(&VarAliasHandlers) == 0) 327a9f484e5SJordan K. Hubbard mode |= MODE_ALIAS; 3286ed9fb2fSBrian Somers else 329927145beSBrian Somers LogPrintf(LogWARN, "Cannot load alias library\n"); 330a9f484e5SJordan K. Hubbard optc--; /* this option isn't exclusive */ 331b6e82f33SBrian Somers #endif 332944f7098SBrian Somers } else 333af57ed9fSAtsushi Murai Usage(); 334af57ed9fSAtsushi Murai optc++; 335944f7098SBrian Somers argv++; 336944f7098SBrian Somers argc--; 337af57ed9fSAtsushi Murai } 338af57ed9fSAtsushi Murai if (argc > 1) { 339af57ed9fSAtsushi Murai fprintf(stderr, "specify only one system label.\n"); 340af57ed9fSAtsushi Murai exit(EX_START); 341af57ed9fSAtsushi Murai } 342af57ed9fSAtsushi Murai 343af57ed9fSAtsushi Murai if (optc > 1) { 344af57ed9fSAtsushi Murai fprintf(stderr, "specify only one mode.\n"); 345af57ed9fSAtsushi Murai exit(EX_START); 346af57ed9fSAtsushi Murai } 34739f94eddSBrian Somers 34839f94eddSBrian Somers return argc == 1 ? *argv : NULL; /* Don't SetLabel yet ! */ 349af57ed9fSAtsushi Murai } 350af57ed9fSAtsushi Murai 351af57ed9fSAtsushi Murai static void 352b6e82f33SBrian Somers Greetings(void) 353af57ed9fSAtsushi Murai { 354927145beSBrian Somers if (VarTerm) { 355927145beSBrian Somers fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 356927145beSBrian Somers fflush(VarTerm); 357927145beSBrian Somers } 358af57ed9fSAtsushi Murai } 359af57ed9fSAtsushi Murai 3604ef16f24SBrian Somers int 361944f7098SBrian Somers main(int argc, char **argv) 362af57ed9fSAtsushi Murai { 363aefd026aSBrian Somers FILE *lockfile; 36439f94eddSBrian Somers char *name, *label; 365e3b4c400SBrian Somers int nfds; 366e3b4c400SBrian Somers 367e3b4c400SBrian Somers nfds = getdtablesize(); 368e3b4c400SBrian Somers if (nfds >= FD_SETSIZE) 369e3b4c400SBrian Somers /* 370e3b4c400SBrian Somers * If we've got loads of file descriptors, make sure they're all 371e3b4c400SBrian Somers * closed. If they aren't, we may end up with a seg fault when our 372e3b4c400SBrian Somers * `fd_set's get too big when select()ing ! 373e3b4c400SBrian Somers */ 374e3b4c400SBrian Somers while (--nfds > 2) 375e3b4c400SBrian Somers close(nfds); 376af57ed9fSAtsushi Murai 3770706ff38SBrian Somers VarTerm = 0; 37875240ed1SBrian Somers name = strrchr(argv[0], '/'); 379927145beSBrian Somers LogOpen(name ? name + 1 : argv[0]); 380927145beSBrian Somers 381944f7098SBrian Somers argc--; 382944f7098SBrian Somers argv++; 38339f94eddSBrian Somers label = ProcessArgs(argc, argv); 38412ef29a8SBrian Somers if (!(mode & MODE_DIRECT)) 3850706ff38SBrian Somers VarTerm = stdout; 38612ef29a8SBrian Somers 3875106c671SBrian Somers ID0init(); 3884562be74SBrian Somers if (ID0realuid() != 0) { 3894562be74SBrian Somers char conf[200], *ptr; 3904562be74SBrian Somers 3914562be74SBrian Somers snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE); 3924562be74SBrian Somers do { 3934562be74SBrian Somers if (!access(conf, W_OK)) { 3944562be74SBrian Somers LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); 3954562be74SBrian Somers return -1; 3964562be74SBrian Somers } 3974562be74SBrian Somers ptr = conf + strlen(conf)-2; 3984562be74SBrian Somers while (ptr > conf && *ptr != '/') 3994562be74SBrian Somers *ptr-- = '\0'; 4004562be74SBrian Somers } while (ptr >= conf); 4014562be74SBrian Somers } 4024562be74SBrian Somers 40339f94eddSBrian Somers if (!ValidSystem(label)) { 40412ef29a8SBrian Somers fprintf(stderr, "You may not use ppp in this mode with this label\n"); 405815624cfSBrian Somers if (mode & MODE_DIRECT) { 406815624cfSBrian Somers const char *l; 40739f94eddSBrian Somers l = label ? label : "default"; 408815624cfSBrian Somers VarTerm = 0; 409815624cfSBrian Somers LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l); 410815624cfSBrian Somers } 411815624cfSBrian Somers LogClose(); 41212ef29a8SBrian Somers return 1; 41312ef29a8SBrian Somers } 41412ef29a8SBrian Somers 415c7d4711fSBrian Somers if (!GetShortHost()) 416c7d4711fSBrian Somers return 1; 417af57ed9fSAtsushi Murai Greetings(); 418af57ed9fSAtsushi Murai IpcpDefAddress(); 419af57ed9fSAtsushi Murai 420082798e7SBrian Somers if (mode & MODE_INTER) 421082798e7SBrian Somers VarLocalAuth = LOCAL_AUTH; 422082798e7SBrian Somers 423927145beSBrian Somers if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 424927145beSBrian Somers fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 425af57ed9fSAtsushi Murai 426af57ed9fSAtsushi Murai if (OpenTunnel(&tunno) < 0) { 427bcc332bdSBrian Somers LogPrintf(LogWARN, "OpenTunnel: %s\n", strerror(errno)); 4284ef16f24SBrian Somers return EX_START; 429af57ed9fSAtsushi Murai } 430af57ed9fSAtsushi Murai if (mode & MODE_INTER) { 431927145beSBrian Somers fprintf(VarTerm, "Interactive mode\n"); 432cc39a98fSBrian Somers netfd = STDOUT_FILENO; 43312ef29a8SBrian Somers } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED)) 43439f94eddSBrian Somers if (label == NULL) { 435927145beSBrian Somers if (VarTerm) 436927145beSBrian Somers fprintf(VarTerm, "Destination system must be specified in" 4376efd9292SBrian Somers " auto, background or ddial mode.\n"); 4384ef16f24SBrian Somers return EX_START; 4396d14e2a8SJordan K. Hubbard } 44012ef29a8SBrian Somers 44153c9f6c0SAtsushi Murai tcgetattr(0, &oldtio); /* Save original tty mode */ 442af57ed9fSAtsushi Murai 443873725ccSBrian Somers pending_signal(SIGHUP, CloseSession); 444f5ff0f7cSBrian Somers pending_signal(SIGTERM, CloseSession); 445873725ccSBrian Somers pending_signal(SIGINT, CloseConnection); 446f5ff0f7cSBrian Somers pending_signal(SIGQUIT, CloseSession); 44753c9f6c0SAtsushi Murai #ifdef SIGPIPE 448e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 44953c9f6c0SAtsushi Murai #endif 45053c9f6c0SAtsushi Murai #ifdef SIGALRM 451f5ff0f7cSBrian Somers pending_signal(SIGALRM, SIG_IGN); 45253c9f6c0SAtsushi Murai #endif 4534ef16f24SBrian Somers if (mode & MODE_INTER) { 454c3899f8dSAtsushi Murai #ifdef SIGTSTP 455f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 456c3899f8dSAtsushi Murai #endif 457c3899f8dSAtsushi Murai #ifdef SIGTTIN 458f5ff0f7cSBrian Somers pending_signal(SIGTTIN, TerminalStop); 459c3899f8dSAtsushi Murai #endif 460c3899f8dSAtsushi Murai #ifdef SIGTTOU 461f5ff0f7cSBrian Somers pending_signal(SIGTTOU, SIG_IGN); 462c3899f8dSAtsushi Murai #endif 463c3899f8dSAtsushi Murai } 46412ef29a8SBrian Somers if (!(mode & MODE_INTER)) { 4654ef16f24SBrian Somers #ifdef SIGUSR1 4664ef16f24SBrian Somers pending_signal(SIGUSR1, SetUpServer); 4674ef16f24SBrian Somers #endif 4688ea8442cSBrian Somers #ifdef SIGUSR2 4698ea8442cSBrian Somers pending_signal(SIGUSR2, BringDownServer); 4708ea8442cSBrian Somers #endif 47112ef29a8SBrian Somers } 472af57ed9fSAtsushi Murai 47339f94eddSBrian Somers if (label) { 47439f94eddSBrian Somers if (SelectSystem(label, CONFFILE) < 0) { 475e4450123SBrian Somers LogPrintf(LogWARN, "Destination system %s not found in conf file.\n", 476e4450123SBrian Somers GetLabel()); 477af57ed9fSAtsushi Murai Cleanup(EX_START); 478af57ed9fSAtsushi Murai } 47939f94eddSBrian Somers /* 48039f94eddSBrian Somers * We don't SetLabel() 'till now in case SelectSystem() has an 48139f94eddSBrian Somers * embeded load "otherlabel" command. 48239f94eddSBrian Somers */ 48339f94eddSBrian Somers SetLabel(label); 48412ef29a8SBrian Somers if (mode & MODE_OUTGOING_DAEMON && 48512ef29a8SBrian Somers DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 486e4450123SBrian Somers LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for" 48739f94eddSBrian Somers " auto, background or ddial mode.\n", label); 488af57ed9fSAtsushi Murai Cleanup(EX_START); 489af57ed9fSAtsushi Murai } 490af57ed9fSAtsushi Murai } 4916efd9292SBrian Somers 49212ef29a8SBrian Somers if (mode & MODE_DAEMON) { 4936d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 4946d14e2a8SJordan K. Hubbard if (pipe(BGFiledes)) { 495afc7fa2cSBrian Somers LogPrintf(LogERROR, "pipe: %s\n", strerror(errno)); 4966d14e2a8SJordan K. Hubbard Cleanup(EX_SOCK); 4976d14e2a8SJordan K. Hubbard } 4986d14e2a8SJordan K. Hubbard } 499af57ed9fSAtsushi Murai 500af57ed9fSAtsushi Murai if (!(mode & MODE_DIRECT)) { 5016d14e2a8SJordan K. Hubbard pid_t bgpid; 502a9c6b5dfSAtsushi Murai 5036d14e2a8SJordan K. Hubbard bgpid = fork(); 5046d14e2a8SJordan K. Hubbard if (bgpid == -1) { 505afc7fa2cSBrian Somers LogPrintf(LogERROR, "fork: %s\n", strerror(errno)); 5066d14e2a8SJordan K. Hubbard Cleanup(EX_SOCK); 5076d14e2a8SJordan K. Hubbard } 5086d14e2a8SJordan K. Hubbard if (bgpid) { 5096d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 510a9c6b5dfSAtsushi Murai 5116d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 5126d14e2a8SJordan K. Hubbard /* Wait for our child to close its pipe before we exit. */ 5136d14e2a8SJordan K. Hubbard BGPid = bgpid; 5146e4959f0SBrian Somers close(BGFiledes[1]); 5156efd9292SBrian Somers if (read(BGFiledes[0], &c, 1) != 1) { 516927145beSBrian Somers fprintf(VarTerm, "Child exit, no status.\n"); 517927145beSBrian Somers LogPrintf(LogPHASE, "Parent: Child exit, no status.\n"); 5186efd9292SBrian Somers } else if (c == EX_NORMAL) { 519927145beSBrian Somers fprintf(VarTerm, "PPP enabled.\n"); 520927145beSBrian Somers LogPrintf(LogPHASE, "Parent: PPP enabled.\n"); 5216efd9292SBrian Somers } else { 522927145beSBrian Somers fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c)); 523927145beSBrian Somers LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 52480e37c72SBrian Somers ex_desc((int) c)); 5256efd9292SBrian Somers } 5266e4959f0SBrian Somers close(BGFiledes[0]); 5276d14e2a8SJordan K. Hubbard } 5284ef16f24SBrian Somers return c; 5296e4959f0SBrian Somers } else if (mode & MODE_BACKGROUND) 5306e4959f0SBrian Somers close(BGFiledes[0]); 531aefd026aSBrian Somers } 532aefd026aSBrian Somers 533d656a4c5SBrian Somers VarTerm = 0; /* We know it's currently stdout */ 534fd2bc5ebSBrian Somers close(1); 535d656a4c5SBrian Somers close(2); 5360706ff38SBrian Somers 537d656a4c5SBrian Somers if (mode & MODE_DIRECT) 538e7250038SBrian Somers /* fd 0 gets used by OpenModem in DIRECT mode */ 539368aee2bSBrian Somers TtyInit(1); 54012ef29a8SBrian Somers else if (mode & MODE_DAEMON) { 541d656a4c5SBrian Somers setsid(); 542fd2bc5ebSBrian Somers close(0); 543d656a4c5SBrian Somers } 544af57ed9fSAtsushi Murai } else { 545e7250038SBrian Somers close(0); 546e7250038SBrian Somers close(2); 547368aee2bSBrian Somers TtyInit(0); 548c3899f8dSAtsushi Murai TtyCommandMode(1); 549af57ed9fSAtsushi Murai } 55035495becSBrian Somers 55170ee81ffSBrian Somers snprintf(pid_filename, sizeof pid_filename, "%stun%d.pid", 55235495becSBrian Somers _PATH_VARRUN, tunno); 5535106c671SBrian Somers lockfile = ID0fopen(pid_filename, "w"); 5545106c671SBrian Somers if (lockfile != NULL) { 55535495becSBrian Somers fprintf(lockfile, "%d\n", (int) getpid()); 55635495becSBrian Somers fclose(lockfile); 55735495becSBrian Somers } else 55835495becSBrian Somers LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 55935495becSBrian Somers pid_filename, strerror(errno)); 56035495becSBrian Somers 561927145beSBrian Somers LogPrintf(LogPHASE, "PPP Started.\n"); 562af57ed9fSAtsushi Murai 563af57ed9fSAtsushi Murai 564af57ed9fSAtsushi Murai do 565af57ed9fSAtsushi Murai DoLoop(); 566af57ed9fSAtsushi Murai while (mode & MODE_DEDICATED); 567af57ed9fSAtsushi Murai 568af57ed9fSAtsushi Murai Cleanup(EX_DONE); 5694ef16f24SBrian Somers return 0; 570af57ed9fSAtsushi Murai } 571af57ed9fSAtsushi Murai 572af57ed9fSAtsushi Murai /* 5736d14e2a8SJordan K. Hubbard * Turn into packet mode, where we speak PPP. 574af57ed9fSAtsushi Murai */ 575af57ed9fSAtsushi Murai void 576af57ed9fSAtsushi Murai PacketMode() 577af57ed9fSAtsushi Murai { 5789780ef31SBrian Somers if (RawModem() < 0) { 579927145beSBrian Somers LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 580af57ed9fSAtsushi Murai return; 581af57ed9fSAtsushi Murai } 582af57ed9fSAtsushi Murai AsyncInit(); 58303604f35SBrian Somers VjInit(15); 584af57ed9fSAtsushi Murai LcpInit(); 585af57ed9fSAtsushi Murai IpcpInit(); 586af57ed9fSAtsushi Murai CcpInit(); 587af57ed9fSAtsushi Murai LcpUp(); 588af57ed9fSAtsushi Murai 589af57ed9fSAtsushi Murai LcpOpen(VarOpenMode); 59012ef29a8SBrian Somers if (mode & MODE_INTER) 591c3899f8dSAtsushi Murai TtyCommandMode(1); 592927145beSBrian Somers if (VarTerm) { 593927145beSBrian Somers fprintf(VarTerm, "Packet mode.\n"); 594b0cdb3ceSJordan K. Hubbard aft_cmd = 1; 595af57ed9fSAtsushi Murai } 596af57ed9fSAtsushi Murai } 597af57ed9fSAtsushi Murai 598af57ed9fSAtsushi Murai static void 599b6e82f33SBrian Somers ShowHelp(void) 600af57ed9fSAtsushi Murai { 601030d3ce6SBrian Somers fprintf(stderr, "The following commands are available:\r\n"); 602030d3ce6SBrian Somers fprintf(stderr, " ~p\tEnter Packet mode\r\n"); 603030d3ce6SBrian Somers fprintf(stderr, " ~-\tDecrease log level\r\n"); 604030d3ce6SBrian Somers fprintf(stderr, " ~+\tIncrease log level\r\n"); 605030d3ce6SBrian Somers fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n"); 606030d3ce6SBrian Somers fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n"); 607030d3ce6SBrian Somers fprintf(stderr, " ~.\tTerminate program\r\n"); 608030d3ce6SBrian Somers fprintf(stderr, " ~?\tThis help\r\n"); 609af57ed9fSAtsushi Murai } 610af57ed9fSAtsushi Murai 611af57ed9fSAtsushi Murai static void 612b6e82f33SBrian Somers ReadTty(void) 613af57ed9fSAtsushi Murai { 614af57ed9fSAtsushi Murai int n; 615af57ed9fSAtsushi Murai char ch; 616af57ed9fSAtsushi Murai static int ttystate; 61786e02934SBrian Somers char linebuff[LINE_LEN]; 618af57ed9fSAtsushi Murai 619927145beSBrian Somers LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 620927145beSBrian Somers TermMode, netfd, mode); 621af57ed9fSAtsushi Murai if (!TermMode) { 62270ee81ffSBrian Somers n = read(netfd, linebuff, sizeof linebuff - 1); 62353c9f6c0SAtsushi Murai if (n > 0) { 624927145beSBrian Somers aft_cmd = 1; 625a1e8f937SBrian Somers if (linebuff[n-1] == '\n') 626a1e8f937SBrian Somers linebuff[--n] = '\0'; 62770ee81ffSBrian Somers else 62870ee81ffSBrian Somers linebuff[n] = '\0'; 629d9181b05SBrian Somers if (n) 630d9181b05SBrian Somers DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client"); 631a1e8f937SBrian Somers Prompt(); 632e7250038SBrian Somers } else if (n <= 0) { 633e7250038SBrian Somers LogPrintf(LogPHASE, "Client connection closed.\n"); 634e7250038SBrian Somers DropClient(0); 635e7250038SBrian Somers } 636af57ed9fSAtsushi Murai return; 637af57ed9fSAtsushi Murai } 638af57ed9fSAtsushi Murai 639af57ed9fSAtsushi Murai /* 640af57ed9fSAtsushi Murai * We are in terminal mode, decode special sequences 641af57ed9fSAtsushi Murai */ 642927145beSBrian Somers n = read(fileno(VarTerm), &ch, 1); 643afc7fa2cSBrian Somers LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n); 644af57ed9fSAtsushi Murai 645af57ed9fSAtsushi Murai if (n > 0) { 646af57ed9fSAtsushi Murai switch (ttystate) { 647af57ed9fSAtsushi Murai case 0: 648af57ed9fSAtsushi Murai if (ch == '~') 649af57ed9fSAtsushi Murai ttystate++; 650af57ed9fSAtsushi Murai else 651af57ed9fSAtsushi Murai write(modem, &ch, n); 652af57ed9fSAtsushi Murai break; 653af57ed9fSAtsushi Murai case 1: 654af57ed9fSAtsushi Murai switch (ch) { 655af57ed9fSAtsushi Murai case '?': 656af57ed9fSAtsushi Murai ShowHelp(); 657af57ed9fSAtsushi Murai break; 658af57ed9fSAtsushi Murai case 'p': 659944f7098SBrian Somers 660af57ed9fSAtsushi Murai /* 661af57ed9fSAtsushi Murai * XXX: Should check carrier. 662af57ed9fSAtsushi Murai */ 663af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 664af57ed9fSAtsushi Murai VarOpenMode = OPEN_ACTIVE; 665af57ed9fSAtsushi Murai PacketMode(); 666af57ed9fSAtsushi Murai } 667af57ed9fSAtsushi Murai break; 668af57ed9fSAtsushi Murai case '.': 669af57ed9fSAtsushi Murai TermMode = 1; 670927145beSBrian Somers aft_cmd = 1; 671c3899f8dSAtsushi Murai TtyCommandMode(1); 672af57ed9fSAtsushi Murai break; 673927145beSBrian Somers case 't': 674927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 675927145beSBrian Somers ShowTimers(); 676927145beSBrian Somers break; 677927145beSBrian Somers } 678927145beSBrian Somers case 'm': 679927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 680b6e82f33SBrian Somers ShowMemMap(NULL); 681927145beSBrian Somers break; 682927145beSBrian Somers } 683af57ed9fSAtsushi Murai default: 684af57ed9fSAtsushi Murai if (write(modem, &ch, n) < 0) 685927145beSBrian Somers LogPrintf(LogERROR, "error writing to modem.\n"); 686af57ed9fSAtsushi Murai break; 687af57ed9fSAtsushi Murai } 688af57ed9fSAtsushi Murai ttystate = 0; 689af57ed9fSAtsushi Murai break; 690af57ed9fSAtsushi Murai } 691af57ed9fSAtsushi Murai } 692af57ed9fSAtsushi Murai } 693af57ed9fSAtsushi Murai 694af57ed9fSAtsushi Murai 695af57ed9fSAtsushi Murai /* 696af57ed9fSAtsushi Murai * Here, we'll try to detect HDLC frame 697af57ed9fSAtsushi Murai */ 698af57ed9fSAtsushi Murai 699b6e82f33SBrian Somers static const char *FrameHeaders[] = { 70053c9f6c0SAtsushi Murai "\176\377\003\300\041", 70153c9f6c0SAtsushi Murai "\176\377\175\043\300\041", 70253c9f6c0SAtsushi Murai "\176\177\175\043\100\041", 70353c9f6c0SAtsushi Murai "\176\175\337\175\043\300\041", 70453c9f6c0SAtsushi Murai "\176\175\137\175\043\100\041", 705af57ed9fSAtsushi Murai NULL, 706af57ed9fSAtsushi Murai }; 707af57ed9fSAtsushi Murai 708b6e82f33SBrian Somers static const u_char * 709944f7098SBrian Somers HdlcDetect(u_char * cp, int n) 710af57ed9fSAtsushi Murai { 711b6e82f33SBrian Somers const char *ptr, *fp, **hp; 712af57ed9fSAtsushi Murai 713af57ed9fSAtsushi Murai cp[n] = '\0'; /* be sure to null terminated */ 714af57ed9fSAtsushi Murai ptr = NULL; 715af57ed9fSAtsushi Murai for (hp = FrameHeaders; *hp; hp++) { 71653c9f6c0SAtsushi Murai fp = *hp; 71753c9f6c0SAtsushi Murai if (DEV_IS_SYNC) 71853c9f6c0SAtsushi Murai fp++; 719ed6a16c1SPoul-Henning Kamp ptr = strstr((char *) cp, fp); 720ed6a16c1SPoul-Henning Kamp if (ptr) 721af57ed9fSAtsushi Murai break; 722af57ed9fSAtsushi Murai } 723b6e82f33SBrian Somers return ((const u_char *) ptr); 724af57ed9fSAtsushi Murai } 725af57ed9fSAtsushi Murai 726af57ed9fSAtsushi Murai static struct pppTimer RedialTimer; 727af57ed9fSAtsushi Murai 728af57ed9fSAtsushi Murai static void 729b6e82f33SBrian Somers RedialTimeout(void *v) 730af57ed9fSAtsushi Murai { 731af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 732927145beSBrian Somers LogPrintf(LogPHASE, "Redialing timer expired.\n"); 733af57ed9fSAtsushi Murai } 734af57ed9fSAtsushi Murai 735af57ed9fSAtsushi Murai static void 736944f7098SBrian Somers StartRedialTimer(int Timeout) 737af57ed9fSAtsushi Murai { 738af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 739a9c6b5dfSAtsushi Murai 74043ea9d19SBrian Somers if (Timeout) { 741af57ed9fSAtsushi Murai RedialTimer.state = TIMER_STOPPED; 742a9c6b5dfSAtsushi Murai 74343ea9d19SBrian Somers if (Timeout > 0) 74443ea9d19SBrian Somers RedialTimer.load = Timeout * SECTICKS; 745a9c6b5dfSAtsushi Murai else 746a9c6b5dfSAtsushi Murai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 747a9c6b5dfSAtsushi Murai 748927145beSBrian Somers LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 74943ea9d19SBrian Somers RedialTimer.load / SECTICKS); 75043ea9d19SBrian Somers 751af57ed9fSAtsushi Murai RedialTimer.func = RedialTimeout; 752af57ed9fSAtsushi Murai StartTimer(&RedialTimer); 753af57ed9fSAtsushi Murai } 754a9c6b5dfSAtsushi Murai } 755af57ed9fSAtsushi Murai 75658f264e1SBrian Somers #define IN_SIZE sizeof(struct sockaddr_in) 75758f264e1SBrian Somers #define UN_SIZE sizeof(struct sockaddr_in) 75858f264e1SBrian Somers #define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE) 759af57ed9fSAtsushi Murai 760af57ed9fSAtsushi Murai static void 761b6e82f33SBrian Somers DoLoop(void) 762af57ed9fSAtsushi Murai { 763af57ed9fSAtsushi Murai fd_set rfds, wfds, efds; 764780700e5SAndrey A. Chernov int pri, i, n, wfd, nfds; 76558f264e1SBrian Somers char hisaddr[ADDRSZ]; 76658f264e1SBrian Somers struct sockaddr *sa = (struct sockaddr *)hisaddr; 76758f264e1SBrian Somers struct sockaddr_in *sin = (struct sockaddr_in *)hisaddr; 768af57ed9fSAtsushi Murai struct timeval timeout, *tp; 76958f264e1SBrian Somers int ssize = ADDRSZ; 770b6e82f33SBrian Somers const u_char *cp; 771a9c6b5dfSAtsushi Murai int tries; 77260e218e4SAtsushi Murai int qlen; 773368aee2bSBrian Somers int res; 7746a6b4bbbSBrian Somers struct tun_data tun; 7756a6b4bbbSBrian Somers #define rbuff tun.data 776c3899f8dSAtsushi Murai 7776efd9292SBrian Somers if (mode & MODE_DIRECT) { 7780706ff38SBrian Somers LogPrintf(LogDEBUG, "Opening modem\n"); 7799780ef31SBrian Somers if (OpenModem() < 0) 780bc240299SBrian Somers return; 781927145beSBrian Somers LogPrintf(LogPHASE, "Packet mode enabled\n"); 782af57ed9fSAtsushi Murai PacketMode(); 783af57ed9fSAtsushi Murai } else if (mode & MODE_DEDICATED) { 784780700e5SAndrey A. Chernov if (modem < 0) 7859780ef31SBrian Somers while (OpenModem() < 0) 7869a571ec7SBrian Somers nointr_sleep(VarReconnectTimer); 787af57ed9fSAtsushi Murai } 788927145beSBrian Somers fflush(VarTerm); 789af57ed9fSAtsushi Murai 79084b8a6ebSAtsushi Murai timeout.tv_sec = 0; 791af57ed9fSAtsushi Murai timeout.tv_usec = 0; 79225aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 793af57ed9fSAtsushi Murai 7946e4959f0SBrian Somers if (mode & MODE_BACKGROUND) 79575240ed1SBrian Somers dial_up = 1; /* Bring the line up */ 7966e4959f0SBrian Somers else 79775240ed1SBrian Somers dial_up = 0; /* XXXX */ 798a9c6b5dfSAtsushi Murai tries = 0; 799af57ed9fSAtsushi Murai for (;;) { 800780700e5SAndrey A. Chernov nfds = 0; 801944f7098SBrian Somers FD_ZERO(&rfds); 802944f7098SBrian Somers FD_ZERO(&wfds); 803944f7098SBrian Somers FD_ZERO(&efds); 80484b8a6ebSAtsushi Murai 80584b8a6ebSAtsushi Murai /* 806944f7098SBrian Somers * If the link is down and we're in DDIAL mode, bring it back up. 807680026d6SNate Williams */ 808680026d6SNate Williams if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 80975240ed1SBrian Somers dial_up = 1; 810680026d6SNate Williams 811680026d6SNate Williams /* 812944f7098SBrian Somers * If we lost carrier and want to re-establish the connection due to the 813944f7098SBrian Somers * "set reconnect" value, we'd better bring the line back up. 81407030d97SBrian Somers */ 8156efd9292SBrian Somers if (LcpFsm.state <= ST_CLOSED) { 81675240ed1SBrian Somers if (!dial_up && reconnectState == RECON_TRUE) { 8176efd9292SBrian Somers if (++reconnectCount <= VarReconnectTries) { 818927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 8196efd9292SBrian Somers reconnectCount, VarReconnectTries); 82007030d97SBrian Somers StartRedialTimer(VarReconnectTimer); 82175240ed1SBrian Somers dial_up = 1; 822298091daSBrian Somers } else { 8236efd9292SBrian Somers if (VarReconnectTries) 824927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 825298091daSBrian Somers VarReconnectTries); 8266efd9292SBrian Somers reconnectCount = 0; 8276efd9292SBrian Somers if (mode & MODE_BACKGROUND) 8286efd9292SBrian Somers Cleanup(EX_DEAD); 8296efd9292SBrian Somers } 83025aa96acSBrian Somers reconnectState = RECON_ENVOKED; 83112ef29a8SBrian Somers } else if (mode & MODE_DEDICATED) 83212ef29a8SBrian Somers if (VarOpenMode == OPEN_ACTIVE) 83312ef29a8SBrian Somers PacketMode(); 83407030d97SBrian Somers } 83507030d97SBrian Somers 83607030d97SBrian Somers /* 837944f7098SBrian Somers * If Ip packet for output is enqueued and require dial up, Just do it! 83884b8a6ebSAtsushi Murai */ 83907030d97SBrian Somers if (dial_up && RedialTimer.state != TIMER_RUNNING) { 840927145beSBrian Somers LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 8419780ef31SBrian Somers if (OpenModem() < 0) { 8420706ff38SBrian Somers tries++; 843712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries) 8440706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 8450706ff38SBrian Somers tries, VarDialTries); 8460706ff38SBrian Somers else 8470706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 8480706ff38SBrian Somers 849712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) { 8500706ff38SBrian Somers if (mode & MODE_BACKGROUND) 8510706ff38SBrian Somers Cleanup(EX_DIAL); /* Can't get the modem */ 85275240ed1SBrian Somers dial_up = 0; 8530706ff38SBrian Somers reconnectState = RECON_UNKNOWN; 8540706ff38SBrian Somers reconnectCount = 0; 8550706ff38SBrian Somers tries = 0; 8560706ff38SBrian Somers } else 85743ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 85884b8a6ebSAtsushi Murai } else { 859944f7098SBrian Somers tries++; /* Tries are per number, not per list of 860944f7098SBrian Somers * numbers. */ 861712ae387SBrian Somers if (!(mode & MODE_DDIAL) && VarDialTries) 862712ae387SBrian Somers LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries); 863c0139fb2SBrian Somers else 864927145beSBrian Somers LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 865712ae387SBrian Somers 866368aee2bSBrian Somers if ((res = DialModem()) == EX_DONE) { 8679a571ec7SBrian Somers nointr_sleep(1); /* little pause to allow peer starts */ 868b6e82f33SBrian Somers ModemTimeout(NULL); 86984b8a6ebSAtsushi Murai PacketMode(); 87075240ed1SBrian Somers dial_up = 0; 87125aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 872a9c6b5dfSAtsushi Murai tries = 0; 87384b8a6ebSAtsushi Murai } else { 8744ed9958fSBrian Somers if (mode & MODE_BACKGROUND) { 875368aee2bSBrian Somers if (VarNextPhone == NULL || res == EX_SIG) 8764ed9958fSBrian Somers Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 8774ed9958fSBrian Somers else 87843ea9d19SBrian Somers /* Try all numbers in background mode */ 87943ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 880368aee2bSBrian Somers } else if (!(mode & MODE_DDIAL) && 881368aee2bSBrian Somers ((VarDialTries && tries >= VarDialTries) || 882368aee2bSBrian Somers res == EX_SIG)) { 883c0139fb2SBrian Somers /* I give up ! Can't get through :( */ 88443ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 88575240ed1SBrian Somers dial_up = 0; 88625aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 88725aa96acSBrian Somers reconnectCount = 0; 888a9c6b5dfSAtsushi Murai tries = 0; 889c0139fb2SBrian Somers } else if (VarNextPhone == NULL) 890c0139fb2SBrian Somers /* Dial failed. Keep quite during redial wait period. */ 89143ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 892c0139fb2SBrian Somers else 89343ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 89484b8a6ebSAtsushi Murai } 89584b8a6ebSAtsushi Murai } 89684b8a6ebSAtsushi Murai } 89760e218e4SAtsushi Murai qlen = ModemQlen(); 89876bd0c0aSDoug Rabson 89976bd0c0aSDoug Rabson if (qlen == 0) { 90076bd0c0aSDoug Rabson IpStartOutput(); 90176bd0c0aSDoug Rabson qlen = ModemQlen(); 90276bd0c0aSDoug Rabson } 903780700e5SAndrey A. Chernov if (modem >= 0) { 904780700e5SAndrey A. Chernov if (modem + 1 > nfds) 905780700e5SAndrey A. Chernov nfds = modem + 1; 90684b8a6ebSAtsushi Murai FD_SET(modem, &rfds); 90784b8a6ebSAtsushi Murai FD_SET(modem, &efds); 90860e218e4SAtsushi Murai if (qlen > 0) { 90984b8a6ebSAtsushi Murai FD_SET(modem, &wfds); 91084b8a6ebSAtsushi Murai } 91184b8a6ebSAtsushi Murai } 912780700e5SAndrey A. Chernov if (server >= 0) { 913780700e5SAndrey A. Chernov if (server + 1 > nfds) 914780700e5SAndrey A. Chernov nfds = server + 1; 915780700e5SAndrey A. Chernov FD_SET(server, &rfds); 916780700e5SAndrey A. Chernov } 917af57ed9fSAtsushi Murai 918944f7098SBrian Somers /* 919944f7098SBrian Somers * *** IMPORTANT *** 920af57ed9fSAtsushi Murai * 921944f7098SBrian Somers * CPU is serviced every TICKUNIT micro seconds. This value must be chosen 922944f7098SBrian Somers * with great care. If this values is too big, it results loss of 923944f7098SBrian Somers * characters from modem and poor responce. If this values is too small, 924944f7098SBrian Somers * ppp process eats many CPU time. 925af57ed9fSAtsushi Murai */ 92653c9f6c0SAtsushi Murai #ifndef SIGALRM 9279a571ec7SBrian Somers nointr_usleep(TICKUNIT); 928af57ed9fSAtsushi Murai TimerService(); 929f5ff0f7cSBrian Somers #else 930f5ff0f7cSBrian Somers handle_signals(); 93153c9f6c0SAtsushi Murai #endif 93268d2b4d6SBruce Evans 93368d2b4d6SBruce Evans /* If there are aren't many packets queued, look for some more. */ 934780700e5SAndrey A. Chernov if (qlen < 20 && tun_in >= 0) { 935780700e5SAndrey A. Chernov if (tun_in + 1 > nfds) 936780700e5SAndrey A. Chernov nfds = tun_in + 1; 93784b8a6ebSAtsushi Murai FD_SET(tun_in, &rfds); 938780700e5SAndrey A. Chernov } 939780700e5SAndrey A. Chernov if (netfd >= 0) { 940780700e5SAndrey A. Chernov if (netfd + 1 > nfds) 941780700e5SAndrey A. Chernov nfds = netfd + 1; 942af57ed9fSAtsushi Murai FD_SET(netfd, &rfds); 943af57ed9fSAtsushi Murai FD_SET(netfd, &efds); 944af57ed9fSAtsushi Murai } 94553c9f6c0SAtsushi Murai #ifndef SIGALRM 946944f7098SBrian Somers 947af57ed9fSAtsushi Murai /* 948944f7098SBrian Somers * Normally, select() will not block because modem is writable. In AUTO 949944f7098SBrian Somers * mode, select will block until we find packet from tun 950af57ed9fSAtsushi Murai */ 951af57ed9fSAtsushi Murai tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL; 952780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 95353c9f6c0SAtsushi Murai #else 954944f7098SBrian Somers 95584b8a6ebSAtsushi Murai /* 956944f7098SBrian Somers * When SIGALRM timer is running, a select function will be return -1 and 957944f7098SBrian Somers * EINTR after a Time Service signal hundler is done. If the redial 958944f7098SBrian Somers * timer is not running and we are trying to dial, poll with a 0 value 959944f7098SBrian Somers * timer. 96084b8a6ebSAtsushi Murai */ 961a9c6b5dfSAtsushi Murai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 962780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 96353c9f6c0SAtsushi Murai #endif 9646b0b88d8SBrian Somers 965af57ed9fSAtsushi Murai if (i == 0) { 966af57ed9fSAtsushi Murai continue; 967af57ed9fSAtsushi Murai } 968534fe541SBrian Somers if (i < 0) { 969534fe541SBrian Somers if (errno == EINTR) { 970f5ff0f7cSBrian Somers handle_signals(); 971f5ff0f7cSBrian Somers continue; 97284b8a6ebSAtsushi Murai } 973afc7fa2cSBrian Somers LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); 974af57ed9fSAtsushi Murai break; 975af57ed9fSAtsushi Murai } 976780700e5SAndrey A. Chernov if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 977927145beSBrian Somers LogPrintf(LogALERT, "Exception detected.\n"); 978af57ed9fSAtsushi Murai break; 979af57ed9fSAtsushi Murai } 980780700e5SAndrey A. Chernov if (server >= 0 && FD_ISSET(server, &rfds)) { 98158f264e1SBrian Somers wfd = accept(server, sa, &ssize); 982e0d3e233SAndrey A. Chernov if (wfd < 0) { 983afc7fa2cSBrian Somers LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno)); 984e0d3e233SAndrey A. Chernov continue; 985e0d3e233SAndrey A. Chernov } 98658f264e1SBrian Somers switch (sa->sa_family) { 98758f264e1SBrian Somers case AF_LOCAL: 98858f264e1SBrian Somers LogPrintf(LogPHASE, "Connected to local client.\n"); 98958f264e1SBrian Somers break; 99058f264e1SBrian Somers case AF_INET: 9914401489aSBrian Somers if (ntohs(sin->sin_port) < 1024) { 99258f264e1SBrian Somers LogPrintf(LogALERT, "Rejected client connection from %s:%u" 99358f264e1SBrian Somers "(invalid port number) !\n", 9944401489aSBrian Somers inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); 995af57ed9fSAtsushi Murai close(wfd); 996af57ed9fSAtsushi Murai continue; 99758f264e1SBrian Somers } 99858f264e1SBrian Somers LogPrintf(LogPHASE, "Connected to client from %s:%u\n", 99958f264e1SBrian Somers inet_ntoa(sin->sin_addr), sin->sin_port); 100058f264e1SBrian Somers break; 100158f264e1SBrian Somers default: 100258f264e1SBrian Somers write(wfd, "Unrecognised access !\n", 22); 100358f264e1SBrian Somers close(wfd); 100458f264e1SBrian Somers continue; 100558f264e1SBrian Somers } 100658f264e1SBrian Somers if (netfd >= 0) { 100758f264e1SBrian Somers write(wfd, "Connection already in use.\n", 27); 100858f264e1SBrian Somers close(wfd); 100958f264e1SBrian Somers continue; 101058f264e1SBrian Somers } 1011af57ed9fSAtsushi Murai netfd = wfd; 1012927145beSBrian Somers VarTerm = fdopen(netfd, "a+"); 10138ea8442cSBrian Somers LocalAuthInit(); 1014af57ed9fSAtsushi Murai Greetings(); 1015a1e8f937SBrian Somers IsInteractive(1); 1016274e766cSBrian Somers Prompt(); 1017af57ed9fSAtsushi Murai } 10180053cc58SBrian Somers if (netfd >= 0 && FD_ISSET(netfd, &rfds)) 1019af57ed9fSAtsushi Murai /* something to read from tty */ 1020af57ed9fSAtsushi Murai ReadTty(); 10210053cc58SBrian Somers if (modem >= 0 && FD_ISSET(modem, &wfds)) { 10220053cc58SBrian Somers /* ready to write into modem */ 1023af57ed9fSAtsushi Murai ModemStartOutput(modem); 10240053cc58SBrian Somers if (modem < 0) 10250053cc58SBrian Somers dial_up = 1; 1026af57ed9fSAtsushi Murai } 10270053cc58SBrian Somers if (modem >= 0 && FD_ISSET(modem, &rfds)) { 10280053cc58SBrian Somers /* something to read from modem */ 102953c9f6c0SAtsushi Murai if (LcpFsm.state <= ST_CLOSED) 10309a571ec7SBrian Somers nointr_usleep(10000); 103170ee81ffSBrian Somers n = read(modem, rbuff, sizeof rbuff); 1032af57ed9fSAtsushi Murai if ((mode & MODE_DIRECT) && n <= 0) { 1033af57ed9fSAtsushi Murai DownConnection(); 1034af57ed9fSAtsushi Murai } else 1035927145beSBrian Somers LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 1036af57ed9fSAtsushi Murai 1037af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 1038af57ed9fSAtsushi Murai /* 1039af57ed9fSAtsushi Murai * In dedicated mode, we just discard input until LCP is started. 1040af57ed9fSAtsushi Murai */ 1041af57ed9fSAtsushi Murai if (!(mode & MODE_DEDICATED)) { 1042af57ed9fSAtsushi Murai cp = HdlcDetect(rbuff, n); 1043af57ed9fSAtsushi Murai if (cp) { 1044af57ed9fSAtsushi Murai /* 1045af57ed9fSAtsushi Murai * LCP packet is detected. Turn ourselves into packet mode. 1046af57ed9fSAtsushi Murai */ 1047af57ed9fSAtsushi Murai if (cp != rbuff) { 1048927145beSBrian Somers write(modem, rbuff, cp - rbuff); 1049927145beSBrian Somers write(modem, "\r\n", 2); 1050af57ed9fSAtsushi Murai } 1051af57ed9fSAtsushi Murai PacketMode(); 1052af57ed9fSAtsushi Murai } else 1053927145beSBrian Somers write(fileno(VarTerm), rbuff, n); 1054af57ed9fSAtsushi Murai } 1055af57ed9fSAtsushi Murai } else { 1056af57ed9fSAtsushi Murai if (n > 0) 1057af57ed9fSAtsushi Murai AsyncInput(rbuff, n); 1058af57ed9fSAtsushi Murai } 1059af57ed9fSAtsushi Murai } 1060944f7098SBrian Somers if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read 1061944f7098SBrian Somers * from tun */ 106270ee81ffSBrian Somers n = read(tun_in, &tun, sizeof tun); 1063af57ed9fSAtsushi Murai if (n < 0) { 1064afc7fa2cSBrian Somers LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno)); 1065af57ed9fSAtsushi Murai continue; 1066af57ed9fSAtsushi Murai } 106770ee81ffSBrian Somers n -= sizeof tun - sizeof tun.data; 10686a6b4bbbSBrian Somers if (n <= 0) { 10696a6b4bbbSBrian Somers LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n); 10706a6b4bbbSBrian Somers continue; 10716a6b4bbbSBrian Somers } 10726a6b4bbbSBrian Somers if (!tun_check_header(tun, AF_INET)) 10736a6b4bbbSBrian Somers continue; 1074de451c68SBrian Somers if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) { 1075de451c68SBrian Somers /* we've been asked to send something addressed *to* us :( */ 1076de451c68SBrian Somers if (VarLoopback) { 1077de451c68SBrian Somers pri = PacketCheck(rbuff, n, FL_IN); 1078de451c68SBrian Somers if (pri >= 0) { 1079de451c68SBrian Somers struct mbuf *bp; 1080944f7098SBrian Somers 1081b6e82f33SBrian Somers #ifndef NOALIAS 1082de451c68SBrian Somers if (mode & MODE_ALIAS) { 1083de451c68SBrian Somers VarPacketAliasIn(rbuff, sizeof rbuff); 1084de451c68SBrian Somers n = ntohs(((struct ip *) rbuff)->ip_len); 1085de451c68SBrian Somers } 1086b6e82f33SBrian Somers #endif 1087de451c68SBrian Somers bp = mballoc(n, MB_IPIN); 108875240ed1SBrian Somers memcpy(MBUF_CTOP(bp), rbuff, n); 1089de451c68SBrian Somers IpInput(bp); 1090de451c68SBrian Somers LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n"); 1091de451c68SBrian Somers } 1092de451c68SBrian Somers continue; 1093de451c68SBrian Somers } else 1094de451c68SBrian Somers LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 1095de451c68SBrian Somers } 1096de451c68SBrian Somers 1097af57ed9fSAtsushi Murai /* 1098af57ed9fSAtsushi Murai * Process on-demand dialup. Output packets are queued within tunnel 1099af57ed9fSAtsushi Murai * device until IPCP is opened. 1100af57ed9fSAtsushi Murai */ 1101c60f92caSBrian Somers if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO) && 1102c60f92caSBrian Somers (pri = PacketCheck(rbuff, n, FL_DIAL)) >= 0) 1103c60f92caSBrian Somers dial_up = 1; 1104c60f92caSBrian Somers 110584b8a6ebSAtsushi Murai pri = PacketCheck(rbuff, n, FL_OUT); 1106a9f484e5SJordan K. Hubbard if (pri >= 0) { 1107b6e82f33SBrian Somers #ifndef NOALIAS 1108a9f484e5SJordan K. Hubbard if (mode & MODE_ALIAS) { 11096ed9fb2fSBrian Somers VarPacketAliasOut(rbuff, sizeof rbuff); 1110a9f484e5SJordan K. Hubbard n = ntohs(((struct ip *) rbuff)->ip_len); 1111a9f484e5SJordan K. Hubbard } 1112b6e82f33SBrian Somers #endif 1113af57ed9fSAtsushi Murai IpEnqueue(pri, rbuff, n); 1114af57ed9fSAtsushi Murai } 1115af57ed9fSAtsushi Murai } 1116a9f484e5SJordan K. Hubbard } 1117927145beSBrian Somers LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1118af57ed9fSAtsushi Murai } 1119