]> git.ozlabs.org Git - ppp.git/blobdiff - linux/ppp.c
update for 2.3.11
[ppp.git] / linux / ppp.c
index f465e066029d62962e78fd6b36eaf877a5bc4df7..0fa98fd1eebffd00101716061106ed3f8a0f342a 100644 (file)
@@ -4,7 +4,7 @@
  *  Al Longyear <longyear@netcom.com>
  *  Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
  *
- *  ==FILEVERSION 981004==
+ *  ==FILEVERSION 990910==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -45,7 +45,7 @@
 
 #define PPP_MAX_RCV_QLEN       32      /* max # frames we queue up for pppd */
 
-/* $Id: ppp.c,v 1.20 1999/01/19 23:57:44 paulus Exp $ */
+/* $Id: ppp.c,v 1.33 1999/12/23 01:48:45 paulus Exp $ */
 
 #include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kerneld.h>
 #endif
 
-#define PPP_VERSION    "2.3.5"
+#undef PPP_VERSION
+#define PPP_VERSION    "2.3.11"
 
 #if LINUX_VERSION_CODE >= VERSION(2,1,4)
 
 #endif
 
 #if LINUX_VERSION_CODE < VERSION(2,1,57)
-#define signal_pending(tsk)    ((tsk)->pending & ~(tsk)->blocked)
+#define signal_pending(tsk)    ((tsk)->signal & ~(tsk)->blocked)
 #endif
 
 #if LINUX_VERSION_CODE < VERSION(2,1,60)
@@ -155,20 +156,43 @@ typedef ssize_t           rw_ret_t;
 typedef size_t         rw_count_t;
 #endif
 
+#if LINUX_VERSION_CODE < VERSION(2,1,86)
+#define KFREE_SKB(s)   dev_kfree_skb((s), FREE_WRITE)
+#else
+#define KFREE_SKB(s)   kfree_skb(s)
+#endif
+
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
+#define LIBERATE_SKB(s)        ((s)->free = 1)
+#else
+#define LIBERATE_SKB(s)        do { } while (0)
+#endif
+
+#if LINUX_VERSION_CODE < VERSION(2,1,95)
+#define SUSER()                suser()
+#else
+#define SUSER()                capable(CAP_NET_ADMIN)
+#endif
+
+#if LINUX_VERSION_CODE < VERSION(2,2,0)
+#define wmb()          mb()
+#endif
+
 /*
  * Local functions
  */
 
-#ifdef CONFIG_MODULES
 static int ppp_register_compressor (struct compressor *cp);
 static void ppp_unregister_compressor (struct compressor *cp);
-#endif
 
 static void ppp_async_init(struct ppp *ppp);
 static void ppp_async_release(struct ppp *ppp);
+static int ppp_tty_sync_push(struct ppp *ppp);
 static int ppp_tty_push(struct ppp *ppp);
 static int ppp_async_encode(struct ppp *ppp);
 static int ppp_async_send(struct ppp *, struct sk_buff *);
+static int ppp_sync_send(struct ppp *, struct sk_buff *);
+static void ppp_tty_flush_output(struct ppp *);
 
 static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
 static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
@@ -241,7 +265,6 @@ static struct symbol_table ppp_syms = {
 #include <linux/symtab_begin.h>
        X(ppp_register_compressor),
        X(ppp_unregister_compressor),
-       X(ppp_crc16_table),
 #include <linux/symtab_end.h>
 };
 #else
@@ -318,7 +341,9 @@ __u16 ppp_crc16_table[256] =
        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
+#if LINUX_VERSION_CODE >= VERSION(2,1,18)
 EXPORT_SYMBOL(ppp_crc16_table);
+#endif
 
 #ifdef CHECK_CHARACTERS
 static __u32 paritytab[8] =
@@ -353,7 +378,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;
@@ -441,10 +468,10 @@ ppp_async_release(struct ppp *ppp)
        struct sk_buff *skb;
 
        if ((skb = ppp->rpkt) != NULL)
-               kfree_skb(skb);
+               KFREE_SKB(skb);
        ppp->rpkt = NULL;
        if ((skb = ppp->tpkt) != NULL)
-               kfree_skb(skb);
+               KFREE_SKB(skb);
        ppp->tpkt = NULL;
 }
 
