Files
rtems/cpukit/pppd/rtemsmain.c
Joel Sherrill 0286b9f614 2001-01-31 Mike Siers <mikes@poliac.com>
* Nice Update of PPPD support which eliminates the
	requiremetn that drivers be in the termios TASK_DRIVEN mode.
	Mike did significant testing and reports that it seems to be
	more stable and handle larger packets better.  This patch
	replaces the termios tasks with more general pppd network
	driver tasks.  The functions pppinput() and pppstart() get
	called from the interrupt service routine.
	* Makefile.am, configure.ac, net/Makefile.am, net/bpf.h,
	net/ethernet.h, net/if.c, net/if.h, net/if_arp.h, net/if_dl.h,
	net/if_ethersubr.c, net/if_llc.h, net/if_loop.c, net/if_ppp.h,
	net/if_pppvar.h, net/if_types.h, net/netisr.h, net/ppp-comp.h,
	net/ppp_defs.h, net/pppcompress.h, net/radix.c, net/radix.h,
	net/raw_cb.c, net/raw_cb.h, net/raw_usrreq.c, net/route.c,
	net/route.h, net/rtsock.c, pppd/Makefile.am, pppd/README,
	pppd/STATUS, pppd/auth.c, pppd/cbcp.c, pppd/ccp.c, pppd/ccp.h,
	pppd/chap.c, pppd/chap.h, pppd/chap_ms.c, pppd/chap_ms.h,
	pppd/chat.c, pppd/demand.c, pppd/fsm.c, pppd/fsm.h, pppd/ipcp.c,
	pppd/ipcp.h, pppd/ipxcp.c, pppd/ipxcp.h, pppd/lcp.c, pppd/lcp.h,
	pppd/magic.c, pppd/magic.h, pppd/options.c, pppd/patchlevel.h,
	pppd/pathnames.h, pppd/pppd.8, pppd/pppd.h, pppd/rtemsmain.c,
	pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/upap.c,
	pppd/upap.h, pppd/utils.c, pppd/example/README,
	pppd/example/netconfig.h, wrapup/Makefile.am: Modified.
	* net/bsd-comp.c, net/if_ppp.c, net/ppp-deflate.c, net/ppp.h,
	net/ppp_tty.c, net/pppcompress.c, net/zlib.c, net/zlib.h: New file.
	* modem/, modem/.cvsignore, modem/Makefile.am, modem/ppp.c,
	modem/ppp.h, modem/ppp_tty.c, modem/pppcompress.c: Subdirectory removed.
2002-01-31 21:42:11 +00:00

900 lines
22 KiB
C

