]> git.ozlabs.org Git - ppp.git/blobdiff - linux/ppp.c
Added updetach option.
[ppp.git] / linux / ppp.c
index 06f39c642149f5411883685c92fb0bdb5f4d0178..aa7af25d8d6187a67e1abfa8bc4732076f8c09a2 100644 (file)
@@ -7,7 +7,7 @@
  *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
  *
- *  ==FILEVERSION 971016==
+ *  ==FILEVERSION 980319==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
 #define CHECK_CHARACTERS       1
 #define PPP_COMPRESS           1
 
-/* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */
+/* $Id: ppp.c,v 1.17 1998/03/24 23:54:59 paulus Exp $ */
 
 #include <linux/version.h>
+#include <linux/config.h> /* for CONFIG_KERNELD */
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+
+#if LINUX_VERSION_CODE >= VERSION(2,1,68)
+#include <linux/rtnetlink.h>
+#endif
+
 #include <linux/inet.h>
 #include <linux/ioctl.h>
 
@@ -103,6 +109,10 @@ typedef struct sk_buff          sk_buff;
 #include <linux/if_pppvar.h>
 #include <linux/ppp-comp.h>
 
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
 #ifndef PPP_IPX
 #define PPP_IPX 0x2b  /* IPX protocol over PPP */
 #endif
@@ -158,6 +168,22 @@ do {                                                                         \
 #define test_and_set_bit(nr, addr)     set_bit(nr, addr)
 #endif
 
+#if LINUX_VERSION_CODE < VERSION(2,1,57)
+#define signal_pending(p)      ((p)->signal & ~(p)->blocked)
+#endif
+
+#if LINUX_VERSION_CODE < VERSION(2,1,25)
+#define net_device_stats       enet_statistics
+#endif
+
+#if LINUX_VERSION_CODE < VERSION(2,1,60)
+typedef int            rw_ret_t;
+typedef unsigned int   rw_count_t;
+#else
+typedef ssize_t                rw_ret_t;
+typedef size_t         rw_count_t;
+#endif
+
 static int ppp_register_compressor (struct compressor *cp);
 static void ppp_unregister_compressor (struct compressor *cp);
 
@@ -220,7 +246,7 @@ static int ppp_dev_open (struct device *);
 static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
 static int ppp_dev_close (struct device *);
 static int ppp_dev_xmit (sk_buff *, struct device *);
-static struct enet_statistics *ppp_dev_stats (struct device *);
+static struct net_device_stats *ppp_dev_stats (struct device *);
 
 #if LINUX_VERSION_CODE < VERSION(2,1,15)
 static int ppp_dev_header (sk_buff *, struct device *, __u16,
@@ -233,17 +259,18 @@ static int ppp_dev_rebuild (void *eth, struct device *dev,
  * TTY callbacks
  */
 
-static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
-                        unsigned int);
-static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *,
-                         unsigned int);
+static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+                            rw_count_t);
+static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+                             rw_count_t);
 static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
                          unsigned long);
 #if LINUX_VERSION_CODE < VERSION(2,1,23)
 static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
                      struct file *filp, int sel_type, select_table * wait);
 #else
-static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait);
+static unsigned int ppp_tty_poll (struct tty_struct *tty, struct file *filp,
+                                 poll_table * wait);
 #endif
 static int ppp_tty_open (struct tty_struct *);
 static void ppp_tty_close (struct tty_struct *);
@@ -403,6 +430,9 @@ ppp_first_time (void)
  */
        (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
        ppp_ldisc.magic         = TTY_LDISC_MAGIC;
+#if LINUX_VERSION_CODE >= VERSION(2,1,28)
+       ppp_ldisc.name          = "ppp";
+#endif
        ppp_ldisc.open          = ppp_tty_open;
        ppp_ldisc.close         = ppp_tty_close;
        ppp_ldisc.read          = ppp_tty_read;
@@ -466,11 +496,13 @@ ppp_init_dev (struct device *dev)
 
        /* New-style flags */
        dev->flags      = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+#if LINUX_VERSION_CODE < VERSION(2,1,67)
        dev->family     = AF_INET;
        dev->pa_addr    = 0;
        dev->pa_brdaddr = 0;
        dev->pa_mask    = 0;
        dev->pa_alen    = 4; /* sizeof (__u32) */
+#endif
 
        return 0;
 }
