[PATCH] bcm43xx: correct "Move IV/ICV stripping into ieee80211_rx"
[safe/jmp/linux-2.6] / drivers / net / ppp_generic.c
index ab726ab..c6de566 100644 (file)
  * ==FILEVERSION 20041108==
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
@@ -46,6 +44,7 @@
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/device.h>
+#include <linux/mutex.h>
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
@@ -137,13 +136,14 @@ struct ppp {
 
 /*
  * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
+ * SC_MUST_COMP
  * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
  * Bits in xstate: SC_COMP_RUN
  */
 #define SC_FLAG_BITS   (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
                         |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
-                        |SC_COMP_TCP|SC_REJ_COMP_TCP)
+                        |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)
 
 /*
  * Private data structure for each channel.
@@ -192,16 +192,16 @@ struct cardmap {
        void *ptr[CARDMAP_WIDTH];
 };
 static void *cardmap_get(struct cardmap *map, unsigned int nr);
-static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
+static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
 static unsigned int cardmap_find_first_free(struct cardmap *map);
 static void cardmap_destroy(struct cardmap **map);
 
 /*
- * all_ppp_sem protects the all_ppp_units mapping.
+ * all_ppp_mutex protects the all_ppp_units mapping.
  * It also ensures that finding a ppp unit in the all_ppp_units map
  * and updating its file.refcnt field is atomic.
  */
-static DECLARE_MUTEX(all_ppp_sem);
+static DEFINE_MUTEX(all_ppp_mutex);
 static struct cardmap *all_ppp_units;
 static atomic_t ppp_unit_count = ATOMIC_INIT(0);
 
@@ -304,7 +304,7 @@ static const int npindex_to_proto[NUM_NP] = {
        PPP_MPLS_UC,
        PPP_MPLS_MC,
 };
-       
+
 /* Translates an ethertype into an NP index */
 static inline int ethertype_to_npindex(int ethertype)
 {
@@ -523,9 +523,6 @@ static int get_filter(void __user *arg, struct sock_filter **p)
        if (copy_from_user(&uprog, arg, sizeof(uprog)))
                return -EFAULT;
 
-       if (uprog.len > BPF_MAXINSNS)
-               return -EINVAL;
-
        if (!uprog.len) {
                *p = NULL;
                return 0;
@@ -806,7 +803,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
                /* Attach to an existing ppp unit */
                if (get_user(unit, p))
                        break;
-               down(&all_ppp_sem);
+               mutex_lock(&all_ppp_mutex);
                err = -ENXIO;
                ppp = ppp_find_unit(unit);
                if (ppp != 0) {
@@ -814,7 +811,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
                        file->private_data = &ppp->file;
                        err = 0;
                }
-               up(&all_ppp_sem);
+               mutex_unlock(&all_ppp_mutex);
                break;
 
        case PPPIOCATTCHAN:
@@ -863,11 +860,7 @@ static int __init ppp_init(void)
                        err = PTR_ERR(ppp_class);
                        goto out_chrdev;
                }
-               class_device_create(ppp_class, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
-               err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
-                               S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
-               if (err)
-                       goto out_class;
+               device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), "ppp");
        }
 
 out:
@@ -875,9 +868,6 @@ out:
                printk(KERN_ERR "failed to register PPP device (%d)\n", err);
        return err;
 
-out_class:
-       class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0));
-       class_destroy(ppp_class);
 out_chrdev:
        unregister_chrdev(PPP_MAJOR, "ppp");
        goto out;
@@ -1027,6 +1017,56 @@ ppp_xmit_process(struct ppp *ppp)
        ppp_xmit_unlock(ppp);
 }
 
+static inline struct sk_buff *
+pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
+{
+       struct sk_buff *new_skb;
+       int len;
+       int new_skb_size = ppp->dev->mtu +
+               ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
+       int compressor_skb_size = ppp->dev->mtu +
+               ppp->xcomp->comp_extra + PPP_HDRLEN;
+       new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
+       if (!new_skb) {
+               if (net_ratelimit())
+                       printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+               return NULL;
+       }
+       if (ppp->dev->hard_header_len > PPP_HDRLEN)
+               skb_reserve(new_skb,
+                           ppp->dev->hard_header_len - PPP_HDRLEN);
+
+       /* compressor still expects A/C bytes in hdr */
+       len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+                                  new_skb->data, skb->len + 2,
+                                  compressor_skb_size);
+       if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+               kfree_skb(skb);
+               skb = new_skb;
+               skb_put(skb, len);
+               skb_pull(skb, 2);       /* pull off A/C bytes */
+       } else if (len == 0) {
+               /* didn't compress, or CCP not up yet */
+               kfree_skb(new_skb);
+               new_skb = skb;
+       } else {
+               /*
+                * (len < 0)
+                * MPPE requires that we do not send unencrypted
+                * frames.  The compressor will return -1 if we
+                * should drop the frame.  We cannot simply test
+                * the compress_proto because MPPE and MPPC share
+                * the same number.
+                */
+               if (net_ratelimit())
+                       printk(KERN_ERR "ppp: compressor dropped pkt\n");
+               kfree_skb(skb);
+               kfree_skb(new_skb);
+               new_skb = NULL;
+       }
+       return new_skb;
+}
+
 /*
  * Compress and send a frame.
  * The caller should have locked the xmit path,
@@ -1113,29 +1153,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        /* try to do packet compression */
        if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
            && proto != PPP_LCP && proto != PPP_CCP) {
-               new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
-                                   GFP_ATOMIC);
-               if (new_skb == 0) {
-                       printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+               if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
                        goto drop;
                }