@@ -531,6 +558,7 @@ ppp_tty_close (struct tty_struct *tty)
                ppp->tty = ppp->backup_tty;
                if (ppp_tty_push(ppp))
                        ppp_output_wakeup(ppp);
+               wake_up_interruptible(&ppp->read_wait);
        } else {
                ppp->tty = 0;
                ppp->sc_xfer = 0;
@@ -596,7 +624,6 @@ ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
                if (file->f_flags & O_NONBLOCK)
                        break;
 
-               current->timeout = 0;
                interruptible_sleep_on(&ppp->read_wait);
                err = -EINTR;
                if (signal_pending(current))
@@ -629,7 +656,7 @@ ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
                err = -EFAULT;
 
 out:
-       kfree_skb(skb);
+       KFREE_SKB(skb);
        return err;
 }
 
@@ -676,13 +703,14 @@ ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
                printk(KERN_ERR "ppp_tty_write: no memory\n");
                return 0;
        }
+       LIBERATE_SKB(skb);
        new_data = skb_put(skb, count);
 
        /*
         * Retrieve the user's buffer
         */
        if (COPY_FROM_USER(new_data, data, count)) {
-               kfree_skb(skb);
+               KFREE_SKB(skb);
                return -EFAULT;
        }
 
@@ -716,7 +744,7 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
        /*
         * The user must have an euid of root to do these requests.
         */
