]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/sys-linux.c
Check for EAGAIN as well as EWOULDBLOCK, since they are
[ppp.git] / pppd / sys-linux.c
index 918fa72c23dd0cca6fcc7295df5c5dca8e0d6443..68e0584aeecb641d914f0b9f3b391f18316deb1c 100644 (file)
@@ -2,20 +2,76 @@
  * sys-linux.c - System-dependent procedures for setting up
  * PPP interfaces on Linux systems
  *
- * Copyright (c) 1989 Carnegie Mellon University.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Paul Mackerras
+ *     <paulus@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Derived from main.c and pppd.h, which are:
+ *
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any legal
+ *    details, please contact
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include <sys/ioctl.h>
@@ -108,7 +164,7 @@ struct in6_ifreq {
 
 #define IN6_LLADDR_FROM_EUI64(sin6, eui64) do {                        \
        memset(&sin6.s6_addr, 0, sizeof(struct in6_addr));      \
-       sin6.s6_addr16[0] = htons(0xfe80);                      \
+       sin6.s6_addr16[0] = htons(0xfe80);                      \
        eui64_copy(eui64, sin6.s6_addr32[2]);                   \
        } while (0)
 
@@ -127,7 +183,14 @@ static int master_fd = -1;
 #ifdef INET6
 static int sock6_fd = -1;
 #endif /* INET6 */
-static int ppp_dev_fd = -1;    /* fd for /dev/ppp (new style driver) */
+
+/*
+ * For the old-style kernel driver, this is the same as ppp_fd.
+ * For the new-style driver, it is the fd of an instance of /dev/ppp
+ * which is attached to the ppp unit and is used for controlling it.
+ */
+int ppp_dev_fd = -1;           /* fd for /dev/ppp (new style driver) */
+
 static int chindex;            /* channel index (new style driver) */
 
 static fd_set in_fds;          /* set of fds that wait_input waits for */
@@ -168,8 +231,7 @@ static int kernel_version;
 #define SIN_ADDR(x)    (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr)
 
 /* Prototypes for procedures local to this file. */
-static int get_flags (int fd);
-static void set_flags (int fd, int flags);
+static int modify_flags(int fd, int clear_bits, int set_bits);
 static int translate_speed (int bps);
 static int baud_rate_of (int speed);
 static void close_route_table (void);
@@ -222,36 +284,26 @@ static int still_ppp(void)
        return 0;
 }
 
-/********************************************************************
- *
- * Functions to read and set the flags value in the device driver
+/*
+ * modify_flags - set and clear flag bits controlling the kernel
+ * PPP driver.
  */
+static int modify_flags(int fd, int clear_bits, int set_bits)
+{
+       int flags;
 
-static int get_flags (int fd)
-{    
-    int flags;
-
-    if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
-       if ( ok_error (errno) )
-           flags = 0;
-       else
-           fatal("ioctl(PPPIOCGFLAGS): %m (line %d)", __LINE__);
-    }
-
-    SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
-    return flags;
-}
-
-/********************************************************************/
+       if (ioctl(fd, PPPIOCGFLAGS, &flags) == -1)
+               goto err;
+       flags = (flags & ~clear_bits) | set_bits;
+       if (ioctl(fd, PPPIOCSFLAGS, &flags) == -1)
+               goto err;
 
-static void set_flags (int fd, int flags)
-{    
-    SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
+       return 0;
 
-    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
-       if (! ok_error (errno) )
-           fatal("ioctl(PPPIOCSFLAGS, %x): %m (line %d)", flags, errno, __LINE__);
-    }
+ err:
+       if (errno != EIO)
+               error("Failed to set PPP kernel option flags: %m");
+       return -1;
 }
 
 /********************************************************************
@@ -261,18 +313,6 @@ static void set_flags (int fd, int flags)
 
 void sys_init(void)
 {
-    int flags;
-
-    if (new_style_driver) {
-       ppp_dev_fd = open("/dev/ppp", O_RDWR);
-       if (ppp_dev_fd < 0)
-           fatal("Couldn't open /dev/ppp: %m");
-       flags = fcntl(ppp_dev_fd, F_GETFL);
-       if (flags == -1
-           || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
-           warn("Couldn't set /dev/ppp to nonblock: %m");
-    }
-
     /* Get an internet socket for doing socket ioctls. */
     sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock_fd < 0)
@@ -321,15 +361,18 @@ void sys_cleanup(void)
 void
 sys_close(void)
 {
-    if (new_style_driver)
+    if (new_style_driver && ppp_dev_fd >= 0)
        close(ppp_dev_fd);
     if (sock_fd >= 0)
        close(sock_fd);
+#ifdef INET6
+    if (sock6_fd >= 0)
+       close(sock6_fd);
+#endif
     if (slave_fd >= 0)
        close(slave_fd);
     if (master_fd >= 0)
        close(master_fd);
-    closelog();
 }
 
 /********************************************************************
@@ -339,7 +382,7 @@ sys_close(void)
 
 static int set_kdebugflag (int requested_level)
 {
-    if (new_style_driver && ifunit < 0)
+    if (ppp_dev_fd < 0)
        return 1;
     if (ioctl(ppp_dev_fd, PPPIOCSDEBUG, &requested_level) < 0) {
        if ( ! ok_error (errno) )
@@ -397,8 +440,8 @@ int tty_establish_ppp (int tty_fd)
                 | SC_LOG_FLUSH)
 
     if (ret_fd >= 0) {
-       set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
-                          | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+       modify_flags(ppp_fd, SC_RCVB | SC_LOGB,
+                    (kdebugflag * SC_DEBUG) & SC_LOGB);
     } else {
        if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
            warn("Couldn't reset tty to normal line discipline: %m");
@@ -416,9 +459,9 @@ int generic_establish_ppp (int fd)
     int x;
 
     if (new_style_driver) {
-       /* Open another instance of /dev/ppp and connect the channel to it */
        int flags;
 
