From 2f1b9304ac4ba89a2dcb6047cb584a5603a33987 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 16 Aug 2001 20:42:09 +0000 Subject: 2001-08-16 Mike Siers * Update of PPPD to 2.3.11 from 2.3.5 and addition of an example application. Mike's notes on the modifications: - renamed error() function because of namespace problems - removed calls to the exit() funciton - removed extra files from the pppd source directory - defined pppd task constant values in rtemspppd.h - modifyied example code to get actual tick per second value - placed the pppd 2.3.11 man page file (pppd.8) into the pppd directory * pppd/cbcp.c, pppd/cbcp.h, pppd/main.c, pppd/ppp_tty.c, pppd/pppmain.c, pppd/rtems-ppp.c, pppd/rtems-ppp.c: Deleted. * pppd/pppd.8, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/utils.c, pppd/example/Makefile, pppd/example/README, pppd/example/init.c, pppd/example/netconfig.h, pppd/example/ppp.conf, pppd/example/pppdapp.c, pppd/example/system.h: New files. * modem/ppp_tty.c, net/if_ppp.h, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.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.h, pppd/upap.c, pppd/upap.h: Modified. --- c/src/libnetworking/pppd/rtemsmain.c | 903 +++++++++++++++++++++++++++++++++++ 1 file changed, 903 insertions(+) create mode 100644 c/src/libnetworking/pppd/rtemsmain.c (limited to 'c/src/libnetworking/pppd/rtemsmain.c') diff --git a/c/src/libnetworking/pppd/rtemsmain.c b/c/src/libnetworking/pppd/rtemsmain.c new file mode 100644 index 0000000000..5a266a9ff3 --- /dev/null +++ b/c/src/libnetworking/pppd/rtemsmain.c @@ -0,0 +1,903 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +extern void rtems_bsdnet_semaphore_obtain(void); +extern void rtems_bsdnet_semaphore_release(void); +extern int chatmain(char *argv); + +#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" + +#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 */ + +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; + +static int waiting; + +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((char *, int, int, int)); + +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)); + */ + + waiting = 0; + + 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(initializer, ttyfd, ttyfd, 0) < 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(connector, ttyfd, ttyfd, 0) < 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(welcomer, ttyfd, ttyfd, 0) < 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); + + rtems_bsdnet_semaphore_obtain(); + lcp_lowerup(0); + lcp_open(0); /* Start protocol */ + rtems_bsdnet_semaphore_release(); + + open_ccp_flag = 0; + status = EXIT_NEGOTIATION_FAILED; + new_phase(PHASE_ESTABLISH); + while (phase != PHASE_DEAD) { + waiting = 1; + wait_input(timeleft(&timo)); + waiting = 0; + + 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(disconnect_script, ttyfd, ttyfd, 0) < 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 { + waiting = 1; + wait_input(timeleft(&timo)); + waiting = 0; + + 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 0; +} + +/* + * 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() +{ + 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; + } + + rtems_bsdnet_semaphore_obtain(); + 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.")); + rtems_bsdnet_semaphore_release(); + 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)); + rtems_bsdnet_semaphore_release(); + 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); + rtems_bsdnet_semaphore_release(); + return; + } + if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag + && protp->datainput != NULL) { + (*protp->datainput)(0, p, len); + rtems_bsdnet_semaphore_release(); + 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); + rtems_bsdnet_semaphore_release(); +} + +/* + * 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(program, in, out, dont_wait) + char *program; + int in, out; + int dont_wait; +{ + char pScript[256]; + + strcpy(pScript, program); + return chatmain(pScript); +} + +/* + * 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); +} -- cgit v1.2.3