@@ -671,9 +703,7 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
  */
        if (new_wbuf == NULL || new_tbuf == NULL ||
            new_rbuf == NULL || new_cbuf == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp: failed to allocate new buffers\n");
+               printk (KERN_ERR "ppp: failed to allocate new buffers\n");
 
                ppp_free_buf (new_wbuf);
                ppp_free_buf (new_tbuf);
@@ -788,11 +818,6 @@ ppp_release (struct ppp *ppp)
        if (tty != NULL && tty->disc_data == ppp)
                tty->disc_data = NULL;  /* Break the tty->ppp link */
 
-       if (dev && dev->flags & IFF_UP) {
-               dev->flags &= ~IFF_UP;   /* prevent recursion */
-               dev_close (dev); /* close the device properly */
-       }
-
        ppp_free_buf (ppp->rbuf);
        ppp_free_buf (ppp->wbuf);
        ppp_free_buf (ppp->cbuf);
@@ -871,8 +896,7 @@ ppp_tty_open (struct tty_struct *tty)
  * There should not be an existing table for this slot.
  */
        if (ppp) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
+               printk (KERN_ERR
                        "ppp_tty_open: gack! tty already associated to %s!\n",
                        ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
                                                : "unknown");
@@ -894,8 +918,7 @@ ppp_tty_open (struct tty_struct *tty)
        } else {
                ppp = ppp_alloc();
                if (ppp == NULL) {
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR "ppp_alloc failed\n");
+                       printk (KERN_ERR "ppp_alloc failed\n");
                        return -ENFILE;
                }
 /*
@@ -909,9 +932,8 @@ ppp_tty_open (struct tty_struct *tty)
  */
                ppp->slcomp = slhc_init (16, 16);
                if (ppp->slcomp == NULL) {
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR "ppp_tty_open: "
-                                       "no space for compression buffers!\n");
+                       printk (KERN_ERR "ppp_tty_open: "
+                               "no space for compression buffers!\n");
                        ppp_release (ppp);
                        return -ENOMEM;
                }
@@ -927,9 +949,8 @@ ppp_tty_open (struct tty_struct *tty)
  */
                ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
                if (ppp->ubuf == NULL) {
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR "ppp_tty_open: "
-                                       "no space for user receive buffer\n");
+                       printk (KERN_ERR "ppp_tty_open: "
+                               "no space for user receive buffer\n");
                        ppp_release (ppp);
                        return -ENOMEM;
                }
@@ -1401,9 +1422,7 @@ ppp_doframe (struct ppp *ppp)
  */
                        new_data = kmalloc (ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
                        if (new_data == NULL) {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk (KERN_ERR
-                                               "ppp_doframe: no memory\n");
+                               printk (KERN_ERR "ppp_doframe: no memory\n");
                                new_count = DECOMP_ERROR;
                        } else {
                                new_count = (*ppp->sc_rcomp->decompress)
@@ -1422,8 +1441,7 @@ ppp_doframe (struct ppp *ppp)
 
                        case DECOMP_FATALERROR:
                                ppp->flags |= SC_DC_FERROR;
-                               if (ppp->flags & SC_DEBUG)
-                                       printk(KERN_ERR "ppp: fatal decomp error\n");
+                               printk(KERN_ERR "ppp: fatal decomp error\n");
                                break;
                        }
 /*
@@ -1441,6 +1459,10 @@ ppp_doframe (struct ppp *ppp)
                        (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
                                                  data, count);
                }
+       } else if (proto == PPP_COMP && (ppp->flags & SC_DEBUG)) {
+               printk(KERN_DEBUG "ppp: frame not decompressed: "
+                      "flags=%x, count=%d, sc_rc_state=%p\n",
+                      ppp->flags, count, ppp->sc_rc_state);
        }
 /*
  * Process the uncompressed frame.
@@ -1778,6 +1800,9 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
                }
                break;
        }
+       if (ppp->flags & SC_DEBUG)
+               printk(KERN_DEBUG "ppp_proto_ccp: %s code %d, flags=%x\n",
+                      (rcvd? "rcvd": "sent"), CCP_CODE(dp), ppp->flags);
        restore_flags(flags);
 }
 
@@ -1811,14 +1836,14 @@ rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
    waiting if necessary
 */
 
-static int
+static rw_ret_t
 ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
-             unsigned int nr)
+             rw_count_t nr)
 {
        struct ppp *ppp = tty2ppp (tty);
        __u8 c;
-       int len, ret;
        int error;
+       rw_ret_t len, ret;
 
 #define GETC(c)                                                \
 {                                                      \
@@ -1864,7 +1889,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
                        current->state   = TASK_INTERRUPTIBLE;
                        schedule ();
 
-                       if (current->signal & ~current->blocked)
+                       if (signal_pending(current))
                                return -EINTR;
                        continue;
                }
@@ -1897,7 +1922,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
                                "ppp_tty_read: sleeping(read_wait)\n");
 #endif
                interruptible_sleep_on (&ppp->read_wait);