+       /* Open an instance of /dev/ppp and connect the channel to it */
        if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
            error("Couldn't get channel number: %m");
            goto err;
@@ -429,6 +472,7 @@ int generic_establish_ppp (int fd)
            error("Couldn't reopen /dev/ppp: %m");
            goto err;
        }
+       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
        if (ioctl(fd, PPPIOCATTCHAN, &chindex) < 0) {
            error("Couldn't attach to channel %d: %m", chindex);
            goto err_close;
@@ -449,7 +493,7 @@ int generic_establish_ppp (int fd)
        }
 
        if (looped)
-           set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) & ~SC_LOOP_TRAFFIC);
+           modify_flags(ppp_dev_fd, SC_LOOP_TRAFFIC, 0);
 
        if (!multilink) {
            add_fd(ppp_dev_fd);
@@ -485,14 +529,14 @@ int generic_establish_ppp (int fd)
        }
     }
 
-    looped = 0;
-
     /*
      * Enable debug in the driver if requested.
      */
     if (!looped)
        set_kdebugflag (kdebugflag);
 
+    looped = 0;
+
     SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
            driver_version, driver_modification, driver_patch));
 
@@ -517,7 +561,10 @@ void tty_disestablish_ppp(int tty_fd)
  * Flush the tty output buffer so that the TIOCSETD doesn't hang.
  */
        if (tcflush(tty_fd, TCIOFLUSH) < 0)
+       {
            warn("tcflush failed: %m");
+           goto flushfailed;
+       }
 /*
  * Restore the previous line discipline
  */
@@ -525,7 +572,7 @@ void tty_disestablish_ppp(int tty_fd)
            if ( ! ok_error (errno))
                error("ioctl(TIOCSETD, N_TTY): %m (line %d)", __LINE__);
        }
-       
+
        if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
            if ( ! ok_error (errno))
                warn("ioctl(TIOCNXCL): %m (line %d)", __LINE__);
@@ -537,6 +584,7 @@ void tty_disestablish_ppp(int tty_fd)
                warn("Couldn't restore device fd flags: %m");
        }
     }
+flushfailed:
     initfdflags = -1;
 
     generic_disestablish_ppp(tty_fd);
@@ -554,16 +602,19 @@ void generic_disestablish_ppp(int dev_fd)
        close(ppp_fd);
        ppp_fd = -1;
        if (demand) {
-           set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC);
+           modify_flags(ppp_dev_fd, 0, SC_LOOP_TRAFFIC);
            looped = 1;
-       } else if (ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
-           error("Couldn't release PPP unit: %m");
-       if (!multilink)
+       } else if (ppp_dev_fd >= 0) {
+           close(ppp_dev_fd);
            remove_fd(ppp_dev_fd);
+           ppp_dev_fd = -1;
+       }
     } else {
        /* old-style driver */
        if (demand)
            set_ppp_fd(slave_fd);
+       else
+           ppp_dev_fd = -1;
     }
 }
 
