]> git.ozlabs.org Git - ppp.git/blobdiff - linux/ppp.c
sifdefaultroute now gets both local and remote addresses
[ppp.git] / linux / ppp.c
index fd01a92db9dfb56c3cdddf6799ee654666bf1ba4..f63bcc4c3c516347c99c32718092a29d69b15173 100644 (file)
@@ -6,7 +6,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 960528==
+ *  ==FILEVERSION 970227==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -51,7 +51,7 @@
 #define PPP_MAX_DEV    256
 #endif
 
-/* From: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp
+/* $Id: ppp.c,v 1.10 1997/03/04 03:29:58 paulus Exp $
  * Added dynamic allocation of channels to eliminate
  *   compiled-in limits on the number of channels.
  *
  *   released under the GNU General Public License Version 2.
  */
 
+#include <linux/version.h>
 #include <linux/module.h>
-#include <endian.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
+
+#undef VERSION
+/* a nice define to generate linux version numbers */
+#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+
+#if LINUX_VERSION_CODE < VERSION(2,1,14)
 #include <linux/ioport.h>
+#endif
+
 #include <linux/in.h>
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <asm/system.h>
 #include <asm/bitops.h>
-#include <asm/segment.h>
-#include <linux/netdevice.h>
 #include <linux/if.h>
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/inet.h>
 #include <linux/ioctl.h>
@@ -99,14 +106,7 @@ typedef struct sk_buff           sk_buff;
 #include <linux/socket.h>
 #include <linux/if_ppp.h>
 #include <linux/if_pppvar.h>
-
-#undef  PACKETPTR
-#define         PACKETPTR 1
 #include <linux/ppp-comp.h>
-#undef  PACKETPTR
-
-#define bsd_decompress (*ppp->sc_rcomp->decompress)
-#define bsd_compress   (*ppp->sc_xcomp->compress)
 
 #ifndef PPP_IPX
 #define PPP_IPX 0x2b  /* IPX protocol over PPP */
@@ -116,6 +116,49 @@ typedef struct sk_buff          sk_buff;
 #define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
 #endif
 
+#if LINUX_VERSION_CODE >= VERSION(2,1,4)
+#include <asm/segment.h>
+#define GET_USER(error,value,addr) error = get_user(value,addr)
+#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#define PUT_USER(error,value,addr) error = put_user(value,addr)
+#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#if LINUX_VERSION_CODE >= VERSION(2,1,5)
+#include <asm/uaccess.h>
+#endif
+
+#else  /* 2.0.x and 2.1.x before 2.1.4 */
+
+#define GET_USER(error,value,addr)                                       \
+do {                                                                     \
+       error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
+       if (error == 0)                                                   \
+               value = get_user(addr);                                   \
+} while (0)
+
+#define COPY_FROM_USER(error,dest,src,size)                              \
+do {                                                                     \
+       error = verify_area (VERIFY_READ, (void *) src, size);            \
+       if (error == 0)                                                   \
+               memcpy_fromfs (dest, src, size);                          \
+} while (0)
+
+#define PUT_USER(error,value,addr)                                        \
+do {                                                                      \
+       error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
+       if (error == 0)                                                    \
+               put_user (value, addr);                                    \
+} while (0)
+
+#define COPY_TO_USER(error,dest,src,size)                                \
+do {                                                                     \
+       error = verify_area (VERIFY_WRITE, (void *) src, size);           \
+       if (error == 0)                                                   \
+               memcpy_tofs (dest, src, size);                            \
+} while (0)
+
+#endif
+
 static int ppp_register_compressor (struct compressor *cp);
 static void ppp_unregister_compressor (struct compressor *cp);
 
@@ -144,7 +187,6 @@ static int rcv_proto_lqr    (struct ppp *, __u16, __u8 *, int);
 static void ppp_doframe_lower  (struct ppp *, __u8 *, int);
 static int ppp_doframe         (struct ppp *);
 
-extern int  ppp_bsd_compressor_init(void);
 static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd);
 static int  rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
 
@@ -180,10 +222,14 @@ 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 *);
+
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
 static int ppp_dev_header (sk_buff *, struct device *, __u16,
                           void *, void *, unsigned int);
 static int ppp_dev_rebuild (void *eth, struct device *dev,
-                            unsigned long raddr, struct sk_buff *skb);
+                           unsigned long raddr, struct sk_buff *skb);
+#endif
+
 /*
  * TTY callbacks
  */
@@ -193,7 +239,7 @@ static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
 static int ppp_tty_write (struct tty_struct *, struct file *, const __u8 *,
                          unsigned int);
 static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
-                          unsigned long);
+                         unsigned long);
 static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
                      struct file *filp, int sel_type, select_table * wait);
 static int ppp_tty_open (struct tty_struct *);
@@ -249,7 +295,7 @@ static ppp_ctrl_t *ppp_list = NULL;
 static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
 
 static char szVersion[]                = PPP_VERSION;
+
 /*
  * Information for the protocol decoder
  */
@@ -341,7 +387,7 @@ ppp_first_time (void)
        int    status;
 
        printk (KERN_INFO
-               "PPP: version %s (dynamic channel allocation)"
+               "PPP: version %s (demand dialling)"
                "\n", szVersion);
 
 #ifndef MODULE /* slhc module logic has its own copyright announcement */
@@ -349,13 +395,13 @@ ppp_first_time (void)
                "TCP compression code copyright 1989 Regents of the "
                "University of California\n");
 #endif