-               if (current->signal & ~current->blocked)
+               if (signal_pending(current))
                        return -EINTR;
        }
 
@@ -1910,8 +1935,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
 
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_DEBUG
-                               "ppp: read of %u bytes too small for %d "
-                               "frame\n", nr, len + 2);
+                               "ppp: read of %lu bytes too small for %ld "
+                               "frame\n", (unsigned long) nr, (long) len + 2);
                ppp->stats.ppp_ierrors++;
                error = -EOVERFLOW;
                goto out;
@@ -1943,10 +1968,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
        }
 
        clear_bit (0, &ppp->ubuf->locked);
-#if 0
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp_tty_read: passing %d bytes up\n", ret);
-#endif
        return ret;
 
 out:
@@ -2101,16 +2122,15 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
            (control == PPP_UI)                 &&
            (proto != PPP_LCP)                  &&
            (proto != PPP_CCP)) {
-               new_data = kmalloc (ppp->mtu, GFP_ATOMIC);
+               new_data = kmalloc (ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);
                if (new_data == NULL) {
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR
-                                       "ppp_dev_xmit_frame: no memory\n");
+                       printk (KERN_ERR "ppp_dev_xmit_frame: no memory\n");
                        return 1;
                }
 
                new_count = (*ppp->sc_xcomp->compress)
-                   (ppp->sc_xc_state, data, new_data, count, ppp->mtu);
+                   (ppp->sc_xc_state, data, new_data, count,
+                    ppp->mtu + PPP_HDRLEN);
 
                if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
                        ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
@@ -2172,13 +2192,14 @@ send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
  * we have to put the FCS field on ourselves
  */
 
-static int
+static rw_ret_t
 ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
