cfg80211: make wdev_list accessible to drivers
[cascardo/linux.git] / net / core / skbuff.c
index d04c2d1..7ff7788 100644 (file)
@@ -3076,8 +3076,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
        struct sk_buff *frag_skb = head_skb;
        unsigned int offset = doffset;
        unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
+       unsigned int partial_segs = 0;
        unsigned int headroom;
-       unsigned int len;
+       unsigned int len = head_skb->len;
        __be16 proto;
        bool csum;
        int sg = !!(features & NETIF_F_SG);
@@ -3094,6 +3095,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
 
        csum = !!can_checksum_protocol(features, proto);
 
+       /* GSO partial only requires that we trim off any excess that
+        * doesn't fit into an MSS sized block, so take care of that
+        * now.
+        */
+       if (features & NETIF_F_GSO_PARTIAL) {
+               partial_segs = len / mss;
+               mss *= partial_segs;
+       }
+
        headroom = skb_headroom(head_skb);
        pos = skb_headlen(head_skb);
 
@@ -3281,6 +3291,23 @@ perform_csum_check:
         */
        segs->prev = tail;
 
+       /* Update GSO info on first skb in partial sequence. */
+       if (partial_segs) {
+               int type = skb_shinfo(head_skb)->gso_type;
+
+               /* Update type to add partial and then remove dodgy if set */
+               type |= SKB_GSO_PARTIAL;
+               type &= ~SKB_GSO_DODGY;
+
+               /* Update GSO info and prepare to start updating headers on
+                * our way back down the stack of protocols.
+                */
+               skb_shinfo(segs)->gso_size = skb_shinfo(head_skb)->gso_size;
+               skb_shinfo(segs)->gso_segs = partial_segs;
+               skb_shinfo(segs)->gso_type = type;
+               SKB_GSO_CB(segs)->data_offset = skb_headroom(segs) + doffset;
+       }
+
        /* Following permits correct backpressure, for protocols
         * using skb_set_owner_w().
         * Idea is to tranfert ownership from head_skb to last segment.
@@ -4502,13 +4529,16 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
                __skb_push(skb, offset);
                err = __vlan_insert_tag(skb, skb->vlan_proto,
                                        skb_vlan_tag_get(skb));
-               if (err)
+               if (err) {
+                       __skb_pull(skb, offset);
                        return err;
+               }
+
                skb->protocol = skb->vlan_proto;
                skb->mac_len += VLAN_HLEN;
-               __skb_pull(skb, offset);
 
                skb_postpush_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN);
+               __skb_pull(skb, offset);
        }
        __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
        return 0;