-       
+
        printk (KERN_INFO
                "PPP Dynamic channel allocation code copyright 1995 "
                "Caldera, Inc.\n");
 /*
  * Register the tty discipline
- */    
+ */
        (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
        ppp_ldisc.magic         = TTY_LDISC_MAGIC;
        ppp_ldisc.open          = ppp_tty_open;
@@ -367,7 +413,7 @@ ppp_first_time (void)
        ppp_ldisc.receive_room  = ppp_tty_room;
        ppp_ldisc.receive_buf   = ppp_tty_receive;
        ppp_ldisc.write_wakeup  = ppp_tty_wakeup;
-       
+
        status = tty_register_ldisc (N_PPP, &ppp_ldisc);
        if (status == 0)
                printk (KERN_INFO "PPP line discipline registered.\n");
@@ -388,8 +434,11 @@ ppp_init_dev (struct device *dev)
 {
        int    indx;
 
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
        dev->hard_header      = ppp_dev_header;
        dev->rebuild_header   = ppp_dev_rebuild;
+#endif
+
        dev->hard_header_len  = PPP_HARD_HDR_LEN;
 
        /* device INFO */
@@ -447,7 +496,8 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
        ppp->last_xmit  = jiffies - flag_time;
 
        /* clear statistics */
-       memset (&ppp->stats, '\0', sizeof (struct pppstat));
+       memset(&ppp->stats, 0, sizeof (struct pppstat));
+       memset(&ppp->estats, 0, sizeof(struct enet_statistics));
 
        /* Reset the demand dial information */
        ppp->ddinfo.xmit_idle=         /* time since last NP packet sent */
@@ -458,6 +508,7 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
        ppp->sc_rc_state = NULL;
 }
 
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
 static struct symbol_table ppp_syms = {
 #include <linux/symtab_begin.h>
        X(ppp_register_compressor),
@@ -465,6 +516,11 @@ static struct symbol_table ppp_syms = {
        X(ppp_crc16_table),
 #include <linux/symtab_end.h>
 };
+#else
+EXPORT_SYMBOL(ppp_register_compressor);
+EXPORT_SYMBOL(ppp_unregister_compressor);
+EXPORT_SYMBOL(ppp_crc16_table);
+#endif
 
 /* called at boot/load time for each ppp device defined in the kernel */
 
@@ -478,8 +534,10 @@ ppp_init (struct device *dev)
        if (first_time) {
                first_time = 0;
                answer     = ppp_first_time();
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
                if (answer == 0)
                        (void) register_symtab (&ppp_syms);
+#endif
        }
        if (answer == 0)
                answer = -ENODEV;
@@ -531,7 +589,7 @@ extern inline int
 lock_buffer (register struct ppp_buffer *buf)
 {
        register int state;
-       int flags;
+       unsigned long flags;
 /*
  * Save the current state and if free then set it to the "busy" state
  */
@@ -580,10 +638,6 @@ ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
                mru = PPP_MRU;
 
        mru += 10;
-       
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
-                       dev->name, new_mtu, new_mru);
 
        new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
        new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24,   BUFFER_TYPE_TTY_WR);
@@ -689,9 +743,9 @@ ppp_release (struct ppp *ppp)
 
        ppp_ccp_closed (ppp);
 
-        /* Ensure that the pppd process is not hanging on select() */
-        wake_up_interruptible (&ppp->read_wait);
-        wake_up_interruptible (&ppp->write_wait);
+       /* Ensure that the pppd process is not hanging on select() */
+       wake_up_interruptible (&ppp->read_wait);
+       wake_up_interruptible (&ppp->write_wait);
 
        if (tty != NULL && tty->disc_data == ppp)
                tty->disc_data = NULL;  /* Break the tty->ppp link */
@@ -723,16 +777,18 @@ ppp_release (struct ppp *ppp)
 
        ppp->inuse = 0;
        ppp->tty   = NULL;
+       ppp->backup_tty = NULL;
 }
 
 /*
- * Device callback.
+ * TTY callback.
  *
- * Called when the PPP device goes down in response to an ifconfig request.
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
  */
 
 static void
-ppp_tty_close_local (struct tty_struct *tty, int sc_xfer)
+ppp_tty_close (struct tty_struct *tty)
 {
        struct ppp *ppp = tty2ppp (tty);
 
@@ -741,24 +797,27 @@ ppp_tty_close_local (struct tty_struct *tty, int sc_xfer)
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_WARNING
                                       "ppp: trying to close unopened tty!\n");
+                       return;
+               }
+               CHECK_PPP_VOID();
+               tty->disc_data = NULL;
+               if (tty == ppp->backup_tty)
+                       ppp->backup_tty = 0;
+               if (tty != ppp->tty)
+                       return;
+               if (ppp->backup_tty) {
+                       ppp->tty = ppp->backup_tty;
                } else {
-                       CHECK_PPP_VOID();
-                       ppp->sc_xfer = sc_xfer;
+                       ppp->sc_xfer = 0;
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO "ppp: channel %s closing.\n",
-                                       ppp2dev(ppp) -> name);
+                                       ppp2dev(ppp)->name);
                        ppp_release (ppp);
                        MOD_DEC_USE_COUNT;
                }
        }
 }
 
-static void
-ppp_tty_close (struct tty_struct *tty)
-{
-       ppp_tty_close_local (tty, 0);
-}
-
 /*
  * TTY callback.
  *
@@ -785,70 +844,74 @@ ppp_tty_open (struct tty_struct *tty)
  * Allocate the structure from the system
  */
        ppp = ppp_find(current->pid);
-       if (ppp == NULL) {
-                ppp = ppp_find(0);
-               if (ppp == NULL)
-                       ppp = ppp_alloc();
-        }
+       if (ppp != NULL) {
+               /*
+                * If we are taking over a ppp unit which is currently
+                * connected to a loopback pty, there's not much to do.
+                */
+               ppp->tty       = tty;
+               tty->disc_data = ppp;
 
-       if (ppp == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                       "ppp_tty_open: couldn't allocate ppp channel\n");
-               return -ENFILE;
-       }
+       } else {
+               ppp = ppp_alloc();
+               if (ppp == NULL) {
+                       if (ppp->flags & SC_DEBUG)
+                               printk (KERN_ERR "ppp_alloc failed\n");
+                       return -ENFILE;
+               }
 /*
  * Initialize the control block
  */
-       ppp_init_ctrl_blk (ppp);
-       ppp->tty       = tty;
-       tty->disc_data = ppp;
-/*
- * Flush any pending characters in the driver and discipline.
- */
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer (tty);
-
-       if (tty->driver.flush_buffer)
-               tty->driver.flush_buffer (tty);
+               ppp_init_ctrl_blk (ppp);
+               ppp->tty       = tty;
+               tty->disc_data = ppp;
 /*
  * Allocate space for the default VJ header compression slots
  */
-       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");
-               ppp_release (ppp);
-               return -ENOMEM;
-       }
+               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");
+                       ppp_release (ppp);
+                       return -ENOMEM;
+               }
 /*
  * Allocate space for the MTU and MRU buffers
  */
-       if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
-               ppp_release (ppp);
-               return -ENOMEM;
-       }
+               if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
+                       ppp_release (ppp);
+                       return -ENOMEM;
+               }
 /*
  * Allocate space for a user level buffer
  */
-       ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
-       if (ppp->ubuf == NULL) {
+               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");
+                       ppp_release (ppp);
+                       return -ENOMEM;
+               }
+
                if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                      "ppp_tty_open: no space for user receive buffer\n");
