]> git.ozlabs.org Git - ppp.git/commitdiff
Update to state of pppd-new directory
authorPaul Mackerras <paulus@samba.org>
Thu, 1 Jun 1995 07:01:42 +0000 (07:01 +0000)
committerPaul Mackerras <paulus@samba.org>
Thu, 1 Jun 1995 07:01:42 +0000 (07:01 +0000)
13 files changed:
pppd/Makefile.sun
pppd/auth.c
pppd/ccp.c
pppd/ipcp.c
pppd/lcp.c
pppd/magic.c
pppd/main.c
pppd/options.c
pppd/patchlevel.h
pppd/pathnames.h
pppd/pppd.h
pppd/sys-bsd.c
pppd/sys-str.c

index 98a335e33fce61e4f3a4e4f0680225958cf78f57..9c1513fccaed02333d90c67a83dbe47492d4f4d4 100644 (file)
@@ -1,24 +1,22 @@
 #
 # pppd makefile for Suns
-# $Id: Makefile.sun,v 1.10 1995/04/28 06:15:48 paulus Exp $
+# $Id: Makefile.sun,v 1.10.2.1 1995/06/01 07:01:19 paulus Exp $
 #
 
 BINDIR = /usr/local/etc
 MANDIR = /usr/local/man
 
-INSTALL= install -o root -g daemon
-
 PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c ccp.c \
        auth.c options.c sys-bsd.c sys-str.c sys-ultrix.c sys-linux.c
 HEADERS = callout.h pathnames.h patchlevel.h chap.h md5.h
 MANPAGES = pppd.8
 
 PPPDOBJS = main.o magic.o fsm.o lcp.o ipcp.o upap.o chap.o md5.o ccp.o \
-       auth.o options.o sys-str.o
+       auth.o options.o sys-str.o demand.o
 
-CC = gcc
-DEBUG_FLAGS =
-COMPILE_FLAGS =
+CC = gcc
+DEBUG_FLAGS = -g
+COMPILE_FLAGS = -DSTREAMS
 COPTS = -O
 LIBS = -lkvm
 
@@ -29,9 +27,9 @@ SOURCE= RELNOTES Makefile \
 
 all: pppd
 
-install: pppd
-       $(INSTALL) -c -m 4555 pppd $(BINDIR)/pppd
-       $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8/pppd.8
+install:
+       install -c -m 4555 -o root -g daemon pppd $(BINDIR)/pppd
+       install -c -m 555 -o root pppd.8 $(MANDIR)/man8
 
 pppd: $(PPPDOBJS)
        $(CC) $(CFLAGS) -o pppd $(PPPDOBJS) $(LIBS)
@@ -42,4 +40,3 @@ clean:
 depend:
        cpp -M $(CFLAGS) $(PPPDSRCS) >.depend
 #      makedepend $(CFLAGS) $(PPPDSRCS)
-
index f08fb312abe2b64f90bb4dc5a04a93faa0002664..7c6bbd3f7a15c344d16fdafe2df7c2022ba50852 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.15 1995/05/19 03:16:12 paulus Exp $";
+static char rcsid[] = "$Id: auth.c,v 1.15.2.1 1995/06/01 07:01:21 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -87,9 +87,19 @@ struct wordlist {
 
 /* Records which authentication operations haven't completed yet. */
 static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called login() */
 static int logged_in;
+
+/* List of addresses which the peer may use. */
 static struct wordlist *addresses[NUM_PPP];
 
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
 /* Bits in auth_pending[] */
 #define UPAP_WITHPEER  1
 #define UPAP_PEER      2
@@ -100,6 +110,7 @@ static struct wordlist *addresses[NUM_PPP];
 void check_access __P((FILE *, char *));
 
 static void network_phase __P((int));
+static void check_idle __P((caddr_t));
 static int  login __P((char *, char *, char **, int *));
 static void logout __P((void));
 static int  null_login __P((int));
@@ -207,6 +218,7 @@ network_phase(unit)
     int unit;
 {
     phase = PHASE_NETWORK;
+    num_np_open = 1;
     ipcp_open(unit);
     ccp_open(unit);
 }
@@ -303,6 +315,67 @@ auth_withpeer_success(unit, protocol)
 }
 
 
+/*
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(unit, proto)
+    int unit, proto;
+{
+    if (num_np_up == 0 && idle_time_limit > 0) {
+       TIMEOUT(check_idle, NULL, idle_time_limit);
+    }
+    ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(unit, proto)
+    int unit, proto;
+{
+    if (--num_np_up == 0 && idle_time_limit > 0) {
+       UNTIMEOUT(check_idle, NULL);
+    }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(unit, proto)
+    int unit, proto;
+{
+    if (--num_np_open <= 0) {
+       /* no further use for the link: shut up shop. */
+       lcp_close(0);
+    }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(arg)
+    caddr_t arg;
+{
+    struct ppp_idle idle;
+    time_t itime;
+
+    if (!get_idle_time(0, &idle))
+       return;
+    itime = MIN(idle.xmit_idle, idle.recv_idle);
+    if (itime >= idle_time_limit) {
+       /* link is idle: shut it down. */
+       syslog(LOG_INFO, "Terminating connection due to lack of activity.");
+       lcp_close(0);
+    } else {
+       TIMEOUT(check_idle, NULL, idle_time_limit - itime);
+    }
+}
+
 /*
  * check_auth_options - called to check authentication options.
  */
index 0ecfc97e281233099182818c316621580f697732..aec179427d232a97b0b265c0c642189fcabdaa31 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: ccp.c,v 1.9 1995/05/19 03:17:09 paulus Exp $";
+static char rcsid[] = "$Id: ccp.c,v 1.9.2.1 1995/06/01 07:01:22 paulus Exp $";
 #endif
 
 #include <syslog.h>
@@ -109,6 +109,7 @@ ccp_init(unit)
     memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
     memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
 
+    ccp_wantoptions[0].bsd_compress = 1;
     ccp_wantoptions[0].bsd_bits = 12;  /* default value */
 
     ccp_allowoptions[0].bsd_compress = 1;
index 112def979666ec79395711d8b2965022b1d0c9b4..260ab8113e40ab62e05a3a87e813db594384656e 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: ipcp.c,v 1.19 1995/06/01 01:30:38 paulus Exp $";
+static char rcsid[] = "$Id: ipcp.c,v 1.19.2.1 1995/06/01 07:01:26 paulus Exp $";
 #endif
 
 /*
@@ -44,7 +44,9 @@ ipcp_options ipcp_allowoptions[NUM_PPP];      /* Options we allow peer to request */
 ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
 
 /* local vars */
-static int cis_received[NUM_PPP];              /* # Conf-Reqs received */
+static int cis_received[NUM_PPP];      /* # Conf-Reqs received */
+static int default_route_set[NUM_PPP]; /* Have set up a default route */
+static int proxy_arp_set[NUM_PPP];     /* Have created proxy arp entry */
 
 /*
  * Callbacks for fsm code.  (CI = Configuration Information)
@@ -59,6 +61,7 @@ static int  ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
 static void ipcp_up __P((fsm *));              /* We're UP */
 static void ipcp_down __P((fsm *));            /* We're DOWN */
 static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */
+static void ipcp_finished __P((fsm *));        /* Don't need lower layer */
 
 fsm ipcp_fsm[NUM_PPP];         /* IPCP fsm structure */
 
@@ -73,7 +76,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
     ipcp_up,                   /* Called when fsm reaches OPENED state */
     ipcp_down,                 /* Called when fsm leaves OPENED state */
     NULL,                      /* Called when we want the lower layer up */
-    NULL,                      /* Called when we want the lower layer down */
+    ipcp_finished,             /* Called when we want the lower layer down */
     NULL,                      /* Called when Protocol-Reject received */
     NULL,                      /* Retransmission is necessary */
     NULL,                      /* Called to handle protocol-specific codes */
@@ -149,6 +152,8 @@ ipcp_init(unit)
     ao->neg_vj = 1;
     ao->maxslotindex = MAX_STATES - 1;
     ao->cflag = 1;
+    ao->default_route = 1;
+    ao->proxy_arp = 1;
 }
 
 
@@ -962,6 +967,57 @@ endswitch:
 }
 
 
