diff options
Diffstat (limited to 'include/net/sock.h')
| -rw-r--r-- | include/net/sock.h | 54 | 
1 files changed, 54 insertions, 0 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 01810a3f19df..f2046e404a61 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -52,6 +52,7 @@  #include <linux/mm.h>  #include <linux/security.h>  #include <linux/slab.h> +#include <linux/uaccess.h>  #include <linux/filter.h>  #include <linux/rculist_nulls.h> @@ -1389,6 +1390,59 @@ static inline void sk_nocaps_add(struct sock *sk, int flags)  	sk->sk_route_caps &= ~flags;  } +static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, +					   char __user *from, char *to, +					   int copy, int offset) +{ +	if (skb->ip_summed == CHECKSUM_NONE) { +		int err = 0; +		__wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); +		if (err) +			return err; +		skb->csum = csum_block_add(skb->csum, csum, offset); +	} else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { +		if (!access_ok(VERIFY_READ, from, copy) || +		    __copy_from_user_nocache(to, from, copy)) +			return -EFAULT; +	} else if (copy_from_user(to, from, copy)) +		return -EFAULT; + +	return 0; +} + +static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, +				       char __user *from, int copy) +{ +	int err, offset = skb->len; + +	err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), +				       copy, offset); +	if (err) +		__skb_trim(skb, offset); + +	return err; +} + +static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, +					   struct sk_buff *skb, +					   struct page *page, +					   int off, int copy) +{ +	int err; + +	err = skb_do_copy_data_nocache(sk, skb, from, page_address(page) + off, +				       copy, skb->len); +	if (err) +		return err; + +	skb->len	     += copy; +	skb->data_len	     += copy; +	skb->truesize	     += copy; +	sk->sk_wmem_queued   += copy; +	sk_mem_charge(sk, copy); +	return 0; +} +  static inline int skb_copy_to_page(struct sock *sk, char __user *from,  				   struct sk_buff *skb, struct page *page,  				   int off, int copy)  |