-       if (!capable(CAP_NET_ADMIN))
+       if (!SUSER())
                return -EPERM;
 
        switch (param2) {
@@ -810,6 +838,21 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
                error = n_tty_ioctl (tty, file, param2, param3);
                break;
 
+       case TCFLSH:
+               /*
+                * Flush our buffers, then call the generic code to
+                * flush the serial port's buffer.
+                */
+               if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {
+                       struct sk_buff *skb;
+                       while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+                               KFREE_SKB(skb);
+               }
+               if (param3 == TCIOFLUSH || param3 == TCOFLUSH)
+                       ppp_tty_flush_output(ppp);
+               error = n_tty_ioctl (tty, file, param2, param3);
+               break;
+
        case FIONREAD:
                /*
                 * Returns how many bytes are available for a read().
@@ -935,6 +978,135 @@ ppp_tty_wakeup (struct tty_struct *tty)
                ppp_output_wakeup(ppp);
 }
 
+/*
+ * Send a packet to the peer over a synchronous tty line.
+ * All encoding and FCS are handled by hardware.
+ * Addr/Ctrl and Protocol field compression implemented.
+ * Returns -1 iff the packet could not be accepted at present,
+ * 0 if the packet was accepted but we can't accept another yet, or
+ * 1 if we can accept another packet immediately.
+ * If this procedure returns 0, ppp_output_wakeup will be called
+ * exactly once.
+ */
+static int
+ppp_sync_send(struct ppp *ppp, struct sk_buff *skb)
+{
+       unsigned char *data;
+       int islcp;
+       
+       CHECK_PPP(0);
+
+       if (ppp->tpkt != NULL)
+               return -1;
+       ppp->tpkt = skb;
+
+       data = ppp->tpkt->data;
+       
+       /*
+        * LCP packets with code values between 1 (configure-reqest)
+        * and 7 (code-reject) must be sent as though no options
+        * had been negotiated.
+        */
+       islcp = PPP_PROTOCOL(data) == PPP_LCP
+               && 1 <= data[PPP_HDRLEN] && data[PPP_HDRLEN] <= 7;
+
+       /* only reset idle time for data packets */
+       if (PPP_PROTOCOL(data) < 0x8000)
+               ppp->last_xmit = jiffies;
+       ++ppp->stats.ppp_opackets;
+       ppp->stats.ppp_ooctects += ppp->tpkt->len;
+
+       if ( !(data[2]) && (ppp->flags & SC_COMP_PROT) ) {
+               /* compress protocol field */
+               data[2] = data[1];
+               data[1] = data[0];
+               skb_pull(ppp->tpkt,1);
+               data = ppp->tpkt->data;
+       }
+       
+       /*
+        * Do address/control compression
+        */
+       if ((ppp->flags & SC_COMP_AC) && !islcp
+           && PPP_ADDRESS(data) == PPP_ALLSTATIONS
+           && PPP_CONTROL(data) == PPP_UI) {
+               /* strip addr and control field */
+               skb_pull(ppp->tpkt,2);
+       }
+
+       return ppp_tty_sync_push(ppp);
+}
+
+/*
+ * Push a synchronous frame out to the tty.
+ * Returns 1 if frame accepted (or discarded), 0 otherwise.
+ */
+static int
+ppp_tty_sync_push(struct ppp *ppp)
+{
+       int sent;
+       struct tty_struct *tty = ppp2tty(ppp);
+       unsigned long flags;
+               
+       CHECK_PPP(0);
+
+       if (ppp->tpkt == NULL)
+               return 0;
+               
+       /* prevent reentrancy with tty_pushing flag */          
+       save_flags(flags);
+       cli();
+       if (ppp->tty_pushing) {
+               /* record wakeup attempt so we don't lose */
+               /* a wakeup call while doing push processing */
+               ppp->woke_up=1;
+               restore_flags(flags);
+               return 0;
+       }
+       ppp->tty_pushing = 1;
+       restore_flags(flags);
+       
+       if (tty == NULL || tty->disc_data != (void *) ppp)
+               goto flush;
+               
+       for(;;){
+               ppp->woke_up=0;
+               
+               /* Note: Sync driver accepts complete frame or nothing */
+               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+               sent = tty->driver.write(tty, 0, ppp->tpkt->data, ppp->tpkt->len);
+               if (sent < 0) {
+                       /* write error (possible loss of CD) */
+                       /* record error and discard current packet */
+                       ppp->stats.ppp_oerrors++;
+                       break;
+               }
+               ppp->stats.ppp_obytes += sent;
+               if (sent < ppp->tpkt->len) {
+                       /* driver unable to accept frame just yet */
+                       save_flags(flags);
+                       cli();
+                       if (ppp->woke_up) {
+                               /* wake up called while processing */
+                               /* try to send the frame again */
+                               restore_flags(flags);
+                               continue;
+                       }
+                       /* wait for wakeup callback to try send again */
+                       ppp->tty_pushing = 0;
+                       restore_flags(flags);
+                       return 0;
+               }
+               break;
+       }
+flush: 
+       /* done with current packet (sent or discarded) */
+       KFREE_SKB(ppp->tpkt);
+       ppp->tpkt = 0;
+       ppp->tty_pushing = 0;
+       return 1;
+}
+
 /*
  * Send a packet to the peer over an async tty line.
  * Returns -1 iff the packet could not be accepted at present,
@@ -967,14 +1139,21 @@ ppp_tty_push(struct ppp *ppp)
 {
        int avail, sent, done = 0;
        struct tty_struct *tty = ppp2tty(ppp);
+       
+       if (ppp->flags & SC_SYNC) 
+               return ppp_tty_sync_push(ppp);
 
        CHECK_PPP(0);
-       if (ppp->tty_pushing)
+       if (ppp->tty_pushing) {
+               ppp->woke_up = 1;
                return 0;
+       }
        if (tty == NULL || tty->disc_data != (void *) ppp)
                goto flush;
        while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
                ppp->tty_pushing = 1;
+               mb();
+               ppp->woke_up = 0;
                avail = ppp->olim - ppp->optr;
                if (avail > 0) {
                        tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
@@ -984,25 +1163,32 @@ ppp_tty_push(struct ppp *ppp)
                        ppp->stats.ppp_obytes += sent;
                        ppp->optr += sent;
                        if (sent < avail) {
+                               wmb();
                                ppp->tty_pushing = 0;
+                               mb();
+                               if (ppp->woke_up)
+                                       continue;
                                return done;
                        }
                }
                if (ppp->tpkt != 0)
                        done = ppp_async_encode(ppp);
+               wmb();
                ppp->tty_pushing = 0;
        }
        return done;
 
 flush:
        ppp->tty_pushing = 1;
+       mb();
        ppp->stats.ppp_oerrors++;
        if (ppp->tpkt != 0) {
-               kfree_skb(ppp->tpkt);
+               KFREE_SKB(ppp->tpkt);
                ppp->tpkt = 0;
                done = 1;
        }
        ppp->optr = ppp->olim;
+       wmb();
        ppp->tty_pushing = 0;
        return done;
 }
@@ -1102,7 +1288,7 @@ ppp_async_encode(struct ppp *ppp)
                *buf++ = PPP_FLAG;
                ppp->olim = buf;
 
-               kfree_skb(ppp->tpkt);
+               KFREE_SKB(ppp->tpkt);
                ppp->tpkt = 0;
                return 1;
        }
@@ -1116,6 +1302,32 @@ ppp_async_encode(struct ppp *ppp)
        return 0;
 }
 
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_tty_flush_output(struct ppp *ppp)
+{
+       struct sk_buff *skb;
+       int done = 0;
+
+       while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+               KFREE_SKB(skb);
+       ppp->tty_pushing = 1;
+       mb();
+       ppp->optr = ppp->olim;
+       if (ppp->tpkt != NULL) {
+               KFREE_SKB(ppp->tpkt);
+               ppp->tpkt = 0;
+               done = 1;
+       }
+       wmb();
+       ppp->tty_pushing = 0;
+       if (done)
+               ppp_output_wakeup(ppp);
+}
+
 /*
  * Callback function from tty driver. Return the amount of space left
  * in the receiver's buffer to decide if remote transmitter is to be
@@ -1165,6 +1377,74 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
 
        ppp->stats.ppp_ibytes += count;
        skb = ppp->rpkt;
+       
+       if ( ppp->flags & SC_SYNC ) {
+               /* synchronous mode */
+               
+               if (ppp->toss==0xE0) {
+                       /* this is the 1st frame, reset vj comp */
+                       ppp_receive_error(ppp);
+                       ppp->toss = 0;
+               }
+               
+               /*
+                * Allocate an skbuff for frame.
+                * The 128 is room for VJ header expansion.
+                */
+               
+               if (skb == NULL)
+                       skb = dev_alloc_skb(ppp->mru + 128 + PPP_HDRLEN);
+                       
+               if (skb == NULL) {
+                       if (ppp->flags & SC_DEBUG)
+                               printk(KERN_DEBUG "couldn't "
+                                      "alloc skb for recv\n");
+               } else {
+                       LIBERATE_SKB(skb);
+                       /*
+                        * Decompress A/C and protocol compression here.
+                        */
+                       p = skb_put(skb, 2);
+                       p[0] = PPP_ALLSTATIONS;
+                       p[1] = PPP_UI;
+                       if (*data == PPP_ALLSTATIONS) {
+                               data += 2;
+                               count -= 2;
+                       }
+                       if ((*data & 1) != 0) {
+                               p = skb_put(skb, 1);
+                               p[0] = 0;
+                       }
+
+                       /* copy frame to socket buffer */
+                       p = skb_put(skb, count);
+                       memcpy(p,data,count);
+                       
+                       /*
+                        * Check if we've overflowed the MRU
+                        */
+                       if (skb->len >= ppp->mru + PPP_HDRLEN + 2
+                           || skb_tailroom(skb) <= 0) {
+                               ++ppp->estats.rx_length_errors;
+                               if (ppp->flags & SC_DEBUG)
+                                       printk(KERN_DEBUG "rcv frame too long: "
+                                              "len=%d mru=%d hroom=%d troom=%d\n",
+                                              skb->len, ppp->mru, skb_headroom(skb),
+                                              skb_tailroom(skb));
+                       } else {
+                               if (!ppp_receive_frame(ppp, skb)) {
+                                       KFREE_SKB(skb);
+                                       ppp_receive_error(ppp);
+                               }
+                       }
+               
+                       /* Reset for the next frame */
+                       skb = NULL;
+               }
+               ppp->rpkt = skb;
+               return;
+       }
+       
        while (count-- > 0) {
                /*
                 * Collect the character and error condition for the character.
@@ -1231,7 +1511,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
                                               "ppp: tossing frame (%x)\n",
                                               ppp->toss);
                                if (skb != NULL)
-                                       kfree_skb(skb);
+                                       KFREE_SKB(skb);
                                if (!(ppp->toss == 0xE0 || ppp->toss == 0x80))
                                        ++ppp->stats.ppp_ierrors;
                                ppp_receive_error(ppp);
@@ -1280,6 +1560,7 @@ ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
                                ppp->toss = 1;
                                continue;
                        }
+                       LIBERATE_SKB(skb);
                }
 
                /*
@@ -1359,6 +1640,7 @@ typedef struct ppp_proto_struct {
 } ppp_proto_type;
 
 static int rcv_proto_ip                (struct ppp *, struct sk_buff *);
+static int rcv_proto_ipv6      (struct ppp *, struct sk_buff *);
 static int rcv_proto_ipx       (struct ppp *, struct sk_buff *);
 static int rcv_proto_at                (struct ppp *, struct sk_buff *);
 static int rcv_proto_vjc_comp  (struct ppp *, struct sk_buff *);
@@ -1369,6 +1651,7 @@ static int rcv_proto_unknown      (struct ppp *, struct sk_buff *);
 static
 ppp_proto_type proto_list[] = {
        { PPP_IP,         rcv_proto_ip         },
+       { PPP_IPV6,       rcv_proto_ipv6       },
        { PPP_IPX,        rcv_proto_ipx        },
        { PPP_AT,         rcv_proto_at         },
        { PPP_VJC_COMP,   rcv_proto_vjc_comp   },
@@ -1531,7 +1814,7 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3)
        /*
         * The user must have an euid of root to do these requests.
         */
-       if (!capable(CAP_NET_ADMIN))
+       if (!SUSER())
                return -EPERM;
 
        switch (param2) {
@@ -1680,6 +1963,9 @@ ppp_ioctl(struct ppp *ppp, unsigned int param2, unsigned long param3)
                        break;
 
                switch (npi.protocol) {
+               case PPP_IPV6:
+                       npi.protocol = NP_IPV6;
+                       break;
                case PPP_IP:
                        npi.protocol = NP_IP;
                        break;
@@ -1985,7 +2271,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
        if (skb == NULL)
                return 1;
        if (skb->len == 0) {
-               kfree_skb(skb);
+               KFREE_SKB(skb);
                return 1;
        }
        data = skb->data;
@@ -2002,23 +2288,25 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
                return 0;
        }
 
-       /*
-        * Verify the FCS of the frame and discard the FCS characters
-        * from the end of the buffer.
-        */
-       if (ppp->rfcs != PPP_GOODFCS) {
-               if (ppp->flags & SC_DEBUG) {
-                       printk(KERN_DEBUG
-                              "ppp: frame with bad fcs, length = %d\n",
-                              count);
-                       ppp_print_buffer("bad frame", data, count);
+       if ( !(ppp->flags & SC_SYNC) ) { 
+               /*
+                * Verify the FCS of the frame and discard the FCS characters
+                * from the end of the buffer.
+                */
+               if (ppp->rfcs != PPP_GOODFCS) {
+                       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;
                }
-               ++ppp->estats.rx_crc_errors;
-               return 0;
+               count -= 2;             /* ignore the fcs characters */
+               skb_trim(skb, count);
        }
-       count -= 2;             /* ignore the fcs characters */
-       skb_trim(skb, count);
-
+       
        /*
         * Process the active decompressor.
         */
@@ -2034,13 +2322,14 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
                                printk(KERN_ERR "ppp_recv_frame: no memory\n");
                                new_count = DECOMP_ERROR;
                        } else {
+                               LIBERATE_SKB(new_skb);
                                new_count = (*ppp->sc_rcomp->decompress)
                                        (ppp->sc_rc_state, data, count,
                                         new_skb->data, ppp->mru + PPP_HDRLEN);
                        }
                        if (new_count > 0) {
                                /* Frame was decompressed OK */
-                               kfree_skb(skb);
+                               KFREE_SKB(skb);
                                skb = new_skb;
                                count = new_count;
                                data = skb_put(skb, count);
@@ -2055,7 +2344,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
                                        printk(KERN_INFO "%s: decomp err %d\n",
                                               ppp->name, new_count);
                                if (new_skb != 0)
-                                       kfree_skb(new_skb);
+                                       KFREE_SKB(new_skb);
                                if (ppp->slcomp != 0)
                                        slhc_toss(ppp->slcomp);
                                ++ppp->stats.ppp_ierrors;
@@ -2103,7 +2392,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb)
         * Update the appropriate statistic counter.
         */
        if (!(*proto_ptr->func)(ppp, skb)) {
-               kfree_skb(skb);
+               KFREE_SKB(skb);
                ++ppp->stats.ppp_discards;
        }
 
@@ -2138,9 +2427,6 @@ ppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb)
        skb_pull(skb, PPP_HDRLEN);      /* pull off ppp header */
        skb->mac.raw   = skb->data;
        ppp->last_recv = jiffies;
-#if LINUX_VERSION_CODE < VERSION(2,1,15)
-       skb->free = 1;
-#endif
        netif_rx (skb);
        return 1;
 }
@@ -2158,6 +2444,19 @@ rcv_proto_ip(struct ppp *ppp, struct sk_buff *skb)
        return 0;
 }
 