+/*
+ * ipcp_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+int
+ipcp_demand_conf(u)
+    int u;
+{
+    ipcp_options *wo = &ipcp_wantoptions[u];
+
+    if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+       return 0;
+    if (!sifup(u))
+       return 0;
+    if (wo->default_route)
+       if (sifdefaultroute(u, wo->hisaddr))
+           default_route_set[u] = 1;
+    if (wo->proxy_arp)
+       if (sifproxyarp(u, wo->hisaddr))
+           proxy_arp_set[u] = 1;
+
+    syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(wo->ouraddr));
+    syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr));
+
+    return 1;
+}
+
+
+/*
+ * ipcp_demand_reset - reset the interface, which has been
+ * configured for dial-on-demand.
+ */
+void
+ipcp_demand_reset(u)
+    int u;
+{
+    ipcp_options *wo = &ipcp_wantoptions[u];
+
+    if (proxy_arp_set[u]) {
+       cifproxyarp(u, wo->hisaddr);
+       proxy_arp_set[u] = 0;
+    }
+    if (default_route_set[u]) {
+       cifdefaultroute(u, wo->hisaddr);
+       default_route_set[u] = 0;
+    }
+    sifdown(u);
+    cifaddr(u, wo->ouraddr, wo->hisaddr);
+}
+
+
 /*
  * ipcp_up - IPCP has come UP.
  *
@@ -974,16 +1030,16 @@ ipcp_up(f)
     u_int32_t mask;
     ipcp_options *ho = &ipcp_hisoptions[f->unit];
     ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
 
+    np_up(f->unit, PPP_IP);
     IPCPDEBUG((LOG_INFO, "ipcp: up"));
-    go->default_route = 0;
-    go->proxy_arp = 0;
 
     /*
      * We must have a non-zero IP address for both ends of the link.
      */
     if (!ho->neg_addr)
-       ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+       ho->hisaddr = wo->hisaddr;
 
     if (ho->hisaddr == 0) {
        syslog(LOG_ERR, "Could not determine remote IP address");
@@ -1006,38 +1062,55 @@ ipcp_up(f)
        return;
     }
 
-    syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(go->ouraddr));
-    syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+    /* set tcp compression */
+    sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
 
     /*
-     * Set IP addresses and (if specified) netmask.
+     * If we are doing dial-on-demand, the interface is already
+     * configured, so we put out any saved-up packets, then set the
+     * interface to pass IP packets.
      */
-    mask = GetMask(go->ouraddr);
-    if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
-       IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
-       ipcp_close(f->unit);
-       return;
-    }
+    if (demand) {
+       if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+           syslog(LOG_ERR, "Failed to negotiate desired IP addresses");
+           ipcp_close(f->unit);
+           return;
+       }
+       demand_rexmit(PPP_IP);
+       sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+    } else {
+
+       /*
+        * Set IP addresses and (if specified) netmask.
+        */
+       mask = GetMask(go->ouraddr);
+       if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+           IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+           ipcp_close(f->unit);
+           return;
+       }
 
-    /* set tcp compression */
-    sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+       /* bring the interface up for IP */
+       if (!sifup(f->unit)) {
+           IPCPDEBUG((LOG_WARNING, "sifup failed"));
+           ipcp_close(f->unit);
+           return;
+       }
 
-    /* bring the interface up for IP */
-    if (!sifup(f->unit)) {
-       IPCPDEBUG((LOG_WARNING, "sifup failed"));
-       ipcp_close(f->unit);
-       return;
-    }
+       /* assign a default route through the interface if required */
+       if (ipcp_wantoptions[f->unit].default_route) 
+           if (sifdefaultroute(f->unit, ho->hisaddr))
+               default_route_set[f->unit] = 1;
 
-    /* assign a default route through the interface if required */
-    if (ipcp_wantoptions[f->unit].default_route) 
-       if (sifdefaultroute(f->unit, ho->hisaddr))
-           go->default_route = 1;
+       /* Make a proxy ARP entry if requested. */
+       if (ipcp_wantoptions[f->unit].proxy_arp)
+           if (sifproxyarp(f->unit, ho->hisaddr))
+               proxy_arp_set[f->unit] = 1;
 
-    /* Make a proxy ARP entry if requested. */
-    if (ipcp_wantoptions[f->unit].proxy_arp)
-       if (sifproxyarp(f->unit, ho->hisaddr))
-           go->proxy_arp = 1;
+       syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(go->ouraddr));
+       syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+    }
 
     /*
      * Execute the ip-up script, like this:
@@ -1060,22 +1133,47 @@ ipcp_down(f)
 {
     u_int32_t ouraddr, hisaddr;
 
+    np_down(f->unit, PPP_IP);
     IPCPDEBUG((LOG_INFO, "ipcp: down"));
 
-    ouraddr = ipcp_gotoptions[f->unit].ouraddr;
-    hisaddr = ipcp_hisoptions[f->unit].hisaddr;
-    if (ipcp_gotoptions[f->unit].proxy_arp)
-       cifproxyarp(f->unit, hisaddr);
-    if (ipcp_gotoptions[f->unit].default_route) 
-       cifdefaultroute(f->unit, hisaddr);
-    sifdown(f->unit);
-    cifaddr(f->unit, ouraddr, hisaddr);
+    /*
+     * If we are doing dial-on-demand, set the interface
+     * to drop outgoing packets with an error (for now).
+     */
+    if (demand) {
+       sifnpmode(f->unit, PPP_IP, NPMODE_ERROR);
+
+    } else {
+       ouraddr = ipcp_gotoptions[f->unit].ouraddr;
+       hisaddr = ipcp_hisoptions[f->unit].hisaddr;
+       if (proxy_arp_set[f->unit]) {
+           cifproxyarp(f->unit, hisaddr);
+           proxy_arp_set[f->unit] = 0;
+       }
+       if (default_route_set[f->unit]) {
+           cifdefaultroute(f->unit, hisaddr);
+           default_route_set[f->unit] = 0;
+       }
+       sifdown(f->unit);
+       cifaddr(f->unit, ouraddr, hisaddr);
+    }
 
     /* Execute the ip-down script */
     ipcp_script(f, _PATH_IPDOWN);
 }
 
 
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(f)
+    fsm *f;
+{
+    np_finished(f->unit, PPP_IP);
+}
+
+
 /*
  * ipcp_script - Execute a script with arguments
  * interface-name tty-name speed local-IP remote-IP.
index af48e9c58a628961042928da73df28f70aef9694..fa90bd039e0c85b1d7f774e12513ff1d3fb51e2d 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: lcp.c,v 1.19 1995/05/19 03:25:16 paulus Exp $";
+static char rcsid[] = "$Id: lcp.c,v 1.19.2.1 1995/06/01 07:01:27 paulus Exp $";
 #endif
 
 /*
@@ -43,11 +43,6 @@ static char rcsid[] = "$Id: lcp.c,v 1.19 1995/05/19 03:25:16 paulus Exp $";
 #include "upap.h"
 #include "ipcp.h"
 
-#ifdef _linux_         /* Needs ppp ioctls */
-#include <net/if.h>
-#include <linux/if_ppp.h>
-#endif
-
 /* global vars */
 fsm lcp_fsm[NUM_PPP];                  /* LCP fsm structure (global)*/
 lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */
@@ -62,11 +57,6 @@ static u_int32_t lcp_echo_timer_running = 0;  /* TRUE if a timer is running */
 
 static u_char nak_buffer[PPP_MRU];     /* where we construct a nak packet */
 
-#ifdef _linux_
-u_int32_t idle_timer_running = 0;
-extern int idle_time_limit;
-#endif
-
 /*
  * Callbacks for fsm code.  (CI = Configuration Information)
  */
@@ -220,65 +210,6 @@ lcp_close(unit)
        fsm_close(&lcp_fsm[unit]);
 }
 
