]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/sys-linux.c
Remove the requirement that redistributions in binary form reproduce
[ppp.git] / pppd / sys-linux.c
index c86a516f0aad475be0818e6cd167798a4fd1ad49..26cadc6e7c797778ca45ca5d80b6eed8f8489b5b 100644 (file)
@@ -2,20 +2,71 @@
  * 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-2004 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. 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.
+ *
+ * 3. 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>
 #endif /* IPX_CHANGE */
 
 #ifdef PPP_FILTER
-#include <net/bpf.h>
+#include <pcap-bpf.h>
 #include <linux/filter.h>
 #endif /* PPP_FILTER */
 
@@ -127,7 +178,14 @@ static int master_fd = -1;
 #ifdef INET6
 static int sock6_fd = -1;
 #endif /* INET6 */
-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 +226,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 +279,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 get_flags (int fd)
+static int modify_flags(int fd, int clear_bits, int set_bits)
 {
-    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;
-}
+       int 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 +308,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 +356,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 +377,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 +435,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 +454,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 +467,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 +488,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 +524,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 +556,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
  */
@@ -537,6 +579,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 +597,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,7 +619,19 @@ 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);
@@ -593,20 +651,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 +694,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;
@@ -889,8 +951,8 @@ void set_up_tty(int tty_fd, int local)
            fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
     }
 
-    if (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0)
-       if (!ok_error(errno))
+    while (tcsetattr(tty_fd, TCSAFLUSH, &tios) < 0 && !ok_error(errno))
+       if (errno != EINTR)
            fatal("tcsetattr: %m (line %d)", __LINE__);
 
     baud_rate    = baud_rate_of(speed);
@@ -954,11 +1016,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
@@ -990,6 +1052,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;
@@ -1022,15 +1086,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;
@@ -1064,7 +1130,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;
@@ -1112,28 +1178,23 @@ netif_get_mtu(int unit)
  * 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;
-    }
+       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 = 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);
+       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);
 }
 
 /********************************************************************
@@ -1160,31 +1221,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");
+       }
 }
 
 /********************************************************************
@@ -1216,12 +1275,11 @@ 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
@@ -1298,9 +1356,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;
 }
 
 /********************************************************************
@@ -2164,21 +2226,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;
 }
 
 /********************************************************************
@@ -2575,7 +2634,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;