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 * 200706ff38SBrian Somers * $Id: main.c,v 1.60 1997/06/09 03:27:28 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 */ 26af57ed9fSAtsushi Murai #include "fsm.h" 27af57ed9fSAtsushi Murai #include <fcntl.h> 28a9c6b5dfSAtsushi Murai #include <paths.h> 29af57ed9fSAtsushi Murai #include <sys/time.h> 30af57ed9fSAtsushi Murai #include <termios.h> 31c3b6ad66SBrian Somers #include <signal.h> 32af57ed9fSAtsushi Murai #include <sys/wait.h> 33af57ed9fSAtsushi Murai #include <errno.h> 34af57ed9fSAtsushi Murai #include <netdb.h> 359f202f0cSJordan K. Hubbard #include <unistd.h> 36af57ed9fSAtsushi Murai #include <sys/socket.h> 37af57ed9fSAtsushi Murai #include <arpa/inet.h> 38a9f484e5SJordan K. Hubbard #include <netinet/in_systm.h> 39a9f484e5SJordan K. Hubbard #include <netinet/ip.h> 40af57ed9fSAtsushi Murai #include "modem.h" 41af57ed9fSAtsushi Murai #include "os.h" 42af57ed9fSAtsushi Murai #include "hdlc.h" 43ed6a16c1SPoul-Henning Kamp #include "ccp.h" 44af57ed9fSAtsushi Murai #include "lcp.h" 45af57ed9fSAtsushi Murai #include "ipcp.h" 466ed9fb2fSBrian Somers #include "loadalias.h" 47af57ed9fSAtsushi Murai #include "vars.h" 4853c9f6c0SAtsushi Murai #include "auth.h" 4984b8a6ebSAtsushi Murai #include "filter.h" 50ed6a16c1SPoul-Henning Kamp #include "systems.h" 51ed6a16c1SPoul-Henning Kamp #include "ip.h" 52f5ff0f7cSBrian Somers #include "sig.h" 5353c9f6c0SAtsushi Murai 5441db6564SAtsushi Murai #define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n" 55927145beSBrian Somers #define LAUTH_M2 "Warning: Manipulation is allowed by anyone\n" 5641db6564SAtsushi Murai 5753c9f6c0SAtsushi Murai #ifndef O_NONBLOCK 5853c9f6c0SAtsushi Murai #ifdef O_NDELAY 5953c9f6c0SAtsushi Murai #define O_NONBLOCK O_NDELAY 6053c9f6c0SAtsushi Murai #endif 6153c9f6c0SAtsushi Murai #endif 62af57ed9fSAtsushi Murai 63af57ed9fSAtsushi Murai extern void VjInit(), AsyncInit(); 64274e766cSBrian Somers extern void AsyncInput(); 65af57ed9fSAtsushi Murai extern int SelectSystem(); 66af57ed9fSAtsushi Murai 67af57ed9fSAtsushi Murai extern void DecodeCommand(), Prompt(); 68b0cdb3ceSJordan K. Hubbard extern int aft_cmd; 69af57ed9fSAtsushi Murai extern int IsInteractive(); 70af57ed9fSAtsushi Murai static void DoLoop(void); 71c3899f8dSAtsushi Murai static void TerminalStop(); 726efd9292SBrian Somers static char *ex_desc(); 73af57ed9fSAtsushi Murai 74af57ed9fSAtsushi Murai static struct termios oldtio; /* Original tty mode */ 75af57ed9fSAtsushi Murai static struct termios comtio; /* Command level tty mode */ 761dff3fc5SAndrey A. Chernov int TermMode; 777b64106aSPoul-Henning Kamp static int server; 786d14e2a8SJordan K. Hubbard static pid_t BGPid = 0; 79af57ed9fSAtsushi Murai struct sockaddr_in ifsin; 8041c6c543SBrian Somers static char pid_filename[MAXPATHLEN]; 8141c6c543SBrian Somers static char if_filename[MAXPATHLEN]; 8263202ff1SAndrey A. Chernov int tunno; 83af57ed9fSAtsushi Murai 84af57ed9fSAtsushi Murai static void 85af57ed9fSAtsushi Murai TtyInit() 86af57ed9fSAtsushi Murai { 87af57ed9fSAtsushi Murai struct termios newtio; 88af57ed9fSAtsushi Murai int stat; 89af57ed9fSAtsushi Murai 90af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 91274e766cSBrian Somers if (stat > 0) { 92af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 93274e766cSBrian Somers (void)fcntl(0, F_SETFL, stat); 94274e766cSBrian Somers } 95af57ed9fSAtsushi Murai newtio = oldtio; 96af57ed9fSAtsushi Murai newtio.c_lflag &= ~(ECHO|ISIG|ICANON); 97af57ed9fSAtsushi Murai newtio.c_iflag = 0; 98af57ed9fSAtsushi Murai newtio.c_oflag &= ~OPOST; 99af57ed9fSAtsushi Murai newtio.c_cc[VEOF] = _POSIX_VDISABLE; 100af57ed9fSAtsushi Murai newtio.c_cc[VINTR] = _POSIX_VDISABLE; 101af57ed9fSAtsushi Murai newtio.c_cc[VMIN] = 1; 102af57ed9fSAtsushi Murai newtio.c_cc[VTIME] = 0; 103af57ed9fSAtsushi Murai newtio.c_cflag |= CS8; 10453c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 105af57ed9fSAtsushi Murai comtio = newtio; 106af57ed9fSAtsushi Murai } 107af57ed9fSAtsushi Murai 108af57ed9fSAtsushi Murai /* 109af57ed9fSAtsushi Murai * Set tty into command mode. We allow canonical input and echo processing. 110af57ed9fSAtsushi Murai */ 111c3899f8dSAtsushi Murai void 112c3899f8dSAtsushi Murai TtyCommandMode(prompt) 113c3899f8dSAtsushi Murai int prompt; 114af57ed9fSAtsushi Murai { 115af57ed9fSAtsushi Murai struct termios newtio; 116af57ed9fSAtsushi Murai int stat; 117af57ed9fSAtsushi Murai 118af57ed9fSAtsushi Murai if (!(mode & MODE_INTER)) 119af57ed9fSAtsushi Murai return; 12053c9f6c0SAtsushi Murai tcgetattr(0, &newtio); 121c3899f8dSAtsushi Murai newtio.c_lflag |= (ECHO|ISIG|ICANON); 122af57ed9fSAtsushi Murai newtio.c_iflag = oldtio.c_iflag; 123af57ed9fSAtsushi Murai newtio.c_oflag |= OPOST; 12453c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &newtio); 125af57ed9fSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 126274e766cSBrian Somers if (stat > 0) { 127af57ed9fSAtsushi Murai stat |= O_NONBLOCK; 128274e766cSBrian Somers (void)fcntl(0, F_SETFL, stat); 129274e766cSBrian Somers } 130af57ed9fSAtsushi Murai TermMode = 0; 131274e766cSBrian Somers if(prompt) Prompt(); 132af57ed9fSAtsushi Murai } 133af57ed9fSAtsushi Murai 134af57ed9fSAtsushi Murai /* 135af57ed9fSAtsushi Murai * Set tty into terminal mode which is used while we invoke term command. 136af57ed9fSAtsushi Murai */ 137af57ed9fSAtsushi Murai void 138af57ed9fSAtsushi Murai TtyTermMode() 139af57ed9fSAtsushi Murai { 140af57ed9fSAtsushi Murai int stat; 141af57ed9fSAtsushi Murai 14253c9f6c0SAtsushi Murai tcsetattr(0, TCSADRAIN, &comtio); 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 = 1; 149af57ed9fSAtsushi Murai } 150af57ed9fSAtsushi Murai 151af57ed9fSAtsushi Murai void 152c3899f8dSAtsushi Murai TtyOldMode() 153c3899f8dSAtsushi Murai { 154c3899f8dSAtsushi Murai int stat; 155c3899f8dSAtsushi Murai 156c3899f8dSAtsushi Murai stat = fcntl(0, F_GETFL, 0); 157274e766cSBrian Somers if (stat > 0) { 158c3899f8dSAtsushi Murai stat &= ~O_NONBLOCK; 159274e766cSBrian Somers (void)fcntl(0, F_SETFL, stat); 160274e766cSBrian Somers } 161c3899f8dSAtsushi Murai tcsetattr(0, TCSANOW, &oldtio); 162c3899f8dSAtsushi Murai } 163c3899f8dSAtsushi Murai 164c3899f8dSAtsushi Murai void 165af57ed9fSAtsushi Murai Cleanup(excode) 166af57ed9fSAtsushi Murai int excode; 167af57ed9fSAtsushi Murai { 168af57ed9fSAtsushi Murai 169af57ed9fSAtsushi Murai OsLinkdown(); 170af57ed9fSAtsushi Murai OsCloseLink(1); 171af57ed9fSAtsushi Murai sleep(1); 1726efd9292SBrian Somers if (mode & MODE_AUTO) 1736e4959f0SBrian Somers DeleteIfRoutes(1); 174aefd026aSBrian Somers (void)unlink(pid_filename); 175aefd026aSBrian Somers (void)unlink(if_filename); 176af57ed9fSAtsushi Murai OsInterfaceDown(1); 1776e4959f0SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 1786e4959f0SBrian Somers char c = EX_ERRDEAD; 1796e4959f0SBrian Somers if (write(BGFiledes[1],&c,1) == 1) 180927145beSBrian Somers LogPrintf(LogPHASE,"Parent notified of failure.\n"); 1816e4959f0SBrian Somers else 182927145beSBrian Somers LogPrintf(LogPHASE,"Failed to notify parent of failure.\n"); 1836e4959f0SBrian Somers close(BGFiledes[1]); 1846e4959f0SBrian Somers } 185927145beSBrian Somers LogPrintf(LogPHASE, "PPP Terminated (%s).\n",ex_desc(excode)); 186af57ed9fSAtsushi Murai LogClose(); 187780700e5SAndrey A. Chernov if (server >= 0) { 188af57ed9fSAtsushi Murai close(server); 189780700e5SAndrey A. Chernov server = -1; 190780700e5SAndrey A. Chernov } 191aefd026aSBrian Somers 192c3899f8dSAtsushi Murai TtyOldMode(); 193af57ed9fSAtsushi Murai 194af57ed9fSAtsushi Murai exit(excode); 195af57ed9fSAtsushi Murai } 196af57ed9fSAtsushi Murai 197af57ed9fSAtsushi Murai static void 1987a8ef19eSAndrey A. Chernov Hangup(signo) 1997a8ef19eSAndrey A. Chernov int signo; 200af57ed9fSAtsushi Murai { 201927145beSBrian Somers #ifdef TRAPSEGV 202af83607cSAndrey A. Chernov if (signo == SIGSEGV) { 203927145beSBrian Somers LogPrintf(LogPHASE, "Signal %d, core dump.\n", signo); 204af83607cSAndrey A. Chernov LogClose(); 205af83607cSAndrey A. Chernov abort(); 206af83607cSAndrey A. Chernov } 207927145beSBrian Somers #endif 2086d14e2a8SJordan K. Hubbard if (BGPid) { 209c6c740beSBrian Somers kill (BGPid, SIGTERM); 2106d14e2a8SJordan K. Hubbard exit (EX_HANGUP); 2116d14e2a8SJordan K. Hubbard } 2126d14e2a8SJordan K. Hubbard else { 213927145beSBrian Somers LogPrintf(LogPHASE, "Signal %d, hangup.\n", signo); 214af57ed9fSAtsushi Murai Cleanup(EX_HANGUP); 215af57ed9fSAtsushi Murai } 2166d14e2a8SJordan K. Hubbard } 217af57ed9fSAtsushi Murai 218af57ed9fSAtsushi Murai static void 2197a8ef19eSAndrey A. Chernov CloseSession(signo) 2207a8ef19eSAndrey A. Chernov int signo; 221af57ed9fSAtsushi Murai { 2226d14e2a8SJordan K. Hubbard if (BGPid) { 2236d14e2a8SJordan K. Hubbard kill (BGPid, SIGINT); 2246d14e2a8SJordan K. Hubbard exit (EX_TERM); 2256d14e2a8SJordan K. Hubbard } 226927145beSBrian Somers LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo); 22725aa96acSBrian Somers reconnect(RECON_FALSE); 228af57ed9fSAtsushi Murai LcpClose(); 229af57ed9fSAtsushi Murai Cleanup(EX_TERM); 230af57ed9fSAtsushi Murai } 231c3899f8dSAtsushi Murai 232c3899f8dSAtsushi Murai static void 233c3899f8dSAtsushi Murai TerminalCont() 234c3899f8dSAtsushi Murai { 235f5ff0f7cSBrian Somers pending_signal(SIGCONT, SIG_DFL); 236f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 237c3899f8dSAtsushi Murai TtyCommandMode(getpgrp() == tcgetpgrp(0)); 238c3899f8dSAtsushi Murai } 239c3899f8dSAtsushi Murai 240c3899f8dSAtsushi Murai static void 241c3899f8dSAtsushi Murai TerminalStop(signo) 242c3899f8dSAtsushi Murai int signo; 243c3899f8dSAtsushi Murai { 244f5ff0f7cSBrian Somers pending_signal(SIGCONT, TerminalCont); 245c3899f8dSAtsushi Murai TtyOldMode(); 246f5ff0f7cSBrian Somers pending_signal(SIGTSTP, SIG_DFL); 247c3899f8dSAtsushi Murai kill(getpid(), signo); 248c3899f8dSAtsushi Murai } 249c3899f8dSAtsushi Murai 2506efd9292SBrian Somers static char * 2516efd9292SBrian Somers ex_desc(int ex) 2526efd9292SBrian Somers { 2536efd9292SBrian Somers static char num[12]; 2546efd9292SBrian Somers static char *desc[] = { "normal", "start", "sock", 2556efd9292SBrian Somers "modem", "dial", "dead", "done", "reboot", "errdead", 2566efd9292SBrian Somers "hangup", "term", "nodial", "nologin" }; 2576efd9292SBrian Somers 2586efd9292SBrian Somers if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc)) 2596efd9292SBrian Somers return desc[ex]; 2606efd9292SBrian Somers snprintf(num, sizeof num, "%d", ex); 2616efd9292SBrian Somers return num; 2626efd9292SBrian Somers } 263c3899f8dSAtsushi Murai 264af57ed9fSAtsushi Murai void 265af57ed9fSAtsushi Murai Usage() 266af57ed9fSAtsushi Murai { 267680026d6SNate Williams fprintf(stderr, 2686d14e2a8SJordan K. Hubbard "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n"); 269af57ed9fSAtsushi Murai exit(EX_START); 270af57ed9fSAtsushi Murai } 271af57ed9fSAtsushi Murai 272af57ed9fSAtsushi Murai void 273af57ed9fSAtsushi Murai ProcessArgs(int argc, char **argv) 274af57ed9fSAtsushi Murai { 275af57ed9fSAtsushi Murai int optc; 276af57ed9fSAtsushi Murai char *cp; 277af57ed9fSAtsushi Murai 278af57ed9fSAtsushi Murai optc = 0; 279af57ed9fSAtsushi Murai while (argc > 0 && **argv == '-') { 280af57ed9fSAtsushi Murai cp = *argv + 1; 281af57ed9fSAtsushi Murai if (strcmp(cp, "auto") == 0) 282af57ed9fSAtsushi Murai mode |= MODE_AUTO; 2836d14e2a8SJordan K. Hubbard else if (strcmp(cp, "background") == 0) 2846efd9292SBrian Somers mode |= MODE_BACKGROUND|MODE_AUTO; 285af57ed9fSAtsushi Murai else if (strcmp(cp, "direct") == 0) 286af57ed9fSAtsushi Murai mode |= MODE_DIRECT; 287af57ed9fSAtsushi Murai else if (strcmp(cp, "dedicated") == 0) 288af57ed9fSAtsushi Murai mode |= MODE_DEDICATED; 289680026d6SNate Williams else if (strcmp(cp, "ddial") == 0) 290680026d6SNate Williams mode |= MODE_DDIAL|MODE_AUTO; 291a9f484e5SJordan K. Hubbard else if (strcmp(cp, "alias") == 0) { 2926ed9fb2fSBrian Somers if (loadAliasHandlers(&VarAliasHandlers) == 0) 293a9f484e5SJordan K. Hubbard mode |= MODE_ALIAS; 2946ed9fb2fSBrian Somers else 295927145beSBrian Somers LogPrintf(LogWARN, "Cannot load alias library\n"); 296a9f484e5SJordan K. Hubbard optc--; /* this option isn't exclusive */ 297a9f484e5SJordan K. Hubbard } 298af57ed9fSAtsushi Murai else 299af57ed9fSAtsushi Murai Usage(); 300af57ed9fSAtsushi Murai optc++; 301af57ed9fSAtsushi Murai argv++; argc--; 302af57ed9fSAtsushi Murai } 303af57ed9fSAtsushi Murai if (argc > 1) { 304af57ed9fSAtsushi Murai fprintf(stderr, "specify only one system label.\n"); 305af57ed9fSAtsushi Murai exit(EX_START); 306af57ed9fSAtsushi Murai } 307af57ed9fSAtsushi Murai if (argc == 1) dstsystem = *argv; 308af57ed9fSAtsushi Murai 309af57ed9fSAtsushi Murai if (optc > 1) { 310af57ed9fSAtsushi Murai fprintf(stderr, "specify only one mode.\n"); 311af57ed9fSAtsushi Murai exit(EX_START); 312af57ed9fSAtsushi Murai } 313af57ed9fSAtsushi Murai } 314af57ed9fSAtsushi Murai 315af57ed9fSAtsushi Murai static void 316af57ed9fSAtsushi Murai Greetings() 317af57ed9fSAtsushi Murai { 318927145beSBrian Somers if (VarTerm) { 319927145beSBrian Somers fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n"); 320927145beSBrian Somers fflush(VarTerm); 321927145beSBrian Somers } 322af57ed9fSAtsushi Murai } 323af57ed9fSAtsushi Murai 324af57ed9fSAtsushi Murai void 325af57ed9fSAtsushi Murai main(argc, argv) 326af57ed9fSAtsushi Murai int argc; 327af57ed9fSAtsushi Murai char **argv; 328af57ed9fSAtsushi Murai { 329aefd026aSBrian Somers FILE *lockfile; 330927145beSBrian Somers char *name; 331af57ed9fSAtsushi Murai 3320706ff38SBrian Somers VarTerm = 0; 333927145beSBrian Somers name = rindex(argv[0], '/'); 334927145beSBrian Somers LogOpen(name ? name+1 : argv[0]); 335927145beSBrian Somers 336927145beSBrian Somers argc--; argv++; 337af57ed9fSAtsushi Murai mode = MODE_INTER; /* default operation is interactive mode */ 338780700e5SAndrey A. Chernov netfd = server = modem = tun_in = -1; 339af57ed9fSAtsushi Murai ProcessArgs(argc, argv); 3401f3dee4cSBrian Somers if (!(mode & MODE_DIRECT)) 3410706ff38SBrian Somers VarTerm = stdout; 342af57ed9fSAtsushi Murai Greetings(); 343af57ed9fSAtsushi Murai GetUid(); 344af57ed9fSAtsushi Murai IpcpDefAddress(); 345af57ed9fSAtsushi Murai 346927145beSBrian Somers if (SelectSystem("default", CONFFILE) < 0 && VarTerm) 347927145beSBrian Somers fprintf(VarTerm, "Warning: No default entry is given in config file.\n"); 348af57ed9fSAtsushi Murai 34953c9f6c0SAtsushi Murai switch ( LocalAuthInit() ) { 35053c9f6c0SAtsushi Murai case NOT_FOUND: 351927145beSBrian Somers if (VarTerm) { 352927145beSBrian Somers fprintf(VarTerm,LAUTH_M1); 353927145beSBrian Somers fprintf(VarTerm,LAUTH_M2); 3540706ff38SBrian Somers fflush(VarTerm); 3551f3dee4cSBrian Somers } 35641db6564SAtsushi Murai /* Fall down */ 35741db6564SAtsushi Murai case VALID: 35853c9f6c0SAtsushi Murai VarLocalAuth = LOCAL_AUTH; 35953c9f6c0SAtsushi Murai break; 36053c9f6c0SAtsushi Murai default: 36153c9f6c0SAtsushi Murai break; 36253c9f6c0SAtsushi Murai } 36353c9f6c0SAtsushi Murai 364af57ed9fSAtsushi Murai if (OpenTunnel(&tunno) < 0) { 365927145beSBrian Somers LogPrintf(LogWARN, "open_tun: %s", strerror(errno)); 366af57ed9fSAtsushi Murai exit(EX_START); 367af57ed9fSAtsushi Murai } 368af57ed9fSAtsushi Murai 3696efd9292SBrian Somers if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED)) 370af57ed9fSAtsushi Murai mode &= ~MODE_INTER; 371af57ed9fSAtsushi Murai if (mode & MODE_INTER) { 372927145beSBrian Somers fprintf(VarTerm, "Interactive mode\n"); 373780700e5SAndrey A. Chernov netfd = STDIN_FILENO; 374af57ed9fSAtsushi Murai } else if (mode & MODE_AUTO) { 375927145beSBrian Somers fprintf(VarTerm, "Automatic Dialer mode\n"); 376af57ed9fSAtsushi Murai if (dstsystem == NULL) { 377927145beSBrian Somers if (VarTerm) 378927145beSBrian Somers fprintf(VarTerm, "Destination system must be specified in" 3796efd9292SBrian Somers " auto, background or ddial mode.\n"); 3806d14e2a8SJordan K. Hubbard exit(EX_START); 3816d14e2a8SJordan K. Hubbard } 382af57ed9fSAtsushi Murai } 383af57ed9fSAtsushi Murai 38453c9f6c0SAtsushi Murai tcgetattr(0, &oldtio); /* Save original tty mode */ 385af57ed9fSAtsushi Murai 386927145beSBrian Somers pending_signal(SIGHUP, Hangup); 387f5ff0f7cSBrian Somers pending_signal(SIGTERM, CloseSession); 388f5ff0f7cSBrian Somers pending_signal(SIGINT, CloseSession); 389f5ff0f7cSBrian Somers pending_signal(SIGQUIT, CloseSession); 390927145beSBrian Somers #ifdef TRAPSEGV 391d7f5ee41SAndrey A. Chernov signal(SIGSEGV, Hangup); 39253c9f6c0SAtsushi Murai #endif 39353c9f6c0SAtsushi Murai #ifdef SIGPIPE 394e0d3e233SAndrey A. Chernov signal(SIGPIPE, SIG_IGN); 39553c9f6c0SAtsushi Murai #endif 39653c9f6c0SAtsushi Murai #ifdef SIGALRM 397f5ff0f7cSBrian Somers pending_signal(SIGALRM, SIG_IGN); 39853c9f6c0SAtsushi Murai #endif 399c3899f8dSAtsushi Murai if(mode & MODE_INTER) 400c3899f8dSAtsushi Murai { 401c3899f8dSAtsushi Murai #ifdef SIGTSTP 402f5ff0f7cSBrian Somers pending_signal(SIGTSTP, TerminalStop); 403c3899f8dSAtsushi Murai #endif 404c3899f8dSAtsushi Murai #ifdef SIGTTIN 405f5ff0f7cSBrian Somers pending_signal(SIGTTIN, TerminalStop); 406c3899f8dSAtsushi Murai #endif 407c3899f8dSAtsushi Murai #ifdef SIGTTOU 408f5ff0f7cSBrian Somers pending_signal(SIGTTOU, SIG_IGN); 409c3899f8dSAtsushi Murai #endif 410c3899f8dSAtsushi Murai } 411af57ed9fSAtsushi Murai 412af57ed9fSAtsushi Murai if (dstsystem) { 413af57ed9fSAtsushi Murai if (SelectSystem(dstsystem, CONFFILE) < 0) { 4140706ff38SBrian Somers LogPrintf(LogWARN, "Destination system not found in conf file.\n"); 415af57ed9fSAtsushi Murai Cleanup(EX_START); 416af57ed9fSAtsushi Murai } 417af57ed9fSAtsushi Murai if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) { 4180706ff38SBrian Somers LogPrintf(LogWARN, "Must specify dstaddr with" 4196efd9292SBrian Somers " auto, background or ddial mode.\n"); 420af57ed9fSAtsushi Murai Cleanup(EX_START); 421af57ed9fSAtsushi Murai } 422af57ed9fSAtsushi Murai } 423af57ed9fSAtsushi Murai 424af57ed9fSAtsushi Murai if (!(mode & MODE_INTER)) { 425af57ed9fSAtsushi Murai int port = SERVER_PORT + tunno; 4266efd9292SBrian Somers 4276d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 4286d14e2a8SJordan K. Hubbard if (pipe (BGFiledes)) { 429927145beSBrian Somers LogPrintf(LogERROR, "pipe: %s", strerror(errno)); 4306d14e2a8SJordan K. Hubbard Cleanup(EX_SOCK); 4316d14e2a8SJordan K. Hubbard } 4326d14e2a8SJordan K. Hubbard } 4336efd9292SBrian Somers 4346efd9292SBrian Somers /* Create server socket and listen at there. */ 435af57ed9fSAtsushi Murai server = socket(PF_INET, SOCK_STREAM, 0); 436af57ed9fSAtsushi Murai if (server < 0) { 437927145beSBrian Somers LogPrintf(LogERROR, "socket: %s", strerror(errno)); 438af57ed9fSAtsushi Murai Cleanup(EX_SOCK); 439af57ed9fSAtsushi Murai } 440af57ed9fSAtsushi Murai ifsin.sin_family = AF_INET; 441af57ed9fSAtsushi Murai ifsin.sin_addr.s_addr = INADDR_ANY; 442af57ed9fSAtsushi Murai ifsin.sin_port = htons(port); 443c9bf343aSBrian Somers setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server); 444af57ed9fSAtsushi Murai if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) { 445927145beSBrian Somers LogPrintf(LogERROR, "bind: %s", strerror(errno)); 446927145beSBrian Somers if (errno == EADDRINUSE && VarTerm) 447927145beSBrian Somers fprintf(VarTerm, "Wait for a while, then try again.\n"); 448af57ed9fSAtsushi Murai Cleanup(EX_SOCK); 449af57ed9fSAtsushi Murai } 450274e766cSBrian Somers if (listen(server, 5) != 0) { 451927145beSBrian Somers LogPrintf(LogERROR, "Unable to listen to socket - OS overload?\n"); 452927145beSBrian Somers Cleanup(EX_SOCK); 453274e766cSBrian Somers } 454af57ed9fSAtsushi Murai 455af57ed9fSAtsushi Murai if (!(mode & MODE_DIRECT)) { 4566d14e2a8SJordan K. Hubbard pid_t bgpid; 457a9c6b5dfSAtsushi Murai 4586d14e2a8SJordan K. Hubbard bgpid = fork (); 4596d14e2a8SJordan K. Hubbard if (bgpid == -1) { 460927145beSBrian Somers LogPrintf(LogERROR, "fork: %s", strerror(errno)); 4616d14e2a8SJordan K. Hubbard Cleanup (EX_SOCK); 4626d14e2a8SJordan K. Hubbard } 4636d14e2a8SJordan K. Hubbard if (bgpid) { 4646d14e2a8SJordan K. Hubbard char c = EX_NORMAL; 465a9c6b5dfSAtsushi Murai 4666d14e2a8SJordan K. Hubbard if (mode & MODE_BACKGROUND) { 4676d14e2a8SJordan K. Hubbard /* Wait for our child to close its pipe before we exit. */ 4686d14e2a8SJordan K. Hubbard BGPid = bgpid; 4696e4959f0SBrian Somers close(BGFiledes[1]); 4706efd9292SBrian Somers if (read(BGFiledes[0], &c, 1) != 1) { 471927145beSBrian Somers fprintf(VarTerm, "Child exit, no status.\n"); 472927145beSBrian Somers LogPrintf (LogPHASE, "Parent: Child exit, no status.\n"); 4736efd9292SBrian Somers } else if (c == EX_NORMAL) { 474927145beSBrian Somers fprintf(VarTerm, "PPP enabled.\n"); 475927145beSBrian Somers LogPrintf (LogPHASE, "Parent: PPP enabled.\n"); 4766efd9292SBrian Somers } else { 477927145beSBrian Somers fprintf(VarTerm, "Child failed (%s).\n",ex_desc((int)c)); 478927145beSBrian Somers LogPrintf(LogPHASE, "Parent: Child failed (%s).\n", 47980e37c72SBrian Somers ex_desc((int)c)); 4806efd9292SBrian Somers } 4816e4959f0SBrian Somers close(BGFiledes[0]); 4826d14e2a8SJordan K. Hubbard } 4836d14e2a8SJordan K. Hubbard exit(c); 4846e4959f0SBrian Somers } else if (mode & MODE_BACKGROUND) 4856e4959f0SBrian Somers close(BGFiledes[0]); 486aefd026aSBrian Somers } 4876d14e2a8SJordan K. Hubbard 488298091daSBrian Somers snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid", 4896d14e2a8SJordan K. Hubbard _PATH_VARRUN, tunno); 490aefd026aSBrian Somers (void)unlink(pid_filename); 491a9c6b5dfSAtsushi Murai 492aefd026aSBrian Somers if ((lockfile = fopen(pid_filename, "w")) != NULL) { 49341c6c543SBrian Somers fprintf(lockfile, "%d\n", (int)getpid()); 49441c6c543SBrian Somers fclose(lockfile); 495aefd026aSBrian Somers } else 496927145beSBrian Somers LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 497927145beSBrian Somers pid_filename, strerror(errno)); 49841c6c543SBrian Somers 49941c6c543SBrian Somers snprintf(if_filename, sizeof if_filename, "%s%s.if", 50041c6c543SBrian Somers _PATH_VARRUN, VarBaseDevice); 501aefd026aSBrian Somers (void)unlink(if_filename); 50241c6c543SBrian Somers 503aefd026aSBrian Somers if ((lockfile = fopen(if_filename, "w")) != NULL) { 50441c6c543SBrian Somers fprintf(lockfile, "tun%d\n", tunno); 50541c6c543SBrian Somers fclose(lockfile); 506aefd026aSBrian Somers } else 507927145beSBrian Somers LogPrintf(LogALERT, "Warning: Can't create %s: %s\n", 508927145beSBrian Somers if_filename, strerror(errno)); 509aefd026aSBrian Somers 510780700e5SAndrey A. Chernov if (server >= 0) 511927145beSBrian Somers LogPrintf(LogPHASE, "Listening at %d.\n", port); 5120706ff38SBrian Somers 5130706ff38SBrian Somers VarTerm = 0; /* We know it's currently stdin */ 5140706ff38SBrian Somers 515af57ed9fSAtsushi Murai #ifdef DOTTYINIT 5160706ff38SBrian Somers if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */ 517af57ed9fSAtsushi Murai #else 5180706ff38SBrian Somers if (mode & MODE_DIRECT) { 519af57ed9fSAtsushi Murai #endif 5200706ff38SBrian Somers chdir("/"); /* Be consistent with daemon() */ 521af57ed9fSAtsushi Murai TtyInit(); 5220706ff38SBrian Somers } else 523927145beSBrian Somers daemon(0,0); 524af57ed9fSAtsushi Murai } else { 525af57ed9fSAtsushi Murai TtyInit(); 526c3899f8dSAtsushi Murai TtyCommandMode(1); 527af57ed9fSAtsushi Murai } 528927145beSBrian Somers LogPrintf(LogPHASE, "PPP Started.\n"); 529af57ed9fSAtsushi Murai 530af57ed9fSAtsushi Murai 531af57ed9fSAtsushi Murai do 532af57ed9fSAtsushi Murai DoLoop(); 533af57ed9fSAtsushi Murai while (mode & MODE_DEDICATED); 534af57ed9fSAtsushi Murai 535af57ed9fSAtsushi Murai Cleanup(EX_DONE); 536af57ed9fSAtsushi Murai } 537af57ed9fSAtsushi Murai 538af57ed9fSAtsushi Murai /* 5396d14e2a8SJordan K. Hubbard * Turn into packet mode, where we speak PPP. 540af57ed9fSAtsushi Murai */ 541af57ed9fSAtsushi Murai void 542af57ed9fSAtsushi Murai PacketMode() 543af57ed9fSAtsushi Murai { 544af57ed9fSAtsushi Murai if (RawModem(modem) < 0) { 545927145beSBrian Somers LogPrintf(LogWARN, "PacketMode: Not connected.\n"); 546af57ed9fSAtsushi Murai return; 547af57ed9fSAtsushi Murai } 548af57ed9fSAtsushi Murai 549af57ed9fSAtsushi Murai AsyncInit(); 550af57ed9fSAtsushi Murai VjInit(); 551af57ed9fSAtsushi Murai LcpInit(); 552af57ed9fSAtsushi Murai IpcpInit(); 553af57ed9fSAtsushi Murai CcpInit(); 554af57ed9fSAtsushi Murai LcpUp(); 555af57ed9fSAtsushi Murai 556af57ed9fSAtsushi Murai LcpOpen(VarOpenMode); 557af57ed9fSAtsushi Murai if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) { 558c3899f8dSAtsushi Murai TtyCommandMode(1); 559927145beSBrian Somers if (VarTerm) { 560927145beSBrian Somers fprintf(VarTerm, "Packet mode.\n"); 561b0cdb3ceSJordan K. Hubbard aft_cmd = 1; 562af57ed9fSAtsushi Murai } 563af57ed9fSAtsushi Murai } 564927145beSBrian Somers } 565af57ed9fSAtsushi Murai 566af57ed9fSAtsushi Murai static void 567af57ed9fSAtsushi Murai ShowHelp() 568af57ed9fSAtsushi Murai { 569927145beSBrian Somers fprintf(stderr, "The following commands are available:\n"); 570927145beSBrian Somers fprintf(stderr, " ~p\tEnter Packet mode\n"); 571927145beSBrian Somers fprintf(stderr, " ~-\tDecrease log level\n"); 572927145beSBrian Somers fprintf(stderr, " ~+\tIncrease log level\n"); 573927145beSBrian Somers fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\n"); 574927145beSBrian Somers fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\n"); 575927145beSBrian Somers fprintf(stderr, " ~.\tTerminate program\n"); 576927145beSBrian Somers fprintf(stderr, " ~?\tThis help\n"); 577af57ed9fSAtsushi Murai } 578af57ed9fSAtsushi Murai 579af57ed9fSAtsushi Murai static void 580af57ed9fSAtsushi Murai ReadTty() 581af57ed9fSAtsushi Murai { 582af57ed9fSAtsushi Murai int n; 583af57ed9fSAtsushi Murai char ch; 584af57ed9fSAtsushi Murai static int ttystate; 585927145beSBrian Somers FILE *oVarTerm; 586af57ed9fSAtsushi Murai #define MAXLINESIZE 200 587af57ed9fSAtsushi Murai char linebuff[MAXLINESIZE]; 588af57ed9fSAtsushi Murai 589927145beSBrian Somers LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n", 590927145beSBrian Somers TermMode, netfd, mode); 591af57ed9fSAtsushi Murai if (!TermMode) { 592af57ed9fSAtsushi Murai n = read(netfd, linebuff, sizeof(linebuff)-1); 59353c9f6c0SAtsushi Murai if (n > 0) { 594927145beSBrian Somers aft_cmd = 1; 595af57ed9fSAtsushi Murai DecodeCommand(linebuff, n, 1); 59653c9f6c0SAtsushi Murai } else { 597927145beSBrian Somers LogPrintf(LogPHASE, "client connection closed.\n"); 598e0d3e233SAndrey A. Chernov VarLocalAuth = LOCAL_NO_AUTH; 599af57ed9fSAtsushi Murai mode &= ~MODE_INTER; 600927145beSBrian Somers oVarTerm = VarTerm; 601927145beSBrian Somers VarTerm = 0; 602927145beSBrian Somers if (oVarTerm && oVarTerm != stdout) 603927145beSBrian Somers fclose(oVarTerm); 604927145beSBrian Somers close(netfd); 605927145beSBrian Somers netfd = -1; 606af57ed9fSAtsushi Murai } 607af57ed9fSAtsushi Murai return; 608af57ed9fSAtsushi Murai } 609af57ed9fSAtsushi Murai 610af57ed9fSAtsushi Murai /* 611af57ed9fSAtsushi Murai * We are in terminal mode, decode special sequences 612af57ed9fSAtsushi Murai */ 613927145beSBrian Somers n = read(fileno(VarTerm), &ch, 1); 614927145beSBrian Somers LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)", n); 615af57ed9fSAtsushi Murai 616af57ed9fSAtsushi Murai if (n > 0) { 617af57ed9fSAtsushi Murai switch (ttystate) { 618af57ed9fSAtsushi Murai case 0: 619af57ed9fSAtsushi Murai if (ch == '~') 620af57ed9fSAtsushi Murai ttystate++; 621af57ed9fSAtsushi Murai else 622af57ed9fSAtsushi Murai write(modem, &ch, n); 623af57ed9fSAtsushi Murai break; 624af57ed9fSAtsushi Murai case 1: 625af57ed9fSAtsushi Murai switch (ch) { 626af57ed9fSAtsushi Murai case '?': 627af57ed9fSAtsushi Murai ShowHelp(); 628af57ed9fSAtsushi Murai break; 629af57ed9fSAtsushi Murai case 'p': 630af57ed9fSAtsushi Murai /* 631af57ed9fSAtsushi Murai * XXX: Should check carrier. 632af57ed9fSAtsushi Murai */ 633af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 634af57ed9fSAtsushi Murai VarOpenMode = OPEN_ACTIVE; 635af57ed9fSAtsushi Murai PacketMode(); 636af57ed9fSAtsushi Murai } 637af57ed9fSAtsushi Murai break; 638af57ed9fSAtsushi Murai case '.': 639af57ed9fSAtsushi Murai TermMode = 1; 640927145beSBrian Somers aft_cmd = 1; 641c3899f8dSAtsushi Murai TtyCommandMode(1); 642af57ed9fSAtsushi Murai break; 643927145beSBrian Somers case 't': 644927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 645927145beSBrian Somers ShowTimers(); 646927145beSBrian Somers break; 647927145beSBrian Somers } 648927145beSBrian Somers case 'm': 649927145beSBrian Somers if (LogIsKept(LogDEBUG)) { 650927145beSBrian Somers ShowMemMap(); 651927145beSBrian Somers break; 652927145beSBrian Somers } 653af57ed9fSAtsushi Murai default: 654af57ed9fSAtsushi Murai if (write(modem, &ch, n) < 0) 655927145beSBrian Somers LogPrintf(LogERROR, "error writing to modem.\n"); 656af57ed9fSAtsushi Murai break; 657af57ed9fSAtsushi Murai } 658af57ed9fSAtsushi Murai ttystate = 0; 659af57ed9fSAtsushi Murai break; 660af57ed9fSAtsushi Murai } 661af57ed9fSAtsushi Murai } 662af57ed9fSAtsushi Murai } 663af57ed9fSAtsushi Murai 664af57ed9fSAtsushi Murai 665af57ed9fSAtsushi Murai /* 666af57ed9fSAtsushi Murai * Here, we'll try to detect HDLC frame 667af57ed9fSAtsushi Murai */ 668af57ed9fSAtsushi Murai 669af57ed9fSAtsushi Murai static char *FrameHeaders[] = { 67053c9f6c0SAtsushi Murai "\176\377\003\300\041", 67153c9f6c0SAtsushi Murai "\176\377\175\043\300\041", 67253c9f6c0SAtsushi Murai "\176\177\175\043\100\041", 67353c9f6c0SAtsushi Murai "\176\175\337\175\043\300\041", 67453c9f6c0SAtsushi Murai "\176\175\137\175\043\100\041", 675af57ed9fSAtsushi Murai NULL, 676af57ed9fSAtsushi Murai }; 677af57ed9fSAtsushi Murai 678af57ed9fSAtsushi Murai u_char * 679af57ed9fSAtsushi Murai HdlcDetect(cp, n) 680af57ed9fSAtsushi Murai u_char *cp; 681af57ed9fSAtsushi Murai int n; 682af57ed9fSAtsushi Murai { 68353c9f6c0SAtsushi Murai char *ptr, *fp, **hp; 684af57ed9fSAtsushi Murai 685af57ed9fSAtsushi Murai cp[n] = '\0'; /* be sure to null terminated */ 686af57ed9fSAtsushi Murai ptr = NULL; 687af57ed9fSAtsushi Murai for (hp = FrameHeaders; *hp; hp++) { 68853c9f6c0SAtsushi Murai fp = *hp; 68953c9f6c0SAtsushi Murai if (DEV_IS_SYNC) 69053c9f6c0SAtsushi Murai fp++; 691ed6a16c1SPoul-Henning Kamp ptr = strstr((char *)cp, fp); 692ed6a16c1SPoul-Henning Kamp if (ptr) 693af57ed9fSAtsushi Murai break; 694af57ed9fSAtsushi Murai } 695af57ed9fSAtsushi Murai return((u_char *)ptr); 696af57ed9fSAtsushi Murai } 697af57ed9fSAtsushi Murai 698af57ed9fSAtsushi Murai static struct pppTimer RedialTimer; 699af57ed9fSAtsushi Murai 700af57ed9fSAtsushi Murai static void 701af57ed9fSAtsushi Murai RedialTimeout() 702af57ed9fSAtsushi Murai { 703af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 704927145beSBrian Somers LogPrintf(LogPHASE, "Redialing timer expired.\n"); 705af57ed9fSAtsushi Murai } 706af57ed9fSAtsushi Murai 707af57ed9fSAtsushi Murai static void 70843ea9d19SBrian Somers StartRedialTimer(Timeout) 70943ea9d19SBrian Somers int Timeout; 710af57ed9fSAtsushi Murai { 711af57ed9fSAtsushi Murai StopTimer(&RedialTimer); 712a9c6b5dfSAtsushi Murai 71343ea9d19SBrian Somers if (Timeout) { 714af57ed9fSAtsushi Murai RedialTimer.state = TIMER_STOPPED; 715a9c6b5dfSAtsushi Murai 71643ea9d19SBrian Somers if (Timeout > 0) 71743ea9d19SBrian Somers RedialTimer.load = Timeout * SECTICKS; 718a9c6b5dfSAtsushi Murai else 719a9c6b5dfSAtsushi Murai RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS; 720a9c6b5dfSAtsushi Murai 721927145beSBrian Somers LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n", 72243ea9d19SBrian Somers RedialTimer.load / SECTICKS); 72343ea9d19SBrian Somers 724af57ed9fSAtsushi Murai RedialTimer.func = RedialTimeout; 725af57ed9fSAtsushi Murai StartTimer(&RedialTimer); 726af57ed9fSAtsushi Murai } 727a9c6b5dfSAtsushi Murai } 728af57ed9fSAtsushi Murai 729af57ed9fSAtsushi Murai 730af57ed9fSAtsushi Murai static void 731af57ed9fSAtsushi Murai DoLoop() 732af57ed9fSAtsushi Murai { 733af57ed9fSAtsushi Murai fd_set rfds, wfds, efds; 734780700e5SAndrey A. Chernov int pri, i, n, wfd, nfds; 735af57ed9fSAtsushi Murai struct sockaddr_in hisaddr; 736af57ed9fSAtsushi Murai struct timeval timeout, *tp; 737af57ed9fSAtsushi Murai int ssize = sizeof(hisaddr); 738af57ed9fSAtsushi Murai u_char *cp; 739af57ed9fSAtsushi Murai u_char rbuff[MAX_MRU]; 74084b8a6ebSAtsushi Murai int dial_up; 741a9c6b5dfSAtsushi Murai int tries; 74260e218e4SAtsushi Murai int qlen; 743c3899f8dSAtsushi Murai pid_t pgroup; 744c3899f8dSAtsushi Murai 745c3899f8dSAtsushi Murai pgroup = getpgrp(); 746af57ed9fSAtsushi Murai 7476efd9292SBrian Somers if (mode & MODE_DIRECT) { 7480706ff38SBrian Somers LogPrintf(LogDEBUG, "Opening modem\n"); 749af57ed9fSAtsushi Murai modem = OpenModem(mode); 750927145beSBrian Somers LogPrintf(LogPHASE, "Packet mode enabled\n"); 751af57ed9fSAtsushi Murai PacketMode(); 752af57ed9fSAtsushi Murai } else if (mode & MODE_DEDICATED) { 753780700e5SAndrey A. Chernov if (modem < 0) 754af57ed9fSAtsushi Murai modem = OpenModem(mode); 755af57ed9fSAtsushi Murai } 756af57ed9fSAtsushi Murai 757927145beSBrian Somers fflush(VarTerm); 758af57ed9fSAtsushi Murai 75984b8a6ebSAtsushi Murai timeout.tv_sec = 0; 760af57ed9fSAtsushi Murai timeout.tv_usec = 0; 76125aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 762af57ed9fSAtsushi Murai 7636e4959f0SBrian Somers if (mode & MODE_BACKGROUND) 7646e4959f0SBrian Somers dial_up = TRUE; /* Bring the line up */ 7656e4959f0SBrian Somers else 76684b8a6ebSAtsushi Murai dial_up = FALSE; /* XXXX */ 767a9c6b5dfSAtsushi Murai tries = 0; 768af57ed9fSAtsushi Murai for (;;) { 769780700e5SAndrey A. Chernov nfds = 0; 770af57ed9fSAtsushi Murai FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); 77184b8a6ebSAtsushi Murai 77284b8a6ebSAtsushi Murai /* 773680026d6SNate Williams * If the link is down and we're in DDIAL mode, bring it back 774680026d6SNate Williams * up. 775680026d6SNate Williams */ 776680026d6SNate Williams if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED) 777680026d6SNate Williams dial_up = TRUE; 778680026d6SNate Williams 779680026d6SNate Williams /* 78007030d97SBrian Somers * If we lost carrier and want to re-establish the connection 78107030d97SBrian Somers * due to the "set reconnect" value, we'd better bring the line 7826efd9292SBrian Somers * back up. 78307030d97SBrian Somers */ 7846efd9292SBrian Somers if (LcpFsm.state <= ST_CLOSED) { 78525aa96acSBrian Somers if (dial_up != TRUE && reconnectState == RECON_TRUE) { 7866efd9292SBrian Somers if (++reconnectCount <= VarReconnectTries) { 787927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n", 7886efd9292SBrian Somers reconnectCount, VarReconnectTries); 78907030d97SBrian Somers StartRedialTimer(VarReconnectTimer); 79007030d97SBrian Somers dial_up = TRUE; 791298091daSBrian Somers } else { 7926efd9292SBrian Somers if (VarReconnectTries) 793927145beSBrian Somers LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n", 794298091daSBrian Somers VarReconnectTries); 7956efd9292SBrian Somers reconnectCount = 0; 7966efd9292SBrian Somers if (mode & MODE_BACKGROUND) 7976efd9292SBrian Somers Cleanup(EX_DEAD); 7986efd9292SBrian Somers } 79925aa96acSBrian Somers reconnectState = RECON_ENVOKED; 8006efd9292SBrian Somers } 80107030d97SBrian Somers } 80207030d97SBrian Somers 80307030d97SBrian Somers /* 80484b8a6ebSAtsushi Murai * If Ip packet for output is enqueued and require dial up, 80584b8a6ebSAtsushi Murai * Just do it! 80684b8a6ebSAtsushi Murai */ 80707030d97SBrian Somers if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { 808927145beSBrian Somers LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem); 80984b8a6ebSAtsushi Murai modem = OpenModem(mode); 81084b8a6ebSAtsushi Murai if (modem < 0) { 8110706ff38SBrian Somers tries++; 8120706ff38SBrian Somers if (VarDialTries) 8130706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 8140706ff38SBrian Somers tries, VarDialTries); 8150706ff38SBrian Somers else 8160706ff38SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries); 8170706ff38SBrian Somers 8180706ff38SBrian Somers if (VarDialTries && tries >= VarDialTries) { 8190706ff38SBrian Somers if (mode & MODE_BACKGROUND) 8200706ff38SBrian Somers Cleanup(EX_DIAL); /* Can't get the modem */ 8210706ff38SBrian Somers dial_up = FALSE; 8220706ff38SBrian Somers reconnectState = RECON_UNKNOWN; 8230706ff38SBrian Somers reconnectCount = 0; 8240706ff38SBrian Somers tries = 0; 8250706ff38SBrian Somers } else 82643ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 82784b8a6ebSAtsushi Murai } else { 828c0139fb2SBrian Somers tries++; /* Tries are per number, not per list of numbers. */ 829c0139fb2SBrian Somers if (VarDialTries) 830927145beSBrian Somers LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, 831c0139fb2SBrian Somers VarDialTries); 832c0139fb2SBrian Somers else 833927145beSBrian Somers LogPrintf(LogCHAT, "Dial attempt %u\n", tries); 834e83481f9SBrian Somers if (DialModem() == EX_DONE) { 83584b8a6ebSAtsushi Murai sleep(1); /* little pause to allow peer starts */ 83684b8a6ebSAtsushi Murai ModemTimeout(); 83784b8a6ebSAtsushi Murai PacketMode(); 83884b8a6ebSAtsushi Murai dial_up = FALSE; 83925aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 840a9c6b5dfSAtsushi Murai tries = 0; 84184b8a6ebSAtsushi Murai } else { 84284b8a6ebSAtsushi Murai CloseModem(); 8434ed9958fSBrian Somers if (mode & MODE_BACKGROUND) { 8444ed9958fSBrian Somers if (VarNextPhone == NULL) 8454ed9958fSBrian Somers Cleanup(EX_DIAL); /* Tried all numbers - no luck */ 8464ed9958fSBrian Somers else 84743ea9d19SBrian Somers /* Try all numbers in background mode */ 84843ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 8494ed9958fSBrian Somers } else if (VarDialTries && tries >= VarDialTries) { 850c0139fb2SBrian Somers /* I give up ! Can't get through :( */ 85143ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 852a9c6b5dfSAtsushi Murai dial_up = FALSE; 85325aa96acSBrian Somers reconnectState = RECON_UNKNOWN; 85425aa96acSBrian Somers reconnectCount = 0; 855a9c6b5dfSAtsushi Murai tries = 0; 856c0139fb2SBrian Somers } else if (VarNextPhone == NULL) 857c0139fb2SBrian Somers /* Dial failed. Keep quite during redial wait period. */ 85843ea9d19SBrian Somers StartRedialTimer(VarRedialTimeout); 859c0139fb2SBrian Somers else 86043ea9d19SBrian Somers StartRedialTimer(VarRedialNextTimeout); 86184b8a6ebSAtsushi Murai } 86284b8a6ebSAtsushi Murai } 86384b8a6ebSAtsushi Murai } 86460e218e4SAtsushi Murai qlen = ModemQlen(); 86576bd0c0aSDoug Rabson 86676bd0c0aSDoug Rabson if (qlen == 0) { 86776bd0c0aSDoug Rabson IpStartOutput(); 86876bd0c0aSDoug Rabson qlen = ModemQlen(); 86976bd0c0aSDoug Rabson } 87076bd0c0aSDoug Rabson 871780700e5SAndrey A. Chernov if (modem >= 0) { 872780700e5SAndrey A. Chernov if (modem + 1 > nfds) 873780700e5SAndrey A. Chernov nfds = modem + 1; 87484b8a6ebSAtsushi Murai FD_SET(modem, &rfds); 87584b8a6ebSAtsushi Murai FD_SET(modem, &efds); 87660e218e4SAtsushi Murai if (qlen > 0) { 87784b8a6ebSAtsushi Murai FD_SET(modem, &wfds); 87884b8a6ebSAtsushi Murai } 87984b8a6ebSAtsushi Murai } 880780700e5SAndrey A. Chernov if (server >= 0) { 881780700e5SAndrey A. Chernov if (server + 1 > nfds) 882780700e5SAndrey A. Chernov nfds = server + 1; 883780700e5SAndrey A. Chernov FD_SET(server, &rfds); 884780700e5SAndrey A. Chernov } 885af57ed9fSAtsushi Murai 886af57ed9fSAtsushi Murai /* *** IMPORTANT *** 887af57ed9fSAtsushi Murai * 888af57ed9fSAtsushi Murai * CPU is serviced every TICKUNIT micro seconds. 889af57ed9fSAtsushi Murai * This value must be chosen with great care. If this values is 890af57ed9fSAtsushi Murai * too big, it results loss of characters from modem and poor responce. 891af57ed9fSAtsushi Murai * If this values is too small, ppp process eats many CPU time. 892af57ed9fSAtsushi Murai */ 89353c9f6c0SAtsushi Murai #ifndef SIGALRM 894af57ed9fSAtsushi Murai usleep(TICKUNIT); 895af57ed9fSAtsushi Murai TimerService(); 896f5ff0f7cSBrian Somers #else 897f5ff0f7cSBrian Somers handle_signals(); 89853c9f6c0SAtsushi Murai #endif 89968d2b4d6SBruce Evans 90068d2b4d6SBruce Evans /* If there are aren't many packets queued, look for some more. */ 901780700e5SAndrey A. Chernov if (qlen < 20 && tun_in >= 0) { 902780700e5SAndrey A. Chernov if (tun_in + 1 > nfds) 903780700e5SAndrey A. Chernov nfds = tun_in + 1; 90484b8a6ebSAtsushi Murai FD_SET(tun_in, &rfds); 905780700e5SAndrey A. Chernov } 90668d2b4d6SBruce Evans 907780700e5SAndrey A. Chernov if (netfd >= 0) { 908780700e5SAndrey A. Chernov if (netfd + 1 > nfds) 909780700e5SAndrey A. Chernov nfds = netfd + 1; 910af57ed9fSAtsushi Murai FD_SET(netfd, &rfds); 911af57ed9fSAtsushi Murai FD_SET(netfd, &efds); 912af57ed9fSAtsushi Murai } 91384b8a6ebSAtsushi Murai 91453c9f6c0SAtsushi Murai #ifndef SIGALRM 915af57ed9fSAtsushi Murai /* 91684b8a6ebSAtsushi Murai * Normally, select() will not block because modem is writable. 91784b8a6ebSAtsushi Murai * In AUTO mode, select will block until we find packet from tun 918af57ed9fSAtsushi Murai */ 919af57ed9fSAtsushi Murai tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL; 920780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 92153c9f6c0SAtsushi Murai #else 92284b8a6ebSAtsushi Murai /* 92384b8a6ebSAtsushi Murai * When SIGALRM timer is running, a select function will be 92484b8a6ebSAtsushi Murai * return -1 and EINTR after a Time Service signal hundler 925a9c6b5dfSAtsushi Murai * is done. If the redial timer is not running and we are 926a9c6b5dfSAtsushi Murai * trying to dial, poll with a 0 value timer. 92784b8a6ebSAtsushi Murai */ 928a9c6b5dfSAtsushi Murai tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL; 929780700e5SAndrey A. Chernov i = select(nfds, &rfds, &wfds, &efds, tp); 93053c9f6c0SAtsushi Murai #endif 9316b0b88d8SBrian Somers 932af57ed9fSAtsushi Murai if ( i == 0 ) { 933af57ed9fSAtsushi Murai continue; 934af57ed9fSAtsushi Murai } 93553c9f6c0SAtsushi Murai 936534fe541SBrian Somers if ( i < 0 ) { 937534fe541SBrian Somers if ( errno == EINTR ) { 938f5ff0f7cSBrian Somers handle_signals(); 939f5ff0f7cSBrian Somers continue; 94084b8a6ebSAtsushi Murai } 941927145beSBrian Somers LogPrintf(LogERROR, "select: %s", strerror(errno)); 942af57ed9fSAtsushi Murai break; 943af57ed9fSAtsushi Murai } 94484b8a6ebSAtsushi Murai 945780700e5SAndrey A. Chernov if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) { 946927145beSBrian Somers LogPrintf(LogALERT, "Exception detected.\n"); 947af57ed9fSAtsushi Murai break; 948af57ed9fSAtsushi Murai } 949af57ed9fSAtsushi Murai 950780700e5SAndrey A. Chernov if (server >= 0 && FD_ISSET(server, &rfds)) { 951927145beSBrian Somers LogPrintf(LogPHASE, "connected to client.\n"); 952af57ed9fSAtsushi Murai wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize); 953e0d3e233SAndrey A. Chernov if (wfd < 0) { 954927145beSBrian Somers LogPrintf(LogERROR, "accept: %s", strerror(errno)); 955e0d3e233SAndrey A. Chernov continue; 956e0d3e233SAndrey A. Chernov } 957780700e5SAndrey A. Chernov if (netfd >= 0) { 958af57ed9fSAtsushi Murai write(wfd, "already in use.\n", 16); 959af57ed9fSAtsushi Murai close(wfd); 960af57ed9fSAtsushi Murai continue; 961af57ed9fSAtsushi Murai } else 962af57ed9fSAtsushi Murai netfd = wfd; 963927145beSBrian Somers VarTerm = fdopen(netfd, "a+"); 964af57ed9fSAtsushi Murai mode |= MODE_INTER; 965af57ed9fSAtsushi Murai Greetings(); 96641db6564SAtsushi Murai switch ( LocalAuthInit() ) { 96741db6564SAtsushi Murai case NOT_FOUND: 968927145beSBrian Somers if (VarTerm) { 969927145beSBrian Somers fprintf(VarTerm,LAUTH_M1); 970927145beSBrian Somers fprintf(VarTerm,LAUTH_M2); 971927145beSBrian Somers fflush(VarTerm); 972927145beSBrian Somers } 97341db6564SAtsushi Murai /* Fall down */ 97441db6564SAtsushi Murai case VALID: 97541db6564SAtsushi Murai VarLocalAuth = LOCAL_AUTH; 97641db6564SAtsushi Murai break; 97741db6564SAtsushi Murai default: 97841db6564SAtsushi Murai break; 97941db6564SAtsushi Murai } 980af57ed9fSAtsushi Murai (void) IsInteractive(); 981274e766cSBrian Somers Prompt(); 982af57ed9fSAtsushi Murai } 983af57ed9fSAtsushi Murai 984780700e5SAndrey A. Chernov if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) && 985f1884650SAtsushi Murai ((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) { 986af57ed9fSAtsushi Murai /* something to read from tty */ 987af57ed9fSAtsushi Murai ReadTty(); 988af57ed9fSAtsushi Murai } 989780700e5SAndrey A. Chernov if (modem >= 0) { 990af57ed9fSAtsushi Murai if (FD_ISSET(modem, &wfds)) { /* ready to write into modem */ 991af57ed9fSAtsushi Murai ModemStartOutput(modem); 992af57ed9fSAtsushi Murai } 993af57ed9fSAtsushi Murai if (FD_ISSET(modem, &rfds)) { /* something to read from modem */ 99453c9f6c0SAtsushi Murai if (LcpFsm.state <= ST_CLOSED) 99553c9f6c0SAtsushi Murai usleep(10000); 996af57ed9fSAtsushi Murai n = read(modem, rbuff, sizeof(rbuff)); 997af57ed9fSAtsushi Murai if ((mode & MODE_DIRECT) && n <= 0) { 998af57ed9fSAtsushi Murai DownConnection(); 999af57ed9fSAtsushi Murai } else 1000927145beSBrian Somers LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n); 1001af57ed9fSAtsushi Murai 1002af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED) { 1003af57ed9fSAtsushi Murai /* 1004af57ed9fSAtsushi Murai * In dedicated mode, we just discard input until LCP is started. 1005af57ed9fSAtsushi Murai */ 1006af57ed9fSAtsushi Murai if (!(mode & MODE_DEDICATED)) { 1007af57ed9fSAtsushi Murai cp = HdlcDetect(rbuff, n); 1008af57ed9fSAtsushi Murai if (cp) { 1009af57ed9fSAtsushi Murai /* 1010af57ed9fSAtsushi Murai * LCP packet is detected. Turn ourselves into packet mode. 1011af57ed9fSAtsushi Murai */ 1012af57ed9fSAtsushi Murai if (cp != rbuff) { 1013927145beSBrian Somers write(modem, rbuff, cp - rbuff); 1014927145beSBrian Somers write(modem, "\r\n", 2); 1015af57ed9fSAtsushi Murai } 1016af57ed9fSAtsushi Murai PacketMode(); 1017af57ed9fSAtsushi Murai } else 1018927145beSBrian Somers write(fileno(VarTerm), rbuff, n); 1019af57ed9fSAtsushi Murai } 1020af57ed9fSAtsushi Murai } else { 1021af57ed9fSAtsushi Murai if (n > 0) 1022af57ed9fSAtsushi Murai AsyncInput(rbuff, n); 1023af57ed9fSAtsushi Murai } 1024af57ed9fSAtsushi Murai } 1025af57ed9fSAtsushi Murai } 102684b8a6ebSAtsushi Murai 1027780700e5SAndrey A. Chernov if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) { /* something to read from tun */ 1028af57ed9fSAtsushi Murai n = read(tun_in, rbuff, sizeof(rbuff)); 1029af57ed9fSAtsushi Murai if (n < 0) { 1030927145beSBrian Somers LogPrintf(LogERROR, "read from tun: %s", strerror(errno)); 1031af57ed9fSAtsushi Murai continue; 1032af57ed9fSAtsushi Murai } 1033af57ed9fSAtsushi Murai /* 1034af57ed9fSAtsushi Murai * Process on-demand dialup. Output packets are queued within tunnel 1035af57ed9fSAtsushi Murai * device until IPCP is opened. 1036af57ed9fSAtsushi Murai */ 1037af57ed9fSAtsushi Murai if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) { 103884b8a6ebSAtsushi Murai pri = PacketCheck(rbuff, n, FL_DIAL); 1039af57ed9fSAtsushi Murai if (pri >= 0) { 1040a9f484e5SJordan K. Hubbard if (mode & MODE_ALIAS) { 10416ed9fb2fSBrian Somers VarPacketAliasOut(rbuff, sizeof rbuff); 1042a9f484e5SJordan K. Hubbard n = ntohs(((struct ip *)rbuff)->ip_len); 1043a9f484e5SJordan K. Hubbard } 1044af57ed9fSAtsushi Murai IpEnqueue(pri, rbuff, n); 104584b8a6ebSAtsushi Murai dial_up = TRUE; /* XXX */ 1046af57ed9fSAtsushi Murai } 1047af57ed9fSAtsushi Murai continue; 1048af57ed9fSAtsushi Murai } 104984b8a6ebSAtsushi Murai pri = PacketCheck(rbuff, n, FL_OUT); 1050a9f484e5SJordan K. Hubbard if (pri >= 0) { 1051a9f484e5SJordan K. Hubbard if (mode & MODE_ALIAS) { 10526ed9fb2fSBrian Somers VarPacketAliasOut(rbuff, sizeof rbuff); 1053a9f484e5SJordan K. Hubbard n = ntohs(((struct ip *)rbuff)->ip_len); 1054a9f484e5SJordan K. Hubbard } 1055af57ed9fSAtsushi Murai IpEnqueue(pri, rbuff, n); 1056af57ed9fSAtsushi Murai } 1057af57ed9fSAtsushi Murai } 1058a9f484e5SJordan K. Hubbard } 1059927145beSBrian Somers LogPrintf(LogDEBUG, "Job (DoLoop) done.\n"); 1060af57ed9fSAtsushi Murai } 1061