|
@@ -52,6 +52,7 @@
|
|
#include <linux/mm.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/security.h>
|
|
#include <linux/security.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/uaccess.h>
|
|
|
|
|
|
#include <linux/filter.h>
|
|
#include <linux/filter.h>
|
|
#include <linux/rculist_nulls.h>
|
|
#include <linux/rculist_nulls.h>
|
|
@@ -1389,6 +1390,58 @@ static inline void sk_nocaps_add(struct sock *sk, int flags)
|
|
sk->sk_route_caps &= ~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)
|
|
|
|
+{
|
|
|
|
+ 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, skb->len);
|
|
|
|
+ } 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;
|
|
|
|
+
|
|
|
|
+ err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), copy);
|
|
|
|
+ if (err)
|
|
|
|
+ __skb_trim(skb, skb->len);
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+ 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,
|
|
static inline int skb_copy_to_page(struct sock *sk, char __user *from,
|
|
struct sk_buff *skb, struct page *page,
|
|
struct sk_buff *skb, struct page *page,
|
|
int off, int copy)
|
|
int off, int copy)
|