-#ifdef _linux_
-static void IdleTimeCheck __P((caddr_t));
-
-/*
- * Timer expired for the LCP echo requests from this process.
- */
-
-static void
-RestartIdleTimer (f)
-    fsm *f;
-{
-    u_long             delta;
-    struct ppp_ddinfo  ddinfo;
-    u_long             latest;
-/*
- * Read the time since the last packet was received.
- */
-    if (ioctl (fd, PPPIOCGTIME, &ddinfo) < 0) {
-        syslog (LOG_ERR, "ioctl(PPPIOCGTIME): %m");
-        die (1);
-    }
-/*
- * Choose the most recient IP activity. It may be a read or write frame
- */
-    latest = ddinfo.ip_sjiffies < ddinfo.ip_rjiffies ? ddinfo.ip_sjiffies
-                                                     : ddinfo.ip_rjiffies;
-/*
- * Compute the time since the last packet was received. If the timer
- *  has expired then send the echo request and reset the timer to maximum.
- */
-    delta = (idle_time_limit * HZ) - latest;
-    if (((int) delta < HZ || (int) latest < 0L) && f->state == OPENED) {
-        syslog (LOG_NOTICE, "No IP frames exchanged within idle time limit");
-       lcp_close(f->unit);             /* Reset connection */
-       phase = PHASE_TERMINATE;        /* Mark it down */
-    } else {
-        delta = (delta + HZ - 1) / HZ;
-        if (delta == 0)
-           delta = (u_long) idle_time_limit;
-        assert (idle_timer_running==0);
-        TIMEOUT (IdleTimeCheck, (caddr_t) f, delta);
-        idle_timer_running = 1;
-    }
-}
-
-/*
- * IdleTimeCheck - Timer expired on the IDLE detection for IP frames
- */
-
-static void
-IdleTimeCheck (arg)
-    caddr_t arg;
-{
-    if (idle_timer_running != 0) {
-        idle_timer_running = 0;
-        RestartIdleTimer ((fsm *) arg);
-    }
-}
-#endif
 
 /*
  * lcp_lowerup - The lower layer is up.
@@ -287,7 +218,6 @@ void
 lcp_lowerup(unit)
     int unit;
 {
-    sifdown(unit);
     ppp_set_xaccm(unit, xmit_accm[unit]);
     ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
     ppp_recv_config(unit, PPP_MRU, 0x00000000, 0, 0);
@@ -461,8 +391,8 @@ lcp_sprotrej(unit, p, len)
  * lcp_resetci - Reset our CI.
  */
 static void
-  lcp_resetci(f)
-fsm *f;
+lcp_resetci(f)
+    fsm *f;
 {
     lcp_wantoptions[f->unit].magicnumber = magic();
     lcp_wantoptions[f->unit].numloops = 0;
@@ -861,6 +791,7 @@ lcp_nakci(f, p, len)
      * Check for a looped-back line.
      */
     NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+             magic_init();
              try.magicnumber = magic();
              looped_back = 1;
              );
@@ -1482,12 +1413,11 @@ lcp_down(f)
     ChapLowerDown(f->unit);
     upap_lowerdown(f->unit);
 
-    sifdown(f->unit);
+    link_down(f->unit);
+
     ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
     ppp_recv_config(f->unit, PPP_MRU, 0x00000000, 0, 0);
     peer_mru[f->unit] = PPP_MRU;
-
-    link_down(f->unit);
 }
 
 
@@ -1658,7 +1588,8 @@ void LcpLinkFailure (f)
     fsm *f;
 {
     if (f->state == OPENED) {
-        syslog (LOG_NOTICE, "Excessive lack of response to LCP echo frames.");
+       syslog(LOG_INFO, "No response to %d echo-requests", lcp_echos_pending);
+        syslog(LOG_NOTICE, "Serial link appears to be disconnected.");
         lcp_close(f->unit);            /* Reset connection */
     }
 }
@@ -1671,43 +1602,13 @@ static void
 LcpEchoCheck (f)
     fsm *f;
 {
-    u_int32_t delta;
-#ifdef __linux__
-    struct ppp_ddinfo ddinfo;
-    u_int32_t latest;
-/*
- * Read the time since the last packet was received.
- */
-    if (ioctl (fd, PPPIOCGTIME, &ddinfo) < 0) {
-        syslog (LOG_ERR, "ioctl(PPPIOCGTIME): %m");
-        die (1);
-    }
-/*
- * Choose the most recient frame received. It may be an IP or NON-IP frame.
- */
-    latest = ddinfo.nip_rjiffies < ddinfo.ip_rjiffies ? ddinfo.nip_rjiffies
-                                                      : ddinfo.ip_rjiffies;
-/*
- * Compute the time since the last packet was received. If the timer
- *  has expired then send the echo request and reset the timer to maximum.
- */
-    delta = (lcp_echo_interval * HZ) - latest;
-    if (delta < HZ || latest < 0L) {
-        LcpSendEchoRequest (f);
-        delta = lcp_echo_interval * HZ;
-    }
-    delta /= HZ;
-
-#else /* Other implementations do not have ability to find delta */
     LcpSendEchoRequest (f);
-    delta = lcp_echo_interval;
-#endif
 
-/*
- * Start the timer for the next interval.
- */
+    /*
    * Start the timer for the next interval.
    */
     assert (lcp_echo_timer_running==0);
-    TIMEOUT (LcpEchoTimeout, (caddr_t) f, delta);
+    TIMEOUT (LcpEchoTimeout, (caddr_t) f, lcp_echo_interval);
     lcp_echo_timer_running = 1;
 }
 
@@ -1763,27 +1664,24 @@ LcpSendEchoRequest (f)
     u_int32_t lcp_magic;
     u_char pkt[4], *pktp;
 
-/*
- * Detect the failure of the peer at this point.
- */
+    /*
    * Detect the failure of the peer at this point.
    */
     if (lcp_echo_fails != 0) {
         if (lcp_echos_pending++ >= lcp_echo_fails) {
             LcpLinkFailure(f);
            lcp_echos_pending = 0;
        }
     }
-/*
- * Make and send the echo request frame.
- */
+
+    /*
+     * Make and send the echo request frame.
+     */
     if (f->state == OPENED) {
-        lcp_magic = lcp_gotoptions[f->unit].neg_magicnumber
-                   ? lcp_gotoptions[f->unit].magicnumber
-                   : 0L;
+        lcp_magic = lcp_gotoptions[f->unit].magicnumber;
        pktp = pkt;
        PUTLONG(lcp_magic, pktp);
-      
-        fsm_sdata(f, ECHOREQ,
-                 lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+        fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
     }
 }
 
@@ -1805,11 +1703,6 @@ lcp_echo_lowerup (unit)
     /* If a timeout interval is specified then start the timer */
     if (lcp_echo_interval != 0)
         LcpEchoCheck (f);
-#ifdef _linux_
-    /* If a idle time limit is given then start it */
-    if (idle_time_limit != 0)
-        RestartIdleTimer (f);
-#endif
 }
 
 /*
@@ -1826,11 +1719,4 @@ lcp_echo_lowerdown (unit)
         UNTIMEOUT (LcpEchoTimeout, (caddr_t) f);
         lcp_echo_timer_running = 0;
     }
-#ifdef _linux_  
-    /* If a idle time limit is running then stop it */
-    if (idle_timer_running != 0) {
-        UNTIMEOUT (IdleTimeCheck, (caddr_t) f);
-        idle_timer_running = 0;
-    }
-#endif
 }
index 7391b1405df8a52b7649bd3390f2f24bcd06afc1..f21924337557720825e9e9e5fcee849cc25c6dd3 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: magic.c,v 1.4 1995/04/24 05:57:01 paulus Exp $";
+static char rcsid[] = "$Id: magic.c,v 1.4.2.1 1995/06/01 07:01:29 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -39,14 +39,17 @@ extern void srand48 __P((long));
  * magic_init - Initialize the magic number generator.
  *
  * Attempts to compute a random number seed which will not repeat.
- * The current method uses the current hostid and current time, currently.
+ * The current method uses the current hostid, current process ID
+ * and current time, currently.
  */
 void
 magic_init()
 {
     long seed;
+    struct timeval t;
 
-    seed = gethostid() ^ time(NULL);
+    gettimeofday(&t, NULL);
+    seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid();
     srand48(seed);
 }
 
index 38af544d7ae0d261826d6c92381cd53054112164..51b5535b4102a8494166b779e0cd168cc1005f6a 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.23 1995/05/19 03:26:25 paulus Exp $";
+static char rcsid[] = "$Id: main.c,v 1.23.2.1 1995/06/01 07:01:31 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -78,24 +78,28 @@ int kill_link;
 int open_ccp_flag;
 
 static int initfdflags = -1;   /* Initial file descriptor flags */
+static int loop_fd = -1;       /* fd for loopback device */
 
 u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
-static u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
 
 int hungup;                    /* terminal has been hung up */
 static int n_children;         /* # child processes still running */
 
 int baud_rate;
 
+static int locked;
+
 /* prototypes */
 static void hup __P((int));
 static void term __P((int));
 static void chld __P((int));
 static void toggle_debug __P((int));
 static void open_ccp __P((int));
+static void holdoff_end __P((void *));
 
 static void get_input __P((void));
-void establish_ppp __P((void));
+void establish_ppp __P((int));
 void calltimeout __P((void));
 struct timeval *timeleft __P((struct timeval *));
 void reap_kids __P((void));
@@ -206,6 +210,14 @@ main(argc, argv)
     sys_init();
     magic_init();
 
