source: rtems/cpukit/pppd/rtemsmain.c @ 9c858e56

4.104.114.84.9
Last change on this file since 9c858e56 was 9c858e56, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 31, 2005 at 10:21:19 PM

2005-01-31 Sergei Organov <osv@…>

PR 771/pppd

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