-              unsigned int count)
+              rw_count_t count)
 {
        struct ppp *ppp = tty2ppp (tty);
        __u8 *new_data;
        int error;
+       struct wait_queue wait = {current, NULL};
 
 /*
  * Verify the pointers.
@@ -2197,7 +2218,7 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_WARNING
                                "ppp_tty_write: truncating user packet "
-                               "from %u to mtu %d\n", count,
+                               "from %lu to mtu %d\n", (unsigned long) count,
                                PPP_MTU + PPP_HDRLEN);
                count = PPP_MTU + PPP_HDRLEN;
        }
@@ -2206,43 +2227,48 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
  */
        new_data = kmalloc (count, GFP_KERNEL);
        if (new_data == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp_tty_write: no memory\n");
+               printk (KERN_ERR "ppp_tty_write: no memory\n");
                return 0;
        }
 /*
  * Retrieve the user's buffer
  */
        COPY_FROM_USER (error, new_data, data, count);
-       if (error) {
-               kfree (new_data);
-               return error;
-       }
+       if (error)
+               goto out_free;
 /*
- * lock this PPP unit so we will be the only writer;
- * sleep if necessary
+ * Lock this PPP unit so we will be the only writer,
+ * sleeping if necessary.
+ *
+ * Note that we add our task to the wait queue before
+ * attempting to lock, as the lock flag may be cleared
+ * from an interrupt.
  */
-       while (lock_buffer (ppp->tbuf) != 0) {
+       add_wait_queue(&ppp->write_wait, &wait);
+       while (1) {
+               error = 0;
                current->timeout = 0;
-#if 0
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
-#endif
-               interruptible_sleep_on (&ppp->write_wait);
+               current->state = TASK_INTERRUPTIBLE;
+               if (lock_buffer(ppp->tbuf) == 0)
+                       break;
+               schedule();
 
+               error = -EIO;
                ppp = tty2ppp (tty);
-               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
-                   || tty != ppp->tty) {
-                       kfree (new_data);
-                       return 0;
-               }
-
-               if (current->signal & ~current->blocked) {
-                       kfree (new_data);
-                       return -EINTR;
+               if (!ppp || ppp->magic != PPP_MAGIC || 
+                   !ppp->inuse || tty != ppp->tty) {
+                       printk("ppp_tty_write: %p invalid after wait!\n", ppp);
+                       break;
                }
+               error = -EINTR;
+               if (signal_pending(current))
+                       break;
        }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&ppp->write_wait, &wait);
+       if (error)
+               goto out_free;
+
 /*
  * Change the LQR frame
  */
@@ -2262,34 +2288,31 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
        } else {
                ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
        }
+       error = count;
 
+out_free:
        kfree (new_data);
