aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c46
1 files changed, 24 insertions, 22 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d788a9845762..fdc065dc869a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2838,41 +2838,42 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
2838 2838
2839/** 2839/**
2840 * skb_segment - Perform protocol segmentation on skb. 2840 * skb_segment - Perform protocol segmentation on skb.
2841 * @skb: buffer to segment 2841 * @head_skb: buffer to segment
2842 * @features: features for the output path (see dev->features) 2842 * @features: features for the output path (see dev->features)
2843 * 2843 *
2844 * This function performs segmentation on the given skb. It returns 2844 * This function performs segmentation on the given skb. It returns
2845 * a pointer to the first in a list of new skbs for the segments. 2845 * a pointer to the first in a list of new skbs for the segments.
2846 * In case of error it returns ERR_PTR(err). 2846 * In case of error it returns ERR_PTR(err).
2847 */ 2847 */
2848struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) 2848struct sk_buff *skb_segment(struct sk_buff *head_skb,
2849 netdev_features_t features)
2849{ 2850{
2850 struct sk_buff *segs = NULL; 2851 struct sk_buff *segs = NULL;
2851 struct sk_buff *tail = NULL; 2852 struct sk_buff *tail = NULL;
2852 struct sk_buff *fskb = skb_shinfo(skb)->frag_list; 2853 struct sk_buff *fskb = skb_shinfo(head_skb)->frag_list;
2853 skb_frag_t *frag = skb_shinfo(skb)->frags; 2854 skb_frag_t *frag = skb_shinfo(head_skb)->frags;
2854 unsigned int mss = skb_shinfo(skb)->gso_size; 2855 unsigned int mss = skb_shinfo(head_skb)->gso_size;
2855 unsigned int doffset = skb->data - skb_mac_header(skb); 2856 unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
2856 unsigned int offset = doffset; 2857 unsigned int offset = doffset;
2857 unsigned int tnl_hlen = skb_tnl_header_len(skb); 2858 unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
2858 unsigned int headroom; 2859 unsigned int headroom;
2859 unsigned int len; 2860 unsigned int len;
2860 __be16 proto; 2861 __be16 proto;
2861 bool csum; 2862 bool csum;
2862 int sg = !!(features & NETIF_F_SG); 2863 int sg = !!(features & NETIF_F_SG);
2863 int nfrags = skb_shinfo(skb)->nr_frags; 2864 int nfrags = skb_shinfo(head_skb)->nr_frags;
2864 int err = -ENOMEM; 2865 int err = -ENOMEM;
2865 int i = 0; 2866 int i = 0;
2866 int pos; 2867 int pos;
2867 2868
2868 proto = skb_network_protocol(skb); 2869 proto = skb_network_protocol(head_skb);
2869 if (unlikely(!proto)) 2870 if (unlikely(!proto))
2870 return ERR_PTR(-EINVAL); 2871 return ERR_PTR(-EINVAL);
2871 2872
2872 csum = !!can_checksum_protocol(features, proto); 2873 csum = !!can_checksum_protocol(features, proto);
2873 __skb_push(skb, doffset); 2874 __skb_push(head_skb, doffset);
2874 headroom = skb_headroom(skb); 2875 headroom = skb_headroom(head_skb);
2875 pos = skb_headlen(skb); 2876 pos = skb_headlen(head_skb);
2876 2877
2877 do { 2878 do {
2878 struct sk_buff *nskb; 2879 struct sk_buff *nskb;
@@ -2880,11 +2881,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2880 int hsize; 2881 int hsize;
2881 int size; 2882 int size;
2882 2883
2883 len = skb->len - offset; 2884 len = head_skb->len - offset;
2884 if (len > mss) 2885 if (len > mss)
2885 len = mss; 2886 len = mss;
2886 2887
2887 hsize = skb_headlen(skb) - offset; 2888 hsize = skb_headlen(head_skb) - offset;
2888 if (hsize < 0) 2889 if (hsize < 0)
2889 hsize = 0; 2890 hsize = 0;
2890 if (hsize > len || !sg) 2891 if (hsize > len || !sg)
@@ -2933,7 +2934,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2933 __skb_push(nskb, doffset); 2934 __skb_push(nskb, doffset);
2934 } else { 2935 } else {
2935 nskb = __alloc_skb(hsize + doffset + headroom, 2936 nskb = __alloc_skb(hsize + doffset + headroom,
2936 GFP_ATOMIC, skb_alloc_rx_flag(skb), 2937 GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
2937 NUMA_NO_NODE); 2938 NUMA_NO_NODE);
2938 2939
2939 if (unlikely(!nskb)) 2940 if (unlikely(!nskb))
@@ -2949,12 +2950,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2949 segs = nskb; 2950 segs = nskb;
2950 tail = nskb; 2951 tail = nskb;
2951 2952
2952 __copy_skb_header(nskb, skb); 2953 __copy_skb_header(nskb, head_skb);
2953 nskb->mac_len = skb->mac_len; 2954 nskb->mac_len = head_skb->mac_len;
2954 2955
2955 skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); 2956 skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
2956 2957
2957 skb_copy_from_linear_data_offset(skb, -tnl_hlen, 2958 skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
2958 nskb->data - tnl_hlen, 2959 nskb->data - tnl_hlen,
2959 doffset + tnl_hlen); 2960 doffset + tnl_hlen);
2960 2961
@@ -2963,7 +2964,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2963 2964
2964 if (!sg) { 2965 if (!sg) {
2965 nskb->ip_summed = CHECKSUM_NONE; 2966 nskb->ip_summed = CHECKSUM_NONE;
2966 nskb->csum = skb_copy_and_csum_bits(skb, offset, 2967 nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
2967 skb_put(nskb, len), 2968 skb_put(nskb, len),
2968 len, 0); 2969 len, 0);
2969 continue; 2970 continue;
@@ -2971,10 +2972,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2971 2972
2972 nskb_frag = skb_shinfo(nskb)->frags; 2973 nskb_frag = skb_shinfo(nskb)->frags;
2973 2974
2974 skb_copy_from_linear_data_offset(skb, offset, 2975 skb_copy_from_linear_data_offset(head_skb, offset,
2975 skb_put(nskb, hsize), hsize); 2976 skb_put(nskb, hsize), hsize);
2976 2977
2977 skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; 2978 skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
2979 SKBTX_SHARED_FRAG;
2978 2980
2979 while (pos < offset + len) { 2981 while (pos < offset + len) {
2980 if (i >= nfrags) { 2982 if (i >= nfrags) {
@@ -3031,7 +3033,7 @@ perform_csum_check:
3031 nskb->len - doffset, 0); 3033 nskb->len - doffset, 0);
3032 nskb->ip_summed = CHECKSUM_NONE; 3034 nskb->ip_summed = CHECKSUM_NONE;
3033 } 3035 }
3034 } while ((offset += len) < skb->len); 3036 } while ((offset += len) < head_skb->len);
3035 3037
3036 return segs; 3038 return segs;
3037 3039