-               ppp_release (ppp);
-               return -ENOMEM;
-       }
+                       printk (KERN_INFO "ppp: channel %s open\n",
+                               ppp2dev(ppp)->name);
 
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_INFO "ppp: channel %s open\n",
-                       ppp2dev(ppp)->name);
+               for (indx = 0; indx < NUM_NP; ++indx)
+                       ppp->sc_npmode[indx] = NPMODE_PASS;
 
-       for (indx = 0; indx < NUM_NP; ++indx)
-               ppp->sc_npmode[indx] = NPMODE_PASS;
+               MOD_INC_USE_COUNT;
+       }
+/*
+ * Flush any pending characters in the driver and discipline.
+ */
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer (tty);
 
-       MOD_INC_USE_COUNT;
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer (tty);
        return (ppp->line);
 }
 
@@ -968,6 +1031,11 @@ ppp_tty_wakeup (struct tty_struct *tty)
 
        if (ppp->magic != PPP_MAGIC)
                return;
+
+       if (tty != ppp->tty) {
+               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               return;
+       }
 /*
  * Ensure that there is a transmission pending. Clear the re-entry flag if
  * there is no pending buffer. Otherwise, send the buffer.
@@ -988,7 +1056,7 @@ ppp_tty_wakeup (struct tty_struct *tty)
 static void
 ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
 {
-       register int flags;
+       unsigned long flags;
 /*
  * Hold interrupts.
  */
@@ -1047,7 +1115,6 @@ ppp_tty_room (struct tty_struct *tty)
 /*
  * Callback function when data is available at the tty driver.
  */
-
 static void
 ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
                 char *flags, int count)
@@ -1055,6 +1122,12 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
        register struct ppp *ppp = tty2ppp (tty);
        register struct ppp_buffer *buf = NULL;
        __u8 chr;
+
+       /*
+        * This can happen if stuff comes in on the backup tty.
+        */
+       if (tty != ppp->tty)
+               return;
 /*
  * Fetch the pointer to the buffer. Be careful about race conditions.
  */
@@ -1088,16 +1161,24 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
                ppp->bytes_rcvd++;
                chr = *data++;
                if (flags) {
-                       if (*flags && ppp->toss == 0)
+                       if (*flags && ppp->toss == 0) {
                                ppp->toss = *flags;
+                               switch (ppp->toss) {
+                               case TTY_OVERRUN:
+                                       ++ppp->estats.rx_fifo_errors;
+                                       break;
+                               case TTY_FRAME:
+                               case TTY_BREAK:
+                                       ++ppp->estats.rx_frame_errors;
+                                       break;
+                               }
+                       }
                        ++flags;
                }
 /*
- * Set the flags for 8 data bits and no parity.
- *
- * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
- * so that the normal processing would have all flags set at the end of the
- * session. A missing flag bit would denote an error condition.
+ * Set the flags for d7 being 0/1 and parity being even/odd so that
+ * the normal processing would have all flags set at the end of the
+ * session.  A missing flag bit indicates an error condition.
  */
 
 #ifdef CHECK_CHARACTERS
@@ -1112,13 +1193,9 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
                        ppp->flags |= SC_RCV_EVNP;
 #endif
 /*
- * Branch on the character. Process the escape character. The sequence ESC ESC
- * is defined to be ESC.
+ * Branch on the character.
  */
                switch (chr) {
-               case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
-                       ppp->escape = PPP_TRANS;
-                       break;
 /*
  * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
  * then the block is to be ignored. In addition, characters before the very
@@ -1132,8 +1209,8 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
  * Process frames which are not to be ignored. If the processing failed,
  * then clean up the VJ tables.
  */
-                       if ((ppp->toss & 0x80) != 0 ||
-                           ppp_doframe (ppp) == 0) {
+                       if (ppp_doframe (ppp) == 0) {
+                               ++ppp->stats.ppp_ierrors;
                                slhc_toss (ppp->slcomp);
                        }
 /*
@@ -1149,17 +1226,27 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
  * receive mask then ignore the character.
  */
                default:
+                       /* If we're tossing, look no further. */
+                       if (ppp->toss != 0)
+                               break;
+
+                       /* If this is a control char to be ignored, do so */
                        if (in_rmap (ppp, chr))
                                break;
-/*
- * Adjust the character and if the frame is to be discarded then simply
- * ignore the character until the ending FLAG is received.
- */
-                       chr ^= ppp->escape;
-                       ppp->escape = 0;
 
-                       if (ppp->toss != 0)
+                       /*
+                        * Modify the next character if preceded by escape.
+                        * The escape character (0x7d) could be an escaped
+                        * 0x5d, if it follows an escape :-)
+                        */
+                       if (ppp->escape) {
+                               chr ^= ppp->escape;
+                               ppp->escape = 0;
+                       } else if (chr == PPP_ESCAPE) {
+                               ppp->escape = PPP_TRANS;
                                break;
+                       }
+
 /*
  * If the count sent is within reason then store the character, bump the
  * count, and update the FCS for the character.
@@ -1173,7 +1260,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
  * The peer sent too much data. Set the flags to discard the current frame
  * and wait for the re-synchronization FLAG to be sent.
  */
-                       ppp->stats.ppp_ierrors++;
+                       ++ppp->estats.rx_length_errors;
                        ppp->toss |= 0xC0;
                        break;
                }
@@ -1208,7 +1295,10 @@ ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
 /*
  * Tag the frame and kick it to the proper receive routine
  */
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
        skb->free = 1;
+#endif
+
        ppp->ddinfo.recv_idle = jiffies;
        netif_rx (skb);
        return 1;
@@ -1333,11 +1423,6 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
                if (ppp->tty->fasync != NULL)
                        kill_fasync (ppp->tty->fasync, SIGIO);
 
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_INFO
-                               "ppp: successfully queued %d bytes, flags = %x\n",
-                               len + 2, ppp->flags);
-
                return 1;
 /*
  * The buffer is full. Unlock the header
@@ -1345,14 +1430,14 @@ rcv_proto_unknown (struct ppp *ppp, __u16 proto,
 failure:
                clear_bit (0, &ppp->ubuf->locked);
                if (ppp->flags & SC_DEBUG)
-                       printk (KERN_INFO
+                       printk (KERN_DEBUG
                                "ppp_us_queue: ran out of buffer space.\n");
        }
 /*
  * Discard the frame. There are no takers for this protocol.
  */
        if (ppp->flags & SC_DEBUG)