+    /*
+     * For dial-on-demand, we need to know the remote address.
+     */
+    if (demand && ipcp_wantoptions[0].hisaddr == 0) {
+       fprintf(stderr, "Remote IP address must be specified for dial-on-demand\n");
+       exit(1);
+    }
+
     /*
      * Detach ourselves from the terminal, if required,
      * and identify who is running us.
@@ -256,13 +268,72 @@ main(argc, argv)
     signal(SIGUSR2, open_ccp);         /* Reopen CCP */
 
     /*
-     * Lock the device if we've been asked to.
+     * If we're doing dial-on-demand, set up the interface now.
      */
-    if (lockflag && !default_device)
-       if (lock(devnam) < 0)
-           die(1);
+    if (demand) {
+       /*
+        * Open the loopback channel and set it up to be the ppp interface.
+        */
+       loop_fd = open_loopback();
+       establish_ppp(loop_fd);
+
+       syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+       (void) sprintf(ifname, "ppp%d", ifunit);
+
+       /* write pid to file */
+       (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
+       if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+           fprintf(pidfile, "%d\n", pid);
+           (void) fclose(pidfile);
+       } else {
+           syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
+           pidfilename[0] = 0;
+       }
+
+       /*
+        * Configure the interface and mark it up, etc.
+        */
+       demand_conf();
+    }
+
+    for (;;) {
+
+       if (demand) {
+           /*
+            * Don't do anything until we see some activity.
+            */
+           phase = PHASE_DORMANT;
+           fd = loop_fd;
+           kill_link = 0;
+           demand_unblock();
+           for (;;) {
+               wait_loop_output(timeleft(&timo));
+               calltimeout();
+               if (kill_link) {
+                   if (!persist)
+                       die(0);
+                   kill_link = 0;
+               }
+               if (get_loop_output())
+                   break;
+               reap_kids();
+           }
+
+           /*
+            * Now we want to bring up the link.
+            */
+           demand_block();
+           syslog(LOG_INFO, "Starting link");
+       }
 
-    do {
+       /*
+        * Lock the device if we've been asked to.
+        */
+       if (lockflag && !default_device) {
+           if (lock(devnam) < 0)
+               goto fail;
+           locked = 1;
+       }
 
        /*
         * Open the serial device and set it up to be the ppp interface.
@@ -273,7 +344,7 @@ main(argc, argv)
        nonblock = (connector || !modem)? O_NONBLOCK: 0;
        if ((fd = open(devnam, nonblock | O_RDWR, 0)) < 0) {
            syslog(LOG_ERR, "Failed to open %s: %m", devnam);
-           die(1);
+           goto fail;
        }
        if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
            syslog(LOG_ERR, "Couldn't get device fd flags: %m");
@@ -303,32 +374,16 @@ main(argc, argv)
            if (device_script(connector, fd, fd) < 0) {
                syslog(LOG_ERR, "Connect script failed");
                setdtr(fd, FALSE);
-               die(1);
+               goto fail;
            }
 
-           syslog(LOG_INFO, "Connected...");
+           syslog(LOG_INFO, "Serial connection established.");
            sleep(1);           /* give it time to set up its terminal */
        }
   
        /* set line speed, flow control, etc.; clear CLOCAL if modem option */
        set_up_tty(fd, 0);
 
-       /* set up the serial device as a ppp interface */
-       establish_ppp();
-
-       syslog(LOG_INFO, "Using interface ppp%d", ifunit);
-       (void) sprintf(ifname, "ppp%d", ifunit);
-
-       /* write pid to file */
-       (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
-       if ((pidfile = fopen(pidfilename, "w")) != NULL) {
-           fprintf(pidfile, "%d\n", pid);
-           (void) fclose(pidfile);
-       } else {
-           syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
-           pidfilename[0] = 0;
-       }
-
        /*
         * Set device for non-blocking reads.
         */
@@ -337,8 +392,33 @@ main(argc, argv)
            die(1);
        }
   
+       if (!demand) {
+           /* set up the serial device as a ppp interface */
+           establish_ppp(fd);
+           
+           syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+           (void) sprintf(ifname, "ppp%d", ifunit);
+           
+           /* write pid to file */
+           (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
+           if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+               fprintf(pidfile, "%d\n", pid);
+               (void) fclose(pidfile);
+           } else {
+               syslog(LOG_ERR, "Failed to create pid file %s: %m",
+                      pidfilename);
+               pidfilename[0] = 0;
+           }
+
+       } else {
+           /*
+            * Transfer the PPP unit over to the real serial device.
+            */
+           transfer_ppp(fd);
+       }
+
        /*
-        * Block all signals, start opening the connection, and wait for
+        * Start opening the connection and wait for
         * incoming events (reply, timeout, etc.).
         */
        syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
@@ -362,33 +442,80 @@ main(argc, argv)
            reap_kids();        /* Don't leave dead kids lying around */
        }
 
+       /*
+        * If we may want to bring the link up again, transfer
+        * the ppp unit back to the loopback.  Set the
+        * real serial device back to its normal mode of operation.
+        */
+       clean_check();
+       if (demand) {
+           transfer_ppp(loop_fd);
+       } else {
+           disestablish_ppp(fd);
+       }
+
        /*
         * Run disconnector script, if requested.
         * First we need to reset non-blocking mode.
+        * XXX we may not be able to do this if the line has hung up!
         */
        if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) >= 0)
            initfdflags = -1;
-       disestablish_ppp();
-       if (disconnector) {
+       if (disconnector && !hungup) {
            set_up_tty(fd, 1);
            if (device_script(disconnector, fd, fd) < 0) {
                syslog(LOG_WARNING, "disconnect script failed");
-               die(1);
+           } else {
+               syslog(LOG_INFO, "Serial link disconnected.");
            }
-
-           syslog(LOG_INFO, "Disconnected...");
        }
 
+    fail:
        close_fd();
-       if (unlink(pidfilename) < 0 && errno != ENOENT) 
-           syslog(LOG_WARNING, "unable to delete pid file: %m");
-       pidfilename[0] = 0;
+       if (locked) {
+           unlock();
+           locked = 0;
+       }
+
+       if (!demand) {
+           if (unlink(pidfilename) < 0 && errno != ENOENT) 
+               syslog(LOG_WARNING, "unable to delete pid file: %m");
+           pidfilename[0] = 0;
+       }
+
+       if (!persist)
+           break;
 
-    } while (persist);
+       demand_discard();
+       if (holdoff > 0) {
+           phase = PHASE_HOLDOFF;
+           TIMEOUT(holdoff_end, NULL, holdoff);
+           do {
+               wait_time(timeleft(&timo));
+               calltimeout();
+               if (kill_link) {
+                   if (!persist)
+                       die(0);
+                   kill_link = 0;
+                   phase = PHASE_DORMANT; /* allow signal to end holdoff */
+               }
+               reap_kids();
+           } while (phase == PHASE_HOLDOFF);
+       }
+    }
 
     die(0);
 }
 
+/*
+ * holdoff_end - called via a timeout when the holdoff period ends.
+ */
+static void
+holdoff_end(arg)
+    void *arg;
+{
+    phase = PHASE_DORMANT;
+}
 
 /*
  * get_input - called when incoming data is available.
@@ -518,8 +645,11 @@ cleanup(status, arg)
        syslog(LOG_WARNING, "unable to delete pid file: %m");
     pidfilename[0] = 0;
 
-    if (lockflag && !default_device)
+    if (locked)
        unlock();
+
+    if (demand)
+       demand_reset();
 }
 
 /*
@@ -536,7 +666,7 @@ close_fd()
        syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
     initfdflags = -1;
 
-    disestablish_ppp();
+    disestablish_ppp(fd);
 
     restore_tty();
 
@@ -760,6 +890,7 @@ device_script(program, in, out)
 {
     int pid;
     int status;
+    int errfd;
 
     pid = fork();
 
@@ -769,10 +900,14 @@ device_script(program, in, out)
     }
 
     if (pid == 0) {
-       setuid(getuid());
-       setgid(getgid());
+       sys_close();
        dup2(in, 0);
        dup2(out, 1);
+       errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
+       if (errfd >= 0)
+           dup2(errfd, 2);
+       setuid(getuid());
+       setgid(getgid());
        execl("/bin/sh", "sh", "-c", program, (char *)0);
        syslog(LOG_ERR, "could not exec /bin/sh: %m");
        _exit(99);
@@ -821,11 +956,11 @@ run_program(prog, args, must_exist)
        setgid(getegid());
 
        /* Ensure that nothing of our device environment is inherited. */
