#
# 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
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)
depend:
cpp -M $(CFLAGS) $(PPPDSRCS) >.depend
# makedepend $(CFLAGS) $(PPPDSRCS)
-
*/
#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>
/* 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
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));
int unit;
{
phase = PHASE_NETWORK;
+ num_np_open = 1;
ipcp_open(unit);
ccp_open(unit);
}
}
+/*
+ * 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.
*/
*/
#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>
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;
*/
#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
/*
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)
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 */
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 */
ao->neg_vj = 1;
ao->maxslotindex = MAX_STATES - 1;
ao->cflag = 1;
+ ao->default_route = 1;
+ ao->proxy_arp = 1;
}
}
+/*
+ * 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.
*
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");
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:
{
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.
*/
#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
/*
#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 */
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)
*/
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.
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);
* 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;
* Check for a looped-back line.
*/
NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ magic_init();
try.magicnumber = magic();
looped_back = 1;
);
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);
}
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 */
}
}
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;
}
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);
}
}
/* 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
}
/*
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
}
*/
#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>
* 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);
}
*/
#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>
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));
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.
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.
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");
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.
*/
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);
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.
syslog(LOG_WARNING, "unable to delete pid file: %m");
pidfilename[0] = 0;
- if (lockflag && !default_device)
+ if (locked)
unlock();
+
+ if (demand)
+ demand_reset();
}
/*
syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
initfdflags = -1;
- disestablish_ppp();
+ disestablish_ppp(fd);
restore_tty();
{
int pid;
int status;
+ int errfd;
pid = fork();
}
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);
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);
*/
#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>
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
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));
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));
{"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 */
{"-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}
};
return (1);
}
+static int
+setdemand()
+{
+ demand = 1;
+ return 1;
+}
+
static int
setmodem()
{
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()
{
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);
+}
-/* $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"
/*
* 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
#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"
* 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 $
*/
/*
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.
/* 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.
#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
#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
*/
#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
/*
#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 */
/*
}
}
+/*
+ * 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.
*/
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;
}
/*
- * 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;
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
die(1);
}
+ ppp_fd = fd;
/*
* Enable debug in the driver if requested.
}
+/*
+ * 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
}
+/*
+ * 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.
*/
int len;
{
if (unit != 0)
- MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+ SYSDEBUG((LOG_WARNING, "output: unit != 0!"));
if (debug)
log_packet(p, len, "sent ");
}
+/*
+ * 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.
*/
}
+/*
+ * 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.
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);
}
}
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);
}
}
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
*/
/*
* 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));
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;
}
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) {
*/
#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
/*
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 */
/*
- * 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 */
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 */
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");
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;
}
}
+/*
+ * 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;
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.
}
+/*
+ * 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.
*/
}
}
+/*
+ * 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.
*/
}
+/*
+ * 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.
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);
}
}
}
/*
- * sifup - Config the interface up and enable IP packets to pass.
+ * sifup - Config the interface up.
*/
int
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;
}
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));
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.
*/