-               printk (KERN_WARNING
+               printk (KERN_DEBUG
                        "ppp: dropping packet on the floor.\n");
        slhc_toss (ppp->slcomp);
        return 0;
@@ -1411,7 +1496,7 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
                             opt_len,
                             ppp2dev (ppp)->base_addr,
                             0,
-                            ppp->flags))
+                            ppp->flags & SC_DEBUG))
                                ppp->flags |= SC_COMP_RUN;
                        break;
                }
@@ -1428,7 +1513,7 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
                     ppp2dev (ppp)->base_addr,
                     0,
                     ppp->mru,
-                    ppp->flags)) {
+                    ppp->flags & SC_DEBUG)) {
                        ppp->flags |= SC_DECOMP_RUN;
                        ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
                }
@@ -1470,9 +1555,6 @@ rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
        return rcv_proto_unknown (ppp, proto, data, len);
 }
 
-/* on entry, a received frame is in ppp->rbuf.bufr
-   check it and dispose as appropriate */
-
 static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
 {
        __u16           proto = PPP_PROTOCOL (data);
@@ -1480,7 +1562,7 @@ static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
 /*
  * Ignore empty frames
  */
-       if (count <= 4)
+       if (count <= PPP_HDRLEN)
                return;
 /*
  * Count the frame and print it
@@ -1522,11 +1604,10 @@ ppp_doframe (struct ppp *ppp)
  * the damaged frame.
  */
        if (ppp->toss) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
-                               "ppp_toss: tossing frame, reason = %d\n",
+               if ((ppp->flags & SC_DEBUG) && count > 0)
+                       printk (KERN_DEBUG
+                               "ppp_toss: tossing frame, reason = %x\n",
                                ppp->toss);
-               ppp->stats.ppp_ierrors++;
                return 0;
        }
 /*
@@ -1540,22 +1621,23 @@ ppp_doframe (struct ppp *ppp)
  */
        if (count < PPP_HARD_HDR_LEN) {
                if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
+                       printk (KERN_DEBUG
                                "ppp: got runt ppp frame, %d chars\n", count);
-               slhc_toss (ppp->slcomp);
-               ppp->stats.ppp_ierrors++;
-               return 1;
+               ++ppp->estats.rx_length_errors;
+               return 0;
        }
 /*
  * Verify the CRC of the frame and discard the CRC characters from the
  * end of the buffer.
  */
        if (ppp->rbuf->fcs != PPP_GOODFCS) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
-                               "ppp: frame with bad fcs, excess = %x\n",
-                               ppp->rbuf->fcs ^ PPP_GOODFCS);
-               ppp->stats.ppp_ierrors++;
+               if (ppp->flags & SC_DEBUG) {
+                       printk (KERN_DEBUG
+                               "ppp: frame with bad fcs, length = %d\n",
+                               count);
+                       ppp_print_buffer("bad frame", data, count);
+               }
+               ++ppp->estats.rx_crc_errors;
                return 0;
        }
        count -= 2;             /* ignore the fcs characters */
@@ -1597,60 +1679,48 @@ ppp_doframe (struct ppp *ppp)
 /*
  * If the frame is compressed then decompress it.
  */
-                       new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
+                       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");
-                               slhc_toss (ppp->slcomp);
-                               (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
-                                                         data,
-                                                         count);
-                               return 1;
+                               new_count = DECOMP_ERROR;
+                       } else {
+                               new_count = (*ppp->sc_rcomp->decompress)
+                                       (ppp->sc_rc_state, data, count,
+                                        new_data, ppp->mru + PPP_HDRLEN);
                        }
-/*
- * Decompress the frame
- */
-                       new_count = bsd_decompress (ppp->sc_rc_state,
-                                                   data,
-                                                   count,
-                                                   new_data,
-                                                   ppp->mru + 4);
                        switch (new_count) {
                        default:
                                ppp_doframe_lower (ppp, new_data, new_count);
                                kfree (new_data);
                                return 1;
 
-                       case DECOMP_OK:
-                               break;
-
                        case DECOMP_ERROR:
                                ppp->flags |= SC_DC_ERROR;
                                break;
 
                        case DECOMP_FATALERROR:
                                ppp->flags |= SC_DC_FERROR;
+                               if (ppp->flags & SC_DEBUG)
+                                       printk(KERN_ERR "ppp: fatal decomp error\n");
                                break;
                        }
 /*
  * Log the error condition and discard the frame.
  */
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_ERR
-                                       "ppp_proto_comp: "
-                                       "decompress err %d\n", new_count);
-                       kfree (new_data);
+                       if (new_data != 0)
+                               kfree (new_data);
                        slhc_toss (ppp->slcomp);
-                       return 1;
-               }
+                       ++ppp->stats.ppp_ierrors;
+               } else {
 /*
  * The frame is not special. Pass it through the compressor without
  * actually compressing the data
  */
-               (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
-                                         data,
-                                         count);
+                       (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+                                                 data, count);
+               }
        }
 /*
  * Process the uncompressed frame.
@@ -1678,6 +1748,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
        struct ppp *ppp = tty2ppp (tty);
        __u8 c;
        int len, indx;
+       int error;
 
 #define GETC(c)                                                \
 {                                                      \
@@ -1695,17 +1766,13 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
                return -EIO;
 
        CHECK_PPP (-ENXIO);
-
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG
-                       "ppp_tty_read: called buf=%p nr=%u\n",
-                       buf, nr);
 /*
  * Acquire the read lock.
  */
        for (;;) {
                ppp = tty2ppp (tty);
-               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+                   || tty != ppp->tty)
                        return 0;
 
                if (set_bit (0, &ppp->ubuf->locked) != 0) {
@@ -1745,13 +1812,8 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
                if (len == 0) {
                        /* no data */
                        clear_bit (0, &ppp->ubuf->locked);
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (ppp->flags & SC_DEBUG)
-                                       printk (KERN_DEBUG
-                                               "ppp_tty_read: no data "
-                                               "(EAGAIN)\n");
+                       if (file->f_flags & O_NONBLOCK)
                                return -EAGAIN;
-                       }
                        current->timeout = 0;
 
                        if (ppp->flags & SC_DEBUG)
@@ -1763,11 +1825,6 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
                                return -EINTR;
                        continue;
                }
