source: rtems-libbsd/rtemsbsd/pppd/rtemsmain.c @ 70fa95a

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 70fa95a was 70fa95a, checked in by Sebastian Huber <sebastian.huber@…>, on 09/30/14 at 12:46:12

ppp: Import from RTEMS sources

  • 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>
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)(void) = NULL;
97int (*new_phase_hook)(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(void);
125static void close_tty(void);
126static void get_input(void);
127static void calltimeout(void);
128static struct timeval *timeleft(struct timeval *);
129static void holdoff_end(void *);
130static int device_script(int, int, char *);
131
132extern  char    *ttyname(int);
133extern  char    *getlogin(void);
134int pppdmain(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(
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(
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(
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(
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(
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(void)
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(void)
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(
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)(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(
756    void (*func)(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
792pppuntimeout(
793    void (*func)(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(void)
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(
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(
893    char *msg)
894{
895    fatal("Virtual memory exhausted allocating %s\n", msg);
896}
Note: See TracBrowser for help on using the repository browser.