source: rtems/cpukit/pppd/rtemsmain.c @ 24312f34

5
Last change on this file since 24312f34 was 5346fa87, checked in by Sebastian Huber <sebastian.huber@…>, on 12/13/17 at 07:33:25

pppd: Include <rtems/rtems*.h>

Prepare for header file move to common include directory.

Update #3254.

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