@@ -3639,6 +3639,97 @@ static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)
3639
3639
return head_frag ;
3640
3640
}
3641
3641
3642
+ struct sk_buff * skb_segment_list (struct sk_buff * skb ,
3643
+ netdev_features_t features ,
3644
+ unsigned int offset )
3645
+ {
3646
+ struct sk_buff * list_skb = skb_shinfo (skb )-> frag_list ;
3647
+ unsigned int tnl_hlen = skb_tnl_header_len (skb );
3648
+ unsigned int delta_truesize = 0 ;
3649
+ unsigned int delta_len = 0 ;
3650
+ struct sk_buff * tail = NULL ;
3651
+ struct sk_buff * nskb ;
3652
+
3653
+ skb_push (skb , - skb_network_offset (skb ) + offset );
3654
+
3655
+ skb_shinfo (skb )-> frag_list = NULL ;
3656
+
3657
+ do {
3658
+ nskb = list_skb ;
3659
+ list_skb = list_skb -> next ;
3660
+
3661
+ if (!tail )
3662
+ skb -> next = nskb ;
3663
+ else
3664
+ tail -> next = nskb ;
3665
+
3666
+ tail = nskb ;
3667
+
3668
+ delta_len += nskb -> len ;
3669
+ delta_truesize += nskb -> truesize ;
3670
+
3671
+ skb_push (nskb , - skb_network_offset (nskb ) + offset );
3672
+
3673
+ __copy_skb_header (nskb , skb );
3674
+
3675
+ skb_headers_offset_update (nskb , skb_headroom (nskb ) - skb_headroom (skb ));
3676
+ skb_copy_from_linear_data_offset (skb , - tnl_hlen ,
3677
+ nskb -> data - tnl_hlen ,
3678
+ offset + tnl_hlen );
3679
+
3680
+ if (skb_needs_linearize (nskb , features ) &&
3681
+ __skb_linearize (nskb ))
3682
+ goto err_linearize ;
3683
+
3684
+ } while (list_skb );
3685
+
3686
+ skb -> truesize = skb -> truesize - delta_truesize ;
3687
+ skb -> data_len = skb -> data_len - delta_len ;
3688
+ skb -> len = skb -> len - delta_len ;
3689
+
3690
+ skb_gso_reset (skb );
3691
+
3692
+ skb -> prev = tail ;
3693
+
3694
+ if (skb_needs_linearize (skb , features ) &&
3695
+ __skb_linearize (skb ))
3696
+ goto err_linearize ;
3697
+
3698
+ skb_get (skb );
3699
+
3700
+ return skb ;
3701
+
3702
+ err_linearize :
3703
+ kfree_skb_list (skb -> next );
3704
+ skb -> next = NULL ;
3705
+ return ERR_PTR (- ENOMEM );
3706
+ }
3707
+ EXPORT_SYMBOL_GPL (skb_segment_list );
3708
+
3709
+ int skb_gro_receive_list (struct sk_buff * p , struct sk_buff * skb )
3710
+ {
3711
+ if (unlikely (p -> len + skb -> len >= 65536 ))
3712
+ return - E2BIG ;
3713
+
3714
+ if (NAPI_GRO_CB (p )-> last == p )
3715
+ skb_shinfo (p )-> frag_list = skb ;
3716
+ else
3717
+ NAPI_GRO_CB (p )-> last -> next = skb ;
3718
+
3719
+ skb_pull (skb , skb_gro_offset (skb ));
3720
+
3721
+ NAPI_GRO_CB (p )-> last = skb ;
3722
+ NAPI_GRO_CB (p )-> count ++ ;
3723
+ p -> data_len += skb -> len ;
3724
+ p -> truesize += skb -> truesize ;
3725
+ p -> len += skb -> len ;
3726
+
3727
+ NAPI_GRO_CB (skb )-> same_flow = 1 ;
3728
+
3729
+ return 0 ;
3730
+ }
3731
+ EXPORT_SYMBOL_GPL (skb_gro_receive_list );
3732
+
3642
3733
/**
3643
3734
* skb_segment - Perform protocol segmentation on skb.
3644
3735
* @head_skb: buffer to segment
0 commit comments