source: rtems/cpukit/pppd/rtemsmain.c @ aee474b

4.104.114.84.95
Last change on this file since aee474b was aee474b, checked in by Joel Sherrill <joel.sherrill@…>, on 10/12/01 at 13:43:05

2001-10-12 Mike Siers <mikes@…>

  • Update to stable working state. Congratulations Mike! :)
  • modem_example: Directory removed.
  • modem_example/16550.h, modem_example/README, modem_example/modem.c, modem_example/modem.h, modem_example/ppp.c, modem_example/ppp.h, modem_example/pppcompress.c: Files removed.
  • pppd/example/pppd.options: New file.
  • pppd/README, pppd/STATUS, pppd/cbcp.c, pppd/cbcp.h, pppd/chat.c, pppd/pppd.h, pppd/rtemsmain.c: Updated.
  • Property mode set to 100644
File size: 22.1 KB
Line 
1/*
2 * main.c - Point-to-Point Protocol main module
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University.  The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20#define RCSID   "$Id$"
21
22#include <stdio.h>
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <signal.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <netdb.h>
31#include <pwd.h>
32#include <setjmp.h>
33#include <sys/param.h>
34#include <sys/types.h>
35#include <sys/wait.h>
36#include <sys/time.h>
37#include <sys/resource.h>
38#include <sys/stat.h>
39#include <sys/socket.h>
40#include <netinet/in.h>
41
42#include <rtems.h>
43#include <rtems/rtems_bsdnet.h>
44extern void rtems_bsdnet_semaphore_obtain(void);
45extern void rtems_bsdnet_semaphore_release(void);
46extern int  chatmain(char *argv);
47
48#include "pppd.h"
49#include "magic.h"
50#include "fsm.h"
51#include "lcp.h"
52#include "ipcp.h"
53#ifdef INET6
54#include "ipv6cp.h"
55#endif
56#include "upap.h"
57#include "chap.h"
58#include "ccp.h"
59#include "pathnames.h"
60#include "patchlevel.h"
61
62#ifdef CBCP_SUPPORT
63#include "cbcp.h"
64#endif
65
66#ifdef IPX_CHANGE
67#include "ipxcp.h"
68#endif /* IPX_CHANGE */
69#ifdef AT_CHANGE
70#include "atcp.h"
71#endif
72
73static const char rcsid[] = RCSID;
74
75/* interface vars */
76char ifname[32];                /* Interface name */
77int pppifunit;                  /* Interface unit number */
78
79char *progname;                 /* Name of this program */
80char hostname[MAXNAMELEN];      /* Our hostname */
81static char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
82
83int ttyfd;                      /* Serial port file descriptor */
84int baud_rate;                  /* Actual bits/second for serial device */
85int hungup;                     /* terminal has been hung up */
86int privileged;                 /* we're running as real uid root */
87int need_holdoff;               /* need holdoff period before restarting */
88int detached;                   /* have detached from terminal */
89struct stat devstat;            /* result of stat() on devnam */
90int prepass = 0;                /* doing prepass to find device name */
91int devnam_fixed;               /* set while in options.ttyxx file */
92volatile int status;            /* exit status for pppd */
93int unsuccess;                  /* # unsuccessful connection attempts */
94int do_callback;                /* != 0 if we should do callback next */
95int doing_callback;             /* != 0 if we are doing callback */
96char *callback_script;          /* script for doing callback */
97
98int (*holdoff_hook) __P((void)) = NULL;
99int (*new_phase_hook) __P((int)) = NULL;
100
101static int fd_ppp = -1;         /* fd for talking PPP */
102static int pty_master;          /* fd for master side of pty */
103static int pty_slave;           /* fd for slave side of pty */
104static int real_ttyfd;          /* fd for actual serial port (not pty) */
105
106int phase;                      /* where the link is at */
107int kill_link;
108int open_ccp_flag;
109
110char **script_env;              /* Env. variable values for scripts */
111int s_env_nalloc;               /* # words avail at script_env */
112
113u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
114u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
115
116char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
117
118static struct timeval start_time;       /* Time when link was started. */
119
120struct pppd_stats link_stats;
121int link_connect_time;
122int link_stats_valid;
123
124/* Prototypes for procedures local to this file. */
125
126static void cleanup __P((void));
127static void close_tty __P((void));
128static void get_input __P((void));
129static void calltimeout __P((void));
130static struct timeval *timeleft __P((struct timeval *));
131static void holdoff_end __P((void *));
132static int device_script __P((char *, int, int, int));
133
134extern  char    *ttyname __P((int));
135extern  char    *getlogin __P((void));
136int pppdmain __P((int, char *[]));
137
138/*
139 * PPP Data Link Layer "protocol" table.
140 * One entry per supported protocol.
141 * The last entry must be NULL.
142 */
143struct protent *protocols[] = {
144    &lcp_protent,
145    &pap_protent,
146    &chap_protent,
147#ifdef CBCP_SUPPORT
148    &cbcp_protent,
149#endif
150    &ipcp_protent,
151#ifdef INET6
152    &ipv6cp_protent,
153#endif
154    &ccp_protent,
155#ifdef IPX_CHANGE
156    &ipxcp_protent,
157#endif
158#ifdef AT_CHANGE
159    &atcp_protent,
160#endif
161    NULL
162};
163
164int
165pppdmain(argc, argv)
166    int argc;
167    char *argv[];
168{
169    int i, fdflags, t;
170    char *connector;
171    struct timeval timo;
172    struct protent *protp;
173
174    new_phase(PHASE_INITIALIZE);
175
176    script_env = NULL;
177    hostname[MAXNAMELEN-1] = 0;
178    privileged = 1;
179    privileged_option = 1;
180
181    /*
182     * Initialize magic number generator now so that protocols may
183     * use magic numbers in initialization.
184     */
185    magic_init();
186
187#ifdef XXX_XXX
188    /* moved code the the rtems_pppd_reset_options function */
189
190    /*
191     * Initialize to the standard option set, then parse, in order,
192     * the system options file, the user's options file,
193     * the tty's options file, and the command line arguments.
194     */
195    for (i = 0; (protp = protocols[i]) != NULL; ++i)
196        (*protp->init)(0);
197#endif
198
199    progname = *argv;
200
201
202    if (!ppp_available()) {
203        option_error(no_ppp_msg);
204        return(EXIT_NO_KERNEL_SUPPORT);
205    }
206
207    /*
208     * Check that the options given are valid and consistent.
209     */
210    if (!sys_check_options()) {
211        return(EXIT_OPTION_ERROR);
212    }
213    if (!auth_check_options()) {
214        return(EXIT_OPTION_ERROR);
215    }
216    for (i = 0; (protp = protocols[i]) != NULL; ++i)
217        if (protp->check_options != NULL)
218            (*protp->check_options)();
219
220    /* default holdoff to 0 if no connect script has been given */
221    if (connect_script == 0 && !holdoff_specified)
222        holdoff = 0;
223
224    if (default_device)
225        nodetach = 1;
226
227    /*
228     * Initialize system-dependent stuff.
229     */
230    sys_init();
231    /* if (debug)
232        setlogmask(LOG_UPTO(LOG_DEBUG));
233    */
234
235    do_callback = 0;
236    for (;;) {
237
238        need_holdoff = 1;
239        ttyfd = -1;
240        real_ttyfd = -1;
241        status = EXIT_OK;
242        ++unsuccess;
243        doing_callback = do_callback;
244        do_callback = 0;
245
246        new_phase(PHASE_SERIALCONN);
247
248        /*
249         * Get a pty master/slave pair if the pty, notty, or record
250         * options were specified.
251         */
252        strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
253        pty_master = -1;
254        pty_slave = -1;
255
256        /*
257         * Open the serial device and set it up to be the ppp interface.
258         * First we open it in non-blocking mode so we can set the
259         * various termios flags appropriately.  If we aren't dialling
260         * out and we want to use the modem lines, we reopen it later
261         * in order to wait for the carrier detect signal from the modem.
262         */
263        hungup = 0;
264        kill_link = 0;
265        connector = doing_callback? callback_script: connect_script;
266        if (devnam[0] != 0) {
267            for (;;) {
268                /* If the user specified the device name, become the
269                   user before opening it. */
270                int err;
271                ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
272                err = errno;
273                if (ttyfd >= 0) {
274                    break;
275                }
276                errno = err;
277                if (err != EINTR) {
278                    error("Failed to open %s: %m", devnam);
279                    status = EXIT_OPEN_FAILED;
280                }
281                if (!persist || err != EINTR)
282                    goto fail;
283            }
284            if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
285                || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
286                warn("Couldn't reset non-blocking mode on device: %m");
287
288            /*
289             * Set line speed, flow control, etc.
290             * If we have a non-null connection or initializer script,
291             * on most systems we set CLOCAL for now so that we can talk
292             * to the modem before carrier comes up.  But this has the
293             * side effect that we might miss it if CD drops before we
294             * get to clear CLOCAL below.  On systems where we can talk
295             * successfully to the modem with CLOCAL clear and CD down,
296             * we could clear CLOCAL at this point.
297             */
298            set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0)
299                               || initializer != NULL));
300            real_ttyfd = ttyfd;
301        }
302
303        /* run connection script */
304        if ((connector && connector[0]) || initializer) {
305            if (real_ttyfd != -1) {
306                /* XXX do this if doing_callback == CALLBACK_DIALIN? */
307                if (!default_device && modem) {
308                    setdtr(real_ttyfd, 0);      /* in case modem is off hook */
309                    sleep(1);
310                    setdtr(real_ttyfd, 1);
311                }
312            }
313
314            if (initializer && initializer[0]) {
315                if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
316                    error("Initializer script failed");
317                    status = EXIT_INIT_FAILED;
318                    goto fail;
319                }
320                if (kill_link)
321                    goto disconnect;
322
323                info("Serial port initialized.");
324            }
325
326            if (connector && connector[0]) {
327                if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
328                    error("Connect script failed");
329                    status = EXIT_CONNECT_FAILED;
330                    goto fail;
331                }
332                if (kill_link)
333                    goto disconnect;
334
335                info("Serial connection established.");
336            }
337
338            /* set line speed, flow control, etc.;
339               clear CLOCAL if modem option */
340            if (real_ttyfd != -1)
341                set_up_tty(real_ttyfd, 0);
342
343            if (doing_callback == CALLBACK_DIALIN)
344                connector = NULL;
345        }
346
347        /* reopen tty if necessary to wait for carrier */
348        if (connector == NULL && modem && devnam[0] != 0) {
349            for (;;) {
350                if ((i = open(devnam, O_RDWR)) >= 0)
351                    break;
352                if (errno != EINTR) {
353                    error("Failed to reopen %s: %m", devnam);
354                    status = EXIT_OPEN_FAILED;
355                }
356                if (!persist || errno != EINTR || hungup || kill_link)
357                    goto fail;
358            }
359            close(i);
360        }
361
362        info("Serial connection established.");
363        sleep(1);
364
365        /* run welcome script, if any */
366        if (welcomer && welcomer[0]) {
367            if (device_script(welcomer, ttyfd, ttyfd, 0) < 0)
368                warn("Welcome script failed");
369        }
370
371        /* set up the serial device as a ppp interface */
372        fd_ppp = establish_ppp(ttyfd);
373        if (fd_ppp < 0) {
374            status = EXIT_FATAL_ERROR;
375            goto disconnect;
376        }
377
378        if (!demand) {
379            info("Using interface ppp%d", pppifunit);
380            slprintf(ifname, sizeof(ifname), "ppp%d", pppifunit);
381        }
382
383        /*
384         * Start opening the connection and wait for
385         * incoming events (reply, timeout, etc.).
386         */
387        notice("Connect: %s <--> %s", ifname, ppp_devnam);
388        gettimeofday(&start_time, NULL);
389
390        rtems_bsdnet_semaphore_obtain();
391        lcp_lowerup(0);
392        lcp_open(0);            /* Start protocol */
393        rtems_bsdnet_semaphore_release();
394
395        open_ccp_flag = 0;
396        status = EXIT_NEGOTIATION_FAILED;
397        new_phase(PHASE_ESTABLISH);
398        while (phase != PHASE_DEAD) {
399            wait_input(timeleft(&timo));
400            calltimeout();
401            get_input();
402
403            if (kill_link) {
404                lcp_close(0, "User request");
405                kill_link = 0;
406            }
407            if (open_ccp_flag) {
408                if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
409                    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
410                    (*ccp_protent.open)(0);
411                }
412                open_ccp_flag = 0;
413            }
414        }
415
416        /*
417         * If we may want to bring the link up again, transfer
418         * the ppp unit back to the loopback.  Set the
419         * real serial device back to its normal mode of operation.
420         */
421        clean_check();
422        if (demand)
423            restore_loop();
424        disestablish_ppp(ttyfd);
425        fd_ppp = -1;
426        if (!hungup)
427            lcp_lowerdown(0);
428
429        /*
430         * Run disconnector script, if requested.
431         * XXX we may not be able to do this if the line has hung up!
432         */
433    disconnect:
434        if (disconnect_script && !hungup) {
435            new_phase(PHASE_DISCONNECT);
436            if (real_ttyfd >= 0)
437                set_up_tty(real_ttyfd, 1);
438            if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) {
439                warn("disconnect script failed");
440            } else {
441                info("Serial link disconnected.");
442            }
443        }
444
445    fail:
446        if (pty_master >= 0)
447            close(pty_master);
448        if (pty_slave >= 0)
449            close(pty_slave);
450        if (real_ttyfd >= 0)
451            close_tty();
452
453        if (!persist || (maxfail > 0 && unsuccess >= maxfail))
454            break;
455
456        kill_link = 0;
457        if (demand)
458            demand_discard();
459        t = need_holdoff? holdoff: 0;
460        if (holdoff_hook)
461            t = (*holdoff_hook)();
462        if (t > 0) {
463            new_phase(PHASE_HOLDOFF);
464            TIMEOUT(holdoff_end, NULL, t);
465            do {
466                wait_input(timeleft(&timo));
467
468                calltimeout();
469                if (kill_link) {
470                    kill_link = 0;
471                    new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
472                }
473            } while (phase == PHASE_HOLDOFF);
474            if (!persist)
475                break;
476        }
477    }
478
479    die(status);
480    return 0;
481}
482
483/*
484 * holdoff_end - called via a timeout when the holdoff period ends.
485 */
486static void
487holdoff_end(arg)
488    void *arg;
489{
490    new_phase(PHASE_DORMANT);
491}
492
493/* List of protocol names, to make our messages a little more informative. */
494struct protocol_list {
495    u_short     proto;
496    const char  *name;
497} protocol_list[] = {
498    { 0x21,     "IP" },
499    { 0x23,     "OSI Network Layer" },
500    { 0x25,     "Xerox NS IDP" },
501    { 0x27,     "DECnet Phase IV" },
502    { 0x29,     "Appletalk" },
503    { 0x2b,     "Novell IPX" },
504    { 0x2d,     "VJ compressed TCP/IP" },
505    { 0x2f,     "VJ uncompressed TCP/IP" },
506    { 0x31,     "Bridging PDU" },
507    { 0x33,     "Stream Protocol ST-II" },
508    { 0x35,     "Banyan Vines" },
509    { 0x39,     "AppleTalk EDDP" },
510    { 0x3b,     "AppleTalk SmartBuffered" },
511    { 0x3d,     "Multi-Link" },
512    { 0x3f,     "NETBIOS Framing" },
513    { 0x41,     "Cisco Systems" },
514    { 0x43,     "Ascom Timeplex" },
515    { 0x45,     "Fujitsu Link Backup and Load Balancing (LBLB)" },
516    { 0x47,     "DCA Remote Lan" },
517    { 0x49,     "Serial Data Transport Protocol (PPP-SDTP)" },
518    { 0x4b,     "SNA over 802.2" },
519    { 0x4d,     "SNA" },
520    { 0x4f,     "IP6 Header Compression" },
521    { 0x6f,     "Stampede Bridging" },
522    { 0xfb,     "single-link compression" },
523    { 0xfd,     "1st choice compression" },
524    { 0x0201,   "802.1d Hello Packets" },
525    { 0x0203,   "IBM Source Routing BPDU" },
526    { 0x0205,   "DEC LANBridge100 Spanning Tree" },
527    { 0x0231,   "Luxcom" },
528    { 0x0233,   "Sigma Network Systems" },
529    { 0x8021,   "Internet Protocol Control Protocol" },
530    { 0x8023,   "OSI Network Layer Control Protocol" },
531    { 0x8025,   "Xerox NS IDP Control Protocol" },
532    { 0x8027,   "DECnet Phase IV Control Protocol" },
533    { 0x8029,   "Appletalk Control Protocol" },
534    { 0x802b,   "Novell IPX Control Protocol" },
535    { 0x8031,   "Bridging NCP" },
536    { 0x8033,   "Stream Protocol Control Protocol" },
537    { 0x8035,   "Banyan Vines Control Protocol" },
538    { 0x803d,   "Multi-Link Control Protocol" },
539    { 0x803f,   "NETBIOS Framing Control Protocol" },
540    { 0x8041,   "Cisco Systems Control Protocol" },
541    { 0x8043,   "Ascom Timeplex" },
542    { 0x8045,   "Fujitsu LBLB Control Protocol" },
543    { 0x8047,   "DCA Remote Lan Network Control Protocol (RLNCP)" },
544    { 0x8049,   "Serial Data Control Protocol (PPP-SDCP)" },
545    { 0x804b,   "SNA over 802.2 Control Protocol" },
546    { 0x804d,   "SNA Control Protocol" },
547    { 0x804f,   "IP6 Header Compression Control Protocol" },
548    { 0x006f,   "Stampede Bridging Control Protocol" },
549    { 0x80fb,   "Single Link Compression Control Protocol" },
550    { 0x80fd,   "Compression Control Protocol" },
551    { 0xc021,   "Link Control Protocol" },
552    { 0xc023,   "Password Authentication Protocol" },
553    { 0xc025,   "Link Quality Report" },
554    { 0xc027,   "Shiva Password Authentication Protocol" },
555    { 0xc029,   "CallBack Control Protocol (CBCP)" },
556    { 0xc081,   "Container Control Protocol" },
557    { 0xc223,   "Challenge Handshake Authentication Protocol" },
558    { 0xc281,   "Proprietary Authentication Protocol" },
559    { 0,        NULL },
560};
561
562/*
563 * protocol_name - find a name for a PPP protocol.
564 */
565const char *
566protocol_name(proto)
567    int proto;
568{
569    struct protocol_list *lp;
570
571    for (lp = protocol_list; lp->proto != 0; ++lp)
572        if (proto == lp->proto)
573            return lp->name;
574    return NULL;
575}
576
577/*
578 * get_input - called when incoming data is available.
579 */
580static void
581get_input()
582{
583    int len, i;
584    u_char *p;
585    u_short protocol;
586    struct protent *protp;
587
588    p = inpacket_buf;   /* point to beginning of packet buffer */
589
590    len = read_packet(inpacket_buf);
591    if (len < 0)
592        return;
593
594    if (len == 0) {
595        notice("Modem hangup");
596        hungup = 1;
597        status = EXIT_HANGUP;
598        lcp_lowerdown(0);       /* serial link is no longer available */
599        link_terminated(0);
600        return;
601    }
602
603    if (debug /*&& (debugflags & DBG_INPACKET)*/)
604        dbglog("rcvd %P", p, len);
605
606    if (len < PPP_HDRLEN) {
607        MAINDEBUG(("io(): Received short packet."));
608        return;
609    }
610
611    rtems_bsdnet_semaphore_obtain();
612    p += 2;                             /* Skip address and control */
613    GETSHORT(protocol, p);
614    len -= PPP_HDRLEN;
615
616    /*
617     * Toss all non-LCP packets unless LCP is OPEN.
618     */
619    if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
620        MAINDEBUG(("get_input: Received non-LCP packet when LCP not open."));
621        rtems_bsdnet_semaphore_release();
622        return;
623    }
624
625    /*
626     * Until we get past the authentication phase, toss all packets
627     * except LCP, LQR and authentication packets.
628     */
629    if (phase <= PHASE_AUTHENTICATE
630        && !(protocol == PPP_LCP || protocol == PPP_LQR
631             || protocol == PPP_PAP || protocol == PPP_CHAP)) {
632        MAINDEBUG(("get_input: discarding proto 0x%x in phase %d",
633                   protocol, phase));
634        rtems_bsdnet_semaphore_release();
635        return;
636    }
637
638    /*
639     * Upcall the proper protocol input routine.
640     */
641    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
642        if (protp->protocol == protocol && protp->enabled_flag) {
643            (*protp->input)(0, p, len);
644            rtems_bsdnet_semaphore_release();
645            return;
646        }
647        if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
648            && protp->datainput != NULL) {
649            (*protp->datainput)(0, p, len);
650            rtems_bsdnet_semaphore_release();
651            return;
652        }
653    }
654
655    if (debug) {
656        const char *pname = protocol_name(protocol);
657        if (pname != NULL)
658            warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
659        else
660            warn("Unsupported protocol 0x%x received", protocol);
661    }
662    lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
663    rtems_bsdnet_semaphore_release();
664}
665
666/*
667 * new_phase - signal the start of a new phase of pppd's operation.
668 */
669void
670new_phase(p)
671    int p;
672{
673    phase = p;
674    if (new_phase_hook)
675        (*new_phase_hook)(p);
676}
677
678/*
679 * die - clean up state and exit with the specified status.
680 */
681void
682die(status)
683    int status;
684{
685    cleanup();
686}
687
688/*
689 * cleanup - restore anything which needs to be restored before we exit
690 */
691/* ARGSUSED */
692static void
693cleanup()
694{
695    sys_cleanup();
696
697    if (fd_ppp >= 0)
698        disestablish_ppp(ttyfd);
699    if (real_ttyfd >= 0)
700        close_tty();
701
702    sys_close();
703}
704
705/*
706 * close_tty - restore the terminal device and close it.
707 */
708static void
709close_tty()
710{
711    /* drop dtr to hang up */
712    if (!default_device && modem) {
713        setdtr(real_ttyfd, 0);
714        /*
715         * This sleep is in case the serial port has CLOCAL set by default,
716         * and consequently will reassert DTR when we close the device.
717         */
718        sleep(1);
719    }
720
721    restore_tty(real_ttyfd);
722
723    close(real_ttyfd);
724    real_ttyfd = -1;
725}
726
727/*
728 * update_link_stats - get stats at link termination.
729 */
730void
731update_link_stats(u)
732    int u;
733{
734    struct timeval now;
735    char numbuf[32];
736
737    if (!get_ppp_stats(u, &link_stats)
738        || gettimeofday(&now, NULL) < 0)
739        return;
740    link_connect_time = now.tv_sec - start_time.tv_sec;
741    link_stats_valid = 1;
742
743    slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
744    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
745    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
746}
747
748struct  callout {
749    struct timeval      c_time;         /* time at which to call routine */
750    void                *c_arg;         /* argument to routine */
751    void                (*c_func) __P((void *)); /* routine */
752    struct              callout *c_next;
753};
754
755static struct callout *callout = NULL;  /* Callout list */
756static struct timeval timenow;          /* Current time */
757
758/*
759 * timeout - Schedule a timeout.
760 *
761 * Note that this timeout takes the number of seconds, NOT hz (as in
762 * the kernel).
763 */
764void
765ppptimeout(func, arg, time)
766    void (*func) __P((void *));
767    void *arg;
768    int time;
769{
770    struct callout *newp, *p, **pp;
771 
772    MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time));
773 
774    /*
775     * Allocate timeout.
776     */
777    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
778        fatal("Out of memory in timeout()!");
779    newp->c_arg = arg;
780    newp->c_func = func;
781    gettimeofday(&timenow, NULL);
782    newp->c_time.tv_sec = timenow.tv_sec + time;
783    newp->c_time.tv_usec = timenow.tv_usec;
784 
785    /*
786     * Find correct place and link it in.
787     */
788    for (pp = &callout; (p = *pp); pp = &p->c_next)
789        if (newp->c_time.tv_sec < p->c_time.tv_sec
790            || (newp->c_time.tv_sec == p->c_time.tv_sec
791                && newp->c_time.tv_usec < p->c_time.tv_usec))
792            break;
793    newp->c_next = p;
794    *pp = newp;
795}
796
797
798/*
799 * untimeout - Unschedule a timeout.
800 */
801void
802untimeout(func, arg)
803    void (*func) __P((void *));
804    void *arg;
805{
806    struct callout **copp, *freep;
807 
808    MAINDEBUG(("Untimeout %p:%p.", func, arg));
809 
810    /*
811     * Find first matching timeout and remove it from the list.
812     */
813    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
814        if (freep->c_func == func && freep->c_arg == arg) {
815            *copp = freep->c_next;
816            free((char *) freep);
817            break;
818        }
819}
820
821
822/*
823 * calltimeout - Call any timeout routines which are now due.
824 */
825static void
826calltimeout()
827{
828    struct callout *p;
829
830    while (callout != NULL) {
831        p = callout;
832
833        if (gettimeofday(&timenow, NULL) < 0)
834            fatal("Failed to get time of day: %m");
835        if (!(p->c_time.tv_sec < timenow.tv_sec
836              || (p->c_time.tv_sec == timenow.tv_sec
837                  && p->c_time.tv_usec <= timenow.tv_usec)))
838            break;              /* no, it's not time yet */
839
840        callout = p->c_next;
841        (*p->c_func)(p->c_arg);
842
843        free((char *) p);
844    }
845}
846
847
848/*
849 * timeleft - return the length of time until the next timeout is due.
850 */
851static struct timeval *
852timeleft(tvp)
853    struct timeval *tvp;
854{
855    if (callout == NULL)
856        return NULL;
857
858    gettimeofday(&timenow, NULL);
859    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
860    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
861    if (tvp->tv_usec < 0) {
862        tvp->tv_usec += 1000000;
863        tvp->tv_sec -= 1;
864    }
865    if (tvp->tv_sec < 0)
866        tvp->tv_sec = tvp->tv_usec = 0;
867
868    return tvp;
869}
870
871/*
872 * device_script - run a program to talk to the serial device
873 * (e.g. to run the connector or disconnector script).
874 */
875static int
876device_script(program, in, out, dont_wait)
877    char *program;
878    int in, out;
879    int dont_wait;
880{
881    char   pScript[256];
882
883    strcpy(pScript, program);
884    return chatmain(pScript);
885}
886
887/*
888 * novm - log an error message saying we ran out of memory, and die.
889 */
890void
891novm(msg)
892    char *msg;
893{
894    fatal("Virtual memory exhausted allocating %s\n", msg);
895}
Note: See TracBrowser for help on using the repository browser.