-/*
- * Reset the time of the last read operation.
- */
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
 /*
  * Ensure that the frame will fit within the caller's buffer. If not, then
  * discard the frame from the input buffer.
@@ -1800,8 +1857,10 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
-               put_user (PPP_ALLSTATIONS, buf++);
-               put_user (PPP_UI,          buf++);
+               PUT_USER (error, (u_char) PPP_ALLSTATIONS, buf);
+               ++buf;
+               PUT_USER (error, (u_char) PPP_UI, buf);
+               ++buf;
 
                indx = len;
 /*
@@ -1809,7 +1868,7 @@ ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
  */
                while (indx-- > 0) {
                        GETC (c);
-                       put_user (c, buf);
+                       PUT_USER (error, c, buf);
                        ++buf;
                }
 
@@ -1836,7 +1895,7 @@ ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
  */
        if (ppp->flags & SC_DEBUG) {
                if ((buf->count < 0) || (buf->count > 3000))
-                       printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+                       printk (KERN_DEBUG "ppp_stuff_char: %d %x\n",
                                (unsigned int) buf->count,
                                (unsigned int) chr);
        }
@@ -1863,9 +1922,13 @@ static void
 ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
                    __u8 *data, int count, int non_ip)
 {
-       __u16   write_fcs;
+       __u16   write_fcs;
        int     address, control;
        int     proto;
+
+       ++ppp->stats.ppp_opackets;
+       ppp->stats.ppp_ooctects += count;
+
 /*
  * Insert the leading FLAG character
  */
@@ -1913,10 +1976,6 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
        write_fcs = buf->fcs ^ 0xFFFF;
        ppp_stuff_char (ppp, buf, write_fcs);
        ppp_stuff_char (ppp, buf, write_fcs >> 8);
-
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
-                       write_fcs);
 /*
  * Add the trailing flag character
  */
@@ -1927,12 +1986,6 @@ ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
        if (ppp->flags & SC_LOG_FLUSH)
                ppp_print_buffer ("ppp flush", buf_base (buf),
                                  buf->count);
-       else {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_DEBUG
-                               "ppp_dev_xmit: writing %d chars\n",
-                               buf->count);
-       }
 /*
  * Send the block to the tty driver.
  */
@@ -1982,32 +2035,20 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
                        return 1;
                }
 
-               new_count = bsd_compress (ppp->sc_xc_state,
-                                         data,
-                                         new_data,
-                                         count,
-                                         count);
-
-               if (new_count > 0) {
-                       ++ppp->stats.ppp_opackets;
-                       ppp->stats.ppp_ooctects += new_count;
+               new_count = (*ppp->sc_xcomp->compress)
+                   (ppp->sc_xc_state, data, new_data, count, count);
 
-                       ppp_dev_xmit_lower (ppp, buf, new_data,
-                                           new_count, 0);
+               if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
+                       ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
                        kfree (new_data);
                        return 0;
                }
 /*
- * The frame could not be compressed.
+ * The frame could not be compressed, or it could not be sent in
+ * compressed form because CCP is not yet up.
  */
                kfree (new_data);
        }
-/*
- * The frame may not be compressed. Update the statistics before the
- * count field is destroyed. The frame will be transmitted.
- */
-       ++ppp->stats.ppp_opackets;
-       ppp->stats.ppp_ooctects += count;
 /*
  * Go to the escape encoding
  */
@@ -2077,12 +2118,13 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
 /*
  * Ensure that the caller does not wish to send too much.
  */
-       if (count > PPP_MTU) {
+       if (count > PPP_MTU + PPP_HDRLEN) {
                if (ppp->flags & SC_DEBUG)
                        printk (KERN_WARNING
                                "ppp_tty_write: truncating user packet "
-                               "from %u to mtu %d\n", count, PPP_MTU);
-               count = PPP_MTU;
+                               "from %u to mtu %d\n", count,
+                               PPP_MTU + PPP_HDRLEN);
+               count = PPP_MTU + PPP_HDRLEN;
        }
 /*
  * Allocate a buffer for the data and fetch it from the user space.
@@ -2105,7 +2147,8 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
                interruptible_sleep_on (&ppp->write_wait);
 
                ppp = tty2ppp (tty);
-               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
+               if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+                   || tty != ppp->tty) {
                        kfree (new_data);
                        return 0;
                }
@@ -2116,16 +2159,18 @@ ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
                }
        }
 /*
- * Ensure that the caller's buffer is valid.
+ * Retrieve the user's buffer
  */
-       status = verify_area (VERIFY_READ, data, count);
+       COPY_FROM_USER (status,
+                       new_data,
+                       data,
+                       count);
+
        if (status != 0) {
                kfree (new_data);
                ppp->tbuf->locked = 0;
                return status;
        }
-
-       memcpy_fromfs (new_data, data, count);
 /*
  * Change the LQR frame
  */
@@ -2154,21 +2199,26 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 /*
  * Fetch the compression parameters
  */
-       error = verify_area (VERIFY_READ, odp, sizeof (data));
-       if (error == 0) {
-               memcpy_fromfs (&data, odp, sizeof (data));
-               nb  = data.length;
-               ptr = data.ptr;
-               if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
-                       nb = CCP_MAX_OPTION_LENGTH;
-       
-               error = verify_area (VERIFY_READ, ptr, nb);
-       }
+       COPY_FROM_USER (error,
+                       &data,
+                       odp,
+                       sizeof (data));
 
        if (error != 0)
                return error;
 
-       memcpy_fromfs (ccp_option, ptr, nb);
+       nb  = data.length;
+       ptr = data.ptr;
+       if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
+               nb = CCP_MAX_OPTION_LENGTH;
+
+       COPY_FROM_USER (error,
+                       ccp_option,
+                       ptr,
+                       nb);
+
+       if (error != 0)
+               return error;
 
        if (ccp_option[1] < 2)  /* preliminary check on the length byte */
                return (-EINVAL);
@@ -2223,7 +2273,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
 
 static int
 ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
-               unsigned int param2, unsigned long param3)
+              unsigned int param2, unsigned long param3)
 {
        struct ppp *ppp = tty2ppp (tty);
        register int temp_i = 0;
@@ -2248,10 +2298,8 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  */
        switch (param2) {
        case PPPIOCSMRU:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       temp_i = get_user ((int *) param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                 "ppp_tty_ioctl: set mru to %x\n", temp_i);
@@ -2264,29 +2312,20 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Fetch the flags
  */
        case PPPIOCGFLAGS:
-               error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (temp_i));
-               if (error == 0) {
-                       temp_i = (ppp->flags & SC_MASK);
+               temp_i = (ppp->flags & SC_MASK);
 #ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
-                       temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
-                                 SC_RCV_ODDP | SC_RCV_EVNP;
+               temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+                         SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
-                       put_user (temp_i, (int *) param3);
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_DEBUG
-                               "ppp_tty_ioctl: get flags: addr %lx flags "
-                               "%x\n", param3, temp_i);
-               }
+               PUT_USER (error, temp_i, (int *) param3);
                break;
 /*
  * Set the flags for the various options
  */
        case PPPIOCSFLAGS:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       temp_i  = get_user ((int *) param3) & SC_MASK;