+       sys_close();
        close (0);
        close (1);
        close (2);
        close (fd);  /* tty interface to the ppp device */
-       /* XXX should call sysdep cleanup procedure here */
 
         /* Don't pass handles to the PPP device, even by accident. */
        new_fd = open (_PATH_DEVNULL, O_RDWR);
index 3d5e020338d88538d11e94f6ebd06749a7cd0ffc..d97f60a5d47a1ffd4f4242b2fc1ec1f726bb570b 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: options.c,v 1.19 1995/04/27 00:20:16 paulus Exp $";
+static char rcsid[] = "$Id: options.c,v 1.19.2.1 1995/06/01 07:01:33 paulus Exp $";
 #endif
 
 #include <stdio.h>
@@ -86,13 +86,11 @@ char        our_name[MAXNAMELEN];   /* Our name for authentication purposes */
 char   remote_name[MAXNAMELEN]; /* Peer's name for authentication */
 int    usehostname = 0;        /* Use hostname for our_name */
 int    disable_defaultip = 0;  /* Don't use hostname for default IP adrs */
+int    demand = 0;             /* do dial-on-demand */
 char   *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
 int    cryptpap;               /* Passwords in pap-secrets are encrypted */
-
-#ifdef _linux_
-int idle_time_limit = 0;
-static int setidle __P((char **));
-#endif
+int    idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
+int    holdoff = 30;           /* # seconds to pause before reconnecting */
 
 /*
  * Prototypes
@@ -138,7 +136,9 @@ static int setremote __P((char **));
 static int setauth __P((void));
 static int readfile __P((char **));
 static int setdefaultroute __P((void));
+static int setnodefaultroute __P((void));
 static int setproxyarp __P((void));
+static int setnoproxyarp __P((void));
 static int setpersist __P((void));
 static int setdologin __P((void));
 static int setusehostname __P((void));
@@ -162,8 +162,11 @@ static int setlcpechointv __P((char **));
 static int setlcpechofails __P((char **));
 static int setbsdcomp __P((char **));
 static int setnobsdcomp __P((void));
+static int setdemand __P((void));
 static int setipparam __P((char **));
 static int setpapcrypt __P((void));
+static int setidle __P((char **));
+static int setholdoff __P((char **));
 
 static int number_option __P((char *, long *, int));
 static int readable __P((int fd));
@@ -222,8 +225,11 @@ static struct cmd {
     {"auth", 0, setauth},      /* Require authentication from peer */
     {"file", 1, readfile},     /* Take options from a file */
     {"defaultroute", 0, setdefaultroute}, /* Add default route */
