Merge branch 'hotfixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[pandora-kernel.git] / net / core / skbuff.c
index 7c57156..8464017 100644 (file)
@@ -459,6 +459,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->tc_verd            = old->tc_verd;
 #endif
 #endif
+       new->vlan_tci           = old->vlan_tci;
+
        skb_copy_secmark(new, old);
 }
 
@@ -483,6 +485,9 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(head);
        C(data);
        C(truesize);
+#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
+       C(do_not_encrypt);
+#endif
        atomic_set(&n->users, 1);
 
        atomic_inc(&(skb_shinfo(skb)->dataref));
@@ -1198,7 +1203,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                int end;
 
-               BUG_TRAP(start <= offset + len);
+               WARN_ON(start > offset + len);
 
                end = start + skb_shinfo(skb)->frags[i].size;
                if ((copy = end - offset) > 0) {
@@ -1227,7 +1232,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
                for (; list; list = list->next) {
                        int end;
 
-                       BUG_TRAP(start <= offset + len);
+                       WARN_ON(start > offset + len);
 
                        end = start + list->len;
                        if ((copy = end - offset) > 0) {
@@ -1280,114 +1285,83 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,
        return 0;
 }
 
-/*
- * Map linear and fragment data from the skb to spd. Returns number of
- * pages mapped.
- */
-static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
-                            unsigned int *total_len,
-                            struct splice_pipe_desc *spd)
-{
-       unsigned int nr_pages = spd->nr_pages;
-       unsigned int poff, plen, len, toff, tlen;
-       int headlen, seg, error = 0;
-
-       toff = *offset;
-       tlen = *total_len;
-       if (!tlen) {
-               error = 1;
-               goto err;
+static inline void __segment_seek(struct page **page, unsigned int *poff,
+                                 unsigned int *plen, unsigned int off)
+{
+       *poff += off;
+       *page += *poff / PAGE_SIZE;
+       *poff = *poff % PAGE_SIZE;
+       *plen -= off;
+}
+
+static inline int __splice_segment(struct page *page, unsigned int poff,
+                                  unsigned int plen, unsigned int *off,
+                                  unsigned int *len, struct sk_buff *skb,
+                                  struct splice_pipe_desc *spd)
+{
+       if (!*len)
+               return 1;
+
+       /* skip this segment if already processed */
+       if (*off >= plen) {
+               *off -= plen;
+               return 0;
        }
 
-       /*
-        * if the offset is greater than the linear part, go directly to
-        * the fragments.
-        */
-       headlen = skb_headlen(skb);
-       if (toff >= headlen) {
-               toff -= headlen;
-               goto map_frag;
+       /* ignore any bits we already processed */
+       if (*off) {
+               __segment_seek(&page, &poff, &plen, *off);
+               *off = 0;
        }
 
-       /*
-        * first map the linear region into the pages/partial map, skipping
-        * any potential initial offset.
-        */
-       len = 0;
-       while (len < headlen) {
-               void *p = skb->data + len;
-
-               poff = (unsigned long) p & (PAGE_SIZE - 1);
-               plen = min_t(unsigned int, headlen - len, PAGE_SIZE - poff);
-               len += plen;
-
-               if (toff) {
-                       if (plen <= toff) {
-                               toff -= plen;
-                               continue;
-                       }
-                       plen -= toff;
-                       poff += toff;
-                       toff = 0;
-               }
+       do {
+               unsigned int flen = min(*len, plen);
 
-               plen = min(plen, tlen);
-               if (!plen)
-                       break;
+               /* the linear region may spread across several pages  */
+               flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
 
-               /*
-                * just jump directly to update and return, no point
-                * in going over fragments when the output is full.
-                */
-               error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb);
-               if (error)
-                       goto done;
+               if (spd_fill_page(spd, page, flen, poff, skb))
+                       return 1;
 
-               tlen -= plen;
-       }
+               __segment_seek(&page, &poff, &plen, flen);
+               *len -= flen;
+
+       } while (*len && plen);
+
+       return 0;
+}
+
+/*
+ * Map linear and fragment data from the skb to spd. It reports failure if the
+ * pipe is full or if we already spliced the requested length.
+ */
+static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
+                     unsigned int *len,
+                     struct splice_pipe_desc *spd)
+{
+       int seg;
+
+       /*
+        * map the linear part
+        */
+       if (__splice_segment(virt_to_page(skb->data),
+                            (unsigned long) skb->data & (PAGE_SIZE - 1),
+                            skb_headlen(skb),
+                            offset, len, skb, spd))
+               return 1;
 
        /*
         * then map the fragments
         */
-map_frag:
        for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) {
                const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];
 
-               plen = f->size;
-               poff = f->page_offset;
-
-               if (toff) {
-                       if (plen <= toff) {
-                               toff -= plen;
-                               continue;
-                       }
-                       plen -= toff;
-                       poff += toff;
-                       toff = 0;
-               }
-
-               plen = min(plen, tlen);
-               if (!plen)
-                       break;
-
-               error = spd_fill_page(spd, f->page, plen, poff, skb);
-               if (error)
-                       break;
-
-               tlen -= plen;
+               if (__splice_segment(f->page, f->page_offset, f->size,
+                                    offset, len, skb, spd))
+                       return 1;
        }
 
-done:
-       if (spd->nr_pages - nr_pages) {
-               *offset = 0;
-               *total_len = tlen;
-               return 0;
-       }
-err:
-       /* update the offset to reflect the linear part skip, if any */
-       if (!error)
-               *offset = toff;
-       return error;
+       return 0;
 }
 
 /*
@@ -1504,7 +1478,7 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
                int end;
 
-               BUG_TRAP(start <= offset + len);
+               WARN_ON(start > offset + len);
 
                end = start + frag->size;
                if ((copy = end - offset) > 0) {
@@ -1532,7 +1506,7 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
                for (; list; list = list->next) {
                        int end;
 
-                       BUG_TRAP(start <= offset + len);
+                       WARN_ON(start > offset + len);
 
                        end = start + list->len;
                        if ((copy = end - offset) > 0) {
@@ -1581,7 +1555,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                int end;
 
-               BUG_TRAP(start <= offset + len);
+               WARN_ON(start > offset + len);
 
                end = start + skb_shinfo(skb)->frags[i].size;
                if ((copy = end - offset) > 0) {
@@ -1610,7 +1584,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
                for (; list; list = list->next) {
                        int end;
 
-                       BUG_TRAP(start <= offset + len);
+                       WARN_ON(start > offset + len);
 
                        end = start + list->len;
                        if ((copy = end - offset) > 0) {
@@ -1658,7 +1632,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                int end;
 
-               BUG_TRAP(start <= offset + len);
+               WARN_ON(start > offset + len);
 
                end = start + skb_shinfo(skb)->frags[i].size;
                if ((copy = end - offset) > 0) {
@@ -1691,7 +1665,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
                        __wsum csum2;
                        int end;
 
-                       BUG_TRAP(start <= offset + len);
+                       WARN_ON(start > offset + len);
 
                        end = start + list->len;
                        if ((copy = end - offset) > 0) {
@@ -2286,6 +2260,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                skb_copy_queue_mapping(nskb, skb);
                nskb->priority = skb->priority;
                nskb->protocol = skb->protocol;
+               nskb->vlan_tci = skb->vlan_tci;
                nskb->dst = dst_clone(skb->dst);
                memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
                nskb->pkt_type = skb->pkt_type;
@@ -2401,7 +2376,7 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                int end;
 
-               BUG_TRAP(start <= offset + len);
+               WARN_ON(start > offset + len);
 
                end = start + skb_shinfo(skb)->frags[i].size;
                if ((copy = end - offset) > 0) {
@@ -2425,7 +2400,7 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
                for (; list; list = list->next) {
                        int end;
 
-                       BUG_TRAP(start <= offset + len);
+                       WARN_ON(start > offset + len);
 
                        end = start + list->len;
                        if ((copy = end - offset) > 0) {