+/*
+ * Process the receipt of an IPv6 frame
+ */
+static int
+rcv_proto_ipv6(struct ppp *ppp, struct sk_buff *skb)
+{
+       CHECK_PPP(0);
+       if ((ppp2dev(ppp)->flags & IFF_UP) && (skb->len > 0)
+           && ppp->sc_npmode[NP_IPV6] == NPMODE_PASS)
+               return ppp_rcv_rx(ppp, ETH_P_IPV6, skb);
+       return 0;
+}
+
 /*
  * Process the receipt of an IPX frame
  */
@@ -2197,13 +2496,17 @@ rcv_proto_vjc_comp(struct ppp *ppp, struct sk_buff *skb)
                return 0;
        new_count = slhc_uncompress(ppp->slcomp, skb->data + PPP_HDRLEN,
                                    skb->len - PPP_HDRLEN);
-       if (new_count < 0) {
+       if (new_count <= 0) {
                if (ppp->flags & SC_DEBUG)
                        printk(KERN_NOTICE
                               "ppp: error in VJ decompression\n");
                return 0;
        }
-       skb_put(skb, new_count + PPP_HDRLEN - skb->len);
+       new_count += PPP_HDRLEN;
+       if (new_count > skb->len)
+               skb_put(skb, new_count - skb->len);
+       else
+               skb_trim(skb, new_count);
        return rcv_proto_ip(ppp, skb);
 }
 