+    {"-defaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
     {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
+    {"-proxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
     {"persist", 0, setpersist},        /* Keep on reopening connection after close */
+    {"demand", 0, setdemand},  /* Dial on demand */
     {"login", 0, setdologin},  /* Use system password database for UPAP */
     {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
     {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
@@ -247,9 +253,8 @@ static struct cmd {
     {"-bsdcomp", 0, setnobsdcomp},     /* don't allow BSD-Compress */
     {"ipparam", 1, setipparam},                /* set ip script parameter */
     {"papcrypt", 0, setpapcrypt},      /* PAP passwords encrypted */
-#ifdef _linux_
-    {"idle-disconnect", 1, setidle}, /* seconds for disconnect of idle IP */
-#endif
+    {"idle", 1, setidle},              /* idle time limit (seconds) */
+    {"holdoff", 1, setholdoff},                /* set holdoff time (seconds) */
     {NULL, 0, NULL}
 };
 
@@ -1278,6 +1283,13 @@ setnodetach()
     return (1);
 }
 
+static int
+setdemand()
+{
+    demand = 1;
+    return 1;
+}
+
 static int
 setmodem()
 {
@@ -1345,17 +1357,41 @@ setauth()
 static int
 setdefaultroute()
 {
+    if (!ipcp_allowoptions[0].default_route) {
+       fprintf(stderr, "%s: defaultroute option is disabled\n", progname);
+       return 0;
+    }
     ipcp_wantoptions[0].default_route = 1;
     return 1;
 }
 
+static int
+setnodefaultroute()
+{
+    ipcp_allowoptions[0].default_route = 0;
+    ipcp_wantoptions[0].default_route = 0;
+    return 1;
+}
+
 static int
 setproxyarp()
 {
+    if (!ipcp_allowoptions[0].proxy_arp) {
+       fprintf(stderr, "%s: proxyarp option is disabled\n", progname);
+       return 0;
+    }
     ipcp_wantoptions[0].proxy_arp = 1;
     return 1;
 }
 
+static int
+setnoproxyarp()
+{
+    ipcp_wantoptions[0].proxy_arp = 0;
+    ipcp_allowoptions[0].proxy_arp = 0;
+    return 1;
+}
+
 static int
 setpersist()
 {
@@ -1545,10 +1581,16 @@ setpapcrypt()
     return 1;
 }
 
-#ifdef _linux_
-static int setidle (argv)
+static int
+setidle(argv)
     char **argv;
 {
     return int_option(*argv, &idle_time_limit);
 }
-#endif
+
+static int
+setholdoff(argv)
+    char **argv;
+{
+    return int_option(*argv, &holdoff);
+}
index 629e48adf4c6f8f224b154b59dc82b2eb1c3c59d..3dac0ce2b737402021527f0145cac6ac1f1d3d4b 100644 (file)
@@ -1,6 +1,6 @@
-/* $Id: patchlevel.h,v 1.13 1994/10/24 04:53:17 paulus Exp $ */
+/* $Id: patchlevel.h,v 1.13.2.1 1995/06/01 07:01:35 paulus Exp $ */
 #define        PATCHLEVEL      0
 
-#define VERSION                "2.2"
-#define IMPLEMENTATION "alpha3"
-#define DATE           "24 Oct 94"
+#define VERSION                "2.3"
+#define IMPLEMENTATION "alpha"
+#define DATE           "22 Dec 94"
index 7baf95a43df8bc2ed2fffc40833577c6d179a286..51ca73d9e7604ae20764abc62fe2cf793a180bc2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * define path names
  *
- * $Id: pathnames.h,v 1.5 1994/09/01 00:32:56 paulus Exp $
+ * $Id: pathnames.h,v 1.5.2.1 1995/06/01 07:01:36 paulus Exp $
  */
 
 #ifdef HAVE_PATHS_H
@@ -18,4 +18,5 @@
 #define _PATH_IPUP     "/etc/ppp/ip-up"
 #define _PATH_IPDOWN   "/etc/ppp/ip-down"
 #define _PATH_TTYOPT   "/etc/ppp/options."
+#define _PATH_CONNERRS "/etc/ppp/connect-errors"
 #define _PATH_USEROPT  ".ppprc"
index 66b0107efca7dc9fc2751a4b820fe16a7da4b530..bbf04fde4b7898a1f63f281d056bb77dbd77bbf2 100644 (file)
@@ -16,7 +16,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * $Id: pppd.h,v 1.8 1995/04/26 06:46:31 paulus Exp $
+ * $Id: pppd.h,v 1.8.2.1 1995/06/01 07:01:37 paulus Exp $
  */
 
 /*
@@ -83,17 +83,22 @@ extern char our_name[];     /* Our name for authentication purposes */
 extern char    remote_name[];  /* Peer's name for authentication */
 extern int     usehostname;    /* Use hostname for our_name */
 extern int     disable_defaultip; /* Don't use hostname for default IP adrs */
+extern int     demand;         /* Do dial-on-demand */
 extern char    *ipparam;       /* Extra parameter for ip up/down scripts */
 extern int     cryptpap;       /* Others' PAP passwords are encrypted */
+extern int     idle_time_limit;/* Shut down link if idle for this long */
+extern int     holdoff;        /* Dead time before restarting */
 
 /*
  * Values for phase.
  */
 #define PHASE_DEAD             0
-#define PHASE_ESTABLISH                1
-#define PHASE_AUTHENTICATE     2
-#define PHASE_NETWORK          3
-#define PHASE_TERMINATE                4
+#define PHASE_DORMANT          1
+#define PHASE_ESTABLISH                2
+#define PHASE_AUTHENTICATE     3
+#define PHASE_NETWORK          4
+#define PHASE_TERMINATE                5
+#define PHASE_HOLDOFF          6
 
 /*
  * Prototypes.
@@ -113,6 +118,9 @@ int  get_secret __P((int, char *, char *, char *, int *, int));
                                /* get "secret" for chap */
 u_int32_t GetMask __P((u_int32_t)); /* get netmask for address */
 void die __P((int));
+void np_up __P((int, int));
+void np_down __P((int, int));
+void np_finished __P((int, int));
 
 /*
  * Inline versions of get/put char/short/long.
@@ -192,9 +200,9 @@ void die __P((int));
 #endif
 
 #ifndef LOG_PPP                        /* we use LOG_LOCAL2 for syslog by default */
-#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
   || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
-  || defined(DEBUGCHAP) 
+  || defined(DEBUGCHAP) || defined(DEBUG)
 #define LOG_PPP LOG_LOCAL2
 #else
 #define LOG_PPP LOG_DAEMON
@@ -207,6 +215,12 @@ void die __P((int));
 #define MAINDEBUG(x)
 #endif
 
+#ifdef DEBUGSYS
+#define SYSDEBUG(x)    if (debug) syslog x
+#else
+#define SYSDEBUG(x)
+#endif
+
 #ifdef DEBUGFSM
 #define FSMDEBUG(x)    if (debug) syslog x
 #else
index 1a7c83a6827a505026ee8b591f13c57ecf872099..c6deb26350bcf907fcc3db8c44241d41c233d2e2 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-bsd.c,v 1.19 1995/05/19 03:27:03 paulus Exp $";
+static char rcsid[] = "$Id: sys-bsd.c,v 1.19.2.1 1995/06/01 07:01:39 paulus Exp $";
 #endif
 
 /*
@@ -53,13 +53,18 @@ static char rcsid[] = "$Id: sys-bsd.c,v 1.19 1995/05/19 03:27:03 paulus Exp $";
 #include "pppd.h"
 
 static int initdisc = -1;      /* Initial TTY discipline */
+static int ppp_fd = -1;                /* fd which is set to PPP discipline */
 static int rtm_seq;
 
-static int     restore_term;   /* 1 => we've munged the terminal */
+static int restore_term;       /* 1 => we've munged the terminal */
 static struct termios inittermios; /* Initial TTY termios */
 
 static char *lock_file;                /* name of lock file created */
 
+static int loop_slave = -1;
+static int loop_master;
+static char loop_name[20];
+
 int sockfd;                    /* socket for doing interface ioctls */
 
 /*
@@ -80,6 +85,17 @@ sys_init()
     }
 }
 
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+    close(sockfd);
+    closelog();
+}
+
+
 /*
  * note_debug_level - note a change in the debug level.
  */
@@ -105,7 +121,7 @@ ppp_available()
     struct ifreq ifr;
 
     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-       return 1;               /* can't tell - maybe we're not root */
+       return 1;               /* can't tell */
 
     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
@@ -115,10 +131,11 @@ ppp_available()
 }
 
 /*
- * establish_ppp - Turn the serial port into a ppp interface.
+ * establish_ppp - Turn the serial port (or loopback) into a ppp interface.
  */
 void
-establish_ppp()
+establish_ppp(fd)
+    int fd;
 {
     int pppdisc = PPPDISC;
     int x;
@@ -139,6 +156,7 @@ establish_ppp()
        syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
        die(1);
     }
+    ppp_fd = fd;
 
     /*
      * Enable debug in the driver if requested.
@@ -155,47 +173,111 @@ establish_ppp()
 }
 
 
+/*
+ * transfer_ppp - make the device on fd `fd' take over the PPP interface
+ * unit that we are using.
+ */
+void
+transfer_ppp(fd)
+    int fd;
+{
+    int x, prevdisc;
+
+    if (fd == ppp_fd)
+       return;                 /* we can't get here */
+
+    /*
+     * Prime the old ppp device to relinquish the unit.
+     */
+    if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) {
+       syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
+       die(1);
+    }
+
+    /*
+     * Save the old line discipline of fd, and set it to PPP.
+     */
+    if (ioctl(fd, TIOCGETD, &prevdisc) < 0) {
+       syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
+       die(1);
+    }
+    x = PPPDISC;
+    if (ioctl(fd, TIOCSETD, &x) < 0) {
+       syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+       die(1);
+    }
+
+    /*
+     * Set the old ppp device back to its previous discipline.
+     */
+    ioctl(ppp_fd, TIOCSETD, &initdisc);
+    initdisc = prevdisc;
+
+    /*
+     * Check that we got the same unit again.
+     */
+    if (ioctl(fd, PPPIOCGUNIT, &x) < 0) {      
+       syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+       die(1);
+    }
+    if (x != ifunit) {
+       syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
+              ifunit, x);
+       die(1);
+    }
+
+    ppp_fd = fd;
+}
+
+
 /*
  * disestablish_ppp - Restore the serial port to normal operation.
  * This shouldn't call die() because it's called from die().
  */
 void
-disestablish_ppp()
+disestablish_ppp(fd)
+    int fd;
+{
+    if (fd == ppp_fd && fd >= 0 && initdisc >= 0) {
+       if (ioctl(fd, TIOCSETD, &initdisc) < 0)
+           syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+       initdisc = -1;
+       ppp_fd = -1;
+    }
+}
+
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
 {
     int x;
     char *s;
 
-    if (initdisc >= 0) {
-       /*
-        * Check whether the link seems not to be 8-bit clean.
-        */
-       if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
-           s = NULL;
-           switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
-           case SC_RCV_B7_0:
-               s = "bit 7 set to 1";
-               break;
-           case SC_RCV_B7_1:
-               s = "bit 7 set to 0";
-               break;
-           case SC_RCV_EVNP:
-               s = "odd parity";
-               break;
-           case SC_RCV_ODDP:
-               s = "even parity";
-               break;
-           }
-           if (s != NULL) {
-               syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
-               syslog(LOG_WARNING, "All received characters had %s", s);
-           }
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+       s = NULL;
+       switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+       case SC_RCV_B7_0:
+           s = "bit 7 set to 1";
+           break;
+       case SC_RCV_B7_1:
+           s = "bit 7 set to 0";
+           break;
+       case SC_RCV_EVNP:
+           s = "odd parity";
+           break;
+       case SC_RCV_ODDP:
+           s = "even parity";
+           break;
+       }
+       if (s != NULL) {
+           syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
+           syslog(LOG_WARNING, "All received characters had %s", s);
        }
-       if (ioctl(fd, TIOCSETD, &initdisc) < 0)
-           syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
     }
 }
 
-
 /*
  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
  * at the requested speed, etc.  If `local' is true, set CLOCAL
@@ -298,6 +380,40 @@ int fd, on;
 }
 
 
+/*
+ * open_loopback - open the device we use for getting packets
+ * in demand mode.  Here we use a pty.
+ */
+int
+open_loopback()
+{
+    int flags;
+    struct termios tios;
+
+    if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0) {
+       syslog(LOG_ERR, "No free pty for loopback");
+       die(1);
+    }
+    SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+    if (tcgetattr(loop_slave, &tios) == 0) {
+       tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+       tios.c_cflag |= CS8 | CREAD;
+       tios.c_iflag = IGNPAR;
+       tios.c_oflag = 0;
+       tios.c_lflag = 0;
+       if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
+           syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
+    }
+    if ((flags = fcntl(loop_slave, F_GETFL)) != -1) 
+       if (fcntl(loop_slave, F_SETFL, flags | O_NONBLOCK) == -1)
+           syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
+    if ((flags = fcntl(loop_master, F_GETFL)) != -1) 
+       if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
+           syslog(LOG_WARNING, "couldn't set loopback(m) to nonblock: %m");
+    return loop_slave;
+}
+
+
 /*
  * output - Output PPP packet.
  */
@@ -308,7 +424,7 @@ output(unit, p, len)
     int len;
 {
     if (unit != 0)
-       MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+       SYSDEBUG((LOG_WARNING, "output: unit != 0!"));
     if (debug)
        log_packet(p, len, "sent ");
 
@@ -340,6 +456,44 @@ wait_input(timo)
 }
 
 
+/*
+ * wait_loop_output - wait until there is data available on the,
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+wait_loop_output(timo)
+    struct timeval *timo;
+{
+    fd_set ready;
+    int n;
+
+    FD_ZERO(&ready);
+    FD_SET(loop_master, &ready);
+    n = select(loop_master + 1, &ready, NULL, &ready, timo);
+    if (n < 0 && errno != EINTR) {
+       syslog(LOG_ERR, "select: %m");
+       die(1);
+    }
+}
+
+
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+wait_time(timo)
+    struct timeval *timo;
+{
+    int n;
+
+    n = select(0, NULL, NULL, NULL, timo);
+    if (n < 0 && errno != EINTR) {
+       syslog(LOG_ERR, "select: %m");
+       die(1);
+    }
+}
+
+
 /*
  * read_packet - get a PPP packet from the serial device.
  */
