diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 50 | 
1 files changed, 30 insertions, 20 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 33245ef54c3..ba646145cd5 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -673,6 +673,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	new->mac_header		= old->mac_header;  	new->inner_transport_header = old->inner_transport_header;  	new->inner_network_header = old->inner_network_header; +	new->inner_mac_header = old->inner_mac_header;  	skb_dst_copy(new, old);  	new->rxhash		= old->rxhash;  	new->ooo_okay		= old->ooo_okay; @@ -867,6 +868,18 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)  }  EXPORT_SYMBOL(skb_clone); +static void skb_headers_offset_update(struct sk_buff *skb, int off) +{ +	/* {transport,network,mac}_header and tail are relative to skb->head */ +	skb->transport_header += off; +	skb->network_header   += off; +	if (skb_mac_header_was_set(skb)) +		skb->mac_header += off; +	skb->inner_transport_header += off; +	skb->inner_network_header += off; +	skb->inner_mac_header += off; +} +  static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  {  #ifndef NET_SKBUFF_DATA_USES_OFFSET @@ -879,13 +892,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	__copy_skb_header(new, old);  #ifndef NET_SKBUFF_DATA_USES_OFFSET -	/* {transport,network,mac}_header are relative to skb->head */ -	new->transport_header += offset; -	new->network_header   += offset; -	if (skb_mac_header_was_set(new)) -		new->mac_header	      += offset; -	new->inner_transport_header += offset; -	new->inner_network_header   += offset; +	skb_headers_offset_update(new, offset);  #endif  	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;  	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; @@ -1077,14 +1084,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  #else  	skb->end      = skb->head + size;  #endif -	/* {transport,network,mac}_header and tail are relative to skb->head */  	skb->tail	      += off; -	skb->transport_header += off; -	skb->network_header   += off; -	if (skb_mac_header_was_set(skb)) -		skb->mac_header += off; -	skb->inner_transport_header += off; -	skb->inner_network_header += off; +	skb_headers_offset_update(skb, off);  	/* Only adjust this if it actually is csum_start rather than csum */  	if (skb->ip_summed == CHECKSUM_PARTIAL)  		skb->csum_start += nhead; @@ -1180,12 +1181,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,  	if (n->ip_summed == CHECKSUM_PARTIAL)  		n->csum_start += off;  #ifdef NET_SKBUFF_DATA_USES_OFFSET -	n->transport_header += off; -	n->network_header   += off; -	if (skb_mac_header_was_set(skb)) -		n->mac_header += off; -	n->inner_transport_header += off; -	n->inner_network_header	   += off; +	skb_headers_offset_update(n, off);  #endif  	return n; @@ -2741,12 +2737,19 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)  	unsigned int tnl_hlen = skb_tnl_header_len(skb);  	unsigned int headroom;  	unsigned int len; +	__be16 proto; +	bool csum;  	int sg = !!(features & NETIF_F_SG);  	int nfrags = skb_shinfo(skb)->nr_frags;  	int err = -ENOMEM;  	int i = 0;  	int pos; +	proto = skb_network_protocol(skb); +	if (unlikely(!proto)) +		return ERR_PTR(-EINVAL); + +	csum = !!can_checksum_protocol(features, proto);  	__skb_push(skb, doffset);  	headroom = skb_headroom(skb);  	pos = skb_headlen(skb); @@ -2884,6 +2887,12 @@ skip_fraglist:  		nskb->data_len = len - hsize;  		nskb->len += nskb->data_len;  		nskb->truesize += nskb->data_len; + +		if (!csum) { +			nskb->csum = skb_checksum(nskb, doffset, +						  nskb->len - doffset, 0); +			nskb->ip_summed = CHECKSUM_NONE; +		}  	} while ((offset += len) < skb->len);  	return segs; @@ -3361,6 +3370,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)  	skb->ip_summed = CHECKSUM_PARTIAL;  	skb->csum_start = skb_headroom(skb) + start;  	skb->csum_offset = off; +	skb_set_transport_header(skb, start);  	return true;  }  EXPORT_SYMBOL_GPL(skb_partial_csum_set);  |