@@ -2248,7 +2551,7 @@ rcv_proto_unknown(struct ppp *ppp, struct sk_buff *skb)
        while (ppp->rcv_q.qlen > PPP_MAX_RCV_QLEN) {
                struct sk_buff *skb = skb_dequeue(&ppp->rcv_q);
                if (skb)
-                       kfree_skb(skb);
+                       KFREE_SKB(skb);
        }
 
        wake_up_interruptible (&ppp->read_wait);
@@ -2345,10 +2648,11 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                new_skb = alloc_skb(ppp->mtu + PPP_HDRLEN, GFP_ATOMIC);
                if (new_skb == NULL) {
                        printk(KERN_ERR "ppp_send_frame: no memory\n");
-                       kfree_skb(skb);
+                       KFREE_SKB(skb);
                        ppp->xmit_busy = 0;
                        return;
                }
+               LIBERATE_SKB(new_skb);
 
                /* Compress the frame. */
                new_count = (*ppp->sc_xcomp->compress)
@@ -2358,21 +2662,24 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                /* Did it compress? */
                if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
                        skb_put(new_skb, new_count);
-                       kfree_skb(skb);
+                       KFREE_SKB(skb);
                        skb = new_skb;
                } else {
                        /*
                         * The frame could not be compressed, or it could not
                         * be sent in compressed form because CCP is down.
                         */
-                       kfree_skb(new_skb);
+                       KFREE_SKB(new_skb);
                }
        }
 
        /*
         * Send the frame
         */