@@ -359,6 +513,29 @@ read_packet(buf)
 }
 
 
+/*
+ * read_loop_output - get characters from the "bottom" of the loopback.
+ */
+int
+read_loop_output(buf, maxlen)
+    u_char *buf;
+    int maxlen;
+{
+    int len;
+
+    if ((len = read(loop_master, buf, maxlen)) < 0) {
+       if (errno == EWOULDBLOCK)
+           return 0;
+       syslog(LOG_ERR, "read from loopback: %m");
+       die(1);
+    } else if (len == 0) {
+       syslog(LOG_ERR, "eof on loopback");
+       die(1);
+    }
+    return len;
+}
+
+
 /*
  * ppp_send_config - configure the transmit characteristics of
  * the ppp interface.
@@ -376,23 +553,23 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
     ifr.ifr_mtu = mtu;
     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
        syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
-       quit();
+       die(1);
     }
 
     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
        syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
-       quit();
+       die(1);
     }
 
     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
        syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
-       quit();
+       die(1);
     }
     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
        syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
-       quit();
+       die(1);
     }
 }
 
@@ -424,20 +601,20 @@ ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
 
     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
        syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
-       quit();
+       die(1);
     }
     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
        syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
-       quit();
+       die(1);
     }
     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
        syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
-       quit();
+       die(1);
     }
     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
        syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
-       quit();
+       die(1);
     }
 }
 
@@ -494,6 +671,18 @@ ccp_fatal_error(unit)
     return x & SC_DC_FERROR;
 }
 
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+    int u;
+    struct ppp_idle *ip;
+{
+    return ioctl(fd, PPPIOCGIDLE, ip) >= 0;
+}
+
+
 /*
  * sifvjcomp - config tcp header compression
  */
@@ -523,16 +712,11 @@ sifvjcomp(u, vjcomp, cidcomp, maxcid)
 /*
  * sifup - Config the interface up and enable IP packets to pass.
  */
-#ifndef SC_ENABLE_IP
-#define SC_ENABLE_IP   0x100   /* compat for old versions of kernel code */
-#endif
-
 int
 sifup(u)
     int u;
 {
     struct ifreq ifr;
-    u_int x;
     struct npioctl npi;
 
     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
@@ -548,20 +732,28 @@ sifup(u)
     npi.protocol = PPP_IP;
     npi.mode = NPMODE_PASS;
     if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
-       if (errno != ENOTTY) {
-           syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
-           return 0;
-       }
-       /* for backwards compatibility */
-       if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
-           syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
-           return 0;
-       }
-       x |= SC_ENABLE_IP;
-       if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
-           syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
-           return 0;
-       }
+       syslog(LOG_ERR, "ioctl(set IP mode to PASS): %m");
+       return 0;
+    }
+    return 1;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+    int u;
+    int proto;
+    enum NPmode mode;
+{
+    struct npioctl npi;
+
+    npi.protocol = proto;
+    npi.mode = mode;
+    if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
+       syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
+       return 0;
     }
     return 1;
 }
@@ -574,31 +766,14 @@ sifdown(u)
     int u;
 {
     struct ifreq ifr;
-    u_int x;
     int rv;
     struct npioctl npi;
 
     rv = 1;
     npi.protocol = PPP_IP;
     npi.mode = NPMODE_ERROR;
-    if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
-       if (errno != ENOTTY) {
-           syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
-           rv = 0;
-       } else {
-           /* backwards compatibility */
-           if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
-               syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
-               rv = 0;
-           } else {
-               x &= ~SC_ENABLE_IP;
-               if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
-                   syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
-                   rv = 0;
-               }
-           }
-       }
-    }
+    ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi);
+    /* ignore errors, because ppp_fd might have been closed by now. */
 
     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
index e5831330cac83bc9922990ddd2aa188be84d4d95..ae3c1018cc3fc94b70b5eafe117071000f7bc895 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-str.c,v 1.20 1995/05/01 00:26:22 paulus Exp $";
+static char rcsid[] = "$Id: sys-str.c,v 1.20.2.1 1995/06/01 07:01:42 paulus Exp $";
 #endif
 
 /*
@@ -65,9 +65,15 @@ static int   str_module_count = 0;
 static int     pushed_ppp;
 static int     closed_stdio;
 
+static int     ppp_fd = -1;    /* fd currently attached to ppp unit */
+
 static int     restore_term;   /* 1 => we've munged the terminal */
 static struct termios inittermios; /* Initial TTY termios */
 
+static int loop_slave = -1;
+static int loop_master;
+static char loop_name[20];
+
 int sockfd;                    /* socket for doing interface ioctls */
 static char *lock_file;                /* lock file created for serial port */
 
@@ -146,19 +152,22 @@ ppp_available()
 
 
 /*
- * establish_ppp - Turn the serial port into a ppp interface.
+ * establish_ppp - Turn the serial port (or loopback) into a ppp interface.
  */
 void
 establish_ppp()
 {
-    /* go through and save the name of all the modules, then pop em */
-    for (;;) { 
-       if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
-           ioctl(fd, I_POP, 0) < 0)
-           break;
-       MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
-                  str_modules[str_module_count].modname));
-       str_module_count++;
+    if (fd != loop_slave) {
+       str_module_count = 0;
+       /* go through and save the name of all the modules, then pop em */
+       for (;;) { 
+           if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
+               ioctl(fd, I_POP, 0) < 0)
+               break;
+           MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
+                      str_modules[str_module_count].modname));
+           str_module_count++;
+       }
     }
 
     /* now push the async/fcs module */
@@ -167,7 +176,7 @@ establish_ppp()
        die(1);
     }
     /* push the compress module */
-    if (ioctl(fd, I_PUSH, "pppcomp") < 0) {
+    if (fd != loop_slave && ioctl(fd, I_PUSH, "pppcomp") < 0) {
        syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
     }
     /* finally, push the ppp_if module that actually handles the */
@@ -177,6 +186,7 @@ establish_ppp()
        die(1);
     }
     pushed_ppp = 1;
+
     /* read mode, message non-discard mode */
     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
        syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
@@ -196,6 +206,8 @@ establish_ppp()
        syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
     }
 
+    ppp_fd = fd;
+
     /* close stdin, stdout, stderr if they might refer to the device */
     if (default_device && !closed_stdio) {
        int i;
@@ -207,17 +219,94 @@ establish_ppp()
     }
 }
 
+/*
+ * transfer_ppp - make the device on fd `fd' take over the PPP interface
+ * unit that we are using.
+ */
+void
+transfer_ppp(fd)
+    int fd;
+{
+    if (fd == ppp_fd)
+       return;                 /* we can't get here */
+
+    if (fd != loop_slave) {
+       /* go through and save the name of all the modules, then pop em */
+       str_module_count = 0;
+       for (;;) { 
+           if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
+               ioctl(fd, I_POP, 0) < 0)
+               break;
+           MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
+                      str_modules[str_module_count].modname));
+           str_module_count++;
+       }
+    }
+
+    /* now push the async/fcs module */
+    if (ioctl(fd, I_PUSH, "pppasync") < 0) {
+       syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
+       die(1);
+    }
+    /* push the compress module */
+    if (ioctl(fd, I_PUSH, "pppcomp") < 0) {
+       syslog(LOG_WARNING, "ioctl(I_PUSH, ppp_comp): %m");
+    }
+    /* finally, push the ppp_if module that actually handles the */
+    /* network interface */ 
+    if (ioctl(fd, I_PUSH, "pppif") < 0) {
+       syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
+       die(1);
+    }
+    pushed_ppp = 1;
+
+    /* read mode, message non-discard mode */
+    if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
+       syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
+       die(1);
+    }
+    /*
+     * Connect to the interface unit we want.
+     * (ppp_if handles this ioctl)
+     */
+    if (ioctl(fd, SIOCSETU, &ifunit) < 0) {
+       syslog(LOG_ERR, "ioctl(SIOCSETU): %m");
+       die(1);
+    }
+
+    /* Set debug flags in driver */
+    if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
+       syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
+    }
+
+    /*
+     * Pop the modules off the old ppp stream, and restore
+     * the modules that were there, if this is the real serial port.
+     */
+    while (ioctl(ppp_fd, I_POP, 0) == 0)       /* pop any we pushed */
+       ;
+    if (fd == loop_slave) {
+       for (; str_module_count > 0; str_module_count--) {
+           if (ioctl(ppp_fd, I_PUSH, str_modules[str_module_count-1].modname)) {
+               if (errno != ENXIO)
+                   syslog(LOG_WARNING,
+                          "Couldn't restore STREAMS module %s: %m",
+                          str_modules[str_module_count-1].modname);
+           }
+       }
+    }
+    ppp_fd = fd;
+}
+
 /*
  * disestablish_ppp - Restore the serial port to normal operation.
  * It attempts to reconstruct the stream with the previously popped
  * modules.  This shouldn't call die() because it's called from die().
  */
 void
