main.c revision 31196
16059Samurai/*
26059Samurai *			User Process PPP
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2031196Sbrian * $Id: main.c,v 1.99 1997/11/16 22:15:05 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Add commands for traffic summary, version display, etc.
246059Samurai *		o Add signal handler for misc controls.
256059Samurai */
2630715Sbrian#include <sys/param.h>
2731195Sbrian#include <sys/time.h>
2831195Sbrian#include <sys/select.h>
2930715Sbrian#include <sys/socket.h>
3030715Sbrian#include <netinet/in.h>
3130715Sbrian#include <netinet/in_systm.h>
3230715Sbrian#include <netinet/ip.h>
3330715Sbrian#include <arpa/inet.h>
3430715Sbrian#include <netdb.h>
3531195Sbrian#include <net/if.h>
3631195Sbrian#include <net/if_var.h>
3731195Sbrian#include <net/if_tun.h>
3830715Sbrian
3930715Sbrian#include <errno.h>
406059Samurai#include <fcntl.h>
4111336Samurai#include <paths.h>
4230715Sbrian#include <signal.h>
4330715Sbrian#include <stdio.h>
4430715Sbrian#include <stdlib.h>
4530715Sbrian#include <string.h>
466059Samurai#include <sys/time.h>
4730715Sbrian#include <sys/wait.h>
4830715Sbrian#include <sysexits.h>
496059Samurai#include <termios.h>
5018786Sjkh#include <unistd.h>
5130715Sbrian
5230715Sbrian#include "mbuf.h"
5330715Sbrian#include "log.h"
5430715Sbrian#include "defs.h"
5531061Sbrian#include "id.h"
5630715Sbrian#include "timer.h"
5730715Sbrian#include "fsm.h"
586059Samurai#include "modem.h"
596059Samurai#include "os.h"
606059Samurai#include "hdlc.h"
6113389Sphk#include "ccp.h"
626059Samurai#include "lcp.h"
636059Samurai#include "ipcp.h"
6426142Sbrian#include "loadalias.h"
6530715Sbrian#include "command.h"
666059Samurai#include "vars.h"
676735Samurai#include "auth.h"
687001Samurai#include "filter.h"
6913389Sphk#include "systems.h"
7013389Sphk#include "ip.h"
7123840Sbrian#include "sig.h"
7226940Sbrian#include "server.h"
7328536Sbrian#include "lcpproto.h"
7430715Sbrian#include "main.h"
7530715Sbrian#include "vjcomp.h"
7630715Sbrian#include "async.h"
7731158Sbrian#include "pathnames.h"
7831195Sbrian#include "tun.h"
796059Samurai
806735Samurai#ifndef O_NONBLOCK
816735Samurai#ifdef O_NDELAY
826735Samurai#define	O_NONBLOCK O_NDELAY
836735Samurai#endif
846735Samurai#endif
856735Samurai
8630715Sbrianint TermMode = 0;
8730715Sbrianint tunno = 0;
886059Samurai
8928679Sbrianstatic struct termios oldtio;	/* Original tty mode */
9028679Sbrianstatic struct termios comtio;	/* Command level tty mode */
9120813Sjkhstatic pid_t BGPid = 0;
9225634Sbrianstatic char pid_filename[MAXPATHLEN];
9327061Sbrianstatic int dial_up;
946059Samurai
9530715Sbrianstatic void DoLoop(void);
9630715Sbrianstatic void TerminalStop(int);
9730715Sbrianstatic char *ex_desc(int);
9830715Sbrian
996059Samuraistatic void
10026858SbrianTtyInit(int DontWantInt)
1016059Samurai{
1026059Samurai  struct termios newtio;
1036059Samurai  int stat;
1046059Samurai
1056059Samurai  stat = fcntl(0, F_GETFL, 0);
10625630Sbrian  if (stat > 0) {
10728679Sbrian    stat |= O_NONBLOCK;
10828679Sbrian    (void) fcntl(0, F_SETFL, stat);
10925630Sbrian  }
1106059Samurai  newtio = oldtio;
11128679Sbrian  newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
1126059Samurai  newtio.c_iflag = 0;
1136059Samurai  newtio.c_oflag &= ~OPOST;
1146059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
11526858Sbrian  if (DontWantInt)
11626858Sbrian    newtio.c_cc[VINTR] = _POSIX_VDISABLE;
1176059Samurai  newtio.c_cc[VMIN] = 1;
1186059Samurai  newtio.c_cc[VTIME] = 0;
1196059Samurai  newtio.c_cflag |= CS8;
1206735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1216059Samurai  comtio = newtio;
1226059Samurai}
1236059Samurai
1246059Samurai/*
1256059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1266059Samurai */
12710528Samuraivoid
12828679SbrianTtyCommandMode(int prompt)
1296059Samurai{
1306059Samurai  struct termios newtio;
1316059Samurai  int stat;
1326059Samurai
1336059Samurai  if (!(mode & MODE_INTER))
1346059Samurai    return;
1356735Samurai  tcgetattr(0, &newtio);
13628679Sbrian  newtio.c_lflag |= (ECHO | ISIG | ICANON);
1376059Samurai  newtio.c_iflag = oldtio.c_iflag;
1386059Samurai  newtio.c_oflag |= OPOST;
1396735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1406059Samurai  stat = fcntl(0, F_GETFL, 0);
14125630Sbrian  if (stat > 0) {
14228679Sbrian    stat |= O_NONBLOCK;
14328679Sbrian    (void) fcntl(0, F_SETFL, stat);
14425630Sbrian  }
1456059Samurai  TermMode = 0;
14628679Sbrian  if (prompt)
14728679Sbrian    Prompt();
1486059Samurai}
1496059Samurai
1506059Samurai/*
1516059Samurai * Set tty into terminal mode which is used while we invoke term command.
1526059Samurai */
1536059Samuraivoid
1546059SamuraiTtyTermMode()
1556059Samurai{
1566059Samurai  int stat;
1576059Samurai
1586735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1596059Samurai  stat = fcntl(0, F_GETFL, 0);
16025630Sbrian  if (stat > 0) {
16128679Sbrian    stat &= ~O_NONBLOCK;
16228679Sbrian    (void) fcntl(0, F_SETFL, stat);
16325630Sbrian  }
1646059Samurai  TermMode = 1;
1656059Samurai}
1666059Samurai
1676059Samuraivoid
16810528SamuraiTtyOldMode()
1696059Samurai{
1706059Samurai  int stat;
1716059Samurai
1726059Samurai  stat = fcntl(0, F_GETFL, 0);
17325630Sbrian  if (stat > 0) {
17428679Sbrian    stat &= ~O_NONBLOCK;
17528679Sbrian    (void) fcntl(0, F_SETFL, stat);
17625630Sbrian  }
1776735Samurai  tcsetattr(0, TCSANOW, &oldtio);
17810528Samurai}
17910528Samurai
18010528Samuraivoid
18128679SbrianCleanup(int excode)
18210528Samurai{
18331081Sbrian  ServerClose();
18430825Sbrian  OsInterfaceDown(1);
18530825Sbrian  HangupModem(1);
18630697Sbrian  nointr_sleep(1);
18731121Sbrian  DeleteIfRoutes(1);
18831061Sbrian  ID0unlink(pid_filename);
18923863Sbrian  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
19023863Sbrian    char c = EX_ERRDEAD;
19128679Sbrian
19228679Sbrian    if (write(BGFiledes[1], &c, 1) == 1)
19328679Sbrian      LogPrintf(LogPHASE, "Parent notified of failure.\n");
19423863Sbrian    else
19528679Sbrian      LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
19623863Sbrian    close(BGFiledes[1]);
19723863Sbrian  }
19828679Sbrian  LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
19910528Samurai  TtyOldMode();
20031061Sbrian  LogClose();
2016059Samurai
2026059Samurai  exit(excode);
2036059Samurai}
2046059Samurai
2056059Samuraistatic void
20628679SbrianCloseConnection(int signo)
2076059Samurai{
20826858Sbrian  /* NOTE, these are manual, we've done a setsid() */
20931121Sbrian  pending_signal(SIGINT, SIG_IGN);
21027157Sbrian  LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
21128679Sbrian  reconnectState = RECON_FALSE;
21228684Sbrian  reconnectCount = 0;
21328684Sbrian  DownConnection();
21430715Sbrian  dial_up = 0;
21531121Sbrian  pending_signal(SIGINT, CloseConnection);
2166059Samurai}
2176059Samurai
2186059Samuraistatic void
21928679SbrianCloseSession(int signo)
2206059Samurai{
22128679Sbrian  if (BGPid) {
22228679Sbrian    kill(BGPid, SIGINT);
22328679Sbrian    exit(EX_TERM);
22428679Sbrian  }
22528679Sbrian  LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
22628679Sbrian  reconnect(RECON_FALSE);
22728679Sbrian  LcpClose();
22828679Sbrian  Cleanup(EX_TERM);
2296059Samurai}
2306059Samurai
23110528Samuraistatic void
23210528SamuraiTerminalCont()
23310528Samurai{
23423840Sbrian  pending_signal(SIGCONT, SIG_DFL);
23523840Sbrian  pending_signal(SIGTSTP, TerminalStop);
23610528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
23710528Samurai}
23810528Samurai
23910528Samuraistatic void
24028679SbrianTerminalStop(int signo)
24110528Samurai{
24223840Sbrian  pending_signal(SIGCONT, TerminalCont);
24310528Samurai  TtyOldMode();
24423840Sbrian  pending_signal(SIGTSTP, SIG_DFL);
24510528Samurai  kill(getpid(), signo);
24610528Samurai}
24710528Samurai
24826940Sbrianstatic void
24928679SbrianSetUpServer(int signo)
25026940Sbrian{
25126940Sbrian  int res;
25228679Sbrian
25331081Sbrian  VarHaveLocalAuthKey = 0;
25431081Sbrian  LocalAuthInit();
25528679Sbrian  if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
25629083Sbrian    LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
25729083Sbrian	      res, SERVER_PORT + tunno);
25826940Sbrian}
25926940Sbrian
26031081Sbrianstatic void
26131081SbrianBringDownServer(int signo)
26231081Sbrian{
26331081Sbrian  VarHaveLocalAuthKey = 0;
26431081Sbrian  LocalAuthInit();
26531081Sbrian  ServerClose();
26631081Sbrian}
26731081Sbrian
26825908Sbrianstatic char *
26925908Sbrianex_desc(int ex)
27025908Sbrian{
27125908Sbrian  static char num[12];
27228679Sbrian  static char *desc[] = {"normal", "start", "sock",
27325908Sbrian    "modem", "dial", "dead", "done", "reboot", "errdead",
27428679Sbrian  "hangup", "term", "nodial", "nologin"};
27510528Samurai
27628679Sbrian  if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
27725908Sbrian    return desc[ex];
27825908Sbrian  snprintf(num, sizeof num, "%d", ex);
27925908Sbrian  return num;
28025908Sbrian}
28125908Sbrian
28230715Sbrianstatic void
2836059SamuraiUsage()
2846059Samurai{
28520120Snate  fprintf(stderr,
28628679Sbrian	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
2876059Samurai  exit(EX_START);
2886059Samurai}
2896059Samurai
29030715Sbrianstatic void
2916059SamuraiProcessArgs(int argc, char **argv)
2926059Samurai{
2936059Samurai  int optc;
2946059Samurai  char *cp;
2956059Samurai
2966059Samurai  optc = 0;
29731121Sbrian  mode = MODE_INTER;
2986059Samurai  while (argc > 0 && **argv == '-') {
2996059Samurai    cp = *argv + 1;
30031121Sbrian    if (strcmp(cp, "auto") == 0) {
3016059Samurai      mode |= MODE_AUTO;
30231121Sbrian      mode &= ~MODE_INTER;
30331121Sbrian    } else if (strcmp(cp, "background") == 0) {
30431121Sbrian      mode |= MODE_BACKGROUND;
30531121Sbrian      mode &= ~MODE_INTER;
30631121Sbrian    } else if (strcmp(cp, "direct") == 0) {
3076059Samurai      mode |= MODE_DIRECT;
30831121Sbrian      mode &= ~MODE_INTER;
30931121Sbrian    } else if (strcmp(cp, "dedicated") == 0) {
3106059Samurai      mode |= MODE_DEDICATED;
31131121Sbrian      mode &= ~MODE_INTER;
31231121Sbrian    } else if (strcmp(cp, "ddial") == 0) {
31331121Sbrian      mode |= MODE_DDIAL;
31431121Sbrian      mode &= ~MODE_INTER;
31531121Sbrian    } else if (strcmp(cp, "alias") == 0) {
31626142Sbrian      if (loadAliasHandlers(&VarAliasHandlers) == 0)
31728679Sbrian	mode |= MODE_ALIAS;
31826142Sbrian      else
31928679Sbrian	LogPrintf(LogWARN, "Cannot load alias library\n");
32028679Sbrian      optc--;			/* this option isn't exclusive */
32128679Sbrian    } else
3226059Samurai      Usage();
3236059Samurai    optc++;
32428679Sbrian    argv++;
32528679Sbrian    argc--;
3266059Samurai  }
3276059Samurai  if (argc > 1) {
3286059Samurai    fprintf(stderr, "specify only one system label.\n");
3296059Samurai    exit(EX_START);
3306059Samurai  }
33128679Sbrian  if (argc == 1)
33231121Sbrian    SetLabel(*argv);
3336059Samurai
3346059Samurai  if (optc > 1) {
3356059Samurai    fprintf(stderr, "specify only one mode.\n");
3366059Samurai    exit(EX_START);
3376059Samurai  }
3386059Samurai}
3396059Samurai
3406059Samuraistatic void
3416059SamuraiGreetings()
3426059Samurai{
34326516Sbrian  if (VarTerm) {
34426516Sbrian    fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
34526516Sbrian    fflush(VarTerm);
34626516Sbrian  }
3476059Samurai}
3486059Samurai
34926940Sbrianint
35028679Sbrianmain(int argc, char **argv)
3516059Samurai{
35225707Sbrian  FILE *lockfile;
35326516Sbrian  char *name;
35426516Sbrian
35526551Sbrian  VarTerm = 0;
35630715Sbrian  name = strrchr(argv[0], '/');
35728679Sbrian  LogOpen(name ? name + 1 : argv[0]);
35826516Sbrian
35928679Sbrian  argc--;
36028679Sbrian  argv++;
3616059Samurai  ProcessArgs(argc, argv);
36231121Sbrian  if (!(mode & MODE_DIRECT))
36326551Sbrian    VarTerm = stdout;
36431121Sbrian
36531121Sbrian  ID0init();
36631158Sbrian  if (ID0realuid() != 0) {
36731158Sbrian    char conf[200], *ptr;
36831158Sbrian
36931158Sbrian    snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
37031158Sbrian    do {
37131158Sbrian      if (!access(conf, W_OK)) {
37231158Sbrian        LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
37331158Sbrian        return -1;
37431158Sbrian      }
37531158Sbrian      ptr = conf + strlen(conf)-2;
37631158Sbrian      while (ptr > conf && *ptr != '/')
37731158Sbrian        *ptr-- = '\0';
37831158Sbrian    } while (ptr >= conf);
37931158Sbrian  }
38031158Sbrian
38131121Sbrian  if (!ValidSystem(GetLabel())) {
38231121Sbrian    fprintf(stderr, "You may not use ppp in this mode with this label\n");
38331157Sbrian    if (mode & MODE_DIRECT) {
38431157Sbrian      const char *l;
38531157Sbrian      if ((l = GetLabel()) == NULL)
38631157Sbrian        l = "default";
38731157Sbrian      VarTerm = 0;
38831157Sbrian      LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
38931157Sbrian    }
39031157Sbrian    LogClose();
39131121Sbrian    return 1;
39229083Sbrian  }
39331121Sbrian
39431196Sbrian  if (!GetShortHost())
39531196Sbrian    return 1;
39626551Sbrian  Greetings();
3976059Samurai  IpcpDefAddress();
3986059Samurai
39926516Sbrian  if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
40026516Sbrian    fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
4016059Samurai
4026059Samurai  if (OpenTunnel(&tunno) < 0) {
40326940Sbrian    LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
40426940Sbrian    return EX_START;
4056059Samurai  }
4066059Samurai  if (mode & MODE_INTER) {
40726516Sbrian    fprintf(VarTerm, "Interactive mode\n");
40826690Sbrian    netfd = STDOUT_FILENO;
40931121Sbrian  } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
41031121Sbrian    if (GetLabel() == NULL) {
41126516Sbrian      if (VarTerm)
41228679Sbrian	fprintf(VarTerm, "Destination system must be specified in"
41328679Sbrian		" auto, background or ddial mode.\n");
41426940Sbrian      return EX_START;
4156059Samurai    }
41631121Sbrian
41728679Sbrian  tcgetattr(0, &oldtio);	/* Save original tty mode */
4186059Samurai
41927157Sbrian  pending_signal(SIGHUP, CloseSession);
42023840Sbrian  pending_signal(SIGTERM, CloseSession);
42127157Sbrian  pending_signal(SIGINT, CloseConnection);
42223840Sbrian  pending_signal(SIGQUIT, CloseSession);
4236735Samurai#ifdef SIGPIPE
42424753Sache  signal(SIGPIPE, SIG_IGN);
4256735Samurai#endif
4266735Samurai#ifdef SIGALRM
42723840Sbrian  pending_signal(SIGALRM, SIG_IGN);
4286735Samurai#endif
42928679Sbrian  if (mode & MODE_INTER) {
43010528Samurai#ifdef SIGTSTP
43126940Sbrian    pending_signal(SIGTSTP, TerminalStop);
43210528Samurai#endif
43310528Samurai#ifdef SIGTTIN
43426940Sbrian    pending_signal(SIGTTIN, TerminalStop);
43510528Samurai#endif
43610528Samurai#ifdef SIGTTOU
43726940Sbrian    pending_signal(SIGTTOU, SIG_IGN);
43810528Samurai#endif
43926940Sbrian  }
44031121Sbrian  if (!(mode & MODE_INTER)) {
44126940Sbrian#ifdef SIGUSR1
44226940Sbrian    pending_signal(SIGUSR1, SetUpServer);
44326940Sbrian#endif
44431081Sbrian#ifdef SIGUSR2
44531081Sbrian    pending_signal(SIGUSR2, BringDownServer);
44631081Sbrian#endif
44731121Sbrian  }
4486059Samurai
44931121Sbrian  if (GetLabel()) {
45031121Sbrian    if (SelectSystem(GetLabel(), CONFFILE) < 0) {
45131154Sbrian      LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
45231154Sbrian                GetLabel());
4536059Samurai      Cleanup(EX_START);
4546059Samurai    }
45531121Sbrian    if (mode & MODE_OUTGOING_DAEMON &&
45631121Sbrian	DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
45731154Sbrian      LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
45831154Sbrian		" auto, background or ddial mode.\n", GetLabel());
4596059Samurai      Cleanup(EX_START);
4606059Samurai    }
4616059Samurai  }
46226940Sbrian
46331121Sbrian  if (mode & MODE_DAEMON) {
46420813Sjkh    if (mode & MODE_BACKGROUND) {
46528679Sbrian      if (pipe(BGFiledes)) {
46628974Sbrian	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
46720813Sjkh	Cleanup(EX_SOCK);
46820813Sjkh      }
4696059Samurai    }
4706059Samurai
4716059Samurai    if (!(mode & MODE_DIRECT)) {
47220813Sjkh      pid_t bgpid;
47311336Samurai
47428679Sbrian      bgpid = fork();
47520813Sjkh      if (bgpid == -1) {
47628974Sbrian	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
47728679Sbrian	Cleanup(EX_SOCK);
47820813Sjkh      }
47920813Sjkh      if (bgpid) {
48020813Sjkh	char c = EX_NORMAL;
48111336Samurai
48220813Sjkh	if (mode & MODE_BACKGROUND) {
48320813Sjkh	  /* Wait for our child to close its pipe before we exit. */
48420813Sjkh	  BGPid = bgpid;
48528679Sbrian	  close(BGFiledes[1]);
48625908Sbrian	  if (read(BGFiledes[0], &c, 1) != 1) {
48726516Sbrian	    fprintf(VarTerm, "Child exit, no status.\n");
48828679Sbrian	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
48925908Sbrian	  } else if (c == EX_NORMAL) {
49026516Sbrian	    fprintf(VarTerm, "PPP enabled.\n");
49128679Sbrian	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
49225908Sbrian	  } else {
49328679Sbrian	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
49426516Sbrian	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
49528679Sbrian		      ex_desc((int) c));
49628679Sbrian	  }
49728679Sbrian	  close(BGFiledes[0]);
49820813Sjkh	}
49928679Sbrian	return c;
50023863Sbrian      } else if (mode & MODE_BACKGROUND)
50128679Sbrian	close(BGFiledes[0]);
50225707Sbrian    }
50320813Sjkh
50428679Sbrian    VarTerm = 0;		/* We know it's currently stdout */
50529551Sbrian    close(1);
50626686Sbrian    close(2);
50726551Sbrian
50826686Sbrian    if (mode & MODE_DIRECT)
50926858Sbrian      TtyInit(1);
51031121Sbrian    else if (mode & MODE_DAEMON) {
51126686Sbrian      setsid();
51229551Sbrian      close(0);
51326686Sbrian    }
5146059Samurai  } else {
51526858Sbrian    TtyInit(0);
51610528Samurai    TtyCommandMode(1);
5176059Samurai  }
51829696Sbrian
51929696Sbrian  snprintf(pid_filename, sizeof(pid_filename), "%stun%d.pid",
52029696Sbrian           _PATH_VARRUN, tunno);
52131061Sbrian  lockfile = ID0fopen(pid_filename, "w");
52231061Sbrian  if (lockfile != NULL) {
52329696Sbrian    fprintf(lockfile, "%d\n", (int) getpid());
52429696Sbrian    fclose(lockfile);
52529696Sbrian  } else
52629696Sbrian    LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
52729696Sbrian              pid_filename, strerror(errno));
52829696Sbrian
52926516Sbrian  LogPrintf(LogPHASE, "PPP Started.\n");
5306059Samurai
5316059Samurai
5326059Samurai  do
53328679Sbrian    DoLoop();
5346059Samurai  while (mode & MODE_DEDICATED);
5356059Samurai
5366059Samurai  Cleanup(EX_DONE);
53726940Sbrian  return 0;
5386059Samurai}
5396059Samurai
5406059Samurai/*
54120813Sjkh *  Turn into packet mode, where we speak PPP.
5426059Samurai */
5436059Samuraivoid
5446059SamuraiPacketMode()
5456059Samurai{
54631034Sbrian  if (RawModem() < 0) {
54726516Sbrian    LogPrintf(LogWARN, "PacketMode: Not connected.\n");
5486059Samurai    return;
5496059Samurai  }
5506059Samurai  AsyncInit();
55130187Sbrian  VjInit(15);
5526059Samurai  LcpInit();
5536059Samurai  IpcpInit();
5546059Samurai  CcpInit();
5556059Samurai  LcpUp();
5566059Samurai
55725872Sbrian  LcpOpen(VarOpenMode);
55831121Sbrian  if (mode & MODE_INTER)
55910528Samurai    TtyCommandMode(1);
56031121Sbrian  if (VarTerm) {
56131121Sbrian    fprintf(VarTerm, "Packet mode.\n");
56231121Sbrian    aft_cmd = 1;
5636059Samurai  }
5646059Samurai}
5656059Samurai
5666059Samuraistatic void
5676059SamuraiShowHelp()
5686059Samurai{
56926901Sbrian  fprintf(stderr, "The following commands are available:\r\n");
57026901Sbrian  fprintf(stderr, " ~p\tEnter Packet mode\r\n");
57126901Sbrian  fprintf(stderr, " ~-\tDecrease log level\r\n");
57226901Sbrian  fprintf(stderr, " ~+\tIncrease log level\r\n");
57326901Sbrian  fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
57426901Sbrian  fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
57526901Sbrian  fprintf(stderr, " ~.\tTerminate program\r\n");
57626901Sbrian  fprintf(stderr, " ~?\tThis help\r\n");
5776059Samurai}
5786059Samurai
5796059Samuraistatic void
5806059SamuraiReadTty()
5816059Samurai{
5826059Samurai  int n;
5836059Samurai  char ch;
5846059Samurai  static int ttystate;
58526516Sbrian  FILE *oVarTerm;
58631070Sbrian  char linebuff[LINE_LEN];
58728679Sbrian
58826516Sbrian  LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
58928679Sbrian	    TermMode, netfd, mode);
5906059Samurai  if (!TermMode) {
59128679Sbrian    n = read(netfd, linebuff, sizeof(linebuff) - 1);
5926735Samurai    if (n > 0) {
59326516Sbrian      aft_cmd = 1;
59430913Sbrian      if (linebuff[n-1] == '\n')
59530913Sbrian        linebuff[--n] = '\0';
59631156Sbrian      if (n)
59731156Sbrian        DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
59831156Sbrian      Prompt();
5996735Samurai    } else {
60026516Sbrian      LogPrintf(LogPHASE, "client connection closed.\n");
60126516Sbrian      oVarTerm = VarTerm;
60226516Sbrian      VarTerm = 0;
60326516Sbrian      if (oVarTerm && oVarTerm != stdout)
60428679Sbrian	fclose(oVarTerm);
6056059Samurai      close(netfd);
6066059Samurai      netfd = -1;
6076059Samurai    }
6086059Samurai    return;
6096059Samurai  }
6106059Samurai
6116059Samurai  /*
61228679Sbrian   * We are in terminal mode, decode special sequences
6136059Samurai   */
61426516Sbrian  n = read(fileno(VarTerm), &ch, 1);
61528974Sbrian  LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
6166059Samurai
6176059Samurai  if (n > 0) {
6186059Samurai    switch (ttystate) {
6196059Samurai    case 0:
6206059Samurai      if (ch == '~')
6216059Samurai	ttystate++;
6226059Samurai      else
6236059Samurai	write(modem, &ch, n);
6246059Samurai      break;
6256059Samurai    case 1:
6266059Samurai      switch (ch) {
6276059Samurai      case '?':
6286059Samurai	ShowHelp();
6296059Samurai	break;
6306059Samurai      case 'p':
63128679Sbrian
6326059Samurai	/*
6336059Samurai	 * XXX: Should check carrier.
6346059Samurai	 */
6356059Samurai	if (LcpFsm.state <= ST_CLOSED) {
6366059Samurai	  VarOpenMode = OPEN_ACTIVE;
6376059Samurai	  PacketMode();
6386059Samurai	}
6396059Samurai	break;
6406059Samurai      case '.':
6416059Samurai	TermMode = 1;
64226516Sbrian	aft_cmd = 1;
64310528Samurai	TtyCommandMode(1);
6446059Samurai	break;
64526516Sbrian      case 't':
64626516Sbrian	if (LogIsKept(LogDEBUG)) {
64726516Sbrian	  ShowTimers();
64826516Sbrian	  break;
64926516Sbrian	}
65026516Sbrian      case 'm':
65126516Sbrian	if (LogIsKept(LogDEBUG)) {
65226516Sbrian	  ShowMemMap();
65326516Sbrian	  break;
65426516Sbrian	}
6556059Samurai      default:
6566059Samurai	if (write(modem, &ch, n) < 0)
65726516Sbrian	  LogPrintf(LogERROR, "error writing to modem.\n");
6586059Samurai	break;
6596059Samurai      }
6606059Samurai      ttystate = 0;
6616059Samurai      break;
6626059Samurai    }
6636059Samurai  }
6646059Samurai}
6656059Samurai
6666059Samurai
6676059Samurai/*
6686059Samurai *  Here, we'll try to detect HDLC frame
6696059Samurai */
6706059Samurai
6716059Samuraistatic char *FrameHeaders[] = {
6726735Samurai  "\176\377\003\300\041",
6736735Samurai  "\176\377\175\043\300\041",
6746735Samurai  "\176\177\175\043\100\041",
6756735Samurai  "\176\175\337\175\043\300\041",
6766735Samurai  "\176\175\137\175\043\100\041",
6776059Samurai  NULL,
6786059Samurai};
6796059Samurai
68030715Sbrianstatic u_char *
68128679SbrianHdlcDetect(u_char * cp, int n)
6826059Samurai{
6836735Samurai  char *ptr, *fp, **hp;
6846059Samurai
68528679Sbrian  cp[n] = '\0';			/* be sure to null terminated */
6866059Samurai  ptr = NULL;
6876059Samurai  for (hp = FrameHeaders; *hp; hp++) {
6886735Samurai    fp = *hp;
6896735Samurai    if (DEV_IS_SYNC)
6906735Samurai      fp++;
69128679Sbrian    ptr = strstr((char *) cp, fp);
69213389Sphk    if (ptr)
6936059Samurai      break;
6946059Samurai  }
69528679Sbrian  return ((u_char *) ptr);
6966059Samurai}
6976059Samurai
6986059Samuraistatic struct pppTimer RedialTimer;
6996059Samurai
7006059Samuraistatic void
7016059SamuraiRedialTimeout()
7026059Samurai{
7036059Samurai  StopTimer(&RedialTimer);
70426516Sbrian  LogPrintf(LogPHASE, "Redialing timer expired.\n");
7056059Samurai}
7066059Samurai
7076059Samuraistatic void
70828679SbrianStartRedialTimer(int Timeout)
7096059Samurai{
7106059Samurai  StopTimer(&RedialTimer);
71111336Samurai
71224939Sbrian  if (Timeout) {
71311336Samurai    RedialTimer.state = TIMER_STOPPED;
71411336Samurai
71524939Sbrian    if (Timeout > 0)
71628679Sbrian      RedialTimer.load = Timeout * SECTICKS;
71711336Samurai    else
71828679Sbrian      RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
71911336Samurai
72026516Sbrian    LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
72124939Sbrian	      RedialTimer.load / SECTICKS);
72224939Sbrian
72311336Samurai    RedialTimer.func = RedialTimeout;
72411336Samurai    StartTimer(&RedialTimer);
72511336Samurai  }
7266059Samurai}
7276059Samurai
7286059Samurai
7296059Samuraistatic void
7306059SamuraiDoLoop()
7316059Samurai{
7326059Samurai  fd_set rfds, wfds, efds;
73323598Sache  int pri, i, n, wfd, nfds;
7346059Samurai  struct sockaddr_in hisaddr;
7356059Samurai  struct timeval timeout, *tp;
7366059Samurai  int ssize = sizeof(hisaddr);
7376059Samurai  u_char *cp;
73811336Samurai  int tries;
7399448Samurai  int qlen;
74026858Sbrian  int res;
74110528Samurai  pid_t pgroup;
74231195Sbrian  struct tun_data tun;
74331195Sbrian#define rbuff tun.data
7446059Samurai
74510528Samurai  pgroup = getpgrp();
74610528Samurai
74725908Sbrian  if (mode & MODE_DIRECT) {
74826551Sbrian    LogPrintf(LogDEBUG, "Opening modem\n");
74931034Sbrian    if (OpenModem() < 0)
75029521Sbrian      return;
75126516Sbrian    LogPrintf(LogPHASE, "Packet mode enabled\n");
7526059Samurai    PacketMode();
7536059Samurai  } else if (mode & MODE_DEDICATED) {
75423598Sache    if (modem < 0)
75531034Sbrian      while (OpenModem() < 0)
75630697Sbrian	nointr_sleep(VarReconnectTimer);
7576059Samurai  }
75826516Sbrian  fflush(VarTerm);
7596059Samurai
7607001Samurai  timeout.tv_sec = 0;
7616059Samurai  timeout.tv_usec = 0;
76226098Sbrian  reconnectState = RECON_UNKNOWN;
7636059Samurai
76423863Sbrian  if (mode & MODE_BACKGROUND)
76530715Sbrian    dial_up = 1;		/* Bring the line up */
76623863Sbrian  else
76730715Sbrian    dial_up = 0;		/* XXXX */
76811336Samurai  tries = 0;
7696059Samurai  for (;;) {
77023598Sache    nfds = 0;
77128679Sbrian    FD_ZERO(&rfds);
77228679Sbrian    FD_ZERO(&wfds);
77328679Sbrian    FD_ZERO(&efds);
7747001Samurai
77528679Sbrian    /*
77628679Sbrian     * If the link is down and we're in DDIAL mode, bring it back up.
77720120Snate     */
77820120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
77930715Sbrian      dial_up = 1;
78020120Snate
78125067Sbrian    /*
78228679Sbrian     * If we lost carrier and want to re-establish the connection due to the
78328679Sbrian     * "set reconnect" value, we'd better bring the line back up.
78425067Sbrian     */
78525908Sbrian    if (LcpFsm.state <= ST_CLOSED) {
78630715Sbrian      if (!dial_up && reconnectState == RECON_TRUE) {
78728679Sbrian	if (++reconnectCount <= VarReconnectTries) {
78828679Sbrian	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
78928679Sbrian		    reconnectCount, VarReconnectTries);
79025908Sbrian	  StartRedialTimer(VarReconnectTimer);
79130715Sbrian	  dial_up = 1;
79228679Sbrian	} else {
79328679Sbrian	  if (VarReconnectTries)
79428679Sbrian	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
79528679Sbrian		      VarReconnectTries);
79628679Sbrian	  reconnectCount = 0;
79728679Sbrian	  if (mode & MODE_BACKGROUND)
79828679Sbrian	    Cleanup(EX_DEAD);
79928679Sbrian	}
80028679Sbrian	reconnectState = RECON_ENVOKED;
80131121Sbrian      } else if (mode & MODE_DEDICATED)
80231121Sbrian        if (VarOpenMode == OPEN_ACTIVE)
80331121Sbrian          PacketMode();
80425908Sbrian    }
80525067Sbrian
80628679Sbrian    /*
80728679Sbrian     * If Ip packet for output is enqueued and require dial up, Just do it!
80828679Sbrian     */
80928679Sbrian    if (dial_up && RedialTimer.state != TIMER_RUNNING) {
81026516Sbrian      LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
81131034Sbrian      if (OpenModem() < 0) {
81228679Sbrian	tries++;
81328679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
81428679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
81528679Sbrian		    tries, VarDialTries);
81628679Sbrian	else
81728679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
81826551Sbrian
81926696Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
82026551Sbrian	  if (mode & MODE_BACKGROUND)
82128679Sbrian	    Cleanup(EX_DIAL);	/* Can't get the modem */
82230715Sbrian	  dial_up = 0;
82328679Sbrian	  reconnectState = RECON_UNKNOWN;
82428679Sbrian	  reconnectCount = 0;
82526551Sbrian	  tries = 0;
82628679Sbrian	} else
82726551Sbrian	  StartRedialTimer(VarRedialTimeout);
82811336Samurai      } else {
82928679Sbrian	tries++;		/* Tries are per number, not per list of
83028679Sbrian				 * numbers. */
83128679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
83226696Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
83328679Sbrian	else
83428679Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
83526696Sbrian
83626858Sbrian	if ((res = DialModem()) == EX_DONE) {
83730697Sbrian	  nointr_sleep(1);		/* little pause to allow peer starts */
83811336Samurai	  ModemTimeout();
83911336Samurai	  PacketMode();
84030715Sbrian	  dial_up = 0;
84128679Sbrian	  reconnectState = RECON_UNKNOWN;
84211336Samurai	  tries = 0;
84311336Samurai	} else {
84424844Sbrian	  if (mode & MODE_BACKGROUND) {
84526858Sbrian	    if (VarNextPhone == NULL || res == EX_SIG)
84628679Sbrian	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
84724844Sbrian	    else
84824939Sbrian	      /* Try all numbers in background mode */
84924939Sbrian	      StartRedialTimer(VarRedialNextTimeout);
85026858Sbrian	  } else if (!(mode & MODE_DDIAL) &&
85128679Sbrian		     ((VarDialTries && tries >= VarDialTries) ||
85228679Sbrian		      res == EX_SIG)) {
85324843Sbrian	    /* I give up !  Can't get through :( */
85424939Sbrian	    StartRedialTimer(VarRedialTimeout);
85530715Sbrian	    dial_up = 0;
85628679Sbrian	    reconnectState = RECON_UNKNOWN;
85728679Sbrian	    reconnectCount = 0;
85824843Sbrian	    tries = 0;
85924843Sbrian	  } else if (VarNextPhone == NULL)
86024843Sbrian	    /* Dial failed. Keep quite during redial wait period. */
86124939Sbrian	    StartRedialTimer(VarRedialTimeout);
86224843Sbrian	  else
86324939Sbrian	    StartRedialTimer(VarRedialNextTimeout);
86411336Samurai	}
86511336Samurai      }
8667001Samurai    }
8679448Samurai    qlen = ModemQlen();
86813733Sdfr
86913733Sdfr    if (qlen == 0) {
87013733Sdfr      IpStartOutput();
87113733Sdfr      qlen = ModemQlen();
87213733Sdfr    }
87323598Sache    if (modem >= 0) {
87423598Sache      if (modem + 1 > nfds)
87523598Sache	nfds = modem + 1;
8767001Samurai      FD_SET(modem, &rfds);
8777001Samurai      FD_SET(modem, &efds);
8789448Samurai      if (qlen > 0) {
8797001Samurai	FD_SET(modem, &wfds);
8807001Samurai      }
8817001Samurai    }
88223598Sache    if (server >= 0) {
88323598Sache      if (server + 1 > nfds)
88423598Sache	nfds = server + 1;
88523598Sache      FD_SET(server, &rfds);
88623598Sache    }
8876059Samurai
88828679Sbrian    /*
88928679Sbrian     * *** IMPORTANT ***
89028679Sbrian     *
89128679Sbrian     * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
89228679Sbrian     * with great care. If this values is too big, it results loss of
89328679Sbrian     * characters from modem and poor responce. If this values is too small,
89428679Sbrian     * ppp process eats many CPU time.
8956059Samurai     */
8966735Samurai#ifndef SIGALRM
89730697Sbrian    nointr_usleep(TICKUNIT);
8986059Samurai    TimerService();
89923840Sbrian#else
90023840Sbrian    handle_signals();
9016735Samurai#endif
90210877Sbde
90310877Sbde    /* If there are aren't many packets queued, look for some more. */
90423598Sache    if (qlen < 20 && tun_in >= 0) {
90523598Sache      if (tun_in + 1 > nfds)
90623598Sache	nfds = tun_in + 1;
90710877Sbde      FD_SET(tun_in, &rfds);
90823598Sache    }
90923598Sache    if (netfd >= 0) {
91023598Sache      if (netfd + 1 > nfds)
91123598Sache	nfds = netfd + 1;
9126059Samurai      FD_SET(netfd, &rfds);
9136059Samurai      FD_SET(netfd, &efds);
9146059Samurai    }
91528679Sbrian#ifndef SIGALRM
9167001Samurai
9176059Samurai    /*
91828679Sbrian     * Normally, select() will not block because modem is writable. In AUTO
91928679Sbrian     * mode, select will block until we find packet from tun
9206059Samurai     */
92128679Sbrian    tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
92223598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9236735Samurai#else
92428679Sbrian
9258857Srgrimes    /*
92628679Sbrian     * When SIGALRM timer is running, a select function will be return -1 and
92728679Sbrian     * EINTR after a Time Service signal hundler is done.  If the redial
92828679Sbrian     * timer is not running and we are trying to dial, poll with a 0 value
92928679Sbrian     * timer.
9307001Samurai     */
93111336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
93223598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9336735Samurai#endif
93422074Sbrian
93528679Sbrian    if (i == 0) {
93628679Sbrian      continue;
9376059Samurai    }
93828679Sbrian    if (i < 0) {
93928679Sbrian      if (errno == EINTR) {
94028679Sbrian	handle_signals();
94128679Sbrian	continue;
94228679Sbrian      }
94328974Sbrian      LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
94428679Sbrian      break;
9458857Srgrimes    }
94623598Sache    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
94726516Sbrian      LogPrintf(LogALERT, "Exception detected.\n");
9486059Samurai      break;
9496059Samurai    }
95023598Sache    if (server >= 0 && FD_ISSET(server, &rfds)) {
95126516Sbrian      LogPrintf(LogPHASE, "connected to client.\n");
95228679Sbrian      wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
95324753Sache      if (wfd < 0) {
95428974Sbrian	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
95524753Sache	continue;
95624753Sache      }
95723598Sache      if (netfd >= 0) {
9586059Samurai	write(wfd, "already in use.\n", 16);
9596059Samurai	close(wfd);
9606059Samurai	continue;
9616059Samurai      } else
9626059Samurai	netfd = wfd;
96326516Sbrian      VarTerm = fdopen(netfd, "a+");
96431081Sbrian      LocalAuthInit();
9656059Samurai      Greetings();
96630913Sbrian      IsInteractive(1);
96725630Sbrian      Prompt();
9686059Samurai    }
96931121Sbrian    if (netfd >= 0 && FD_ISSET(netfd, &rfds) &&
97031121Sbrian	((mode & MODE_OUTGOING_DAEMON) || pgroup == tcgetpgrp(0))) {
9716059Samurai      /* something to read from tty */
9726059Samurai      ReadTty();
9736059Samurai    }
97423598Sache    if (modem >= 0) {
9756059Samurai      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
97628679Sbrian	ModemStartOutput(modem);
9776059Samurai      }
9786059Samurai      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
9796735Samurai	if (LcpFsm.state <= ST_CLOSED)
98030697Sbrian	  nointr_usleep(10000);
9816059Samurai	n = read(modem, rbuff, sizeof(rbuff));
9826059Samurai	if ((mode & MODE_DIRECT) && n <= 0) {
9836059Samurai	  DownConnection();
9846059Samurai	} else
98528679Sbrian	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
9866059Samurai
9876059Samurai	if (LcpFsm.state <= ST_CLOSED) {
98828679Sbrian
9896059Samurai	  /*
99028679Sbrian	   * In dedicated mode, we just discard input until LCP is started.
9916059Samurai	   */
9926059Samurai	  if (!(mode & MODE_DEDICATED)) {
9936059Samurai	    cp = HdlcDetect(rbuff, n);
9946059Samurai	    if (cp) {
99528679Sbrian
9966059Samurai	      /*
9976059Samurai	       * LCP packet is detected. Turn ourselves into packet mode.
9986059Samurai	       */
9996059Samurai	      if (cp != rbuff) {
100028679Sbrian		write(modem, rbuff, cp - rbuff);
100128679Sbrian		write(modem, "\r\n", 2);
10026059Samurai	      }
10036059Samurai	      PacketMode();
10046059Samurai	    } else
100526516Sbrian	      write(fileno(VarTerm), rbuff, n);
10066059Samurai	  }
10076059Samurai	} else {
10086059Samurai	  if (n > 0)
10096059Samurai	    AsyncInput(rbuff, n);
10106059Samurai	}
10116059Samurai      }
10126059Samurai    }
101328679Sbrian    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
101428679Sbrian							 * from tun */
101531195Sbrian      n = read(tun_in, &tun, sizeof(tun));
10166059Samurai      if (n < 0) {
101728974Sbrian	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
10186059Samurai	continue;
10196059Samurai      }
102031195Sbrian      n -= sizeof(tun)-sizeof(tun.data);
102131195Sbrian      if (n <= 0) {
102231195Sbrian	LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n);
102331195Sbrian	continue;
102431195Sbrian      }
102531195Sbrian      if (!tun_check_header(tun, AF_INET))
102631195Sbrian          continue;
102728679Sbrian      if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
102828536Sbrian	/* we've been asked to send something addressed *to* us :( */
102928536Sbrian	if (VarLoopback) {
103028536Sbrian	  pri = PacketCheck(rbuff, n, FL_IN);
103128536Sbrian	  if (pri >= 0) {
103228536Sbrian	    struct mbuf *bp;
103328679Sbrian
103428536Sbrian	    if (mode & MODE_ALIAS) {
103528536Sbrian	      VarPacketAliasIn(rbuff, sizeof rbuff);
103628679Sbrian	      n = ntohs(((struct ip *) rbuff)->ip_len);
103728536Sbrian	    }
103828536Sbrian	    bp = mballoc(n, MB_IPIN);
103930715Sbrian	    memcpy(MBUF_CTOP(bp), rbuff, n);
104028536Sbrian	    IpInput(bp);
104128536Sbrian	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
104228536Sbrian	  }
104328536Sbrian	  continue;
104428679Sbrian	} else
104528536Sbrian	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
104628536Sbrian      }
104728536Sbrian
10486059Samurai      /*
104928679Sbrian       * Process on-demand dialup. Output packets are queued within tunnel
105028679Sbrian       * device until IPCP is opened.
10516059Samurai       */
10526059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
10537001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
10546059Samurai	if (pri >= 0) {
105520365Sjkh	  if (mode & MODE_ALIAS) {
105626142Sbrian	    VarPacketAliasOut(rbuff, sizeof rbuff);
105728679Sbrian	    n = ntohs(((struct ip *) rbuff)->ip_len);
105820365Sjkh	  }
10596059Samurai	  IpEnqueue(pri, rbuff, n);
106030715Sbrian	  dial_up = 1;	/* XXX */
10616059Samurai	}
10626059Samurai	continue;
10636059Samurai      }
10647001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
106520365Sjkh      if (pri >= 0) {
106628679Sbrian	if (mode & MODE_ALIAS) {
106728679Sbrian	  VarPacketAliasOut(rbuff, sizeof rbuff);
106828679Sbrian	  n = ntohs(((struct ip *) rbuff)->ip_len);
106928679Sbrian	}
10706059Samurai	IpEnqueue(pri, rbuff, n);
107120365Sjkh      }
10726059Samurai    }
10736059Samurai  }
107426516Sbrian  LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
10756059Samurai}
1076