-               if (ppp->dev->hard_header_len > PPP_HDRLEN)
-                       skb_reserve(new_skb,
-                                   ppp->dev->hard_header_len - PPP_HDRLEN);
-
-               /* compressor still expects A/C bytes in hdr */
-               len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
-                                          new_skb->data, skb->len + 2,
-                                          ppp->dev->mtu + PPP_HDRLEN);
-               if (len > 0 && (ppp->flags & SC_CCP_UP)) {
-                       kfree_skb(skb);
-                       skb = new_skb;
-                       skb_put(skb, len);
-                       skb_pull(skb, 2);       /* pull off A/C bytes */
-               } else {
-                       /* didn't compress, or CCP not up yet */
-                       kfree_skb(new_skb);
-               }
+               skb = pad_compress_skb(ppp, skb);
+               if (!skb)
+                       goto drop;
        }
 
        /*
@@ -1155,7 +1180,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        return;
 
  drop:
-       kfree_skb(skb);
+       if (skb)
+               kfree_skb(skb);
        ++ppp->stats.tx_errors;
 }
 
@@ -1232,13 +1258,11 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
        navail = 0;     /* total # of usable channels (not deregistered) */
        hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
        i = 0;
-       list = &ppp->channels;
-       while ((list = list->next) != &ppp->channels) {
-               pch = list_entry(list, struct channel, clist);
+       list_for_each_entry(pch, &ppp->channels, clist) {
                navail += pch->avail = (pch->chan != NULL);
                if (pch->avail) {
-                       if (skb_queue_len(&pch->file.xq) == 0
-                           || !pch->had_frag) {
+                       if (skb_queue_empty(&pch->file.xq) ||
+                           !pch->had_frag) {
                                pch->avail = 2;
                                ++nfree;
                        }
@@ -1280,6 +1304,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 
        /* skip to the channel after the one we last used
           and start at that one */
+       list = &ppp->channels;
        for (i = 0; i < ppp->nxchan; ++i) {
                list = list->next;
                if (list == &ppp->channels) {
@@ -1374,8 +1399,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 
                /* try to send it down the channel */
                chan = pch->chan;
-               if (skb_queue_len(&pch->file.xq)
-                   || !chan->ops->start_xmit(chan, frag))
+               if (!skb_queue_empty(&pch->file.xq) ||
+                   !chan->ops->start_xmit(chan, frag))
                        skb_queue_tail(&pch->file.xq, frag);
                pch->had_frag = 1;
                p += flen;
@@ -1412,7 +1437,7 @@ ppp_channel_push(struct channel *pch)
 
        spin_lock_bh(&pch->downl);
        if (pch->chan != 0) {
-               while (skb_queue_len(&pch->file.xq) > 0) {
+               while (!skb_queue_empty(&pch->file.xq)) {
                        skb = skb_dequeue(&pch->file.xq);
                        if (!pch->chan->ops->start_xmit(pch->chan, skb)) {
                                /* put the packet back and try again later */
@@ -1426,7 +1451,7 @@ ppp_channel_push(struct channel *pch)
        }
        spin_unlock_bh(&pch->downl);
        /* see if there is anything from the attached unit to be sent */
-       if (skb_queue_len(&pch->file.xq) == 0) {
+       if (skb_queue_empty(&pch->file.xq)) {
                read_lock_bh(&pch->upl);
                ppp = pch->ppp;
                if (ppp != 0)
@@ -1553,6 +1578,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
            && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
                skb = ppp_decompress_frame(ppp, skb);
 
+       if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
+               goto err;
+
        proto = PPP_PROTO(skb);
        switch (proto) {
        case PPP_VJC_COMP:
@@ -1572,8 +1600,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                        kfree_skb(skb);
                        skb = ns;
                }
-               else if (!pskb_may_pull(skb, skb->len))
-                       goto err;
+               else
+                       skb->ip_summed = CHECKSUM_NONE;
 
                len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
                if (len <= 0) {
@@ -1591,11 +1619,11 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
        case PPP_VJC_UNCOMP:
                if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
                        goto err;
-               
+
                /* Until we fix the decompressor need to make sure
                 * data portion is linear.
                 */
-               if (!pskb_may_pull(skb, skb->len)) 
+               if (!pskb_may_pull(skb, skb->len))
                        goto err;
 
                if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
@@ -1653,11 +1681,11 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                    || ppp->npmode[npi] != NPMODE_PASS) {
                        kfree_skb(skb);
                } else {
-                       skb_pull(skb, 2);       /* chop off protocol */
+                       /* chop off protocol */
+                       skb_pull_rcsum(skb, 2);
                        skb->dev = ppp->dev;
                        skb->protocol = htons(npindex_to_ethertype[npi]);
                        skb->mac.raw = skb->data;
-                       skb->input_dev = ppp->dev;
                        netif_rx(skb);
                        ppp->dev->last_rx = jiffies;
                }
@@ -1731,7 +1759,7 @@ static void
 ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 {
        u32 mask, seq;
-       struct list_head *l;
+       struct channel *ch;
        int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
 
        if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
@@ -1785,8 +1813,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
         * The list of channels can't change because we have the receive
         * side of the ppp unit locked.
         */
-       for (l = ppp->channels.next; l != &ppp->channels; l = l->next) {
-               struct channel *ch = list_entry(l, struct channel, clist);
+       list_for_each_entry(ch, &ppp->channels, clist) {
                if (seq_before(ch->lastseq, seq))
                        seq = ch->lastseq;
        }
@@ -1968,10 +1995,9 @@ ppp_register_channel(struct ppp_channel *chan)
 {
        struct channel *pch;
 
-       pch = kmalloc(sizeof(struct channel), GFP_KERNEL);
+       pch = kzalloc(sizeof(struct channel), GFP_KERNEL);
        if (pch == 0)
                return -ENOMEM;
-       memset(pch, 0, sizeof(struct channel));
        pch->ppp = NULL;
        pch->chan = chan;
        chan->ppp = pch;
@@ -2159,7 +2185,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
        switch (CCP_CODE(dp)) {
        case CCP_CONFREQ:
 
-               /* A ConfReq starts negotiation of compression 
+               /* A ConfReq starts negotiation of compression
                 * in one direction of transmission,
                 * and hence brings it down...but which way?
                 *
@@ -2169,16 +2195,16 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
                if(inbound)
                        /* He is proposing what I should send */
                        ppp->xstate &= ~SC_COMP_RUN;
-               else    
+               else
                        /* I am proposing to what he should send */
                        ppp->rstate &= ~SC_DECOMP_RUN;
-               
+
                break;
-               
+
        case CCP_TERMREQ:
        case CCP_TERMACK:
                /*
-                * CCP is going down, both directions of transmission 
+                * CCP is going down, both directions of transmission
                 */
                ppp->rstate &= ~SC_DECOMP_RUN;
                ppp->xstate &= ~SC_COMP_RUN;
@@ -2272,10 +2298,8 @@ static struct compressor_entry *
 find_comp_entry(int proto)
 {
        struct compressor_entry *ce;
-       struct list_head *list = &compressor_list;
 
-       while ((list = list->next) != &compressor_list) {
-               ce = list_entry(list, struct compressor_entry, list);
+       list_for_each_entry(ce, &compressor_list, list) {
                if (ce->comp->compress_proto == proto)
                        return ce;
        }
@@ -2383,13 +2407,12 @@ ppp_create_interface(int unit, int *retp)
        int ret = -ENOMEM;
        int i;
 
-       ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL);
+       ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL);
        if (!ppp)
                goto out;
        dev = alloc_netdev(0, "", ppp_setup);
        if (!dev)
                goto out1;
-       memset(ppp, 0, sizeof(struct ppp));
 
        ppp->mru = PPP_MRU;
        init_ppp_file(&ppp->file, INTERFACE);
@@ -2411,7 +2434,7 @@ ppp_create_interface(int unit, int *retp)
        dev->do_ioctl = ppp_net_ioctl;
 
        ret = -EEXIST;
-       down(&all_ppp_sem);
+       mutex_lock(&all_ppp_mutex);
        if (unit < 0)
                unit = cardmap_find_first_free(all_ppp_units);
        else if (cardmap_get(all_ppp_units, unit) != NULL)
@@ -2429,13 +2452,18 @@ ppp_create_interface(int unit, int *retp)
        }
 
        atomic_inc(&ppp_unit_count);
-       cardmap_set(&all_ppp_units, unit, ppp);
-       up(&all_ppp_sem);
+       ret = cardmap_set(&all_ppp_units, unit, ppp);
+       if (ret != 0)
+               goto out3;
+
+       mutex_unlock(&all_ppp_mutex);
        *retp = 0;
        return ppp;
 
+out3:
+       atomic_dec(&ppp_unit_count);
 out2:
-       up(&all_ppp_sem);
+       mutex_unlock(&all_ppp_mutex);
        free_netdev(dev);
 out1:
        kfree(ppp);
@@ -2465,7 +2493,7 @@ static void ppp_shutdown_interface(struct ppp *ppp)
 {
        struct net_device *dev;
 
-       down(&all_ppp_sem);
+       mutex_lock(&all_ppp_mutex);
        ppp_lock(ppp);
        dev = ppp->dev;
        ppp->dev = NULL;
@@ -2479,7 +2507,7 @@ static void ppp_shutdown_interface(struct ppp *ppp)
        ppp->file.dead = 1;
        ppp->owner = NULL;
        wake_up_interruptible(&ppp->file.rwait);
-       up(&all_ppp_sem);
+       mutex_unlock(&all_ppp_mutex);
 }
 
 /*
@@ -2521,7 +2549,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
 
 /*
  * Locate an existing ppp unit.
- * The caller should have locked the all_ppp_sem.
+ * The caller should have locked the all_ppp_mutex.
  */
 static struct ppp *
 ppp_find_unit(int unit)
@@ -2541,20 +2569,14 @@ static struct channel *
 ppp_find_channel(int unit)
 {
        struct channel *pch;
-       struct list_head *list;
 
-       list = &new_channels;
-       while ((list = list->next) != &new_channels) {
-               pch = list_entry(list, struct channel, list);
+       list_for_each_entry(pch, &new_channels, list) {
                if (pch->file.index == unit) {
-                       list_del(&pch->list);
-                       list_add(&pch->list, &all_channels);
+                       list_move(&pch->list, &all_channels);
                        return pch;
                }
        }
-       list = &all_channels;
-       while ((list = list->next) != &all_channels) {
-               pch = list_entry(list, struct channel, list);
+       list_for_each_entry(pch, &all_channels, list) {
                if (pch->file.index == unit)
                        return pch;
        }
@@ -2571,7 +2593,7 @@ ppp_connect_channel(struct channel *pch, int unit)
        int ret = -ENXIO;
        int hdrlen;
 
-       down(&all_ppp_sem);
+       mutex_lock(&all_ppp_mutex);
        ppp = ppp_find_unit(unit);
        if (ppp == 0)
                goto out;
@@ -2596,7 +2618,7 @@ ppp_connect_channel(struct channel *pch, int unit)
  outl:
        write_unlock_bh(&pch->upl);
  out:
-       up(&all_ppp_sem);
+       mutex_unlock(&all_ppp_mutex);
        return ret;
 }
 
@@ -2653,8 +2675,7 @@ static void __exit ppp_cleanup(void)
        cardmap_destroy(&all_ppp_units);
        if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
                printk(KERN_ERR "PPP: failed to unregister PPP device\n");
-       devfs_remove("ppp");
-       class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
+       device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
        class_destroy(ppp_class);
 }
 
@@ -2677,7 +2698,7 @@ static void *cardmap_get(struct cardmap *map, unsigned int nr)
        return NULL;
 }
 
-static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
+static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
 {
        struct cardmap *p;
        int i;
@@ -2686,8 +2707,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
        if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
                do {
                        /* need a new top level */
-                       struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
-                       memset(np, 0, sizeof(*np));
+                       struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
+                       if (!np)
+                               goto enomem;
                        np->ptr[0] = p;
                        if (p != NULL) {
                                np->shift = p->shift + CARDMAP_ORDER;
@@ -2701,8 +2723,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
        while (p->shift > 0) {
                i = (nr >> p->shift) & CARDMAP_MASK;
                if (p->ptr[i] == NULL) {
-                       struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
-                       memset(np, 0, sizeof(*np));
+                       struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
+                       if (!np)
+                               goto enomem;
                        np->shift = p->shift - CARDMAP_ORDER;
                        np->parent = p;
                        p->ptr[i] = np;
@@ -2717,6 +2740,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
                set_bit(i, &p->inuse);
        else
                clear_bit(i, &p->inuse);
+       return 0;
+ enomem:
+       return -ENOMEM;
 }
 
 static unsigned int cardmap_find_first_free(struct cardmap *map)