+                       temp_i &= SC_MASK;
                        temp_i |= (ppp->flags & ~SC_MASK);
 
                        if ((ppp->flags & SC_CCP_OPEN) &&
@@ -2310,26 +2349,15 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Retrieve the transmit async map
  */
        case PPPIOCGASYNCMAP:
-               error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (temp_i));
-               if (error == 0) {
-                       put_user (ppp->xmit_async_map[0], (int *) param3);
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_INFO
-                                    "ppp_tty_ioctl: get asyncmap: addr "
-                                    "%lx asyncmap %x\n",
-                                    param3,
-                                    ppp->xmit_async_map[0]);
-               }
+               PUT_USER (error, ppp->xmit_async_map[0], (int *) param3);
                break;
 /*
  * Set the transmit async map
  */
        case PPPIOCSASYNCMAP:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       ppp->xmit_async_map[0] = get_user ((int *) param3);
+                       ppp->xmit_async_map[0] = temp_i;
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set xmit asyncmap %x\n",
@@ -2340,10 +2368,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Set the receive async map
  */
        case PPPIOCSRASYNCMAP:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       ppp->recv_async_map = get_user ((int *) param3);
+                       ppp->recv_async_map = temp_i;
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set rcv asyncmap %x\n",
@@ -2354,13 +2381,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Obtain the unit number for this device.
  */
        case PPPIOCGUNIT:
-               error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (temp_i));
+               PUT_USER (error, ppp2dev (ppp)->base_addr, (int *) param3);
                if (error == 0) {
-                       put_user (ppp2dev (ppp)->base_addr, (int *) param3);
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
-                                       "ppp_tty_ioctl: get unit: %ld",
+                                       "ppp_tty_ioctl: get unit: %ld\n",
                                        ppp2dev (ppp)->base_addr);
                }
                break;
@@ -2368,10 +2393,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Set the debug level
  */
        case PPPIOCSDEBUG:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       temp_i  = (get_user ((int *) param3) & 0x1F) << 16;
+                       temp_i  = (temp_i & 0x1F) << 16;
                        temp_i |= (ppp->flags & ~0x1F0000);
 
                        if ((ppp->flags | temp_i) & SC_DEBUG)
@@ -2384,82 +2408,65 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Get the debug level
  */
        case PPPIOCGDEBUG:
-               error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (temp_i));
-               if (error == 0) {
-                       temp_i = (ppp->flags >> 16) & 0x1F;
-                       put_user (temp_i, (int *) param3);
-
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_INFO
-                                       "ppp_tty_ioctl: get debug level %d\n",
-                                       temp_i);
-               }
+               temp_i = (ppp->flags >> 16) & 0x1F;
+               PUT_USER (error, temp_i, (int *) param3);
                break;
 /*
  * Get the times since the last send/receive frame operation
  */
        case PPPIOCGIDLE:
-               error = verify_area (VERIFY_WRITE, (void *) param3,
-                                    sizeof (struct ppp_idle));
-               if (error == 0) {
+               {
                        struct ppp_idle cur_ddinfo;
                        __u32 cur_jiffies = jiffies;
 
                        /* change absolute times to relative times. */
                        cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
                        cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
-                       memcpy_tofs ((void *) param3, &cur_ddinfo,
-                                    sizeof (cur_ddinfo));
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_INFO
-                               "ppp_tty_ioctl: read demand dial info\n");
+                       COPY_TO_USER (error,
+                                     (void *) param3,
+                                     &cur_ddinfo,
+                                     sizeof (cur_ddinfo));
                }
                break;
 /*
  * Retrieve the extended async map
  */
        case PPPIOCGXASYNCMAP:
-               error = verify_area (VERIFY_WRITE,
-                                    (void *) param3,
-                                    sizeof (ppp->xmit_async_map));
-               if (error == 0) {
-                       memcpy_tofs ((void *) param3,
-                                    ppp->xmit_async_map,
-                                    sizeof (ppp->xmit_async_map));
-
-                       if (ppp->flags & SC_DEBUG)
-                               printk (KERN_INFO
-                               "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
-                               param3);
-               }
+               COPY_TO_USER (error,
+                             (void *) param3,
+                             ppp->xmit_async_map,
+                             sizeof (ppp->xmit_async_map));
                break;
 /*
  * Set the async extended map
  */
        case PPPIOCSXASYNCMAP:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (ppp->xmit_async_map));
-               if (error == 0) {
+               {
                        __u32 temp_tbl[8];
 
-                       memcpy_fromfs (temp_tbl, (void *) param3,
-                                      sizeof (ppp->xmit_async_map));
-                       temp_tbl[1]  =  0x00000000;
-                       temp_tbl[2] &= ~0x40000000;
-                       temp_tbl[3] |=  0x60000000;
-
-                       if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
-                           (temp_tbl[4] & temp_tbl[5]) != 0 ||
-                           (temp_tbl[6] & temp_tbl[7]) != 0)
-                               error = -EINVAL;
-                       else {
-                               memcpy (ppp->xmit_async_map, temp_tbl,
-                                       sizeof (ppp->xmit_async_map));
-
-                               if (ppp->flags & SC_DEBUG)
-                                       printk (KERN_INFO
-                                       "ppp_tty_ioctl: set xasyncmap\n");
+                       COPY_FROM_USER (error,
+                                       temp_tbl,
+                                       (void *) param3,
+                                       sizeof (temp_tbl));
+
+                       if (error == 0) {
+                               temp_tbl[1]  =  0x00000000;
+                               temp_tbl[2] &= ~0x40000000;
+                               temp_tbl[3] |=  0x60000000;
+
+                               if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
+                                   (temp_tbl[4] & temp_tbl[5]) != 0 ||
+                                   (temp_tbl[6] & temp_tbl[7]) != 0)
+                                       error = -EINVAL;
+                               else {
+                                       memcpy (ppp->xmit_async_map,
+                                               temp_tbl,
+                                               sizeof (ppp->xmit_async_map));
+
+                                       if (ppp->flags & SC_DEBUG)
+                                               printk (KERN_INFO
+                                                       "ppp_tty_ioctl: set xasyncmap\n");
+                               }
                        }
                }
                break;
