]> git.ozlabs.org Git - ppp.git/commitdiff
Merge branch 'monotonic-time' of https://github.com/themiron/ppp
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 25 May 2020 03:26:55 +0000 (13:26 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Mon, 25 May 2020 03:26:55 +0000 (13:26 +1000)
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
1  2 
pppd/Makefile.linux
pppd/main.c
pppd/pppd.h
pppd/sys-linux.c
pppd/sys-solaris.c
pppd/tty.c

diff --combined pppd/Makefile.linux
index 853b15c14be42703aa5ff203da287ded9209794a,2a05bc42492b4b2973653b05cc2007e9eb963238..a22dcfab9d74f9658a1522bada021a41249aa90d
@@@ -33,7 -33,7 +33,7 @@@ endi
  # CC = gcc
  #
  COPTS = -O2 -pipe -Wall -g
- LIBS =
+ LIBS = -lrt
  
  # Uncomment the next line to include support for Microsoft's
  # MS-CHAP authentication protocol.  Also, edit plugins/radius/Makefile.linux.
@@@ -99,7 -99,6 +99,7 @@@ CFLAGS   += -DMSLANMAN=
  endif
  ifdef MPPE
  CFLAGS   += -DMPPE=1
 +HEADERS  += mppe.h
  endif
  endif
  
@@@ -126,7 -125,7 +126,7 @@@ CFLAGS   += -DHAS_SHADO
  #LIBS     += -lshadow $(LIBS)
  endif
  
 -ifneq ($(wildcard /usr/include/crypt.h),)
 +ifneq ($(wildcard $(shell $(CC) --print-sysroot)/usr/include/crypt.h),)
  CFLAGS  += -DHAVE_CRYPT_H=1
  LIBS  += -lcrypt
  endif
@@@ -138,7 -137,7 +138,7 @@@ endi
  
  ifdef NEEDDES
  ifndef USE_CRYPT
 -CFLAGS   += -I/usr/include/openssl
 +CFLAGS   += -I$(shell $(CC) --print-sysroot)/usr/include/openssl
  LIBS     += -lcrypto
  else
  CFLAGS   += -DUSE_CRYPT=1
diff --combined pppd/main.c
index 652240cc6868bf13b4404be886beff2231263cd0,dccd78b28d07aacdf45a1da146ecbf439f99bf9e..c18ea510582adc7f9365ad2497a7d9a39c4a2072
@@@ -80,6 -80,7 +80,6 @@@
  #include <netdb.h>
  #include <utmp.h>
  #include <pwd.h>
 -#include <setjmp.h>
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/wait.h>
  #include "atcp.h"
  #endif
  
 -static const char rcsid[] = RCSID;
  
  /* interface vars */
  char ifname[MAXIFNAMELEN];    /* Interface name */
@@@ -179,7 -181,7 +179,7 @@@ int got_sighup
  
  static sigset_t signals_handled;
  static int waiting;
 -static sigjmp_buf sigjmp;
 +static int sigpipe[2];
  
  char **script_env;            /* Env. variable values for scripts */
  int s_env_nalloc;             /* # words avail at script_env */
@@@ -520,7 -522,7 +520,7 @@@ main(argc, argv
            info("Starting link");
        }
  
-       gettimeofday(&start_time, NULL);
+       get_time(&start_time);
        script_unsetenv("CONNECT_TIME");
        script_unsetenv("BYTES_SENT");
        script_unsetenv("BYTES_RCVD");
@@@ -597,21 -599,19 +597,21 @@@ static voi
  handle_events()
  {
      struct timeval timo;
 +    unsigned char buf[16];
  
      kill_link = open_ccp_flag = 0;
 -    if (sigsetjmp(sigjmp, 1) == 0) {
 -      sigprocmask(SIG_BLOCK, &signals_handled, NULL);
 -      if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
 -          sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
 -      } else {
 -          waiting = 1;
 -          sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
 -          wait_input(timeleft(&timo));
 -      }
 -    }
 +
 +    /* alert via signal pipe */
 +    waiting = 1;
 +    /* flush signal pipe */
 +    for (; read(sigpipe[0], buf, sizeof(buf)) > 0; );
 +    add_fd(sigpipe[0]);
 +    /* wait if necessary */
 +    if (!(got_sighup || got_sigterm || got_sigusr2 || got_sigchld))
 +      wait_input(timeleft(&timo));
      waiting = 0;
 +    remove_fd(sigpipe[0]);
 +
      calltimeout();
      if (got_sighup) {
        info("Hangup (SIGHUP)");
@@@ -646,14 -646,6 +646,14 @@@ setup_signals(
  {
      struct sigaction sa;
  
 +    /* create pipe to wake up event handler from signal handler */
 +    if (pipe(sigpipe) < 0)
 +      fatal("Couldn't create signal pipe: %m");
 +    fcntl(sigpipe[0], F_SETFD, fcntl(sigpipe[0], F_GETFD) | FD_CLOEXEC);
 +    fcntl(sigpipe[1], F_SETFD, fcntl(sigpipe[1], F_GETFD) | FD_CLOEXEC);
 +    fcntl(sigpipe[0], F_SETFL, fcntl(sigpipe[0], F_GETFL) | O_NONBLOCK);
 +    fcntl(sigpipe[1], F_SETFL, fcntl(sigpipe[1], F_GETFL) | O_NONBLOCK);
 +
      /*
       * Compute mask of all interesting signals and install signal handlers
       * for each.  Only one signal handler may be active at a time.  Therefore,
@@@ -737,16 -729,12 +737,16 @@@ voi
  set_ifunit(iskey)
      int iskey;
  {
 +    char ifkey[32];
 +
      if (req_ifname[0] != '\0')
        slprintf(ifname, sizeof(ifname), "%s", req_ifname);
      else
        slprintf(ifname, sizeof(ifname), "%s%d", PPP_DRV_NAME, ifunit);
      info("Using interface %s", ifname);
      script_setenv("IFNAME", ifname, iskey);
 +    slprintf(ifkey, sizeof(ifkey), "%d", ifunit);
 +    script_setenv("UNIT", ifkey, iskey);
      if (iskey) {
        create_pidfile(getpid());       /* write pid to file */
        create_linkpidfile(getpid());
@@@ -1228,7 -1216,7 +1228,7 @@@ reset_link_stats(u
  {
      if (!get_ppp_stats(u, &old_link_stats))
        return;
-     gettimeofday(&start_time, NULL);
+     get_time(&start_time);
  }
  
  /*
@@@ -1242,7 -1230,7 +1242,7 @@@ update_link_stats(u
      char numbuf[32];
  
      if (!get_ppp_stats(u, &link_stats)
-       || gettimeofday(&now, NULL) < 0)
+       || get_time(&now) < 0)
        return;
      link_connect_time = now.tv_sec - start_time.tv_sec;
      link_stats_valid = 1;
@@@ -1289,7 -1277,7 +1289,7 @@@ timeout(func, arg, secs, usecs
        fatal("Out of memory in timeout()!");
      newp->c_arg = arg;
      newp->c_func = func;
-     gettimeofday(&timenow, NULL);
+     get_time(&timenow);
      newp->c_time.tv_sec = timenow.tv_sec + secs;
      newp->c_time.tv_usec = timenow.tv_usec + usecs;
      if (newp->c_time.tv_usec >= 1000000) {
@@@ -1343,7 -1331,7 +1343,7 @@@ calltimeout(
      while (callout != NULL) {
        p = callout;
  
-       if (gettimeofday(&timenow, NULL) < 0)
+       if (get_time(&timenow) < 0)
            fatal("Failed to get time of day: %m");
        if (!(p->c_time.tv_sec < timenow.tv_sec
              || (p->c_time.tv_sec == timenow.tv_sec
@@@ -1368,7 -1356,7 +1368,7 @@@ timeleft(tvp
      if (callout == NULL)
        return NULL;
  
-     gettimeofday(&timenow, NULL);
+     get_time(&timenow);
      tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
      tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
      if (tvp->tv_usec < 0) {
@@@ -1444,7 -1432,7 +1444,7 @@@ hup(sig
        kill_my_pg(sig);
      notify(sigreceived, sig);
      if (waiting)
 -      siglongjmp(sigjmp, 1);
 +      write(sigpipe[1], &sig, sizeof(sig));
  }
  
  
@@@ -1465,7 -1453,7 +1465,7 @@@ term(sig
        kill_my_pg(sig);
      notify(sigreceived, sig);
      if (waiting)
 -      siglongjmp(sigjmp, 1);
 +      write(sigpipe[1], &sig, sizeof(sig));
  }
  
  
@@@ -1479,7 -1467,7 +1479,7 @@@ chld(sig
  {
      got_sigchld = 1;
      if (waiting)
 -      siglongjmp(sigjmp, 1);
 +      write(sigpipe[1], &sig, sizeof(sig));
  }
  
  
@@@ -1514,7 -1502,7 +1514,7 @@@ open_ccp(sig
  {
      got_sigusr2 = 1;
      if (waiting)
 -      siglongjmp(sigjmp, 1);
 +      write(sigpipe[1], &sig, sizeof(sig));
  }
  
  
@@@ -1578,8 -1566,7 +1578,8 @@@ safe_fork(int infd, int outfd, int errf
        /* Executing in the child */
        sys_close();
  #ifdef USE_TDB
 -      tdb_close(pppdb);
 +      if (pppdb != NULL)
 +              tdb_close(pppdb);
  #endif
  
        /* make sure infd, outfd and errfd won't get tromped on below */
diff --combined pppd/pppd.h
index b31b78da7e727a005edf3544487721a70d465620,9214aaeb6ff1c778032c922af3cc62bc6de10b5b..4ab2ac1309902b05b21fe71a5113f3d16a066800
@@@ -50,8 -50,6 +50,8 @@@
  #define __PPPD_H__
  
  #include <stdio.h>            /* for FILE */
 +#include <stdlib.h>           /* for encrypt */
 +#include <unistd.h>           /* for setkey */
  #include <limits.h>           /* for NGROUPS_MAX */
  #include <sys/param.h>                /* for MAXPATHLEN and BSD4_4, if defined */
  #include <sys/types.h>                /* for u_int32_t, if defined */
@@@ -685,12 -683,6 +685,12 @@@ int  sifdefaultroute __P((int, u_int32_
                                /* Create default route through i/f */
  int  cifdefaultroute __P((int, u_int32_t, u_int32_t));
                                /* Delete default route through i/f */
 +#ifdef INET6
 +int  sif6defaultroute __P((int, eui64_t, eui64_t));
 +                              /* Create default IPv6 route through i/f */
 +int  cif6defaultroute __P((int, eui64_t, eui64_t));
 +                              /* Delete default IPv6 route through i/f */
 +#endif
  int  sifproxyarp __P((int, u_int32_t));
                                /* Add proxy ARP entry for peer */
  int  cifproxyarp __P((int, u_int32_t));
@@@ -713,6 -705,8 +713,8 @@@ int  cipxfaddr __P((int))
  #endif
  int  get_if_hwaddr __P((u_char *addr, char *name));
  char *get_first_ethernet __P((void));
+ int get_time __P((struct timeval *));
+                               /* Get current time, monotonic if possible. */
  
  /* Procedures exported from options.c */
  int setipaddr __P((char *, char **, int)); /* Set local/remote ip addresses */
diff --combined pppd/sys-linux.c
index a0531e9d351d094e138600e3b24945c9b27d1f60,b3959915938c19b758c38b0d267e0d2a95abce6a..fc309ad267d02b6ac4e3f66b56ecdf1733bd610e
  #define MAX_ADDR_LEN 7
  #endif
  
 -#if __GLIBC__ >= 2
 +#if !defined(__GLIBC__) || __GLIBC__ >= 2
  #include <asm/types.h>                /* glibc 2 conflicts with linux/types.h */
  #include <net/if.h>
  #include <net/if_arp.h>
@@@ -163,7 -163,6 +163,7 @@@ struct in6_ifreq 
        eui64_copy(eui64, sin6.s6_addr32[2]);                   \
        } while (0)
  
 +static const eui64_t nulleui64;
  #endif /* INET6 */
  
  /* We can get an EIO error on an ioctl if the modem has hung up */
@@@ -208,7 -207,6 +208,7 @@@ static unsigned char inbuf[512]; /* buf
  static int    if_is_up;       /* Interface has been marked up */
  static int    if6_is_up;      /* Interface has been marked up for IPv6, to help differentiate */
  static int    have_default_route;     /* Gateway for default route added */
 +static int    have_default_route6;    /* Gateway for default IPv6 route added */
  static u_int32_t proxy_arp_addr;      /* Addr for proxy arp entry added */
  static char proxy_arp_dev[16];                /* Device for proxy arp entry */
  static u_int32_t our_old_addr;                /* for detecting address changes */
@@@ -236,7 -234,6 +236,7 @@@ static void close_route_table (void)
  static int open_route_table (void);
  static int read_route_table (struct rtentry *rt);
  static int defaultroute_exists (struct rtentry *rt, int metric);
 +static int defaultroute6_exists (struct in6_rtmsg *rt, int metric);
  static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
                           char *name, int namelen);
  static void decode_version (char *buf, int *version, int *mod, int *patch);
@@@ -353,10 -350,6 +353,10 @@@ void sys_cleanup(void
   */
      if (have_default_route)
        cifdefaultroute(0, 0, 0);
 +#ifdef INET6
 +    if (have_default_route6)
 +      cif6defaultroute(0, nulleui64, nulleui64);
 +#endif
  
      if (has_proxy_arp)
        cifproxyarp(0, proxy_arp_addr);
@@@ -656,8 -649,8 +656,8 @@@ static int make_ppp_unit(
                char t[MAXIFNAMELEN];
                memset(&ifr, 0, sizeof(struct ifreq));
                slprintf(t, sizeof(t), "%s%d", PPP_DRV_NAME, ifunit);
 -              strncpy(ifr.ifr_name, t, IF_NAMESIZE);
 -              strncpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE);
 +              strlcpy(ifr.ifr_name, t, IF_NAMESIZE);
 +              strlcpy(ifr.ifr_newname, req_ifname, IF_NAMESIZE);
                x = ioctl(sock_fd, SIOCSIFNAME, &ifr);
                if (x < 0)
                    error("Couldn't rename interface %s to %s: %m", t, req_ifname);
@@@ -1717,198 -1710,6 +1717,198 @@@ int cifdefaultroute (int unit, u_int32_
      return 1;
  }
  
 +#ifdef INET6
 +/*
 + * /proc/net/ipv6_route parsing stuff.
 + */
 +static int route_dest_plen_col;
 +static int open_route6_table (void);
 +static int read_route6_table (struct in6_rtmsg *rt);
 +
 +/********************************************************************
 + *
 + * open_route6_table - open the interface to the route table
 + */
 +static int open_route6_table (void)
 +{
 +    char *path;
 +
 +    close_route_table();
 +
 +    path = path_to_procfs("/net/ipv6_route");
 +    route_fd = fopen (path, "r");
 +    if (route_fd == NULL) {
 +      error("can't open routing table %s: %m", path);
 +      return 0;
 +    }
 +
 +    /* default to usual columns */
 +    route_dest_col = 0;
 +    route_dest_plen_col = 1;
 +    route_gw_col = 4;
 +    route_metric_col = 5;
 +    route_flags_col = 8;
 +    route_dev_col = 9;
 +    route_num_cols = 10;
 +
 +    return 1;
 +}
 +
 +/********************************************************************
 + *
 + * read_route6_table - read the next entry from the route table
 + */
 +
 +static void hex_to_in6_addr(struct in6_addr *addr, const char *s)
 +{
 +    char hex8[9];
 +    unsigned i;
 +    uint32_t v;
 +
 +    hex8[8] = 0;
 +    for (i = 0; i < 4; i++) {
 +      memcpy(hex8, s + 8*i, 8);
 +      v = strtoul(hex8, NULL, 16);
 +      addr->s6_addr32[i] = v;
 +    }
 +}
 +
 +static int read_route6_table(struct in6_rtmsg *rt)
 +{
 +    char *cols[ROUTE_MAX_COLS], *p;
 +    int col;
 +
 +    memset (rt, '\0', sizeof (struct in6_rtmsg));
 +
 +    if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
 +      return 0;
 +
 +    p = route_buffer;
 +    for (col = 0; col < route_num_cols; ++col) {
 +      cols[col] = strtok(p, route_delims);
 +      if (cols[col] == NULL)
 +          return 0;           /* didn't get enough columns */
 +      p = NULL;
 +    }
 +
 +    hex_to_in6_addr(&rt->rtmsg_dst, cols[route_dest_col]);
 +    rt->rtmsg_dst_len = strtoul(cols[route_dest_plen_col], NULL, 16);
 +    hex_to_in6_addr(&rt->rtmsg_gateway, cols[route_gw_col]);
 +
 +    rt->rtmsg_metric = strtoul(cols[route_metric_col], NULL, 16);
 +    rt->rtmsg_flags = strtoul(cols[route_flags_col], NULL, 16);
 +    rt->rtmsg_ifindex = if_nametoindex(cols[route_dev_col]);
 +
 +    return 1;
 +}
 +
 +/********************************************************************
 + *
 + * defaultroute6_exists - determine if there is a default route
 + */
 +
 +static int defaultroute6_exists (struct in6_rtmsg *rt, int metric)
 +{
 +    int result = 0;
 +
 +    if (!open_route6_table())
 +      return 0;
 +
 +    while (read_route6_table(rt) != 0) {
 +      if ((rt->rtmsg_flags & RTF_UP) == 0)
 +          continue;
 +
 +      if (rt->rtmsg_dst_len != 0)
 +          continue;
 +      if (rt->rtmsg_dst.s6_addr32[0] == 0L
 +       && rt->rtmsg_dst.s6_addr32[1] == 0L
 +       && rt->rtmsg_dst.s6_addr32[2] == 0L
 +       && rt->rtmsg_dst.s6_addr32[3] == 0L
 +       && (metric < 0 || rt->rtmsg_metric == metric)) {
 +          result = 1;
 +          break;
 +      }
 +    }
 +
 +    close_route_table();
 +    return result;
 +}
 +
 +/********************************************************************
 + *
 + * sif6defaultroute - assign a default route through the address given.
 + *
 + * If the global default_rt_repl_rest flag is set, then this function
 + * already replaced the original system defaultroute with some other
 + * route and it should just replace the current defaultroute with
 + * another one, without saving the current route. Use: demand mode,
 + * when pppd sets first a defaultroute it it's temporary ppp0 addresses
 + * and then changes the temporary addresses to the addresses for the real
 + * ppp connection when it has come up.
 + */
 +
 +int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 +{
 +    struct in6_rtmsg rt;
 +    char buf[IF_NAMESIZE];
 +
 +    if (defaultroute6_exists(&rt, dfl_route_metric) &&
 +          rt.rtmsg_ifindex != if_nametoindex(ifname)) {
 +      if (rt.rtmsg_flags & RTF_GATEWAY)
 +          error("not replacing existing default route via gateway");
 +      else
 +          error("not replacing existing default route through %s",
 +                if_indextoname(rt.rtmsg_ifindex, buf));
 +      return 0;
 +    }
 +
 +    memset (&rt, 0, sizeof (rt));
 +
 +    rt.rtmsg_ifindex = if_nametoindex(ifname);
 +    rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
 +    rt.rtmsg_dst_len = 0;
 +
 +    rt.rtmsg_flags = RTF_UP;
 +    if (ioctl(sock6_fd, SIOCADDRT, &rt) < 0) {
 +      if ( ! ok_error ( errno ))
 +          error("default route ioctl(SIOCADDRT): %m");
 +      return 0;
 +    }
 +
 +    have_default_route6 = 1;
 +    return 1;
 +}
 +
 +/********************************************************************
 + *
 + * cif6defaultroute - delete a default route through the address given.
 + */
 +
 +int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
 +{
 +    struct in6_rtmsg rt;
 +
 +    have_default_route6 = 0;
 +
 +    memset (&rt, '\0', sizeof (rt));
 +
 +    rt.rtmsg_ifindex = if_nametoindex(ifname);
 +    rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
 +    rt.rtmsg_dst_len = 0;
 +
 +    rt.rtmsg_flags = RTF_UP;
 +    if (ioctl(sock6_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
 +      if (still_ppp()) {
 +          if ( ! ok_error ( errno ))
 +              error("default route ioctl(SIOCDELRT): %m");
 +          return 0;
 +      }
 +    }
 +
 +    return 1;
 +}
 +#endif /* INET6 */
 +
  /********************************************************************
   *
   * sifproxyarp - Make a proxy ARP entry for the peer.
@@@ -3165,3 -2966,38 +3165,38 @@@ ether_to_eui64(eui64_t *p_eui64
      return 1;
  }
  #endif
+ /********************************************************************
+  *
+  * get_time - Get current time, monotonic if possible.
+  */
+ int
+ get_time(struct timeval *tv)
+ {
+ /* Old glibc (< 2.3.4) does define CLOCK_MONOTONIC, but kernel may have it.
+  * Runtime checking makes it safe. */
+ #ifndef CLOCK_MONOTONIC
+ #define CLOCK_MONOTONIC 1
+ #endif
+     static int monotonic = -1;
+     struct timespec ts;
+     int ret;
+     if (monotonic) {
+       ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+       if (ret == 0) {
+           monotonic = 1;
+           if (tv) {
+               tv->tv_sec = ts.tv_sec;
+               tv->tv_usec = ts.tv_nsec / 1000;
+           }
+           return ret;
+       } else if (monotonic > 0)
+           return ret;
+       monotonic = 0;
+       warn("Couldn't use monotonic clock source: %m");
+     }
+     return gettimeofday(tv, NULL);
+ }
diff --combined pppd/sys-solaris.c
index 0b993a50139ed0136d8511f7ee5838c64ea6e0df,83b1815080cd60be33e0e02aa283ed6bbb73b4be..65b173a79695b7e80b8b421072532073be513ca0
  #include <sys/dlpi.h>
  #include <sys/stat.h>
  #include <sys/mkdev.h>
+ #include <sys/time.h>
  #include <net/if.h>
  #include <net/if_arp.h>
  #include <net/route.h>
  #define       UDP6_DEV_NAME   "/dev/udp6"
  #endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */
  
 -static const char rcsid[] = RCSID;
  
  #if defined(SOL2)
  /*
@@@ -188,12 -190,6 +189,12 @@@ static int       ip6fd;          /* IP file descripto
  static int    ip6muxid = -1;  /* Multiplexer file descriptor */
  static int    if6_is_up = 0;  /* IPv6 interface has been marked up */
  
 +#define IN6_SOCKADDR_FROM_EUI64(s, eui64) do { \
 +      (s)->sin6_family = AF_INET6; \
 +      (s)->sin6_addr.s6_addr32[0] = htonl(0xfe800000); \
 +      eui64_copy(eui64, (s)->sin6_addr.s6_addr32[2]); \
 +      } while(0)
 +
  #define _IN6_LLX_FROM_EUI64(l, s, eui64, as) do {     \
        s->sin6_addr.s6_addr32[0] = htonl(as);  \
        eui64_copy(eui64, s->sin6_addr.s6_addr32[2]);   \
        l.lifr_addr = laddr;                    \
        } while (0)
  
 +#define _IN6A_LLX_FROM_EUI64(s, eui64, as) do {       \
 +      s->s6_addr32[0] = htonl(as);    \
 +      eui64_copy(eui64, s->s6_addr32[2]);     \
 +      } while (0)
 +
  #define IN6_LLADDR_FROM_EUI64(l, s, eui64)  \
      _IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000)
  
  #define IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
      _IN6_LLX_FROM_EUI64(l, s, eui64, 0)
  
 +#define IN6A_LLADDR_FROM_EUI64(s, eui64)  \
 +    _IN6A_LLX_FROM_EUI64(s, eui64, 0xfe800000)
 +
  #endif /* defined(INET6) && defined(SOL2) */
  
  #if defined(INET6) && defined(SOL2)
@@@ -251,7 -239,6 +252,7 @@@ static int tty_npushed
  static int    if_is_up;       /* Interface has been marked up */
  static u_int32_t remote_addr;         /* IP address of peer */
  static u_int32_t default_route_gateway;       /* Gateway for default route added */
 +static eui64_t        default_route_gateway6; /* Gateway for default IPv6 route added */
  static u_int32_t proxy_arp_addr;      /* Addr for proxy arp entry added */
  
  /* Prototypes for procedures local to this file. */
@@@ -801,8 -788,6 +802,8 @@@ sys_cleanup(
        sifdown(0);
      if (default_route_gateway)
        cifdefaultroute(0, default_route_gateway, default_route_gateway);
 +    if (default_route_gateway6.e32[0] != 0 || default_route_gateway6.e32[1] != 0)
 +      cif6defaultroute(0, default_route_gateway6, default_route_gateway6);
      if (proxy_arp_addr)
        cifproxyarp(0, proxy_arp_addr);
  #if defined(SOL2)
@@@ -1973,70 -1958,6 +1974,70 @@@ cif6addr(u, o, h
      return 1;
  }
  
 +/*
 + * sif6defaultroute - assign a default route through the address given.
 + */
 +int
 +sif6defaultroute(u, l, g)
 +    int u;
 +    eui64_t l, g;
 +{
 +    struct {
 +      struct rt_msghdr rtm;
 +      struct sockaddr_in6 dst;
 +      struct sockaddr_in6 gw;
 +    } rmsg;
 +    static int seq;
 +    int rtsock;
 +
 +#if defined(__USLC__)
 +    g = l;                    /* use the local address as gateway */
 +#endif
 +    memset(&rmsg, 0, sizeof(rmsg));
 +
 +    rmsg.rtm.rtm_msglen = sizeof (rmsg);
 +    rmsg.rtm.rtm_version = RTM_VERSION;
 +    rmsg.rtm.rtm_type = RTM_ADD;
 +    rmsg.rtm.rtm_flags = RTF_GATEWAY;
 +    rmsg.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
 +    rmsg.rtm.rtm_pid = getpid();
 +    rmsg.rtm.rtm_seq = seq++;
 +
 +    rmsg.dst.sin6_family = AF_INET6;
 +
 +    rmsg.gw.sin6_family = AF_INET6;
 +    IN6_SOCKADDR_FROM_EUI64(&rmsg.gw, g);
 +
 +    rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
 +
 +    if (rtsock < 0) {
 +      error("Can't add default route: %m");
 +      return 0;
 +    }
 +
 +    if (write(rtsock, &rmsg, sizeof(rmsg)) < 0)
 +      error("Can't add default route: %m");
 +
 +    close(rtsock);
 +
 +    default_route_gateway6 = g;
 +    return 1;
 +}
 +
 +/*
 + * cif6defaultroute - delete a default route through the address given.
 + */
 +int
 +cif6defaultroute(u, l, g)
 +    int u;
 +    eui64_t l, g;
 +{
 +    /* No need to do this on Solaris; the kernel deletes the
 +       route when the interface goes down. */
 +    memset(&default_route_gateway6, 0, sizeof(default_route_gateway6));
 +    return 1;
 +}
 +
  #endif /* defined(SOL2) && defined(INET6) */
  
  
@@@ -2863,3 -2784,13 +2864,13 @@@ get_pty(master_fdp, slave_fdp, slave_na
  
      return 1;
  }
+ /********************************************************************
+  *
+  * get_time - Get current time, monotonic if possible.
+  */
+ int
+ get_time(struct timeval *tv)
+ {
+     return gettimeofday(tv, NULL);
+ }
diff --combined pppd/tty.c
index 7ece6753a0f3ac19733d556f8b4bbe5b5cc3a7c2,485a44d8102cf665b878c384279896217789eb5f..4d5b2dbb534a330d32ee0eb316515049b7ea9d05
@@@ -83,6 -83,7 +83,6 @@@
  #include <netdb.h>
  #include <utmp.h>
  #include <pwd.h>
 -#include <setjmp.h>
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/wait.h>
@@@ -1071,7 -1072,7 +1071,7 @@@ charshunt(ifd, ofd, record_file
      pty_readable = stdin_readable = 1;
  
      ilevel = olevel = 0;
-     gettimeofday(&levelt, NULL);
+     get_time(&levelt);
      if (max_data_rate) {
        max_level = max_data_rate / 10;
        if (max_level < 100)
            int nbt;
            struct timeval now;
  
-           gettimeofday(&now, NULL);
+           get_time(&now);
            dt = (now.tv_sec - levelt.tv_sec
                  + (now.tv_usec - levelt.tv_usec) / 1e6);
            nbt = (int)(dt * max_data_rate);