-       return (int) count;
+       return error;
 }
 
 /*
- * Process the BSD compression IOCTL event for the tty device.
+ * Process the set-compression ioctl.
  */
 
 static int
 ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 {
        struct compressor *cp;
-       struct ppp_option_data data;
-       int error;
-       int nb;
+       int error, nb;
+       unsigned long flags;
        __u8 *ptr;
        __u8 ccp_option[CCP_MAX_OPTION_LENGTH];
-       unsigned long flags;
+       struct ppp_option_data data;
 
 /*
  * Fetch the compression parameters
  */
-       COPY_FROM_USER (error,
-                       &data,
-                       odp,
-                       sizeof (data));
-
+       COPY_FROM_USER (error, &data, odp, sizeof (data));
        if (error != 0)
                return error;
 
@@ -2298,11 +2321,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
        if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
                nb = CCP_MAX_OPTION_LENGTH;
 
-       COPY_FROM_USER (error,
-                       ccp_option,
-                       ptr,
-                       nb);
-
+       COPY_FROM_USER (error, ccp_option, ptr, nb);
        if (error != 0)
                return error;
 
@@ -2311,52 +2330,58 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 
        save_flags(flags);
        cli();
-       ppp->flags &= ~(SC_COMP_RUN | SC_DECOMP_RUN);
+       ppp->flags &= ~(data.transmit? SC_COMP_RUN: SC_DECOMP_RUN);
        restore_flags(flags);
 
        cp = find_compressor (ccp_option[0]);
-       if (cp != (struct compressor *) 0) {
-               /*
-                * Found a handler for the protocol - try to allocate
-                * a compressor or decompressor.
-                */
-               error = 0;
-               if (data.transmit) {
-                       if (ppp->sc_xc_state != NULL)
-                               (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+#ifdef CONFIG_KERNELD
+       if (cp == NULL) {
+               char modname[32];
+               sprintf(modname, "ppp-compress-%d", ccp_option[0]);
+               request_module(modname);
+               cp = find_compressor(ccp_option[0]);
+       }
+#endif /* CONFIG_KERNELD */
 
-                       ppp->sc_xcomp    = cp;
-                       ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+       if (cp == NULL)
+               goto out_no_comp;
+       /*
+        * Found a handler for the protocol - try to allocate
+        * a compressor or decompressor.
+        */
+       error = 0;
+       if (data.transmit) {
+               if (ppp->sc_xc_state != NULL)
+                       (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+               ppp->sc_xc_state = NULL;
 
-                       if (ppp->sc_xc_state == NULL) {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk(KERN_DEBUG "%s: comp_alloc failed\n",
-                                              ppp->name);
-                               error = -ENOBUFS;
-                       } else {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk(KERN_DEBUG "%s: comp_alloc -> %p\n",
-                                              ppp->name, ppp->sc_xc_state);
-                       }
-               } else {
-                       if (ppp->sc_rc_state != NULL)
-                               (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
-                       ppp->sc_rcomp    = cp;
-                       ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
-                       if (ppp->sc_rc_state == NULL) {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk(KERN_DEBUG "%s: decomp_alloc failed\n",
-                                              ppp->name);
-                               error = -ENOBUFS;
-                       } else {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk(KERN_DEBUG "%s: decomp_alloc -> %p\n",
-                                              ppp->name, ppp->sc_rc_state);
-                       }
-               }
-               return (error);
+               ppp->sc_xcomp    = cp;
+               ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+               if (ppp->sc_xc_state == NULL) {
+                       printk(KERN_WARNING "%s: comp_alloc failed\n",
+                               ppp->name);
+                       error = -ENOBUFS;
+               } else if (ppp->flags & SC_DEBUG)
+                       printk(KERN_DEBUG "%s: comp_alloc -> %p\n",
+                              ppp->name, ppp->sc_xc_state);
+       } else {
+               if (ppp->sc_rc_state != NULL)
+                       (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+               ppp->sc_rc_state = NULL;
+
+               ppp->sc_rcomp    = cp;
+               ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+               if (ppp->sc_rc_state == NULL) {
+                       printk(KERN_WARNING "%s: decomp_alloc failed\n",
+                               ppp->name);
+                       error = -ENOBUFS;
+               } else if (ppp->flags & SC_DEBUG)
+                       printk(KERN_DEBUG "%s: decomp_alloc -> %p\n",
+                              ppp->name, ppp->sc_rc_state);
        }
+       return error;
 
+out_no_comp:
        if (ppp->flags & SC_DEBUG)
                printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n",
                       ppp->name, ccp_option[0], ccp_option[1],
@@ -2373,8 +2398,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                unsigned int param2, unsigned long param3)
 {
        struct ppp *ppp = tty2ppp (tty);
-       register int temp_i = 0;
+       register int temp_i = 0, oldflags;
        int error = 0;
+       unsigned long flags;
 /*
  * Verify the status of the PPP device.
  */
@@ -2424,16 +2450,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                if (error != 0)
                        break;
                temp_i &= SC_MASK;
-               temp_i |= (ppp->flags & ~SC_MASK);
 
-               if ((ppp->flags & SC_CCP_OPEN) &&
-                   (temp_i & SC_CCP_OPEN) == 0)
-                       ppp_ccp_closed (ppp);
+               if ((ppp->flags & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0)
+                       ppp_ccp_closed(ppp);
 
-               if ((ppp->flags | temp_i) & SC_DEBUG)
+               save_flags(flags);
+               cli();
+               oldflags = ppp->flags;
+               ppp->flags = temp_i |= (ppp->flags & ~SC_MASK);
+               restore_flags(flags);
+               if ((oldflags | temp_i) & SC_DEBUG)
                        printk (KERN_INFO
                                "ppp_tty_ioctl: set flags to %x\n", temp_i);
-               ppp->flags = temp_i;
                break;
 /*
  * Set the compression mode
@@ -2518,9 +2546,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                        /* change absolute times to relative times. */
                        cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
                        cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ;
-                       COPY_TO_USER (error,
-                                     (void *) param3,
-                                     &cur_ddinfo,
+                       COPY_TO_USER (error, (void *) param3, &cur_ddinfo,
                                      sizeof (cur_ddinfo));
                }
                break;
@@ -2528,9 +2554,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Retrieve the extended async map
  */
        case PPPIOCGXASYNCMAP:
-               COPY_TO_USER (error,
-                             (void *) param3,
-                             ppp->xmit_async_map,
+               COPY_TO_USER (error, (void *) param3, ppp->xmit_async_map,
                              sizeof (ppp->xmit_async_map));
                break;
 /*
@@ -2540,13 +2564,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                {
                        __u32 temp_tbl[8];
 
-                       COPY_FROM_USER (error,
-                                       temp_tbl,
-                                       (void *) param3,
+                       COPY_FROM_USER (error, temp_tbl, (void *) param3,
                                        sizeof (temp_tbl));
-
                        if (error != 0)
                                break;
+
                        temp_tbl[1]  =  0x00000000;
                        temp_tbl[2] &= ~0x40000000;
                        temp_tbl[3] |=  0x60000000;
@@ -2576,16 +2598,15 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                temp_i = (temp_i & 255) + 1;
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_INFO
-                               "ppp_tty_ioctl: set maxcid to %d\n",
-                               temp_i);
+                               "ppp_tty_ioctl: set maxcid to %d\n", temp_i);
                if (ppp->slcomp != NULL)
                        slhc_free (ppp->slcomp);
-               ppp->slcomp = slhc_init (16, temp_i);
+               ppp->slcomp = NULL;
 
+               ppp->slcomp = slhc_init (16, temp_i);
                if (ppp->slcomp == NULL) {
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR
-                                       "ppp: no space for compression buffers!\n");
+                       printk (KERN_ERR "ppp_tty_ioctl: "
+                               "no space for compression buffers!\n");
                        ppp_release (ppp);
                        error = -ENOMEM;
                }
@@ -2601,9 +2622,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                {
                        struct npioctl npi;
 
-                       COPY_FROM_USER (error,
-                                       &npi,
-                                       (void *) param3,
+                       COPY_FROM_USER (error, &npi, (void *) param3,
                                        sizeof (npi));
                        if (error != 0)
                                break;
@@ -2615,7 +2634,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                        default:
                                if (ppp->flags & SC_DEBUG)
                                        printk(KERN_DEBUG "pppioc[gs]npmode: "
-                                              "invalid proto %d\n", npi.protocol);
+                                              "invalid protocol %d\n",
+                                               npi.protocol);
                                error = -EINVAL;
                        }
 
@@ -2625,9 +2645,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                        if (param2 == PPPIOCGNPMODE) {
                                npi.mode = ppp->sc_npmode[npi.protocol];
 
-                               COPY_TO_USER (error,
-                                             (void *) param3,
-                                             &npi,
+                               COPY_TO_USER (error, (void *) param3, &npi,
                                              sizeof (npi));
                                break;
                        }
@@ -2661,11 +2679,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  */
        default:
                if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                               "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
-                               param2,
-                               param3);
-
+                       printk (KERN_WARNING "ppp_tty_ioctl: "
+                               "invalid ioctl=%x, addr=%lx\n", param2, param3);
                error = -ENOIOCTLCMD;
                break;
        }
@@ -2748,8 +2763,13 @@ ppp_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait)
        if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) {
                CHECK_PPP (0);
 
+#if LINUX_VERSION_CODE < VERSION(2,1,89)
                poll_wait(&ppp->read_wait, wait);
                poll_wait(&ppp->write_wait, wait);
+#else
+               poll_wait(filp, &ppp->read_wait, wait);
+               poll_wait(filp, &ppp->write_wait, wait);
+#endif
 
                /* Must lock the user buffer area while checking. */
                CHECK_BUF_MAGIC(ppp->ubuf);
@@ -2787,14 +2807,8 @@ ppp_dev_open (struct device *dev)
 {
        struct ppp *ppp = dev2ppp (dev);
 
-#if 0
-       /* reset POINTOPOINT every time, since dev_close zaps it! */
-       dev->flags |= IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-#endif
-
        if (ppp2tty (ppp) == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
+               printk (KERN_ERR
                        "ppp: %s not connected to a TTY! can't go open!\n",
                        dev->name);
                return -ENXIO;
@@ -2846,10 +2860,7 @@ ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
 /*
  * Move the version data
  */
-       COPY_TO_USER (error,
-                     result,
-                     szVersion,
-                     len);
+       COPY_TO_USER (error, result, szVersion, len);
 
        return error;
 }
@@ -2885,10 +2896,7 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
 
        result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
 
-       COPY_TO_USER (error,
-                     result,
-                     &temp,
-                     sizeof (temp));
+       COPY_TO_USER (error, result, &temp, sizeof (temp));
 
        return error;
 }
@@ -2920,10 +2928,7 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev
  */
        result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
 
-       COPY_TO_USER (error,
-                     result,
-                     &temp,
-                     sizeof (temp));
+       COPY_TO_USER (error, result, &temp, sizeof (temp));
 
        return error;
 }
@@ -3071,6 +3076,11 @@ ppp_dev_xmit_other (struct device *dev, struct ppp *ppp,
 /*
  * Send a frame to the remote.
  */
+#if LINUX_VERSION_CODE < VERSION(2,1,86)
+#define FREE_SKB(skb)  dev_kfree_skb(skb)
+#else
+#define FREE_SKB(skb)  dev_kfree_skb(skb, FREE_WRITE)
+#endif
 
 static int
 ppp_dev_xmit (sk_buff *skb, struct device *dev)
@@ -3091,7 +3101,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * Avoid timing problem should tty hangup while data is queued to be sent
  */
        if (!ppp->inuse) {
-               dev_kfree_skb (skb, FREE_WRITE);
+               FREE_SKB (skb);
                return 0;
        }
 /*
@@ -3102,7 +3112,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
                        printk (KERN_ERR
                                "ppp_dev_xmit: %s not connected to a TTY!\n",
                                dev->name);
-               dev_kfree_skb (skb, FREE_WRITE);
+               FREE_SKB (skb);
                return 0;
        }
 /*
@@ -3115,7 +3125,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n",
                                dev->name);
-               dev_kfree_skb (skb, FREE_WRITE);
+               FREE_SKB (skb);
                return 0;
        }
 /*
@@ -3156,7 +3166,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
                break;
 
        default: /* All others have no support at this time. */
-               dev_kfree_skb (skb, FREE_WRITE);
+               FREE_SKB (skb);
                return 0;
        }
 /*
@@ -3164,12 +3174,12 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  */
        if (answer == 0) {
                /* packet queued OK */
-               dev_kfree_skb (skb, FREE_WRITE);
+               FREE_SKB (skb);
        } else {
                ppp->wbuf->locked = 0;
                if (answer < 0) {
                        /* packet should be dropped */
-                       dev_kfree_skb (skb, FREE_WRITE);
+                       FREE_SKB (skb);
                        answer = 0;
                } else {
                        /* packet should be queued for later */
@@ -3183,7 +3193,7 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  * Generate the statistic information for the /proc/net/dev listing.
  */
 
-static struct enet_statistics *
+static struct net_device_stats *
 ppp_dev_stats (struct device *dev)
 {
        struct ppp *ppp = dev2ppp (dev);
@@ -3237,6 +3247,29 @@ ppp_find (int pid_value)
        return ppp;
 }
 
+/* Collect hung up channels */
+
+static void ppp_sync(void)
+{
+       struct device   *dev;
+       struct ppp      *ppp;
+
+#if LINUX_VERSION_CODE >= VERSION(2,1,68)
+       rtnl_lock();
+#endif
+       for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
+               if (!ppp->inuse) {
+                       dev = ppp2dev(ppp);
+                       if (dev->flags & IFF_UP)
+                               dev_close(dev);
+               }
+       }
+#if LINUX_VERSION_CODE >= VERSION(2,1,68)
+       rtnl_unlock();
+#endif
+}
+
+
 /* allocate or create a PPP channel */
 static struct ppp *
 ppp_alloc (void)
@@ -3246,11 +3279,24 @@ ppp_alloc (void)
        struct device   *dev;
        struct ppp      *ppp;
 
+       ppp_sync();
+
        /* try to find an free device */
        if_num = 0;
        for (ppp = ppp_list; ppp != 0; ppp = ppp->next) {
-               if (!test_and_set_bit(0, &ppp->inuse))
+               if (!test_and_set_bit(0, &ppp->inuse)) {
+
+                       /* Reregister device */
+
+                       dev = ppp2dev(ppp);
+                       unregister_netdev (dev);
+
+                       if (register_netdev (dev)) {
+                               printk(KERN_DEBUG "cannot reregister ppp device\n");
+                               return NULL;
+                       }
                        return ppp;
+               }
                ++if_num;
        }
 /*