@@ -2467,10 +2474,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
  * Set the maximum VJ header compression slot number.
  */
        case PPPIOCSMAXCID:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (temp_i));
+               GET_USER (error, temp_i, (int *) param3);
                if (error == 0) {
-                       temp_i = get_user ((int *) param3) + 1;
+                       temp_i = (temp_i & 255) + 1;
                        if (ppp->flags & SC_DEBUG)
                                printk (KERN_INFO
                                     "ppp_tty_ioctl: set maxcid to %d\n",
@@ -2490,24 +2496,30 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                break;
 
     case PPPIOCXFERUNIT:
-               ppp_tty_close_local (tty, current->pid);
+               ppp->backup_tty = tty;
+               ppp->sc_xfer = current->pid;
                break;
 
     case PPPIOCGNPMODE:
     case PPPIOCSNPMODE:
-               error = verify_area (VERIFY_READ, (void *) param3,
-                                    sizeof (struct npioctl));
-               if (error == 0) {
+               {
                        struct npioctl npi;
-                       memcpy_fromfs (&npi,
-                                      (void *) param3,
-                                      sizeof (npi));
+                       COPY_FROM_USER (error,
+                                       &npi,
+                                       (void *) param3,
+                                       sizeof (npi));
+
+                       if (error != 0)
+                               break;
 
                        switch (npi.protocol) {
                        case PPP_IP:
                                npi.protocol = NP_IP;
                                break;
                        default:
+                               if (ppp->flags & SC_DEBUG)
+                                       printk(KERN_DEBUG "pppioc[gs]npmode: "
+                                              "invalid proto %d\n", npi.protocol);
                                error = -EINVAL;
                        }
 
@@ -2516,15 +2528,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
 
                        if (param2 == PPPIOCGNPMODE) {
                                npi.mode = ppp->sc_npmode[npi.protocol];
-                               error = verify_area (VERIFY_WRITE,
-                                                    (void *) param3,
-                                                    sizeof (npi));
-                               if (error != 0)
-                                       break;
 
-                               memcpy_tofs ((void *) param3,
-                                            &npi,
-                                            sizeof (npi));
+                               COPY_TO_USER (error,
+                                             (void *) param3,
+                                             &npi,
+                                             sizeof (npi));
                                break;
                        }
 
@@ -2546,15 +2554,11 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                break;
 
        case FIONREAD:
-               error = verify_area (VERIFY_WRITE,
-                                    (void *) param3,
-                                    sizeof (int));
-               if (error == 0) {
+               {
                        int count = ppp->ubuf->tail - ppp->ubuf->head;
                        if (count < 0)
                                count += (ppp->ubuf->size + 1);
-
-                       put_user (count, (int *) param3);
+                       PUT_USER (error, count, (int *) param3);
                }
                break;
 /*
@@ -2591,7 +2595,7 @@ ppp_tty_select (struct tty_struct *tty, struct inode *inode,
        if (!ppp)
                return -EBADF;
 
-       if (ppp->magic != PPP_MAGIC)
+       if (ppp->magic != PPP_MAGIC || tty != ppp->tty)
                return -EBADF;
 
        CHECK_PPP (0);
@@ -2684,10 +2688,6 @@ ppp_dev_close (struct device *dev)
        struct ppp *ppp = dev2ppp (dev);
 
        if (ppp2tty (ppp) == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                       "ppp: %s not connected to a TTY! can't go down!\n",
-                       dev->name);
                return -ENXIO;
        }
 /*
@@ -2710,19 +2710,15 @@ static int
 ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
 {
        int error;
-       int len;
-       char *result;
-/*
- * Must have write access to the buffer.
- */
-       result = (char *) ifr->ifr_ifru.ifru_data;
-       len    = strlen (szVersion) + 1;
-       error  = verify_area (VERIFY_WRITE, result, len);
+       char *result  = (char *) ifr->ifr_ifru.ifru_data;
+       int  len      = strlen (szVersion) + 1;
 /*
  * Move the version data
  */
-       if (error == 0)
-               memcpy_tofs (result, szVersion, len);
+       COPY_TO_USER (error,
+                     result,
+                     szVersion,
+                     len);
 
        return error;
 }
@@ -2736,19 +2732,12 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
 {
        struct ppp_stats *result, temp;
        int    error;
-/*
- * Must have write access to the buffer.
- */
-       result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
-       error = verify_area (VERIFY_WRITE,
-                            result,
-                            sizeof (temp));
 /*
  * Supply the information for the caller. First move the version data
  * then move the ppp stats; and finally the vj stats.
  */
        memset (&temp, 0, sizeof(temp));
-       if (error == 0 && dev->flags & IFF_UP) {
+       if (dev->flags & IFF_UP) {
                memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
                if (ppp->slcomp != NULL) {
                        temp.vj.vjs_packets    = ppp->slcomp->sls_o_compressed+
@@ -2763,8 +2752,13 @@ ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
                }
        }
 
-       if (error == 0)
-               memcpy_tofs (result, &temp, sizeof (temp));
+       result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+
+       COPY_TO_USER (error,
+                     result,
+                     &temp,
+                     sizeof (temp));
+
        return error;
 }
 
@@ -2777,13 +2771,6 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev
 {
        struct ppp_comp_stats *result, temp;
        int    error;
-/*
- * Must have write access to the buffer.
- */
-       result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
-       error = verify_area (VERIFY_WRITE,
-                            result,
-                            sizeof (temp));
 /*
  * Supply the information for the caller.
  */
@@ -2800,8 +2787,13 @@ ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev
 /*
  * Move the data to the caller's buffer
  */
-       if (error == 0)
-               memcpy_tofs (result, &temp, sizeof (temp));
+       result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
+
+       COPY_TO_USER (error,
+                     result,
+                     &temp,
+                     sizeof (temp));
+
        return error;
 }
 
@@ -2885,17 +2877,11 @@ ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, __u8 *data)
                break;
 
        case NPMODE_ERROR:
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
-                               "ppp_dev_xmit: npmode = NPMODE_ERROR on %s\n",
-                               dev->name);
-               return 0;
-
        case NPMODE_DROP:
                if (ppp->flags & SC_DEBUG)
-                       printk (KERN_WARNING
-                               "ppp_dev_xmit: npmode = NPMODE_DROP on %s\n",
-                               dev->name);
+                       printk (KERN_DEBUG
+                               "ppp_dev_xmit: npmode = %d on %s\n",
+                               ppp->sc_npmode[NP_IP], dev->name);
                return 0;
 
        case NPMODE_QUEUE:
@@ -3059,12 +3045,6 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
                dev_close (dev);
                return 0;
        }
-/*
- * Validate the tty linkage
- */
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
-                       dev->name, skb);
 /*
  * Validate the tty interface
  */
@@ -3081,6 +3061,14 @@ ppp_dev_xmit (sk_buff *skb, struct device *dev)
  */
        len   = skb->len;
        data  = skb_data(skb);
+
+       if (data == (__u8 *) 0) {
+               if (ppp->flags & SC_DEBUG)
+                       printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n",
+                               dev->name);
+               dev_kfree_skb (skb, FREE_WRITE);
+               return 0;
+       }
 /*
  * Look at the protocol in the skb to determine the difference between
  * an IP frame and an IPX frame.
@@ -3116,31 +3104,16 @@ static struct enet_statistics *
 ppp_dev_stats (struct device *dev)
 {
        struct ppp *ppp = dev2ppp (dev);
-       static struct enet_statistics ppp_stats;
-
-       ppp_stats.rx_packets          = ppp->stats.ppp_ipackets;
-       ppp_stats.rx_errors           = ppp->stats.ppp_ierrors;
-       ppp_stats.rx_dropped          = ppp->stats.ppp_ierrors;
-       ppp_stats.rx_fifo_errors      = 0;
-       ppp_stats.rx_length_errors    = 0;
-       ppp_stats.rx_over_errors      = 0;
-       ppp_stats.rx_crc_errors       = 0;
-       ppp_stats.rx_frame_errors     = 0;
-       ppp_stats.tx_packets          = ppp->stats.ppp_opackets;
-       ppp_stats.tx_errors           = ppp->stats.ppp_oerrors;
-       ppp_stats.tx_dropped          = 0;
-       ppp_stats.tx_fifo_errors      = 0;
-       ppp_stats.collisions          = 0;
-       ppp_stats.tx_carrier_errors   = 0;
-       ppp_stats.tx_aborted_errors   = 0;
-       ppp_stats.tx_window_errors    = 0;
-       ppp_stats.tx_heartbeat_errors = 0;
 
-       if (ppp->flags & SC_DEBUG)
-               printk (KERN_INFO "ppp_dev_stats called");
-       return &ppp_stats;
+       ppp->estats.rx_packets        = ppp->stats.ppp_ipackets;
+       ppp->estats.rx_errors         = ppp->stats.ppp_ierrors;
+       ppp->estats.tx_packets        = ppp->stats.ppp_opackets;
+       ppp->estats.tx_errors         = ppp->stats.ppp_oerrors;
+
+       return &ppp->estats;
 }
 
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
 static int ppp_dev_header (sk_buff *skb, struct device *dev,
                           __u16 type, void *daddr,
                           void *saddr, unsigned int len)
@@ -3150,10 +3123,11 @@ static int ppp_dev_header (sk_buff *skb, struct device *dev,
 
 static int
 ppp_dev_rebuild (void *eth, struct device *dev,
-                 unsigned long raddr, struct sk_buff *skb)
+                unsigned long raddr, struct sk_buff *skb)
 {
        return (0);
 }
+#endif
 
 /*************************************************************
  * UTILITIES
@@ -3171,15 +3145,13 @@ ppp_find (int pid_value)
        /* try to find the exact same free device which we had before */
        ctl      = ppp_list;
        if_num   = 0;