/*
* main.c - Point-to-Point Protocol main module
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define RCSID "$Id$"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <rtems.h>
#include <rtems/rtems_bsdnet.h>
#include "pppd.h"
#include "magic.h"
#include "fsm.h"
#include "lcp.h"
#include "ipcp.h"
#ifdef INET6
#include "ipv6cp.h"
#endif
#include "upap.h"
#include "chap.h"
#include "ccp.h"
#include "pathnames.h"
#include "patchlevel.h"
#include "rtemsdialer.h"
#ifdef CBCP_SUPPORT
#include "cbcp.h"
#endif
#ifdef IPX_CHANGE
#include "ipxcp.h"
#endif /* IPX_CHANGE */
#ifdef AT_CHANGE
#include "atcp.h"
#endif
static const char rcsid[] = RCSID;
/* interface vars */
char ifname[32]; /* Interface name */
int pppifunit; /* Interface unit number */
char *progname; /* Name of this program */
char hostname[MAXNAMELEN]; /* Our hostname */
static char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
int ttyfd; /* Serial port file descriptor */
int baud_rate; /* Actual bits/second for serial device */
int hungup; /* terminal has been hung up */
int privileged; /* we're running as real uid root */
int need_holdoff; /* need holdoff period before restarting */
int detached; /* have detached from terminal */
struct stat devstat; /* result of stat() on devnam */
int prepass = 0; /* doing prepass to find device name */
int devnam_fixed; /* set while in options.ttyxx file */
volatile int status; /* exit status for pppd */
int unsuccess; /* # unsuccessful connection attempts */
int do_callback; /* != 0 if we should do callback next */
int doing_callback; /* != 0 if we are doing callback */
char *callback_script; /* script for doing callback */
dialerfp pppd_dialer;
int (*holdoff_hook) __P((void)) = NULL;
int (*new_phase_hook) __P((int)) = NULL;
static int fd_ppp = -1; /* fd for talking PPP */
static int pty_master; /* fd for master side of pty */
static int pty_slave; /* fd for slave side of pty */
static int real_ttyfd; /* fd for actual serial port (not pty) */
int phase; /* where the link is at */
int kill_link;
int open_ccp_flag;
char **script_env; /* Env. variable values for scripts */
int s_env_nalloc; /* # words avail at script_env */
u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
static struct timeval start_time; /* Time when link was started. */
struct pppd_stats link_stats;
int link_connect_time;
int link_stats_valid;
/* Prototypes for procedures local to this file. */
static void cleanup __P((void));
static void close_tty __P((void));
static void get_input __P((void));
static void calltimeout __P((void));
static struct timeval *timeleft __P((struct timeval *));
static void holdoff_end __P((void *));
static int device_script __P((int, int, char *));
extern char *ttyname __P((int));
extern char *getlogin __P((void));
int pppdmain __P((int, char *[]));
/*
* PPP Data Link Layer "protocol" table.
* One entry per supported protocol.
* The last entry must be NULL.
*/
struct protent *protocols[] = {
&lcp_protent,
&pap_protent,
&chap_protent,
#ifdef CBCP_SUPPORT
&cbcp_protent,
#endif
&ipcp_protent,
#ifdef INET6
&ipv6cp_protent,
#endif
&ccp_protent,
#ifdef IPX_CHANGE
&ipxcp_protent,
#endif
#ifdef AT_CHANGE
&atcp_protent,
#endif
NULL
};
int
pppdmain(argc, argv)
int argc;
char *argv[];
{
int i, fdflags, t;
char *connector;
struct timeval timo;
struct protent *protp;
new_phase(PHASE_INITIALIZE);
script_env = NULL;
hostname[MAXNAMELEN-1] = 0;
privileged = 1;
privileged_option = 1;
/*
* Initialize magic number generator now so that protocols may
* use magic numbers in initialization.
*/
magic_init();
#ifdef XXX_XXX
/* moved code the the rtems_pppd_reset_options function */
/*
* Initialize to the standard option set, then parse, in order,
* the system options file, the user's options file,
* the tty's options file, and the command line arguments.
*/
for (i = 0; (protp = protocols[i]) != NULL; ++i)
(*protp->init)(0);
#endif
progname = *argv;
if (!ppp_available()) {
option_error(no_ppp_msg);
return(EXIT_NO_KERNEL_SUPPORT);
}
/*
* Check that the options given are valid and consistent.
*/
if (!sys_check_options()) {
return(EXIT_OPTION_ERROR);
}
if (!auth_check_options()) {
return(EXIT_OPTION_ERROR);
}
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->check_options != NULL)
(*protp->check_options)();
/* default holdoff to 0 if no connect script has been given */
if (connect_script == 0 && !holdoff_specified)
holdoff = 0;
if (default_device)
nodetach = 1;
/*
* Initialize system-dependent stuff.
*/
sys_init();
/* if (debug)
setlogmask(LOG_UPTO(LOG_DEBUG));
*/
do_callback = 0;
for (;;) {
need_holdoff = 1;
ttyfd = -1;
real_ttyfd = -1;
status = EXIT_OK;
++unsuccess;
doing_callback = do_callback;
do_callback = 0;
new_phase(PHASE_SERIALCONN);
/*
* Get a pty master/slave pair if the pty, notty, or record
* options were specified.
*/
strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
pty_master = -1;
pty_slave = -1;
/*
* Open the serial device and set it up to be the ppp interface.
* First we open it in non-blocking mode so we can set the
* various termios flags appropriately. If we aren't dialling
* out and we want to use the modem lines, we reopen it later
* in order to wait for the carrier detect signal from the modem.
*/
hungup = 0;
kill_link = 0;
connector = doing_callback? callback_script: connect_script;
if (devnam[0] != 0) {
for (;;) {
/* If the user specified the device name, become the
user before opening it. */
int err;
ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
if (ttyfd >= 0) {
break;
}
errno = err;
if (err != EINTR) {
error("Failed to open %s: %m", devnam);
status = EXIT_OPEN_FAILED;
}
if (!persist || err != EINTR)
goto fail;
}
if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
|| fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
warn("Couldn't reset non-blocking mode on device: %m");
/*
* Set line speed, flow control, etc.
* If we have a non-null connection or initializer script,
* on most systems we set CLOCAL for now so that we can talk
* to the modem before carrier comes up. But this has the
* side effect that we might miss it if CD drops before we
* get to clear CLOCAL below. On systems where we can talk
* successfully to the modem with CLOCAL clear and CD down,
* we could clear CLOCAL at this point.
*/
set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0)
|| initializer != NULL));
real_ttyfd = ttyfd;
}
/* run connection script */
if ((connector && connector[0]) || initializer) {
if (real_ttyfd != -1) {
/* XXX do this if doing_callback == CALLBACK_DIALIN? */
if (!default_device && modem) {
setdtr(real_ttyfd, 0); /* in case modem is off hook */
sleep(1);
setdtr(real_ttyfd, 1);
}
}
if (initializer && initializer[0]) {
if (device_script(ttyfd, DIALER_INIT, initializer) < 0) {
error("Initializer script failed");
status = EXIT_INIT_FAILED;
goto fail;
}
if (kill_link)
goto disconnect;
info("Serial port initialized.");
}
if (connector && connector[0]) {
if (device_script(ttyfd, DIALER_CONNECT, connector) < 0) {
error("Connect script failed");
status = EXIT_CONNECT_FAILED;
goto fail;
}
if (kill_link)
goto disconnect;
info("Serial connection established.");
}
/* set line speed, flow control, etc.;
clear CLOCAL if modem option */
if (real_ttyfd != -1)
set_up_tty(real_ttyfd, 0);
if (doing_callback == CALLBACK_DIALIN)
connector = NULL;
}
/* reopen tty if necessary to wait for carrier */
if (connector == NULL && modem && devnam[0] != 0) {
for (;;) {
if ((i = open(devnam, O_RDWR)) >= 0)
break;
if (errno != EINTR) {
error("Failed to reopen %s: %m", devnam);
status = EXIT_OPEN_FAILED;
}
if (!persist || errno != EINTR || hungup || kill_link)
goto fail;
}
close(i);
}
info("Serial connection established.");
sleep(1);
/* run welcome script, if any */
if (welcomer && welcomer[0]) {
if (device_script(ttyfd, DIALER_WELCOME, welcomer) < 0)
warn("Welcome script failed");
}
/* set up the serial device as a ppp interface */
fd_ppp = establish_ppp(ttyfd);
if (fd_ppp < 0) {
status = EXIT_FATAL_ERROR;
goto disconnect;
}
if (!demand) {
info("Using interface ppp%d", pppifunit);
slprintf(ifname, sizeof(ifname), "ppp%d", pppifunit);
}
/*
* Start opening the connection and wait for
* incoming events (reply, timeout, etc.).
*/
notice("Connect: %s <--> %s", ifname, ppp_devnam);
gettimeofday(&start_time, NULL);
lcp_lowerup(0);
lcp_open(0); /* Start protocol */
open_ccp_flag = 0;
status = EXIT_NEGOTIATION_FAILED;
new_phase(PHASE_ESTABLISH);
while (phase != PHASE_DEAD) {
wait_input(timeleft(&timo));
calltimeout();
get_input();
if (kill_link) {
lcp_close(0, "User request");
kill_link = 0;
}
if (open_ccp_flag) {
if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
(*ccp_protent.open)(0);
}
open_ccp_flag = 0;
}
}
/*
* 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)
restore_loop();
disestablish_ppp(ttyfd);
fd_ppp = -1;
if (!hungup)
lcp_lowerdown(0);
/*
* Run disconnector script, if requested.
* XXX we may not be able to do this if the line has hung up!
*/
disconnect:
if (disconnect_script && !hungup) {
new_phase(PHASE_DISCONNECT);
if (real_ttyfd >= 0)
set_up_tty(real_ttyfd, 1);
if (device_script(ttyfd, DIALER_DISCONNECT, disconnect_script) < 0) {
warn("disconnect script failed");
} else {
info("Serial link disconnected.");
}
}
fail:
if (pty_master >= 0)
close(pty_master);
if (pty_slave >= 0)
close(pty_slave);
if (real_ttyfd >= 0)
close_tty();
if (!persist || (maxfail > 0 && unsuccess >= maxfail))
break;
kill_link = 0;
if (demand)
demand_discard();
t = need_holdoff? holdoff: 0;
if (holdoff_hook)
t = (*holdoff_hook)();
if (t > 0) {
new_phase(PHASE_HOLDOFF);
TIMEOUT(holdoff_end, NULL, t);
do {
wait_input(timeleft(&timo));
calltimeout();
if (kill_link) {
kill_link = 0;
new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
}
} while (phase == PHASE_HOLDOFF);
if (!persist)
break;
}
}
die(status);
return status;
}
/*
* holdoff_end - called via a timeout when the holdoff period ends.
*/
static void
holdoff_end(arg)
void *arg;
{
new_phase(PHASE_DORMANT);
}
/* List of protocol names, to make our messages a little more informative. */
struct protocol_list {
u_short proto;
const char *name;
} protocol_list[] = {
{ 0x21, "IP" },
{ 0x23, "OSI Network Layer" },
{ 0x25, "Xerox NS IDP" },
{ 0x27, "DECnet Phase IV" },
{ 0x29, "Appletalk" },
{ 0x2b, "Novell IPX" },
{ 0x2d, "VJ compressed TCP/IP" },
{ 0x2f, "VJ uncompressed TCP/IP" },
{ 0x31, "Bridging PDU" },
{ 0x33, "Stream Protocol ST-II" },
{ 0x35, "Banyan Vines" },
{ 0x39, "AppleTalk EDDP" },
{ 0x3b, "AppleTalk SmartBuffered" },
{ 0x3d, "Multi-Link" },
{ 0x3f, "NETBIOS Framing" },
{ 0x41, "Cisco Systems" },
{ 0x43, "Ascom Timeplex" },
{ 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" },
{ 0x47, "DCA Remote Lan" },
{ 0x49, "Serial Data Transport Protocol (PPP-SDTP)" },
{ 0x4b, "SNA over 802.2" },
{ 0x4d, "SNA" },
{ 0x4f, "IP6 Header Compression" },
{ 0x6f, "Stampede Bridging" },
{ 0xfb, "single-link compression" },
{ 0xfd, "1st choice compression" },
{ 0x0201, "802.1d Hello Packets" },
{ 0x0203, "IBM Source Routing BPDU" },
{ 0x0205, "DEC LANBridge100 Spanning Tree" },
{ 0x0231, "Luxcom" },
{ 0x0233, "Sigma Network Systems" },
{ 0x8021, "Internet Protocol Control Protocol" },
{ 0x8023, "OSI Network Layer Control Protocol" },
{ 0x8025, "Xerox NS IDP Control Protocol" },
{ 0x8027, "DECnet Phase IV Control Protocol" },
{ 0x8029, "Appletalk Control Protocol" },
{ 0x802b, "Novell IPX Control Protocol" },
{ 0x8031, "Bridging NCP" },
{ 0x8033, "Stream Protocol Control Protocol" },
{ 0x8035, "Banyan Vines Control Protocol" },
{ 0x803d, "Multi-Link Control Protocol" },
{ 0x803f, "NETBIOS Framing Control Protocol" },
{ 0x8041, "Cisco Systems Control Protocol" },
{ 0x8043, "Ascom Timeplex" },
{ 0x8045, "Fujitsu LBLB Control Protocol" },
{ 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" },
{ 0x8049, "Serial Data Control Protocol (PPP-SDCP)" },
{ 0x804b, "SNA over 802.2 Control Protocol" },
{ 0x804d, "SNA Control Protocol" },
{ 0x804f, "IP6 Header Compression Control Protocol" },
{ 0x006f, "Stampede Bridging Control Protocol" },
{ 0x80fb, "Single Link Compression Control Protocol" },
{ 0x80fd, "Compression Control Protocol" },
{ 0xc021, "Link Control Protocol" },
{ 0xc023, "Password Authentication Protocol" },
{ 0xc025, "Link Quality Report" },
{ 0xc027, "Shiva Password Authentication Protocol" },
{ 0xc029, "CallBack Control Protocol (CBCP)" },
{ 0xc081, "Container Control Protocol" },
{ 0xc223, "Challenge Handshake Authentication Protocol" },
{ 0xc281, "Proprietary Authentication Protocol" },
{ 0, NULL },
};
/*
* protocol_name - find a name for a PPP protocol.
*/
const char *
protocol_name(proto)
int proto;
{
struct protocol_list *lp;
for (lp = protocol_list; lp->proto != 0; ++lp)
if (proto == lp->proto)
return lp->name;
return NULL;
}
/*
* get_input - called when incoming data is available.
*/
static void
get_input(void)
{
int len, i;
u_char *p;
u_short protocol;
struct protent *protp;
p = inpacket_buf; /* point to beginning of packet buffer */
len = read_packet(inpacket_buf);
if (len < 0)
return;
if (len == 0) {
notice("Modem hangup");
hungup = 1;
status = EXIT_HANGUP;
lcp_lowerdown(0); /* serial link is no longer available */
link_terminated(0);
return;
}
if (debug /*&& (debugflags & DBG_INPACKET)*/)
dbglog("rcvd %P", p, len);
if (len < PPP_HDRLEN) {
MAINDEBUG(("io(): Received short packet."));
return;
}
p += 2; /* Skip address and control */
GETSHORT(protocol, p);
len -= PPP_HDRLEN;
/*
* Toss all non-LCP packets unless LCP is OPEN.
*/
if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
MAINDEBUG(("get_input: Received non-LCP packet when LCP not open."));
return;
}
/*
* Until we get past the authentication phase, toss all packets
* except LCP, LQR and authentication packets.
*/
if (phase <= PHASE_AUTHENTICATE
&& !(protocol == PPP_LCP || protocol == PPP_LQR
|| protocol == PPP_PAP || protocol == PPP_CHAP)) {
MAINDEBUG(("get_input: discarding proto 0x%x in phase %d",
protocol, phase));
return;
}
/*
* Upcall the proper protocol input routine.
*/
for (i = 0; (protp = protocols[i]) != NULL; ++i) {
if (protp->protocol == protocol && protp->enabled_flag) {
(*protp->input)(0, p, len);
return;
}
if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
&& protp->datainput != NULL) {
(*protp->datainput)(0, p, len);
return;
}
}
if (debug) {
const char *pname = protocol_name(protocol);
if (pname != NULL)
warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
else
warn("Unsupported protocol 0x%x received", protocol);
}
lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
return;
}
/*
* new_phase - signal the start of a new phase of pppd's operation.
*/
void
new_phase(p)
int p;
{
phase = p;
if (new_phase_hook)
(*new_phase_hook)(p);
}
/*
* die - clean up state and exit with the specified status.
*/
void
die(status)
int status;
{
cleanup();
}
/*
* cleanup - restore anything which needs to be restored before we exit
*/
/* ARGSUSED */
static void
cleanup()
{
sys_cleanup();
if (fd_ppp >= 0)
disestablish_ppp(ttyfd);
if (real_ttyfd >= 0)
close_tty();
sys_close();
}
/*
* close_tty - restore the terminal device and close it.
*/
static void
close_tty()
{
/* drop dtr to hang up */
if (!default_device && modem) {
setdtr(real_ttyfd, 0);
/*
* This sleep is in case the serial port has CLOCAL set by default,
* and consequently will reassert DTR when we close the device.
*/
sleep(1);
}
restore_tty(real_ttyfd);
close(real_ttyfd);
real_ttyfd = -1;
}
/*
* update_link_stats - get stats at link termination.
*/
void
update_link_stats(u)
int u;
{
struct timeval now;
char numbuf[32];
if (!get_ppp_stats(u, &link_stats)
|| gettimeofday(&now, NULL) < 0)
return;
link_connect_time = now.tv_sec - start_time.tv_sec;
link_stats_valid = 1;
slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
}
struct callout {
struct timeval c_time; /* time at which to call routine */
void *c_arg; /* argument to routine */
void (*c_func) __P((void *)); /* routine */
struct callout *c_next;
};
static struct callout *callout = NULL; /* Callout list */
static struct timeval timenow; /* Current time */
/*
* timeout - Schedule a timeout.
*
* Note that this timeout takes the number of seconds, NOT hz (as in
* the kernel).
*/
void
ppptimeout(func, arg, time)
void (*func) __P((void *));
void *arg;
int time;
{
struct callout *newp, *p, **pp;
MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time));
/*
* Allocate timeout.
*/
if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
fatal("Out of memory in timeout()!");
newp->c_arg = arg;
newp->c_func = func;
gettimeofday(&timenow, NULL);
newp->c_time.tv_sec = timenow.tv_sec + time;
newp->c_time.tv_usec = timenow.tv_usec;
/*
* Find correct place and link it in.
*/
for (pp = &callout; (p = *pp); pp = &p->c_next)
if (newp->c_time.tv_sec < p->c_time.tv_sec
|| (newp->c_time.tv_sec == p->c_time.tv_sec
&& newp->c_time.tv_usec < p->c_time.tv_usec))
break;
newp->c_next = p;
*pp = newp;
}
/*
* untimeout - Unschedule a timeout.
*/
void
untimeout(func, arg)
void (*func) __P((void *));
void *arg;
{
struct callout **copp, *freep;
MAINDEBUG(("Untimeout %p:%p.", func, arg));
/*
* Find first matching timeout and remove it from the list.
*/
for (copp = &callout; (freep = *copp); copp = &freep->c_next)
if (freep->c_func == func && freep->c_arg == arg) {
*copp = freep->c_next;
free((char *) freep);
break;
}
}
/*
* calltimeout - Call any timeout routines which are now due.
*/
static void
calltimeout()
{
struct callout *p;
while (callout != NULL) {
p = callout;
if (gettimeofday(&timenow, NULL) < 0)
fatal("Failed to get time of day: %m");
if (!(p->c_time.tv_sec < timenow.tv_sec
|| (p->c_time.tv_sec == timenow.tv_sec
&& p->c_time.tv_usec <= timenow.tv_usec)))
break; /* no, it's not time yet */
callout = p->c_next;
(*p->c_func)(p->c_arg);
free((char *) p);
}
}
/*
* timeleft - return the length of time until the next timeout is due.
*/
static struct timeval *
timeleft(tvp)
struct timeval *tvp;
{
if (callout == NULL)
return NULL;
gettimeofday(&timenow, NULL);
tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
if (tvp->tv_usec < 0) {
tvp->tv_usec += 1000000;
tvp->tv_sec -= 1;
}
if (tvp->tv_sec < 0)
tvp->tv_sec = tvp->tv_usec = 0;
return tvp;
}
/*
* device_script - run a program to talk to the serial device
* (e.g. to run the connector or disconnector script).
*/
static int device_script(int fd, int mode, char *program)
{
int iReturn = -1;
char pScript[128];
/* copyt script into temporary location */
strcpy(pScript, program);
/* check to see if dialer was initialized */
if ( !pppd_dialer ) {
/* set default dialer to chatmain */
pppd_dialer = chatmain;
}
/* check to see if dialer is set */
if ( pppd_dialer ) {
/* call the dialer */
iReturn = (*pppd_dialer)(fd, mode, program);
}
return ( -iReturn );
}
/*
* novm - log an error message saying we ran out of memory, and die.
*/
void
novm(msg)
char *msg;
{
fatal("Virtual memory exhausted allocating %s\n", msg);
}