@@ -3639,6 +3639,97 @@ static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)
36393639 return head_frag ;
36403640}
36413641
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+
36423733/**
36433734 * skb_segment - Perform protocol segmentation on skb.
36443735 * @head_skb: buffer to segment
0 commit comments