-  
+
        while (ctl) {
                ppp = ctl2ppp (ctl);
-               if (!set_bit(0, &ppp->inuse)) {
-                       if (ppp->sc_xfer == pid_value) {
-                               ppp->sc_xfer = 0;
-                               return (ppp);
-                       }
-                       clear_bit (0, &ppp->inuse);
+               if (ppp->sc_xfer == pid_value) {
+                       set_bit(0, &ppp->inuse);
+                       ppp->sc_xfer = 0;
+                       return (ppp);
                }
                ctl = ctl->next;
                if (++if_num == max_dev)
@@ -3201,7 +3173,7 @@ ppp_alloc (void)
        /* try to find an free device */
        ctl      = ppp_list;
        if_num   = 0;
-  
+
        while (ctl) {
                ppp = ctl2ppp (ctl);
                if (!set_bit(0, &ppp->inuse))
@@ -3224,8 +3196,9 @@ ppp_alloc (void)
 
                ppp->line      = if_num;
                ppp->tty       = NULL;
+               ppp->backup_tty = NULL;
                ppp->dev       = dev;
-    
+
                dev->next      = NULL;
                dev->init      = ppp_init_dev;
                dev->name      = ctl->name;
@@ -3233,7 +3206,7 @@ ppp_alloc (void)
                dev->priv      = (void *) ppp;
 
                sprintf (dev->name, "ppp%d", if_num);
-    
+
                /* link in the new channel */
                ctl->next      = ppp_list;
                ppp_list       = ctl;
@@ -3331,7 +3304,7 @@ static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
 static struct compressor *find_compressor (int type)
 {
        struct compressor_link *lnk;
-       __u32 flags;
+       unsigned long flags;
 
        save_flags(flags);
        cli();
@@ -3352,7 +3325,7 @@ static struct compressor *find_compressor (int type)
 static int ppp_register_compressor (struct compressor *cp)
 {
        struct compressor_link *new;
-       __u32 flags;
+       unsigned long flags;
 
        new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
 
@@ -3380,7 +3353,7 @@ static void ppp_unregister_compressor (struct compressor *cp)
 {
        struct compressor_link *prev = (struct compressor_link *) 0;
        struct compressor_link *lnk;
-       __u32 flags;
+       unsigned long flags;
 
        save_flags(flags);
        cli();
@@ -3416,8 +3389,10 @@ init_module(void)
        if (status != 0)
                printk (KERN_INFO
                       "PPP: ppp_init() failure %d\n", status);
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
        else
                (void) register_symtab (&ppp_syms);
+#endif
        return (status);
 }
 
@@ -3472,7 +3447,7 @@ cleanup_module(void)
                       "PPP: ppp line discipline successfully unregistered\n");
 /*
  * De-register the devices so that there is no problem with them
- */    
+ */
        next_ctl = ppp_list;
        while (next_ctl) {
                ctl      = next_ctl;