diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/skbuff.c | 46 |
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 | */ |
2848 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) | 2848 | struct 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 | ||