@@ -573,12 +624,24 @@ void generic_disestablish_ppp(int dev_fd)
  */
 static int make_ppp_unit()
 {
-       int x;
+       int x, flags;
+
+       if (ppp_dev_fd >= 0) {
+               dbglog("in make_ppp_unit, already had /dev/ppp open?");
+               close(ppp_dev_fd);
+       }
+       ppp_dev_fd = open("/dev/ppp", O_RDWR);
+       if (ppp_dev_fd < 0)
+               fatal("Couldn't open /dev/ppp: %m");
+       flags = fcntl(ppp_dev_fd, F_GETFL);
+       if (flags == -1
+           || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+               warn("Couldn't set /dev/ppp to nonblock: %m");
 
        ifunit = req_unit;
        x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
        if (x < 0 && req_unit >= 0 && errno == EEXIST) {
-               warn("Couldn't allocate PPP unit %d as it is already in use");
+               warn("Couldn't allocate PPP unit %d as it is already in use", req_unit);
                ifunit = -1;
                x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);
        }
@@ -593,20 +656,16 @@ static int make_ppp_unit()
  */
 void cfg_bundle(int mrru, int mtru, int rssn, int tssn)
 {
-       int flags;
-
        if (!new_style_driver)
                return;
 
        /* set the mrru, mtu and flags */
        if (ioctl(ppp_dev_fd, PPPIOCSMRRU, &mrru) < 0)
                error("Couldn't set MRRU: %m");
-       flags = get_flags(ppp_dev_fd);
-       flags &= ~(SC_MP_SHORTSEQ | SC_MP_XSHORTSEQ);
-       flags |= (rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
-               | (mrru? SC_MULTILINK: 0);
 
-       set_flags(ppp_dev_fd, flags);
+       modify_flags(ppp_dev_fd, SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ|SC_MULTILINK,
+                    ((rssn? SC_MP_SHORTSEQ: 0) | (tssn? SC_MP_XSHORTSEQ: 0)
+                     | (mrru? SC_MULTILINK: 0)));
 
        /* connect up the channel */
        if (ioctl(ppp_fd, PPPIOCCONNECT, &ifunit) < 0)
@@ -640,17 +699,25 @@ void make_new_bundle(int mrru, int mtru, int rssn, int tssn)
  */
 int bundle_attach(int ifnum)
 {
+       int master_fd;
+
        if (!new_style_driver)
                return -1;
 
-       if (ioctl(ppp_dev_fd, PPPIOCATTACH, &ifnum) < 0) {
-               if (errno == ENXIO)
+       master_fd = open("/dev/ppp", O_RDWR);
+       if (master_fd < 0)
+               fatal("Couldn't open /dev/ppp: %m");
+       if (ioctl(master_fd, PPPIOCATTACH, &ifnum) < 0) {
+               if (errno == ENXIO) {
+                       close(master_fd);
                        return 0;       /* doesn't still exist */
+               }
                fatal("Couldn't attach to interface unit %d: %m\n", ifnum);
        }
        if (ioctl(ppp_fd, PPPIOCCONNECT, &ifnum) < 0)
                fatal("Couldn't connect to interface unit %d: %m", ifnum);
-       set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_MULTILINK);
+       modify_flags(master_fd, 0, SC_MULTILINK);
+       close(master_fd);
 
        ifunit = ifnum;
        return 1;
@@ -673,20 +740,20 @@ void clean_check(void)
            case SC_RCV_B7_0:
                s = "all had bit 7 set to 1";
                break;
-               
+
            case SC_RCV_B7_1:
                s = "all had bit 7 set to 0";
                break;
-               
+
            case SC_RCV_EVNP:
                s = "all had odd parity";
                break;
-               
+
            case SC_RCV_ODDP:
                s = "all had even parity";
                break;
            }
-           
+
            if (s != NULL) {
                warn("Receive serial link is not 8-bit clean:");
                warn("Problem: %s", s);
@@ -694,7 +761,7 @@ void clean_check(void)
        }
     }
 }
-       
+
 
 /*
  * List of valid speeds.
@@ -811,7 +878,7 @@ static int translate_speed (int bps)
 static int baud_rate_of (int speed)
 {
     struct speed *speedp;
-    
+
     if (speed != 0) {
        for (speedp = speeds; speedp->speed_int; speedp++) {
            if (speed == speedp->speed_val)
@@ -839,10 +906,10 @@ void set_up_tty(int tty_fd, int local)
            fatal("tcgetattr: %m (line %d)", __LINE__);
        return;
     }
-    
+
     if (!restore_term)
        inittermios = tios;
-    
+
     tios.c_cflag     &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
     tios.c_cflag     |= CS8 | CREAD | HUPCL;
 
@@ -851,7 +918,7 @@ void set_up_tty(int tty_fd, int local)
     tios.c_lflag      = 0;
     tios.c_cc[VMIN]   = 1;
     tios.c_cc[VTIME]  = 0;
-    
+
     if (local || !modem)
        tios.c_cflag ^= (CLOCAL | HUPCL);
 
@@ -873,7 +940,7 @@ void set_up_tty(int tty_fd, int local)
     default:
        break;
     }
-    
+
     speed = translate_speed(inspeed);
     if (speed) {
        cfsetospeed (&tios, speed);
@@ -892,7 +959,7 @@ void set_up_tty(int tty_fd, int local)
     if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
        if (!ok_error(errno))
            fatal("tcsetattr: %m (line %d)", __LINE__);
-    
+
     baud_rate    = baud_rate_of(speed);
     restore_term = 1;
 }
@@ -927,7 +994,7 @@ void restore_tty (int tty_fd)
  */
        if (!default_device)
            inittermios.c_lflag &= ~(ECHO | ECHONL);
-       
+
        if (tcsetattr(tty_fd, TCSAFLUSH, &inittermios) < 0) {
            if (! ok_error (errno))
                warn("tcsetattr: %m (line %d)", __LINE__);
@@ -946,6 +1013,7 @@ void output (int unit, unsigned char *p, int len)
     int proto;
 
     dump_packet("sent", p, len);
+    if (snoop_send_hook) snoop_send_hook(p, len);
 
     if (len < PPP_HDRLEN)
        return;
@@ -953,11 +1021,11 @@ void output (int unit, unsigned char *p, int len)
        p += 2;
        len -= 2;
        proto = (p[0] << 8) + p[1];
-       if (ifunit >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
+       if (ppp_dev_fd >= 0 && !(proto >= 0xc000 || proto == PPP_CCPFRAG))
            fd = ppp_dev_fd;
     }
     if (write(fd, p, len) < 0) {
-       if (errno == EWOULDBLOCK || errno == ENOBUFS
+       if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS
            || errno == ENXIO || errno == EIO || errno == EINTR)
            warn("write: warning: %m (%d)", errno);
        else
@@ -989,6 +1057,8 @@ void wait_input(struct timeval *timo)
  */
 void add_fd(int fd)
 {
+    if (fd >= FD_SETSIZE)
+       fatal("internal error: file descriptor too large (%d)", fd);
     FD_SET(fd, &in_fds);
     if (fd > max_in_fd)
        max_in_fd = fd;
@@ -1021,15 +1091,17 @@ int read_packet (unsigned char *buf)
     nr = -1;
     if (ppp_fd >= 0) {
        nr = read(ppp_fd, buf, len);
-       if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+       if (nr < 0 && errno != EWOULDBLOCK && errno != EAGAIN
+           && errno != EIO && errno != EINTR)
            error("read: %m");
        if (nr < 0 && errno == ENXIO)
            return 0;
     }
-    if (nr < 0 && new_style_driver && ifunit >= 0) {
+    if (nr < 0 && new_style_driver && ppp_dev_fd >= 0) {
        /* N.B. we read ppp_fd first since LCP packets come in there. */
        nr = read(ppp_dev_fd, buf, len);
-       if (nr < 0 && errno != EWOULDBLOCK && errno != EIO && errno != EINTR)
+       if (nr < 0 && errno != EWOULDBLOCK && errno != EAGAIN
+           && errno != EIO && errno != EINTR)
            error("read /dev/ppp: %m");
        if (nr < 0 && errno == ENXIO)
            return 0;
@@ -1063,7 +1135,7 @@ get_loop_output(void)
     if (n == 0)
        fatal("eof on loopback");
 
-    if (errno != EWOULDBLOCK)
+    if (errno != EWOULDBLOCK && errno != EAGAIN)
        fatal("read from loopback: %m(%d)", errno);
 
     return rv;
@@ -1082,39 +1154,52 @@ netif_set_mtu(int unit, int mtu)
     memset (&ifr, '\0', sizeof (ifr));
     strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
     ifr.ifr_mtu = mtu;
-       
+
     if (ifunit >= 0 && ioctl(sock_fd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
        error("ioctl(SIOCSIFMTU): %m (line %d)", __LINE__);
 }
 
+/*
+ * netif_get_mtu - get the MTU on the PPP network interface.
+ */
+int
+netif_get_mtu(int unit)
+{
+    struct ifreq ifr;
+
+    memset (&ifr, '\0', sizeof (ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+    if (ifunit >= 0 && ioctl(sock_fd, SIOCGIFMTU, (caddr_t) &ifr) < 0) {
+       error("ioctl(SIOCGIFMTU): %m (line %d)", __LINE__);
+       return 0;
+    }
+    return ifr.ifr_mtu;
+}
+
 /********************************************************************
  *
  * tty_send_config - configure the transmit characteristics of
  * the ppp interface.
  */
 
-void tty_send_config (int mtu,u_int32_t asyncmap,int pcomp,int accomp)
+void tty_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp)
 {
-    u_int x;
+       int x;
 
-/*
- * Set the asyncmap and other parameters for the ppp device
- */
-    if (!still_ppp())
-       return;
-    link_mtu = mtu;
-    SYSDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
-    if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
-       if (!ok_error(errno))
-           fatal("ioctl(PPPIOCSASYNCMAP): %m (line %d)", __LINE__);
-       return;
-    }
-    
-    x = get_flags(ppp_fd);
-    x = pcomp  ? x | SC_COMP_PROT : x & ~SC_COMP_PROT;
-    x = accomp ? x | SC_COMP_AC   : x & ~SC_COMP_AC;
-    x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC;
-    set_flags(ppp_fd, x);
+       if (!still_ppp())
+               return;
+       link_mtu = mtu;
+       if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+               if (errno != EIO && errno != ENOTTY)
+                       error("Couldn't set transmit async character map: %m");
+               ++error_count;
+               return;
+       }
+
+       x = (pcomp? SC_COMP_PROT: 0) | (accomp? SC_COMP_AC: 0)
+           | (sync_serial? SC_SYNC: 0);
+       modify_flags(ppp_fd, SC_COMP_PROT|SC_COMP_AC|SC_SYNC, x);
 }
 
 /********************************************************************
@@ -1141,31 +1226,29 @@ void tty_set_xaccm (ext_accm accm)
  * the ppp interface.
  */
 
-void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
+void tty_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp)
 {
-    SYSDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
 /*
  * If we were called because the link has gone down then there is nothing
  * which may be done. Just return without incident.
  */
-    if (!still_ppp())
-       return;
+       if (!still_ppp())
+               return;
 /*
  * Set the receiver parameters
  */
-    if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
-       if ( ! ok_error (errno))
-           error("ioctl(PPPIOCSMRU): %m (line %d)", __LINE__);
-    }
-    if (new_style_driver && ifunit >= 0
-       && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
-       error("Couldn't set MRU in generic PPP layer: %m");
+       if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+               if (errno != EIO && errno != ENOTTY)
+                       error("Couldn't set channel receive MRU: %m");
+       }
+       if (new_style_driver && ppp_dev_fd >= 0
+           && ioctl(ppp_dev_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+               error("Couldn't set MRU in generic PPP layer: %m");
 
-    SYSDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
-    if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
-       if (!ok_error(errno))
-           error("ioctl(PPPIOCSRASYNCMAP): %m (line %d)", __LINE__);
-    }
+       if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+               if (errno != EIO && errno != ENOTTY)
+                       error("Couldn't set channel receive asyncmap: %m");
+       }
 }
 
 /********************************************************************
@@ -1174,7 +1257,8 @@ void tty_recv_config (int mru,u_int32_t asyncmap,int pcomp,int accomp)
  * is acceptable for use.
  */
 
-int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
+int
+ccp_test(int unit, u_char *opt_ptr, int opt_len, int for_transmit)
 {
     struct ppp_option_data data;
 
@@ -1196,12 +1280,11 @@ int ccp_test (int unit, u_char *opt_ptr, int opt_len, int for_transmit)
 
 void ccp_flags_set (int unit, int isopen, int isup)
 {
-    if (still_ppp() && ifunit >= 0) {
-       int x = get_flags(ppp_dev_fd);
-       x = isopen? x | SC_CCP_OPEN : x &~ SC_CCP_OPEN;
-       x = isup?   x | SC_CCP_UP   : x &~ SC_CCP_UP;
-       set_flags (ppp_dev_fd, x);
-    }
+       int x;
+
+       x = (isopen? SC_CCP_OPEN: 0) | (isup? SC_CCP_UP: 0);
+       if (still_ppp() && ppp_dev_fd >= 0)
+               modify_flags(ppp_dev_fd, SC_CCP_OPEN|SC_CCP_UP, x);
 }
 
 #ifdef PPP_FILTER
@@ -1241,7 +1324,7 @@ get_idle_time(u, ip)
     struct ppp_idle *ip;
 {
     return ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) >= 0;
-} 
+}
 
 /********************************************************************
  *
@@ -1278,9 +1361,13 @@ get_ppp_stats(u, stats)
 
 int ccp_fatal_error (int unit)
 {
-    int x = get_flags(ppp_dev_fd);
+       int flags;
 
-    return x & SC_DC_FERROR;
+       if (ioctl(ppp_dev_fd, PPPIOCGFLAGS, &flags) < 0) {
+               error("Couldn't read compression error flags: %m");
+               flags = 0;
+       }
+       return flags & SC_DC_FERROR;
 }
 
 /********************************************************************
@@ -1341,8 +1428,8 @@ static int read_route_table (struct rtentry *rt);
 static void close_route_table (void)
 {
     if (route_fd != (FILE *) 0) {
-        fclose (route_fd);
-        route_fd = (FILE *) 0;
+       fclose (route_fd);
+       route_fd = (FILE *) 0;
     }
 }
 
@@ -1361,8 +1448,8 @@ static int open_route_table (void)
     path = path_to_procfs("/net/route");
     route_fd = fopen (path, "r");
     if (route_fd == NULL) {
-        error("can't open routing table %s: %m", path);
-        return 0;
+       error("can't open routing table %s: %m", path);
+       return 0;
     }
 
     route_dev_col = 0;         /* default to usual columns */
@@ -1410,7 +1497,7 @@ static int read_route_table(struct rtentry *rt)
 {
     char *cols[ROUTE_MAX_COLS], *p;
     int col;
-       
+
     memset (rt, '\0', sizeof (struct rtentry));
 
     if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
@@ -1444,15 +1531,15 @@ static int defaultroute_exists (struct rtentry *rt)
     int result = 0;
 
     if (!open_route_table())
-        return 0;
+       return 0;
 
     while (read_route_table(rt) != 0) {
-        if ((rt->rt_flags & RTF_UP) == 0)
+       if ((rt->rt_flags & RTF_UP) == 0)
            continue;
 
        if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
            continue;
-        if (SIN_ADDR(rt->rt_dst) == 0L) {
+       if (SIN_ADDR(rt->rt_dst) == 0L) {
            result = 1;
            break;
        }
@@ -1512,13 +1599,15 @@ int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
     SET_SA_FAMILY (rt.rt_dst,     AF_INET);
     SET_SA_FAMILY (rt.rt_gateway, AF_INET);
 
+    rt.rt_dev = ifname;
+
     if (kernel_version > KVERSION(2,1,0)) {
        SET_SA_FAMILY (rt.rt_genmask, AF_INET);
        SIN_ADDR(rt.rt_genmask) = 0L;
     }
 
     SIN_ADDR(rt.rt_gateway) = gateway;
-    
+
     rt.rt_flags = RTF_UP | RTF_GATEWAY;
     if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) {
        if ( ! ok_error ( errno ))
@@ -1551,7 +1640,7 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
     }
 
     SIN_ADDR(rt.rt_gateway) = gateway;
-    
+
     rt.rt_flags = RTF_UP | RTF_GATEWAY;
     if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
        if (still_ppp()) {
@@ -1576,7 +1665,7 @@ int sifproxyarp (int unit, u_int32_t his_adr)
 
     if (has_proxy_arp == 0) {
        memset (&arpreq, '\0', sizeof(arpreq));
-    
+
        SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
        SIN_ADDR(arpreq.arp_pa) = his_adr;
        arpreq.arp_flags = ATF_PERM | ATF_PUBL;
@@ -1640,7 +1729,7 @@ int cifproxyarp (int unit, u_int32_t his_adr)
     }
     return 1;
 }
-     
+
 /********************************************************************
  *
  * get_ether_addr - get the hardware address of an interface on the
@@ -1654,10 +1743,13 @@ static int get_ether_addr (u_int32_t ipaddr,
     struct ifreq *ifr, *ifend;
     u_int32_t ina, mask;
     char *aliasp;
-    struct ifreq ifreq;
+    struct ifreq ifreq, bestifreq;
     struct ifconf ifc;
     struct ifreq ifs[MAX_IFS];
-    
+
+    u_int32_t bestmask=0;
+    int found_interface = 0;
+
     ifc.ifc_len = sizeof(ifs);
     ifc.ifc_req = ifs;
     if (ioctl(sock_fd, SIOCGIFCONF, &ifc) < 0) {
@@ -1677,7 +1769,7 @@ static int get_ether_addr (u_int32_t ipaddr,
        if (ifr->ifr_addr.sa_family == AF_INET) {
            ina = SIN_ADDR(ifr->ifr_addr);
            strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
-            SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+           SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
                        ifreq.ifr_name));
 /*
  * Check that the interface is up, and not point-to-point
@@ -1692,22 +1784,28 @@ static int get_ether_addr (u_int32_t ipaddr,
  * Get its netmask and check that it's on the right subnet.
  */
            if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0)
-               continue;
+               continue;
 
            mask = SIN_ADDR(ifreq.ifr_addr);
            SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
-                       ip_ntoa(ina), ntohl(mask)));
+                      ip_ntoa(ina), ntohl(mask)));
 
            if (((ipaddr ^ ina) & mask) != 0)
