]> err.no Git - linux-2.6/blobdiff - net/ipv4/ipcomp.c
[TIPC] Fixed sk_buff panic caused by tipc_link_bundle_buf (REVISED)
[linux-2.6] / net / ipv4 / ipcomp.c
index 04a429465665cd8ff0c377eed4d1caf0d40a4a3a..8e0374847532970b502609fbfecb9d75332a8896 100644 (file)
@@ -13,7 +13,6 @@
  *   - Compression stats.
  *   - Adaptive compression.
  */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/scatterlist.h>
 #include <asm/semaphore.h>
@@ -45,7 +44,6 @@ static LIST_HEAD(ipcomp_tfms_list);
 static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err, plen, dlen;
-       struct iphdr *iph;
        struct ipcomp_data *ipcd = x->data;
        u8 *start, *scratch;
        struct crypto_tfm *tfm;
@@ -74,8 +72,6 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
                
        skb_put(skb, dlen - plen);
        memcpy(skb->data, scratch, dlen);
-       iph = skb->nh.iph;
-       iph->tot_len = htons(dlen + iph->ihl * 4);
 out:   
        put_cpu();
        return err;
@@ -83,34 +79,21 @@ out:
 
 static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       u8 nexthdr;
-       int err = 0;
+       int err = -ENOMEM;
        struct iphdr *iph;
-       union {
-               struct iphdr    iph;
-               char            buf[60];
-       } tmp_iph;
-
+       struct ip_comp_hdr *ipch;
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-           skb_linearize(skb, GFP_ATOMIC) != 0) {
-               err = -ENOMEM;
+       if (skb_linearize_cow(skb))
                goto out;
-       }
 
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Remove ipcomp header and decompress original payload */      
        iph = skb->nh.iph;
-       memcpy(&tmp_iph, iph, iph->ihl * 4);
-       nexthdr = *(u8 *)skb->data;
-       skb_pull(skb, sizeof(struct ip_comp_hdr));
-       skb->nh.raw += sizeof(struct ip_comp_hdr);
-       memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4);
-       iph = skb->nh.iph;
-       iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ip_comp_hdr));
-       iph->protocol = nexthdr;
-       skb->h.raw = skb->data;
+       ipch = (void *)skb->data;
+       iph->protocol = ipch->nexthdr;
+       skb->h.raw = skb->nh.raw + sizeof(*ipch);
+       __skb_pull(skb, sizeof(*ipch));
        err = ipcomp_decompress(x, skb);
 
 out:   
@@ -171,10 +154,8 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
                goto out_ok;
        }
 
-       if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
-           skb_linearize(skb, GFP_ATOMIC) != 0) {
+       if (skb_linearize_cow(skb))
                goto out_ok;
-       }
        
        err = ipcomp_compress(x, skb);
        iph = skb->nh.iph;
@@ -210,7 +191,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
            skb->h.icmph->code != ICMP_FRAG_NEEDED)
                return;
 
-       spi = ntohl(ntohs(ipch->cpi));
+       spi = htonl(ntohs(ipch->cpi));
        x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr,
                              spi, IPPROTO_COMP, AF_INET);
        if (!x)
@@ -290,11 +271,8 @@ static void ipcomp_free_scratches(void)
        if (!scratches)
                return;
 
-       for_each_possible_cpu(i) {
-               void *scratch = *per_cpu_ptr(scratches, i);
-               if (scratch)
-                       vfree(scratch);
-       }
+       for_each_possible_cpu(i)
+               vfree(*per_cpu_ptr(scratches, i));
 
        free_percpu(scratches);
 }