-disestablish_ppp()
+disestablish_ppp(fd)
+    int fd;
 {
-    int flags;
-    char *s;
-
     if (hungup) {
        /* we can't push or pop modules after the stream has hung up */
        str_module_count = 0;
@@ -225,49 +314,55 @@ disestablish_ppp()
        return;
     }
 
-    if (pushed_ppp) {
-       /*
-        * Check whether the link seems not to be 8-bit clean.
-        */
-       if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
-           s = NULL;
-           switch (~flags & PAI_FLAGS_HIBITS) {
-           case PAI_FLAGS_B7_0:
-               s = "bit 7 set to 1";
-               break;
-           case PAI_FLAGS_B7_1:
-               s = "bit 7 set to 0";
-               break;
-           case PAI_FLAGS_PAR_EVEN:
-               s = "odd parity";
-               break;
-           case PAI_FLAGS_PAR_ODD:
-               s = "even parity";
-               break;
-           }
-           if (s != NULL) {
-               syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
-               syslog(LOG_WARNING, "All received characters had %s", s);
-           }
-       }
-
+    if (fd == ppp_fd && fd >= 0 && pushed_ppp) {
        while (ioctl(fd, I_POP, 0) == 0)        /* pop any we pushed */
            ;
+       pushed_ppp = 0;
   
        for (; str_module_count > 0; str_module_count--) {
            if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
                if (errno != ENXIO)
-                   syslog(LOG_WARNING, "Couldn't restore module %s: %m",
+                   syslog(LOG_WARNING,
+                          "Couldn't restore STREAMS module %s: %m",
                           str_modules[str_module_count-1].modname);
-           } else {
-               MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
-                          str_modules[str_module_count-1].modname));
            }
        }
+       ppp_fd = -1;
        pushed_ppp = 0;
     }
 }
 
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
+{
+    int flags;
+    char *s;
+
+    if (ioctl(ppp_fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
+       s = NULL;
+       switch (~flags & PAI_FLAGS_HIBITS) {
+       case PAI_FLAGS_B7_0:
+           s = "bit 7 set to 1";
+           break;
+       case PAI_FLAGS_B7_1:
+           s = "bit 7 set to 0";
+           break;
+       case PAI_FLAGS_PAR_EVEN:
+           s = "odd parity";
+           break;
+       case PAI_FLAGS_PAR_ODD:
+           s = "even parity";
+           break;
+       }
+       if (s != NULL) {
+           syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
+           syslog(LOG_WARNING, "All received characters had %s", s);
+       }
+    }
+}
 
 /*
  * List of valid speeds.
@@ -481,6 +576,65 @@ int fd, on;
 }
 
 
+/*
+ * open_loopback - open the device we use for getting packets
+ * in demand mode.  Here we use a pty.
+ */
+int
+open_loopback()
+{
+    int flags;
+    struct termios tios;
+    static char c1[] = "pqrstuvwxyzPQRST";
+    static char c2[] = "0123456789abcdef";
+    char *p1, *p2;
+
+    p1 = c1;
+    p2 = c2;
+    strcpy(loop_name, "/dev/ptyxx");
+    loop_slave = -1;
+    for (;;) {
+       loop_name[8] = *p1;
+       loop_name[9] = *p2;
+       if ((loop_master = open(loop_name, O_RDWR, 0)) >= 0) {
+           loop_name[5] = 't';
+           chown(loop_name, geteuid(), getegid());
+           chmod(loop_name, S_IRUSR|S_IWUSR);
+           if ((loop_slave = open(loop_name, O_RDWR, 0)) >= 0)
+               break;
+           close(loop_master);
+           loop_name[5] = 'p';
+       } else if (errno == ENOENT)
+           break;
+       if (*++p2 == 0) {
+           p2 = c2;
+           if (*++p1 == 0)
+               break;
+       }
+    }
+    if (loop_slave < 0) {
+       syslog(LOG_ERR, "No free pty for loopback");
+       die(1);
+    }
+    SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+    if (tcgetattr(loop_slave, &tios) == 0) {
+       tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+       tios.c_cflag |= CS8 | CREAD;
+       tios.c_iflag = IGNPAR;
+       tios.c_oflag = 0;
+       tios.c_lflag = 0;
+       if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
+           syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
+    }
+    if ((flags = fcntl(loop_slave, F_GETFL)) != -1) 
+       if (fcntl(loop_slave, F_SETFL, flags | O_NONBLOCK) == -1)
+           syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
+    if ((flags = fcntl(loop_master, F_GETFL)) != -1) 
+       if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
+           syslog(LOG_WARNING, "couldn't set loopback(m) to nonblock: %m");
+    return loop_slave;
+}
+
 /*
  * output - Output PPP packet.
  */
@@ -525,6 +679,26 @@ wait_input(timo)
     }
 }
 
+/*
+ * wait_loop_output - wait until there is data available on the,
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+wait_loop_output(timo)
+    struct timeval *timo;
+{
+    fd_set ready;
+    int n;
+
+    FD_ZERO(&ready);
+    FD_SET(loop_master, &ready);
+    n = select(loop_master + 1, &ready, NULL, &ready, timo);
+    if (n < 0 && errno != EINTR) {
+       syslog(LOG_ERR, "select: %m");
+       die(1);
+    }
+}
+
 /*
  * read_packet - get a PPP packet from the serial device.
  */
@@ -564,6 +738,29 @@ read_packet(buf)
 }
 
 
+/*
+ * read_loop_output - get characters from the "bottom" of the loopback.
+ */
+int
+read_loop_output(buf, maxlen)
+    u_char *buf;
+    int maxlen;
+{
+    int len;
+
+    if ((len = read(loop_master, buf, maxlen)) < 0) {
+       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+           return 0;
+       syslog(LOG_ERR, "read from loopback: %m");
+       die(1);
+    } else if (len == 0) {
+       syslog(LOG_ERR, "eof on loopback");
+       die(1);
+    }
+    return len;
+}
+
+
 /*
  * ppp_send_config - configure the transmit characteristics of
  * the ppp interface.
@@ -581,24 +778,24 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
     ifr.ifr_mtu = mtu;
     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
        syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
-       quit();
+       die(1);
     }
 
     if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
        syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
-       quit();
+       die(1);
     }
 
     c = (pcomp? 1: 0);
     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
        syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
-       quit();
+       die(1);
     }
 
     c = (accomp? 1: 0);
     if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
        syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
-       quit();
+       die(1);
     }
 }
 
@@ -715,7 +912,7 @@ sifvjcomp(u, vjcomp, cidcomp, maxcid)
 }
 
 /*
- * sifup - Config the interface up and enable IP packets to pass.
+ * sifup - Config the interface up.
  */
 int
 sifup(u)
@@ -737,10 +934,8 @@ sifup(u)
     npi.protocol = PPP_IP;
     npi.mode = NPMODE_PASS;
     if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
-       if (errno != ENOTTY) {
-           syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
-           return 0;
-       }
+       syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
+       return 0;
     }
     return 1;
 }
@@ -760,10 +955,8 @@ sifdown(u)
     npi.protocol = PPP_IP;
     npi.mode = NPMODE_ERROR;
     if (ioctl(fd, SIOCSETNPMODE, (caddr_t) &npi) < 0) {
-       if (errno != ENOTTY) {
-           syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
-           rv = 0;
-       }
+       syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
+       rv = 0;
     }
 
     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
@@ -780,6 +973,26 @@ sifdown(u)
     return rv;
 }
 
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+    int u;
+    int proto;
+    enum NPmode mode;
+{
+    struct npioctl npi;
+
+    npi.protocol = proto;
+    npi.mode = mode;
+    if (ioctl(fd, SIOCSETNPMODE, &npi) < 0) {
+       syslog(LOG_ERR, "ioctl(SIOCSETNPMODE): %m");
+       return 0;
+    }
+    return 1;
+}
+
 /*
  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
  */