-               continue;
-           break;
+               continue; /* no match */
+           /* matched */
+           if (mask >= bestmask) {
+               /* Compare using >= instead of > -- it is possible for
+                  an interface to have a netmask of 0.0.0.0 */
+               found_interface = 1;
+               bestifreq = ifreq;
+               bestmask = mask;
+           }
        }
     }
-    
-    if (ifr >= ifend)
-        return 0;
 
-    strlcpy(name, ifreq.ifr_name, namelen);
+    if (!found_interface) return 0;
+
+    strlcpy(name, bestifreq.ifr_name, namelen);
 
     /* trim off the :1 in eth0:1 */
     aliasp = strchr(name, ':');
@@ -1718,14 +1816,14 @@ static int get_ether_addr (u_int32_t ipaddr,
 /*
  * Now get the hardware address.
  */
-    memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
-    if (ioctl (sock_fd, SIOCGIFHWADDR, &ifreq) < 0) {
-        error("SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
-        return 0;
+    memset (&bestifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
+    if (ioctl (sock_fd, SIOCGIFHWADDR, &bestifreq) < 0) {
+       error("SIOCGIFHWADDR(%s): %m", bestifreq.ifr_name);
+       return 0;
     }
 
     memcpy (hwaddr,
-           &ifreq.ifr_hwaddr,
+           &bestifreq.ifr_hwaddr,
            sizeof (struct sockaddr));
 
     SYSDEBUG ((LOG_DEBUG,
@@ -1791,14 +1889,14 @@ u_int32_t GetMask (u_int32_t addr)
     struct ifreq ifs[MAX_IFS];
 
     addr = ntohl(addr);
-    
+
     if (IN_CLASSA(addr))       /* determine network mask for address class */
        nmask = IN_CLASSA_NET;
     else if (IN_CLASSB(addr))
            nmask = IN_CLASSB_NET;
     else
            nmask = IN_CLASSC_NET;
-    
+
     /* class D nets are disallowed by bad_ip_adrs */
     mask = netmask | htonl(nmask);
 /*
@@ -1811,7 +1909,7 @@ u_int32_t GetMask (u_int32_t addr)
            warn("ioctl(SIOCGIFCONF): %m (line %d)", __LINE__);
        return mask;
     }
-    
+
     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
     for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
 /*
@@ -1828,7 +1926,7 @@ u_int32_t GetMask (u_int32_t addr)
        strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
        if (ioctl(sock_fd, SIOCGIFFLAGS, &ifreq) < 0)
            continue;
-       
+
        if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
            continue;
 /*
@@ -1855,7 +1953,7 @@ static void decode_version (char *buf, int *version,
     *version      = (int) strtoul (buf, &endp, 10);
     *modification = 0;
     *patch        = 0;
-    
+
     if (endp != buf && *endp == '.') {
        buf = endp + 1;
        *modification = (int) strtoul (buf, &endp, 10);
@@ -1898,7 +1996,7 @@ ppp_registered(void)
        error("ioctl(TIOCSETD(PPP)): %m (line %d)", __LINE__);
     } else
        ret = 1;
-    
+
     close(local_fd);
     close(mfd);
     return ret;
@@ -1918,7 +2016,7 @@ int ppp_available(void)
     int    my_version, my_modification, my_patch;
     int osmaj, osmin, ospatch;
 
-    no_ppp_msg = 
+    no_ppp_msg =
        "This system lacks kernel support for PPP.  This could be because\n"
        "the PPP kernel module could not be loaded, or because PPP was not\n"
        "included in the kernel configuration.  If PPP was included as a\n"
@@ -1970,11 +2068,11 @@ int ppp_available(void)
 
 /*
  * Open a socket for doing the ioctl operations.
- */    
+ */
     s = socket(AF_INET, SOCK_DGRAM, 0);
     if (s < 0)
        return 0;
-    
+
     strlcpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
 /*
@@ -1992,10 +2090,10 @@ int ppp_available(void)
  * Ensure that the hardware address is for PPP and not something else
  */
     if (ok)
-        ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
+       ok = ioctl (s, SIOCGIFHWADDR, (caddr_t) &ifr) >= 0;
 
     if (ok && ((ifr.ifr_hwaddr.sa_family & ~0xFF) != ARPHRD_PPP))
-        ok = 0;
+       ok = 0;
 
 /*
  *  This is the PPP device. Validate the version of the driver at this
@@ -2027,7 +2125,7 @@ int ppp_available(void)
            /* The version numbers must match */
            if (driver_version != my_version)
                ok = 0;
-      
+
            /* The modification levels must be legal */
            if (driver_modification < 3) {
                if (driver_modification >= 2) {
@@ -2071,11 +2169,8 @@ void logwtmp (const char *line, const char *name, const char *host)
     utmpname(_PATH_UTMP);
     setutent();
     while ((utp = getutent()) && (utp->ut_pid != mypid))
-        /* nothing */;
+       /* nothing */;
 
-    /* Is this call really necessary? There is another one after the 'put' */
-    endutent();
-    
     if (utp)
        memcpy(&ut, utp, sizeof(ut));
     else
@@ -2084,7 +2179,7 @@ void logwtmp (const char *line, const char *name, const char *host)
 
     if (ut.ut_id[0] == 0)
        strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
-       
+
     strncpy(ut.ut_user, name, sizeof(ut.ut_user));
     strncpy(ut.ut_line, line, sizeof(ut.ut_line));
 
@@ -2101,7 +2196,7 @@ void logwtmp (const char *line, const char *name, const char *host)
     if (ipcp_protent.enabled_flag && ipcp_hisoptions[0].neg_addr)
        memcpy(&ut.ut_addr, (char *) &ipcp_hisoptions[0].hisaddr,
                 sizeof(ut.ut_addr));
-       
+
     /* CL: Makes sure that the logout works */
     if (*host == 0 && *name==0)
        ut.ut_host[0]=0;
@@ -2136,21 +2231,18 @@ void logwtmp (const char *line, const char *name, const char *host)
 
 int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
 {
-    u_int x = get_flags(ppp_dev_fd);
+       u_int x;
 
-    if (vjcomp) {
-        if (ioctl (ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
-           if (! ok_error (errno))
-               error("ioctl(PPPIOCSMAXCID): %m (line %d)", __LINE__);
-           vjcomp = 0;
+       if (vjcomp) {
+               if (ioctl(ppp_dev_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0)
+                       error("Couldn't set up TCP header compression: %m");
+               vjcomp = 0;
        }
-    }
 
-    x = vjcomp  ? x | SC_COMP_TCP     : x &~ SC_COMP_TCP;
-    x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
-    set_flags (ppp_dev_fd, x);
+       x = (vjcomp? SC_COMP_TCP: 0) | (cidcomp? 0: SC_NO_TCP_CCID);
+       modify_flags(ppp_dev_fd, SC_COMP_TCP|SC_NO_TCP_CCID, x);
 
-    return 1;
+       return 1;
 }
 
 /********************************************************************
@@ -2220,15 +2312,15 @@ int sifdown (int u)
 int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
             u_int32_t net_mask)
 {
-    struct ifreq   ifr; 
+    struct ifreq   ifr;
     struct rtentry rt;
-    
+
     memset (&ifr, '\0', sizeof (ifr));
     memset (&rt,  '\0', sizeof (rt));
-    
-    SET_SA_FAMILY (ifr.ifr_addr,    AF_INET); 
-    SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET); 
-    SET_SA_FAMILY (ifr.ifr_netmask, AF_INET); 
+
+    SET_SA_FAMILY (ifr.ifr_addr,    AF_INET);
+    SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+    SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
 
     strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
 /*
@@ -2240,10 +2332,10 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
            if (! ok_error (errno))
                error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
        }
-        else {
+       else {
            warn("ioctl(SIOCSIFADDR): Address already exists");
        }
-        return (0);
+       return (0);
     }
 /*
  *  Set the gateway address
@@ -2251,9 +2343,9 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
     SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
     if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
        if (! ok_error (errno))
-           error("ioctl(SIOCSIFDSTADDR): %m (line %d)", __LINE__); 
+           error("ioctl(SIOCSIFDSTADDR): %m (line %d)", __LINE__);
        return (0);
-    } 
+    }
 /*
  *  Set the netmask.
  *  For recent kernels, force the netmask to 255.255.255.255.
@@ -2264,9 +2356,9 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
        SIN_ADDR(ifr.ifr_netmask) = net_mask;
        if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
            if (! ok_error (errno))
-               error("ioctl(SIOCSIFNETMASK): %m (line %d)", __LINE__); 
+               error("ioctl(SIOCSIFNETMASK): %m (line %d)", __LINE__);
            return (0);
-       } 
+       }
     }
 /*
  *  Add the device route
@@ -2353,7 +2445,7 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
     memset(&ifr, 0, sizeof(ifr));
     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-    
+
     if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
        if (! ok_error (errno)) {
            error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
@@ -2368,7 +2460,7 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
 
 #ifdef INET6
 /********************************************************************
- * 
+ *
  * sif6addr - Config the interface with an IPv6 link-local address
  */
 int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
@@ -2388,7 +2480,7 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
        error("sif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
        return 0;
     }
-    
+
     /* Local interface */
     memset(&ifr6, 0, sizeof(ifr6));
     IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
@@ -2399,7 +2491,7 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
        error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
        return 0;
     }
-    
+
     /* Route to remote host */
     memset(&rt6, 0, sizeof(rt6));
     IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
@@ -2407,7 +2499,7 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
     rt6.rtmsg_dst_len = 10;
     rt6.rtmsg_ifindex = ifr.ifr_ifindex;
     rt6.rtmsg_metric = 1;
-    
+
     if (ioctl(sock6_fd, SIOCADDRT, &rt6) < 0) {
        error("sif6addr: ioctl(SIOCADDRT): %m (line %d)", __LINE__);
        return 0;
@@ -2437,7 +2529,7 @@ int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
        error("cif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
        return 0;
     }
-    
+
     memset(&ifr6, 0, sizeof(ifr6));
     IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
     ifr6.ifr6_ifindex = ifr.ifr_ifindex;
@@ -2448,10 +2540,10 @@ int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
            if (! ok_error (errno))
                error("cif6addr: ioctl(SIOCDIFADDR): %m (line %d)", __LINE__);
        }
-        else {
+       else {
            warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
        }
-        return (0);
+       return (0);
     }
     return 1;
 }
@@ -2547,7 +2639,7 @@ open_ppp_loopback(void)
        /* allocate ourselves a ppp unit */
        if (make_ppp_unit() < 0)
            die(1);
-       set_flags(ppp_dev_fd, SC_LOOP_TRAFFIC);
+       modify_flags(ppp_dev_fd, 0, SC_LOOP_TRAFFIC);
        set_kdebugflag(kdebugflag);
        ppp_fd = -1;
        return ppp_dev_fd;
@@ -2618,12 +2710,12 @@ int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
     int    result = 1;
 
 #ifdef IPX_CHANGE
-    int    skfd; 
+    int    skfd;
     struct ifreq         ifr;
     struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
 
     skfd = socket (AF_IPX, SOCK_DGRAM, 0);
-    if (skfd < 0) { 
+    if (skfd < 0) {
        if (! ok_error (errno))
            dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
        result = 0;
@@ -2669,12 +2761,12 @@ int cipxfaddr (int unit)
     int    result = 1;
 
 #ifdef IPX_CHANGE
-    int    skfd; 
+    int    skfd;
     struct ifreq         ifr;
     struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
 
     skfd = socket (AF_IPX, SOCK_DGRAM, 0);
-    if (skfd < 0) { 
+    if (skfd < 0) {
        if (! ok_error (errno))
            dbglog("socket(AF_IPX): %m (line %d)", __LINE__);
        result = 0;
@@ -2731,7 +2823,7 @@ sys_check_options(void)
 
     if (ipxcp_protent.enabled_flag) {
        struct stat stat_buf;
-        if ((path = path_to_procfs("/net/ipx_interface")) == 0
+       if ((path = path_to_procfs("/net/ipx_interface")) == 0
            || lstat(path, &stat_buf) < 0) {
            error("IPX support is not present in the kernel\n");
            ipxcp_protent.enabled_flag = 0;
@@ -2750,3 +2842,51 @@ sys_check_options(void)
     }
     return 1;
 }
+
+#ifdef INET6
+/*
+ * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
+ *
+ * convert the 48-bit MAC address of eth0 into EUI 64. caller also assumes
+ * that the system has a properly configured Ethernet interface for this
+ * function to return non-zero.
+ */
+int
+ether_to_eui64(eui64_t *p_eui64)
+{
+    struct ifreq ifr;
+    int skfd;
+    const unsigned char *ptr;
+
+    skfd = socket(PF_INET6, SOCK_DGRAM, 0);
+    if(skfd == -1)
+    {
+        warn("could not open IPv6 socket");
+        return 0;
+    }
+
+    strcpy(ifr.ifr_name, "eth0");
+    if(ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
+    {
+        close(skfd);
+        warn("could not obtain hardware address for eth0");
+        return 0;
+    }
+    close(skfd);
+
+    /*
+     * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
+     */
+    ptr = ifr.ifr_hwaddr.sa_data;
+    p_eui64->e8[0] = ptr[0] | 0x02;
+    p_eui64->e8[1] = ptr[1];
+    p_eui64->e8[2] = ptr[2];
+    p_eui64->e8[3] = 0xFF;
+    p_eui64->e8[4] = 0xFE;
+    p_eui64->e8[5] = ptr[3];
+    p_eui64->e8[6] = ptr[4];
+    p_eui64->e8[7] = ptr[5];
+
+    return 1;
+}
+#endif