diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 40 | 
1 files changed, 40 insertions, 0 deletions
| diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4eaf7ed0d1f4..2bfa6a7ba244 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -62,6 +62,7 @@  #include <linux/if_vlan.h>  #include <linux/mpls.h>  #include <linux/kcov.h> +#include <linux/iov_iter.h>  #include <net/protocol.h>  #include <net/dst.h> @@ -6931,3 +6932,42 @@ out:  	return spliced ?: ret;  }  EXPORT_SYMBOL(skb_splice_from_iter); + +static __always_inline +size_t memcpy_from_iter_csum(void *iter_from, size_t progress, +			     size_t len, void *to, void *priv2) +{ +	__wsum *csum = priv2; +	__wsum next = csum_partial_copy_nocheck(iter_from, to + progress, len); + +	*csum = csum_block_add(*csum, next, progress); +	return 0; +} + +static __always_inline +size_t copy_from_user_iter_csum(void __user *iter_from, size_t progress, +				size_t len, void *to, void *priv2) +{ +	__wsum next, *csum = priv2; + +	next = csum_and_copy_from_user(iter_from, to + progress, len); +	*csum = csum_block_add(*csum, next, progress); +	return next ? 0 : len; +} + +bool csum_and_copy_from_iter_full(void *addr, size_t bytes, +				  __wsum *csum, struct iov_iter *i) +{ +	size_t copied; + +	if (WARN_ON_ONCE(!i->data_source)) +		return false; +	copied = iterate_and_advance2(i, bytes, addr, csum, +				      copy_from_user_iter_csum, +				      memcpy_from_iter_csum); +	if (likely(copied == bytes)) +		return true; +	iov_iter_revert(i, copied); +	return false; +} +EXPORT_SYMBOL(csum_and_copy_from_iter_full); | 