-       ret = ppp_async_send(ppp, skb);
+       if ( ppp->flags & SC_SYNC ) 
+               ret = ppp_sync_send(ppp, skb);
+       else
+               ret = ppp_async_send(ppp, skb);
        if (ret > 0) {
                /* we can release the lock */
                ppp->xmit_busy = 0;
@@ -2397,6 +2704,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb)
                printk(KERN_ERR "ppp: no memory for vj compression\n");
                return skb;
        }
+       LIBERATE_SKB(new_skb);
 
        orig_data = data = skb->data + PPP_HDRLEN;
        len = slhc_compress(ppp->slcomp, data, skb->len - PPP_HDRLEN,
@@ -2405,7 +2713,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb)
 
        if (data == orig_data) {
                /* Couldn't compress the data */
-               kfree_skb(new_skb);
+               KFREE_SKB(new_skb);
                return skb;
        }
 
@@ -2427,7 +2735,7 @@ ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb)
        data[2] = 0;
        data[3] = proto;
 
-       kfree_skb(skb);
+       KFREE_SKB(skb);
        return new_skb;
 }
 
@@ -2505,7 +2813,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
        if (skb == NULL)
                return 0;
        if (skb->data == NULL) {
-               kfree_skb(skb);
+               KFREE_SKB(skb);
                return 0;
        }
 
