aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c103
1 files changed, 54 insertions, 49 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5976ef0846bd..869c7afe3b07 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -707,9 +707,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
707 new->mark = old->mark; 707 new->mark = old->mark;
708 new->skb_iif = old->skb_iif; 708 new->skb_iif = old->skb_iif;
709 __nf_copy(new, old); 709 __nf_copy(new, old);
710#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
711 new->nf_trace = old->nf_trace;
712#endif
713#ifdef CONFIG_NET_SCHED 710#ifdef CONFIG_NET_SCHED
714 new->tc_index = old->tc_index; 711 new->tc_index = old->tc_index;
715#ifdef CONFIG_NET_CLS_ACT 712#ifdef CONFIG_NET_CLS_ACT
@@ -2841,81 +2838,84 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
2841 2838
2842/** 2839/**
2843 * skb_segment - Perform protocol segmentation on skb. 2840 * skb_segment - Perform protocol segmentation on skb.
2844 * @skb: buffer to segment 2841 * @head_skb: buffer to segment
2845 * @features: features for the output path (see dev->features) 2842 * @features: features for the output path (see dev->features)
2846 * 2843 *
2847 * This function performs segmentation on the given skb. It returns 2844 * This function performs segmentation on the given skb. It returns
2848 * 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.
2849 * In case of error it returns ERR_PTR(err). 2846 * In case of error it returns ERR_PTR(err).
2850 */ 2847 */
2851struct 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)
2852{ 2850{
2853 struct sk_buff *segs = NULL; 2851 struct sk_buff *segs = NULL;
2854 struct sk_buff *tail = NULL; 2852 struct sk_buff *tail = NULL;
2855 struct sk_buff *fskb = skb_shinfo(skb)->frag_list; 2853 struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
2856 skb_frag_t *skb_frag = skb_shinfo(skb)->frags; 2854 skb_frag_t *frag = skb_shinfo(head_skb)->frags;
2857 unsigned int mss = skb_shinfo(skb)->gso_size; 2855 unsigned int mss = skb_shinfo(head_skb)->gso_size;
2858 unsigned int doffset = skb->data - skb_mac_header(skb); 2856 unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
2857 struct sk_buff *frag_skb = head_skb;
2859 unsigned int offset = doffset; 2858 unsigned int offset = doffset;
2860 unsigned int tnl_hlen = skb_tnl_header_len(skb); 2859 unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
2861 unsigned int headroom; 2860 unsigned int headroom;
2862 unsigned int len; 2861 unsigned int len;
2863 __be16 proto; 2862 __be16 proto;
2864 bool csum; 2863 bool csum;
2865 int sg = !!(features & NETIF_F_SG); 2864 int sg = !!(features & NETIF_F_SG);
2866 int nfrags = skb_shinfo(skb)->nr_frags; 2865 int nfrags = skb_shinfo(head_skb)->nr_frags;
2867 int err = -ENOMEM; 2866 int err = -ENOMEM;
2868 int i = 0; 2867 int i = 0;
2869 int pos; 2868 int pos;
2870 2869
2871 proto = skb_network_protocol(skb); 2870 proto = skb_network_protocol(head_skb);
2872 if (unlikely(!proto)) 2871 if (unlikely(!proto))
2873 return ERR_PTR(-EINVAL); 2872 return ERR_PTR(-EINVAL);
2874 2873
2875 csum = !!can_checksum_protocol(features, proto); 2874 csum = !!can_checksum_protocol(features, proto);
2876 __skb_push(skb, doffset); 2875 __skb_push(head_skb, doffset);
2877 headroom = skb_headroom(skb); 2876 headroom = skb_headroom(head_skb);
2878 pos = skb_headlen(skb); 2877 pos = skb_headlen(head_skb);
2879 2878
2880 do { 2879 do {
2881 struct sk_buff *nskb; 2880 struct sk_buff *nskb;
2882 skb_frag_t *frag; 2881 skb_frag_t *nskb_frag;
2883 int hsize; 2882 int hsize;
2884 int size; 2883 int size;
2885 2884
2886 len = skb->len - offset; 2885 len = head_skb->len - offset;
2887 if (len > mss) 2886 if (len > mss)
2888 len = mss; 2887 len = mss;
2889 2888
2890 hsize = skb_headlen(skb) - offset; 2889 hsize = skb_headlen(head_skb) - offset;
2891 if (hsize < 0) 2890 if (hsize < 0)
2892 hsize = 0; 2891 hsize = 0;
2893 if (hsize > len || !sg) 2892 if (hsize > len || !sg)
2894 hsize = len; 2893 hsize = len;
2895 2894
2896 if (!hsize && i >= nfrags && skb_headlen(fskb) && 2895 if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
2897 (skb_headlen(fskb) == len || sg)) { 2896 (skb_headlen(list_skb) == len || sg)) {
2898 BUG_ON(skb_headlen(fskb) > len); 2897 BUG_ON(skb_headlen(list_skb) > len);
2899 2898
2900 i = 0; 2899 i = 0;
2901 nfrags = skb_shinfo(fskb)->nr_frags; 2900 nfrags = skb_shinfo(list_skb)->nr_frags;
2902 skb_frag = skb_shinfo(fskb)->frags; 2901 frag = skb_shinfo(list_skb)->frags;
2903 pos += skb_headlen(fskb); 2902 frag_skb = list_skb;
2903 pos += skb_headlen(list_skb);
2904 2904
2905 while (pos < offset + len) { 2905 while (pos < offset + len) {
2906 BUG_ON(i >= nfrags); 2906 BUG_ON(i >= nfrags);
2907 2907
2908 size = skb_frag_size(skb_frag); 2908 size = skb_frag_size(frag);
2909 if (pos + size > offset + len) 2909 if (pos + size > offset + len)
2910 break; 2910 break;
2911 2911
2912 i++; 2912 i++;
2913 pos += size; 2913 pos += size;
2914 skb_frag++; 2914 frag++;
2915 } 2915 }
2916 2916
2917 nskb = skb_clone(fskb, GFP_ATOMIC); 2917 nskb = skb_clone(list_skb, GFP_ATOMIC);
2918 fskb = fskb->next; 2918 list_skb = list_skb->next;
2919 2919
2920 if (unlikely(!nskb)) 2920 if (unlikely(!nskb))
2921 goto err; 2921 goto err;
@@ -2936,7 +2936,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2936 __skb_push(nskb, doffset); 2936 __skb_push(nskb, doffset);
2937 } else { 2937 } else {
2938 nskb = __alloc_skb(hsize + doffset + headroom, 2938 nskb = __alloc_skb(hsize + doffset + headroom,
2939 GFP_ATOMIC, skb_alloc_rx_flag(skb), 2939 GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
2940 NUMA_NO_NODE); 2940 NUMA_NO_NODE);
2941 2941
2942 if (unlikely(!nskb)) 2942 if (unlikely(!nskb))
@@ -2952,12 +2952,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2952 segs = nskb; 2952 segs = nskb;
2953 tail = nskb; 2953 tail = nskb;
2954 2954
2955 __copy_skb_header(nskb, skb); 2955 __copy_skb_header(nskb, head_skb);
2956 nskb->mac_len = skb->mac_len; 2956 nskb->mac_len = head_skb->mac_len;
2957 2957
2958 skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); 2958 skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
2959 2959
2960 skb_copy_from_linear_data_offset(skb, -tnl_hlen, 2960 skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
2961 nskb->data - tnl_hlen, 2961 nskb->data - tnl_hlen,
2962 doffset + tnl_hlen); 2962 doffset + tnl_hlen);
2963 2963
@@ -2966,30 +2966,32 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
2966 2966
2967 if (!sg) { 2967 if (!sg) {
2968 nskb->ip_summed = CHECKSUM_NONE; 2968 nskb->ip_summed = CHECKSUM_NONE;
2969 nskb->csum = skb_copy_and_csum_bits(skb, offset, 2969 nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
2970 skb_put(nskb, len), 2970 skb_put(nskb, len),
2971 len, 0); 2971 len, 0);
2972 continue; 2972 continue;
2973 } 2973 }
2974 2974
2975 frag = skb_shinfo(nskb)->frags; 2975 nskb_frag = skb_shinfo(nskb)->frags;
2976 2976
2977 skb_copy_from_linear_data_offset(skb, offset, 2977 skb_copy_from_linear_data_offset(head_skb, offset,
2978 skb_put(nskb, hsize), hsize); 2978 skb_put(nskb, hsize), hsize);
2979 2979
2980 skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; 2980 skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
2981 SKBTX_SHARED_FRAG;
2981 2982
2982 while (pos < offset + len) { 2983 while (pos < offset + len) {
2983 if (i >= nfrags) { 2984 if (i >= nfrags) {
2984 BUG_ON(skb_headlen(fskb)); 2985 BUG_ON(skb_headlen(list_skb));
2985 2986
2986 i = 0; 2987 i = 0;
2987 nfrags = skb_shinfo(fskb)->nr_frags; 2988 nfrags = skb_shinfo(list_skb)->nr_frags;
2988 skb_frag = skb_shinfo(fskb)->frags; 2989 frag = skb_shinfo(list_skb)->frags;
2990 frag_skb = list_skb;
2989 2991
2990 BUG_ON(!nfrags); 2992 BUG_ON(!nfrags);
2991 2993
2992 fskb = fskb->next; 2994 list_skb = list_skb->next;
2993 } 2995 }
2994 2996
2995 if (unlikely(skb_shinfo(nskb)->nr_frags >= 2997 if (unlikely(skb_shinfo(nskb)->nr_frags >=
@@ -3000,27 +3002,30 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
3000 goto err; 3002 goto err;
3001 } 3003 }
3002 3004
3003 *frag = *skb_frag; 3005 if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
3004 __skb_frag_ref(frag); 3006 goto err;
3005 size = skb_frag_size(frag); 3007
3008 *nskb_frag = *frag;
3009 __skb_frag_ref(nskb_frag);
3010 size = skb_frag_size(nskb_frag);
3006 3011
3007 if (pos < offset) { 3012 if (pos < offset) {
3008 frag->page_offset += offset - pos; 3013 nskb_frag->page_offset += offset - pos;
3009 skb_frag_size_sub(frag, offset - pos); 3014 skb_frag_size_sub(nskb_frag, offset - pos);
3010 } 3015 }
3011 3016
3012 skb_shinfo(nskb)->nr_frags++; 3017 skb_shinfo(nskb)->nr_frags++;
3013 3018
3014 if (pos + size <= offset + len) { 3019 if (pos + size <= offset + len) {
3015 i++; 3020 i++;
3016 skb_frag++; 3021 frag++;
3017 pos += size; 3022 pos += size;
3018 } else { 3023 } else {
3019 skb_frag_size_sub(frag, pos + size - (offset + len)); 3024 skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
3020 goto skip_fraglist; 3025 goto skip_fraglist;
3021 } 3026 }
3022 3027
3023 frag++; 3028 nskb_frag++;
3024 } 3029 }
3025 3030
3026skip_fraglist: 3031skip_fraglist:
@@ -3034,7 +3039,7 @@ perform_csum_check:
3034 nskb->len - doffset, 0); 3039 nskb->len - doffset, 0);
3035 nskb->ip_summed = CHECKSUM_NONE; 3040 nskb->ip_summed = CHECKSUM_NONE;
3036 } 3041 }
3037 } while ((offset += len) < skb->len); 3042 } while ((offset += len) < head_skb->len);
3038 3043
3039 return segs; 3044 return segs;
3040 3045