@@ -2514,7 +2822,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
         * queued to be sent.
         */
        if (!ppp->inuse) {
-               dev_kfree_skb(skb);
+               KFREE_SKB(skb);
                return 0;
        }
 
@@ -2526,7 +2834,7 @@ ppp_dev_xmit(struct 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);
+               KFREE_SKB(skb);
                return 0;
        }
 
@@ -2539,6 +2847,10 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
                proto = PPP_IP;
                npmode = ppp->sc_npmode[NP_IP];
                break;
+       case ETH_P_IPV6:
+               proto = PPP_IPV6;
+               npmode = ppp->sc_npmode[NP_IPV6];
+               break;
        case ETH_P_IPX:
                proto = PPP_IPX;
                npmode = ppp->sc_npmode[NP_IPX];
@@ -2552,7 +2864,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
                if (ppp->flags & SC_DEBUG)
                        printk(KERN_INFO "%s: packet for unknown proto %x\n",
                               ppp->name, ntohs(skb->protocol));
-               dev_kfree_skb(skb);
+               KFREE_SKB(skb);
                return 0;
        }
 
@@ -2571,7 +2883,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
                 */
                if (ppp->flags & SC_DEBUG)
                        printk(KERN_DEBUG "%s: returning frame\n", ppp->name);
-               dev_kfree_skb(skb);
+               KFREE_SKB(skb);
                return 0;
 
        case NPMODE_ERROR:
@@ -2580,7 +2892,7 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
                        printk(KERN_DEBUG
                               "ppp_dev_xmit: dropping (npmode = %d) on %s\n",
                               npmode, ppp->name);
-               dev_kfree_skb(skb);
+               KFREE_SKB(skb);
                return 0;
        }
 
@@ -2609,14 +2921,15 @@ ppp_dev_xmit(struct sk_buff *skb, struct device *dev)
                if (new_skb == NULL) {
                        printk(KERN_ERR "%s: skb hdr alloc failed\n",
                               ppp->name);
-                       dev_kfree_skb(skb);
+                       KFREE_SKB(skb);
                        ppp->xmit_busy = 0;
                        ppp_send_frames(ppp);
                        return 0;
                }
+               LIBERATE_SKB(new_skb);
                skb_reserve(new_skb, PPP_HDRLEN);
                memcpy(skb_put(new_skb, skb->len), skb->data, skb->len);
-               dev_kfree_skb(skb);
+               KFREE_SKB(skb);
                skb = new_skb;
        }
 
@@ -2738,7 +3051,12 @@ ppp_alloc(void)
         */
        dev = ppp2dev(ppp);
        dev->name = ppp->name;
+#if LINUX_VERSION_CODE < VERSION(2,1,31)
+       if_num = (ppp_list == 0)? 0: ppp_last->line + 1;
+       sprintf(ppp->name, "ppp%d", if_num);
+#else
        if_num = dev_alloc_name(dev, "ppp%d");
+#endif
        if (if_num < 0) {
                printk(KERN_ERR "ppp: dev_alloc_name failed (%d)\n", if_num);
                kfree(ppp);
@@ -2830,9 +3148,9 @@ ppp_release(struct ppp *ppp)
        }
 
        while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
-               kfree_skb(skb);
+               KFREE_SKB(skb);
        while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
-               kfree_skb(skb);
+               KFREE_SKB(skb);
 
        ppp->inuse = 0;
        if (ppp->dev.tbusy) {
@@ -2934,7 +3252,6 @@ static struct compressor *find_compressor (int type)
        return (struct compressor *) 0;
 }
 
-#ifdef CONFIG_MODULES
 static int ppp_register_compressor (struct compressor *cp)
 {
        struct compressor_link *new;
@@ -2987,7 +3304,6 @@ static void ppp_unregister_compressor (struct compressor *cp)
        }
        restore_flags(flags);
 }
-#endif
 
 /*************************************************************
  * Module support routines