18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/skmsg.h>
58c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
68c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <net/sock.h>
98c2ecf20Sopenharmony_ci#include <net/tcp.h>
108c2ecf20Sopenharmony_ci#include <net/tls.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic bool sk_msg_try_coalesce_ok(struct sk_msg *msg, int elem_first_coalesce)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	if (msg->sg.end > msg->sg.start &&
158c2ecf20Sopenharmony_ci	    elem_first_coalesce < msg->sg.end)
168c2ecf20Sopenharmony_ci		return true;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (msg->sg.end < msg->sg.start &&
198c2ecf20Sopenharmony_ci	    (elem_first_coalesce > msg->sg.start ||
208c2ecf20Sopenharmony_ci	     elem_first_coalesce < msg->sg.end))
218c2ecf20Sopenharmony_ci		return true;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	return false;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciint sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len,
278c2ecf20Sopenharmony_ci		 int elem_first_coalesce)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct page_frag *pfrag = sk_page_frag(sk);
308c2ecf20Sopenharmony_ci	u32 osize = msg->sg.size;
318c2ecf20Sopenharmony_ci	int ret = 0;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	len -= msg->sg.size;
348c2ecf20Sopenharmony_ci	while (len > 0) {
358c2ecf20Sopenharmony_ci		struct scatterlist *sge;
368c2ecf20Sopenharmony_ci		u32 orig_offset;
378c2ecf20Sopenharmony_ci		int use, i;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci		if (!sk_page_frag_refill(sk, pfrag)) {
408c2ecf20Sopenharmony_ci			ret = -ENOMEM;
418c2ecf20Sopenharmony_ci			goto msg_trim;
428c2ecf20Sopenharmony_ci		}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		orig_offset = pfrag->offset;
458c2ecf20Sopenharmony_ci		use = min_t(int, len, pfrag->size - orig_offset);
468c2ecf20Sopenharmony_ci		if (!sk_wmem_schedule(sk, use)) {
478c2ecf20Sopenharmony_ci			ret = -ENOMEM;
488c2ecf20Sopenharmony_ci			goto msg_trim;
498c2ecf20Sopenharmony_ci		}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		i = msg->sg.end;
528c2ecf20Sopenharmony_ci		sk_msg_iter_var_prev(i);
538c2ecf20Sopenharmony_ci		sge = &msg->sg.data[i];
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if (sk_msg_try_coalesce_ok(msg, elem_first_coalesce) &&
568c2ecf20Sopenharmony_ci		    sg_page(sge) == pfrag->page &&
578c2ecf20Sopenharmony_ci		    sge->offset + sge->length == orig_offset) {
588c2ecf20Sopenharmony_ci			sge->length += use;
598c2ecf20Sopenharmony_ci		} else {
608c2ecf20Sopenharmony_ci			if (sk_msg_full(msg)) {
618c2ecf20Sopenharmony_ci				ret = -ENOSPC;
628c2ecf20Sopenharmony_ci				break;
638c2ecf20Sopenharmony_ci			}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci			sge = &msg->sg.data[msg->sg.end];
668c2ecf20Sopenharmony_ci			sg_unmark_end(sge);
678c2ecf20Sopenharmony_ci			sg_set_page(sge, pfrag->page, use, orig_offset);
688c2ecf20Sopenharmony_ci			get_page(pfrag->page);
698c2ecf20Sopenharmony_ci			sk_msg_iter_next(msg, end);
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci		sk_mem_charge(sk, use);
738c2ecf20Sopenharmony_ci		msg->sg.size += use;
748c2ecf20Sopenharmony_ci		pfrag->offset += use;
758c2ecf20Sopenharmony_ci		len -= use;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return ret;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cimsg_trim:
818c2ecf20Sopenharmony_ci	sk_msg_trim(sk, msg, osize);
828c2ecf20Sopenharmony_ci	return ret;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_alloc);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciint sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src,
878c2ecf20Sopenharmony_ci		 u32 off, u32 len)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	int i = src->sg.start;
908c2ecf20Sopenharmony_ci	struct scatterlist *sge = sk_msg_elem(src, i);
918c2ecf20Sopenharmony_ci	struct scatterlist *sgd = NULL;
928c2ecf20Sopenharmony_ci	u32 sge_len, sge_off;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	while (off) {
958c2ecf20Sopenharmony_ci		if (sge->length > off)
968c2ecf20Sopenharmony_ci			break;
978c2ecf20Sopenharmony_ci		off -= sge->length;
988c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
998c2ecf20Sopenharmony_ci		if (i == src->sg.end && off)
1008c2ecf20Sopenharmony_ci			return -ENOSPC;
1018c2ecf20Sopenharmony_ci		sge = sk_msg_elem(src, i);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	while (len) {
1058c2ecf20Sopenharmony_ci		sge_len = sge->length - off;
1068c2ecf20Sopenharmony_ci		if (sge_len > len)
1078c2ecf20Sopenharmony_ci			sge_len = len;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		if (dst->sg.end)
1108c2ecf20Sopenharmony_ci			sgd = sk_msg_elem(dst, dst->sg.end - 1);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		if (sgd &&
1138c2ecf20Sopenharmony_ci		    (sg_page(sge) == sg_page(sgd)) &&
1148c2ecf20Sopenharmony_ci		    (sg_virt(sge) + off == sg_virt(sgd) + sgd->length)) {
1158c2ecf20Sopenharmony_ci			sgd->length += sge_len;
1168c2ecf20Sopenharmony_ci			dst->sg.size += sge_len;
1178c2ecf20Sopenharmony_ci		} else if (!sk_msg_full(dst)) {
1188c2ecf20Sopenharmony_ci			sge_off = sge->offset + off;
1198c2ecf20Sopenharmony_ci			sk_msg_page_add(dst, sg_page(sge), sge_len, sge_off);
1208c2ecf20Sopenharmony_ci		} else {
1218c2ecf20Sopenharmony_ci			return -ENOSPC;
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		off = 0;
1258c2ecf20Sopenharmony_ci		len -= sge_len;
1268c2ecf20Sopenharmony_ci		sk_mem_charge(sk, sge_len);
1278c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
1288c2ecf20Sopenharmony_ci		if (i == src->sg.end && len)
1298c2ecf20Sopenharmony_ci			return -ENOSPC;
1308c2ecf20Sopenharmony_ci		sge = sk_msg_elem(src, i);
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_clone);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_civoid sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	int i = msg->sg.start;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	do {
1428c2ecf20Sopenharmony_ci		struct scatterlist *sge = sk_msg_elem(msg, i);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		if (bytes < sge->length) {
1458c2ecf20Sopenharmony_ci			sge->length -= bytes;
1468c2ecf20Sopenharmony_ci			sge->offset += bytes;
1478c2ecf20Sopenharmony_ci			sk_mem_uncharge(sk, bytes);
1488c2ecf20Sopenharmony_ci			break;
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		sk_mem_uncharge(sk, sge->length);
1528c2ecf20Sopenharmony_ci		bytes -= sge->length;
1538c2ecf20Sopenharmony_ci		sge->length = 0;
1548c2ecf20Sopenharmony_ci		sge->offset = 0;
1558c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
1568c2ecf20Sopenharmony_ci	} while (bytes && i != msg->sg.end);
1578c2ecf20Sopenharmony_ci	msg->sg.start = i;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_return_zero);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_civoid sk_msg_return(struct sock *sk, struct sk_msg *msg, int bytes)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	int i = msg->sg.start;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	do {
1668c2ecf20Sopenharmony_ci		struct scatterlist *sge = &msg->sg.data[i];
1678c2ecf20Sopenharmony_ci		int uncharge = (bytes < sge->length) ? bytes : sge->length;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		sk_mem_uncharge(sk, uncharge);
1708c2ecf20Sopenharmony_ci		bytes -= uncharge;
1718c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
1728c2ecf20Sopenharmony_ci	} while (i != msg->sg.end);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_return);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int sk_msg_free_elem(struct sock *sk, struct sk_msg *msg, u32 i,
1778c2ecf20Sopenharmony_ci			    bool charge)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct scatterlist *sge = sk_msg_elem(msg, i);
1808c2ecf20Sopenharmony_ci	u32 len = sge->length;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* When the skb owns the memory we free it from consume_skb path. */
1838c2ecf20Sopenharmony_ci	if (!msg->skb) {
1848c2ecf20Sopenharmony_ci		if (charge)
1858c2ecf20Sopenharmony_ci			sk_mem_uncharge(sk, len);
1868c2ecf20Sopenharmony_ci		put_page(sg_page(sge));
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	memset(sge, 0, sizeof(*sge));
1898c2ecf20Sopenharmony_ci	return len;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int __sk_msg_free(struct sock *sk, struct sk_msg *msg, u32 i,
1938c2ecf20Sopenharmony_ci			 bool charge)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct scatterlist *sge = sk_msg_elem(msg, i);
1968c2ecf20Sopenharmony_ci	int freed = 0;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	while (msg->sg.size) {
1998c2ecf20Sopenharmony_ci		msg->sg.size -= sge->length;
2008c2ecf20Sopenharmony_ci		freed += sk_msg_free_elem(sk, msg, i, charge);
2018c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
2028c2ecf20Sopenharmony_ci		sk_msg_check_to_free(msg, i, msg->sg.size);
2038c2ecf20Sopenharmony_ci		sge = sk_msg_elem(msg, i);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	consume_skb(msg->skb);
2068c2ecf20Sopenharmony_ci	sk_msg_init(msg);
2078c2ecf20Sopenharmony_ci	return freed;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciint sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	return __sk_msg_free(sk, msg, msg->sg.start, false);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free_nocharge);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ciint sk_msg_free(struct sock *sk, struct sk_msg *msg)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	return __sk_msg_free(sk, msg, msg->sg.start, true);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void __sk_msg_free_partial(struct sock *sk, struct sk_msg *msg,
2238c2ecf20Sopenharmony_ci				  u32 bytes, bool charge)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct scatterlist *sge;
2268c2ecf20Sopenharmony_ci	u32 i = msg->sg.start;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	while (bytes) {
2298c2ecf20Sopenharmony_ci		sge = sk_msg_elem(msg, i);
2308c2ecf20Sopenharmony_ci		if (!sge->length)
2318c2ecf20Sopenharmony_ci			break;
2328c2ecf20Sopenharmony_ci		if (bytes < sge->length) {
2338c2ecf20Sopenharmony_ci			if (charge)
2348c2ecf20Sopenharmony_ci				sk_mem_uncharge(sk, bytes);
2358c2ecf20Sopenharmony_ci			sge->length -= bytes;
2368c2ecf20Sopenharmony_ci			sge->offset += bytes;
2378c2ecf20Sopenharmony_ci			msg->sg.size -= bytes;
2388c2ecf20Sopenharmony_ci			break;
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		msg->sg.size -= sge->length;
2428c2ecf20Sopenharmony_ci		bytes -= sge->length;
2438c2ecf20Sopenharmony_ci		sk_msg_free_elem(sk, msg, i, charge);
2448c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
2458c2ecf20Sopenharmony_ci		sk_msg_check_to_free(msg, i, bytes);
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci	msg->sg.start = i;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_civoid sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, u32 bytes)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	__sk_msg_free_partial(sk, msg, bytes, true);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free_partial);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_civoid sk_msg_free_partial_nocharge(struct sock *sk, struct sk_msg *msg,
2578c2ecf20Sopenharmony_ci				  u32 bytes)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	__sk_msg_free_partial(sk, msg, bytes, false);
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_civoid sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	int trim = msg->sg.size - len;
2658c2ecf20Sopenharmony_ci	u32 i = msg->sg.end;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (trim <= 0) {
2688c2ecf20Sopenharmony_ci		WARN_ON(trim < 0);
2698c2ecf20Sopenharmony_ci		return;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	sk_msg_iter_var_prev(i);
2738c2ecf20Sopenharmony_ci	msg->sg.size = len;
2748c2ecf20Sopenharmony_ci	while (msg->sg.data[i].length &&
2758c2ecf20Sopenharmony_ci	       trim >= msg->sg.data[i].length) {
2768c2ecf20Sopenharmony_ci		trim -= msg->sg.data[i].length;
2778c2ecf20Sopenharmony_ci		sk_msg_free_elem(sk, msg, i, true);
2788c2ecf20Sopenharmony_ci		sk_msg_iter_var_prev(i);
2798c2ecf20Sopenharmony_ci		if (!trim)
2808c2ecf20Sopenharmony_ci			goto out;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	msg->sg.data[i].length -= trim;
2848c2ecf20Sopenharmony_ci	sk_mem_uncharge(sk, trim);
2858c2ecf20Sopenharmony_ci	/* Adjust copybreak if it falls into the trimmed part of last buf */
2868c2ecf20Sopenharmony_ci	if (msg->sg.curr == i && msg->sg.copybreak > msg->sg.data[i].length)
2878c2ecf20Sopenharmony_ci		msg->sg.copybreak = msg->sg.data[i].length;
2888c2ecf20Sopenharmony_ciout:
2898c2ecf20Sopenharmony_ci	sk_msg_iter_var_next(i);
2908c2ecf20Sopenharmony_ci	msg->sg.end = i;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* If we trim data a full sg elem before curr pointer update
2938c2ecf20Sopenharmony_ci	 * copybreak and current so that any future copy operations
2948c2ecf20Sopenharmony_ci	 * start at new copy location.
2958c2ecf20Sopenharmony_ci	 * However trimed data that has not yet been used in a copy op
2968c2ecf20Sopenharmony_ci	 * does not require an update.
2978c2ecf20Sopenharmony_ci	 */
2988c2ecf20Sopenharmony_ci	if (!msg->sg.size) {
2998c2ecf20Sopenharmony_ci		msg->sg.curr = msg->sg.start;
3008c2ecf20Sopenharmony_ci		msg->sg.copybreak = 0;
3018c2ecf20Sopenharmony_ci	} else if (sk_msg_iter_dist(msg->sg.start, msg->sg.curr) >=
3028c2ecf20Sopenharmony_ci		   sk_msg_iter_dist(msg->sg.start, msg->sg.end)) {
3038c2ecf20Sopenharmony_ci		sk_msg_iter_var_prev(i);
3048c2ecf20Sopenharmony_ci		msg->sg.curr = i;
3058c2ecf20Sopenharmony_ci		msg->sg.copybreak = msg->sg.data[i].length;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_trim);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ciint sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from,
3118c2ecf20Sopenharmony_ci			      struct sk_msg *msg, u32 bytes)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	int i, maxpages, ret = 0, num_elems = sk_msg_elem_used(msg);
3148c2ecf20Sopenharmony_ci	const int to_max_pages = MAX_MSG_FRAGS;
3158c2ecf20Sopenharmony_ci	struct page *pages[MAX_MSG_FRAGS];
3168c2ecf20Sopenharmony_ci	ssize_t orig, copied, use, offset;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	orig = msg->sg.size;
3198c2ecf20Sopenharmony_ci	while (bytes > 0) {
3208c2ecf20Sopenharmony_ci		i = 0;
3218c2ecf20Sopenharmony_ci		maxpages = to_max_pages - num_elems;
3228c2ecf20Sopenharmony_ci		if (maxpages == 0) {
3238c2ecf20Sopenharmony_ci			ret = -EFAULT;
3248c2ecf20Sopenharmony_ci			goto out;
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		copied = iov_iter_get_pages(from, pages, bytes, maxpages,
3288c2ecf20Sopenharmony_ci					    &offset);
3298c2ecf20Sopenharmony_ci		if (copied <= 0) {
3308c2ecf20Sopenharmony_ci			ret = -EFAULT;
3318c2ecf20Sopenharmony_ci			goto out;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		iov_iter_advance(from, copied);
3358c2ecf20Sopenharmony_ci		bytes -= copied;
3368c2ecf20Sopenharmony_ci		msg->sg.size += copied;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		while (copied) {
3398c2ecf20Sopenharmony_ci			use = min_t(int, copied, PAGE_SIZE - offset);
3408c2ecf20Sopenharmony_ci			sg_set_page(&msg->sg.data[msg->sg.end],
3418c2ecf20Sopenharmony_ci				    pages[i], use, offset);
3428c2ecf20Sopenharmony_ci			sg_unmark_end(&msg->sg.data[msg->sg.end]);
3438c2ecf20Sopenharmony_ci			sk_mem_charge(sk, use);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			offset = 0;
3468c2ecf20Sopenharmony_ci			copied -= use;
3478c2ecf20Sopenharmony_ci			sk_msg_iter_next(msg, end);
3488c2ecf20Sopenharmony_ci			num_elems++;
3498c2ecf20Sopenharmony_ci			i++;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		/* When zerocopy is mixed with sk_msg_*copy* operations we
3528c2ecf20Sopenharmony_ci		 * may have a copybreak set in this case clear and prefer
3538c2ecf20Sopenharmony_ci		 * zerocopy remainder when possible.
3548c2ecf20Sopenharmony_ci		 */
3558c2ecf20Sopenharmony_ci		msg->sg.copybreak = 0;
3568c2ecf20Sopenharmony_ci		msg->sg.curr = msg->sg.end;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ciout:
3598c2ecf20Sopenharmony_ci	/* Revert iov_iter updates, msg will need to use 'trim' later if it
3608c2ecf20Sopenharmony_ci	 * also needs to be cleared.
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	if (ret)
3638c2ecf20Sopenharmony_ci		iov_iter_revert(from, msg->sg.size - orig);
3648c2ecf20Sopenharmony_ci	return ret;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_zerocopy_from_iter);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ciint sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from,
3698c2ecf20Sopenharmony_ci			     struct sk_msg *msg, u32 bytes)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	int ret = -ENOSPC, i = msg->sg.curr;
3728c2ecf20Sopenharmony_ci	struct scatterlist *sge;
3738c2ecf20Sopenharmony_ci	u32 copy, buf_size;
3748c2ecf20Sopenharmony_ci	void *to;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	do {
3778c2ecf20Sopenharmony_ci		sge = sk_msg_elem(msg, i);
3788c2ecf20Sopenharmony_ci		/* This is possible if a trim operation shrunk the buffer */
3798c2ecf20Sopenharmony_ci		if (msg->sg.copybreak >= sge->length) {
3808c2ecf20Sopenharmony_ci			msg->sg.copybreak = 0;
3818c2ecf20Sopenharmony_ci			sk_msg_iter_var_next(i);
3828c2ecf20Sopenharmony_ci			if (i == msg->sg.end)
3838c2ecf20Sopenharmony_ci				break;
3848c2ecf20Sopenharmony_ci			sge = sk_msg_elem(msg, i);
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		buf_size = sge->length - msg->sg.copybreak;
3888c2ecf20Sopenharmony_ci		copy = (buf_size > bytes) ? bytes : buf_size;
3898c2ecf20Sopenharmony_ci		to = sg_virt(sge) + msg->sg.copybreak;
3908c2ecf20Sopenharmony_ci		msg->sg.copybreak += copy;
3918c2ecf20Sopenharmony_ci		if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY)
3928c2ecf20Sopenharmony_ci			ret = copy_from_iter_nocache(to, copy, from);
3938c2ecf20Sopenharmony_ci		else
3948c2ecf20Sopenharmony_ci			ret = copy_from_iter(to, copy, from);
3958c2ecf20Sopenharmony_ci		if (ret != copy) {
3968c2ecf20Sopenharmony_ci			ret = -EFAULT;
3978c2ecf20Sopenharmony_ci			goto out;
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci		bytes -= copy;
4008c2ecf20Sopenharmony_ci		if (!bytes)
4018c2ecf20Sopenharmony_ci			break;
4028c2ecf20Sopenharmony_ci		msg->sg.copybreak = 0;
4038c2ecf20Sopenharmony_ci		sk_msg_iter_var_next(i);
4048c2ecf20Sopenharmony_ci	} while (i != msg->sg.end);
4058c2ecf20Sopenharmony_ciout:
4068c2ecf20Sopenharmony_ci	msg->sg.curr = i;
4078c2ecf20Sopenharmony_ci	return ret;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic struct sk_msg *sk_psock_create_ingress_msg(struct sock *sk,
4128c2ecf20Sopenharmony_ci						  struct sk_buff *skb)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct sk_msg *msg;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
4178c2ecf20Sopenharmony_ci		return NULL;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (!sk_rmem_schedule(sk, skb, skb->truesize))
4208c2ecf20Sopenharmony_ci		return NULL;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC);
4238c2ecf20Sopenharmony_ci	if (unlikely(!msg))
4248c2ecf20Sopenharmony_ci		return NULL;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	sk_msg_init(msg);
4278c2ecf20Sopenharmony_ci	return msg;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,
4318c2ecf20Sopenharmony_ci					struct sk_psock *psock,
4328c2ecf20Sopenharmony_ci					struct sock *sk,
4338c2ecf20Sopenharmony_ci					struct sk_msg *msg)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	int num_sge, copied;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* skb linearize may fail with ENOMEM, but lets simply try again
4388c2ecf20Sopenharmony_ci	 * later if this happens. Under memory pressure we don't want to
4398c2ecf20Sopenharmony_ci	 * drop the skb. We need to linearize the skb so that the mapping
4408c2ecf20Sopenharmony_ci	 * in skb_to_sgvec can not error.
4418c2ecf20Sopenharmony_ci	 */
4428c2ecf20Sopenharmony_ci	if (skb_linearize(skb))
4438c2ecf20Sopenharmony_ci		return -EAGAIN;
4448c2ecf20Sopenharmony_ci	num_sge = skb_to_sgvec(skb, msg->sg.data, 0, skb->len);
4458c2ecf20Sopenharmony_ci	if (unlikely(num_sge < 0))
4468c2ecf20Sopenharmony_ci		return num_sge;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	copied = skb->len;
4498c2ecf20Sopenharmony_ci	msg->sg.start = 0;
4508c2ecf20Sopenharmony_ci	msg->sg.size = copied;
4518c2ecf20Sopenharmony_ci	msg->sg.end = num_sge;
4528c2ecf20Sopenharmony_ci	msg->skb = skb;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	sk_psock_queue_msg(psock, msg);
4558c2ecf20Sopenharmony_ci	sk_psock_data_ready(sk, psock);
4568c2ecf20Sopenharmony_ci	return copied;
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct sock *sk = psock->sk;
4648c2ecf20Sopenharmony_ci	struct sk_msg *msg;
4658c2ecf20Sopenharmony_ci	int err;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* If we are receiving on the same sock skb->sk is already assigned,
4688c2ecf20Sopenharmony_ci	 * skip memory accounting and owner transition seeing it already set
4698c2ecf20Sopenharmony_ci	 * correctly.
4708c2ecf20Sopenharmony_ci	 */
4718c2ecf20Sopenharmony_ci	if (unlikely(skb->sk == sk))
4728c2ecf20Sopenharmony_ci		return sk_psock_skb_ingress_self(psock, skb);
4738c2ecf20Sopenharmony_ci	msg = sk_psock_create_ingress_msg(sk, skb);
4748c2ecf20Sopenharmony_ci	if (!msg)
4758c2ecf20Sopenharmony_ci		return -EAGAIN;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* This will transition ownership of the data from the socket where
4788c2ecf20Sopenharmony_ci	 * the BPF program was run initiating the redirect to the socket
4798c2ecf20Sopenharmony_ci	 * we will eventually receive this data on. The data will be released
4808c2ecf20Sopenharmony_ci	 * from skb_consume found in __tcp_bpf_recvmsg() after its been copied
4818c2ecf20Sopenharmony_ci	 * into user buffers.
4828c2ecf20Sopenharmony_ci	 */
4838c2ecf20Sopenharmony_ci	skb_set_owner_r(skb, sk);
4848c2ecf20Sopenharmony_ci	err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg);
4858c2ecf20Sopenharmony_ci	if (err < 0)
4868c2ecf20Sopenharmony_ci		kfree(msg);
4878c2ecf20Sopenharmony_ci	return err;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci/* Puts an skb on the ingress queue of the socket already assigned to the
4918c2ecf20Sopenharmony_ci * skb. In this case we do not need to check memory limits or skb_set_owner_r
4928c2ecf20Sopenharmony_ci * because the skb is already accounted for here.
4938c2ecf20Sopenharmony_ci */
4948c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct sk_msg *msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC);
4978c2ecf20Sopenharmony_ci	struct sock *sk = psock->sk;
4988c2ecf20Sopenharmony_ci	int err;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (unlikely(!msg))
5018c2ecf20Sopenharmony_ci		return -EAGAIN;
5028c2ecf20Sopenharmony_ci	sk_msg_init(msg);
5038c2ecf20Sopenharmony_ci	skb_set_owner_r(skb, sk);
5048c2ecf20Sopenharmony_ci	err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg);
5058c2ecf20Sopenharmony_ci	if (err < 0)
5068c2ecf20Sopenharmony_ci		kfree(msg);
5078c2ecf20Sopenharmony_ci	return err;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
5118c2ecf20Sopenharmony_ci			       u32 off, u32 len, bool ingress)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	if (!ingress) {
5148c2ecf20Sopenharmony_ci		if (!sock_writeable(psock->sk))
5158c2ecf20Sopenharmony_ci			return -EAGAIN;
5168c2ecf20Sopenharmony_ci		return skb_send_sock_locked(psock->sk, skb, off, len);
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	return sk_psock_skb_ingress(psock, skb);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void sk_psock_backlog(struct work_struct *work)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct sk_psock *psock = container_of(work, struct sk_psock, work);
5248c2ecf20Sopenharmony_ci	struct sk_psock_work_state *state = &psock->work_state;
5258c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5268c2ecf20Sopenharmony_ci	bool ingress;
5278c2ecf20Sopenharmony_ci	u32 len, off;
5288c2ecf20Sopenharmony_ci	int ret;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	/* Lock sock to avoid losing sk_socket during loop. */
5318c2ecf20Sopenharmony_ci	lock_sock(psock->sk);
5328c2ecf20Sopenharmony_ci	if (state->skb) {
5338c2ecf20Sopenharmony_ci		skb = state->skb;
5348c2ecf20Sopenharmony_ci		len = state->len;
5358c2ecf20Sopenharmony_ci		off = state->off;
5368c2ecf20Sopenharmony_ci		state->skb = NULL;
5378c2ecf20Sopenharmony_ci		goto start;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&psock->ingress_skb))) {
5418c2ecf20Sopenharmony_ci		len = skb->len;
5428c2ecf20Sopenharmony_ci		off = 0;
5438c2ecf20Sopenharmony_cistart:
5448c2ecf20Sopenharmony_ci		ingress = tcp_skb_bpf_ingress(skb);
5458c2ecf20Sopenharmony_ci		do {
5468c2ecf20Sopenharmony_ci			ret = -EIO;
5478c2ecf20Sopenharmony_ci			if (likely(psock->sk->sk_socket))
5488c2ecf20Sopenharmony_ci				ret = sk_psock_handle_skb(psock, skb, off,
5498c2ecf20Sopenharmony_ci							  len, ingress);
5508c2ecf20Sopenharmony_ci			if (ret <= 0) {
5518c2ecf20Sopenharmony_ci				if (ret == -EAGAIN) {
5528c2ecf20Sopenharmony_ci					state->skb = skb;
5538c2ecf20Sopenharmony_ci					state->len = len;
5548c2ecf20Sopenharmony_ci					state->off = off;
5558c2ecf20Sopenharmony_ci					goto end;
5568c2ecf20Sopenharmony_ci				}
5578c2ecf20Sopenharmony_ci				/* Hard errors break pipe and stop xmit. */
5588c2ecf20Sopenharmony_ci				sk_psock_report_error(psock, ret ? -ret : EPIPE);
5598c2ecf20Sopenharmony_ci				sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
5608c2ecf20Sopenharmony_ci				kfree_skb(skb);
5618c2ecf20Sopenharmony_ci				goto end;
5628c2ecf20Sopenharmony_ci			}
5638c2ecf20Sopenharmony_ci			off += ret;
5648c2ecf20Sopenharmony_ci			len -= ret;
5658c2ecf20Sopenharmony_ci		} while (len);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		if (!ingress)
5688c2ecf20Sopenharmony_ci			kfree_skb(skb);
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ciend:
5718c2ecf20Sopenharmony_ci	release_sock(psock->sk);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistruct sk_psock *sk_psock_init(struct sock *sk, int node)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct sk_psock *psock;
5778c2ecf20Sopenharmony_ci	struct proto *prot;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	write_lock_bh(&sk->sk_callback_lock);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (inet_csk_has_ulp(sk)) {
5828c2ecf20Sopenharmony_ci		psock = ERR_PTR(-EINVAL);
5838c2ecf20Sopenharmony_ci		goto out;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (sk->sk_user_data) {
5878c2ecf20Sopenharmony_ci		psock = ERR_PTR(-EBUSY);
5888c2ecf20Sopenharmony_ci		goto out;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	psock = kzalloc_node(sizeof(*psock), GFP_ATOMIC | __GFP_NOWARN, node);
5928c2ecf20Sopenharmony_ci	if (!psock) {
5938c2ecf20Sopenharmony_ci		psock = ERR_PTR(-ENOMEM);
5948c2ecf20Sopenharmony_ci		goto out;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	prot = READ_ONCE(sk->sk_prot);
5988c2ecf20Sopenharmony_ci	psock->sk = sk;
5998c2ecf20Sopenharmony_ci	psock->eval = __SK_NONE;
6008c2ecf20Sopenharmony_ci	psock->sk_proto = prot;
6018c2ecf20Sopenharmony_ci	psock->saved_unhash = prot->unhash;
6028c2ecf20Sopenharmony_ci	psock->saved_close = prot->close;
6038c2ecf20Sopenharmony_ci	psock->saved_write_space = sk->sk_write_space;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&psock->link);
6068c2ecf20Sopenharmony_ci	spin_lock_init(&psock->link_lock);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	INIT_WORK(&psock->work, sk_psock_backlog);
6098c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&psock->ingress_msg);
6108c2ecf20Sopenharmony_ci	skb_queue_head_init(&psock->ingress_skb);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	sk_psock_set_state(psock, SK_PSOCK_TX_ENABLED);
6138c2ecf20Sopenharmony_ci	refcount_set(&psock->refcnt, 1);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	__rcu_assign_sk_user_data_with_flags(sk, psock,
6168c2ecf20Sopenharmony_ci					     SK_USER_DATA_NOCOPY |
6178c2ecf20Sopenharmony_ci					     SK_USER_DATA_PSOCK);
6188c2ecf20Sopenharmony_ci	sock_hold(sk);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ciout:
6218c2ecf20Sopenharmony_ci	write_unlock_bh(&sk->sk_callback_lock);
6228c2ecf20Sopenharmony_ci	return psock;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_init);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistruct sk_psock_link *sk_psock_link_pop(struct sk_psock *psock)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct sk_psock_link *link;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	spin_lock_bh(&psock->link_lock);
6318c2ecf20Sopenharmony_ci	link = list_first_entry_or_null(&psock->link, struct sk_psock_link,
6328c2ecf20Sopenharmony_ci					list);
6338c2ecf20Sopenharmony_ci	if (link)
6348c2ecf20Sopenharmony_ci		list_del(&link->list);
6358c2ecf20Sopenharmony_ci	spin_unlock_bh(&psock->link_lock);
6368c2ecf20Sopenharmony_ci	return link;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_civoid __sk_psock_purge_ingress_msg(struct sk_psock *psock)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct sk_msg *msg, *tmp;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	list_for_each_entry_safe(msg, tmp, &psock->ingress_msg, list) {
6448c2ecf20Sopenharmony_ci		list_del(&msg->list);
6458c2ecf20Sopenharmony_ci		sk_msg_free(psock->sk, msg);
6468c2ecf20Sopenharmony_ci		kfree(msg);
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic void sk_psock_zap_ingress(struct sk_psock *psock)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	__skb_queue_purge(&psock->ingress_skb);
6538c2ecf20Sopenharmony_ci	__sk_psock_purge_ingress_msg(psock);
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic void sk_psock_link_destroy(struct sk_psock *psock)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	struct sk_psock_link *link, *tmp;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	list_for_each_entry_safe(link, tmp, &psock->link, list) {
6618c2ecf20Sopenharmony_ci		list_del(&link->list);
6628c2ecf20Sopenharmony_ci		sk_psock_free_link(link);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic void sk_psock_destroy_deferred(struct work_struct *gc)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	struct sk_psock *psock = container_of(gc, struct sk_psock, gc);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	/* No sk_callback_lock since already detached. */
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* Parser has been stopped */
6738c2ecf20Sopenharmony_ci	if (psock->progs.skb_parser)
6748c2ecf20Sopenharmony_ci		strp_done(&psock->parser.strp);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	cancel_work_sync(&psock->work);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	psock_progs_drop(&psock->progs);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	sk_psock_link_destroy(psock);
6818c2ecf20Sopenharmony_ci	sk_psock_cork_free(psock);
6828c2ecf20Sopenharmony_ci	sk_psock_zap_ingress(psock);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (psock->sk_redir)
6858c2ecf20Sopenharmony_ci		sock_put(psock->sk_redir);
6868c2ecf20Sopenharmony_ci	sock_put(psock->sk);
6878c2ecf20Sopenharmony_ci	kfree(psock);
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic void sk_psock_destroy(struct rcu_head *rcu)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	struct sk_psock *psock = container_of(rcu, struct sk_psock, rcu);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	INIT_WORK(&psock->gc, sk_psock_destroy_deferred);
6958c2ecf20Sopenharmony_ci	schedule_work(&psock->gc);
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_civoid sk_psock_drop(struct sock *sk, struct sk_psock *psock)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	sk_psock_cork_free(psock);
7018c2ecf20Sopenharmony_ci	sk_psock_zap_ingress(psock);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	write_lock_bh(&sk->sk_callback_lock);
7048c2ecf20Sopenharmony_ci	sk_psock_restore_proto(sk, psock);
7058c2ecf20Sopenharmony_ci	rcu_assign_sk_user_data(sk, NULL);
7068c2ecf20Sopenharmony_ci	if (psock->progs.skb_parser)
7078c2ecf20Sopenharmony_ci		sk_psock_stop_strp(sk, psock);
7088c2ecf20Sopenharmony_ci	else if (psock->progs.skb_verdict)
7098c2ecf20Sopenharmony_ci		sk_psock_stop_verdict(sk, psock);
7108c2ecf20Sopenharmony_ci	write_unlock_bh(&sk->sk_callback_lock);
7118c2ecf20Sopenharmony_ci	sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	call_rcu(&psock->rcu, sk_psock_destroy);
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_drop);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic int sk_psock_map_verd(int verdict, bool redir)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	switch (verdict) {
7208c2ecf20Sopenharmony_ci	case SK_PASS:
7218c2ecf20Sopenharmony_ci		return redir ? __SK_REDIRECT : __SK_PASS;
7228c2ecf20Sopenharmony_ci	case SK_DROP:
7238c2ecf20Sopenharmony_ci	default:
7248c2ecf20Sopenharmony_ci		break;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	return __SK_DROP;
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ciint sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock,
7318c2ecf20Sopenharmony_ci			 struct sk_msg *msg)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
7348c2ecf20Sopenharmony_ci	int ret;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	rcu_read_lock();
7378c2ecf20Sopenharmony_ci	prog = READ_ONCE(psock->progs.msg_parser);
7388c2ecf20Sopenharmony_ci	if (unlikely(!prog)) {
7398c2ecf20Sopenharmony_ci		ret = __SK_PASS;
7408c2ecf20Sopenharmony_ci		goto out;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	sk_msg_compute_data_pointers(msg);
7448c2ecf20Sopenharmony_ci	msg->sk = sk;
7458c2ecf20Sopenharmony_ci	ret = bpf_prog_run_pin_on_cpu(prog, msg);
7468c2ecf20Sopenharmony_ci	ret = sk_psock_map_verd(ret, msg->sk_redir);
7478c2ecf20Sopenharmony_ci	psock->apply_bytes = msg->apply_bytes;
7488c2ecf20Sopenharmony_ci	if (ret == __SK_REDIRECT) {
7498c2ecf20Sopenharmony_ci		if (psock->sk_redir)
7508c2ecf20Sopenharmony_ci			sock_put(psock->sk_redir);
7518c2ecf20Sopenharmony_ci		psock->sk_redir = msg->sk_redir;
7528c2ecf20Sopenharmony_ci		if (!psock->sk_redir) {
7538c2ecf20Sopenharmony_ci			ret = __SK_DROP;
7548c2ecf20Sopenharmony_ci			goto out;
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci		sock_hold(psock->sk_redir);
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ciout:
7598c2ecf20Sopenharmony_ci	rcu_read_unlock();
7608c2ecf20Sopenharmony_ci	return ret;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_msg_verdict);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_cistatic int sk_psock_bpf_run(struct sk_psock *psock, struct bpf_prog *prog,
7658c2ecf20Sopenharmony_ci			    struct sk_buff *skb)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	bpf_compute_data_end_sk_skb(skb);
7688c2ecf20Sopenharmony_ci	return bpf_prog_run_pin_on_cpu(prog, skb);
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic struct sk_psock *sk_psock_from_strp(struct strparser *strp)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	struct sk_psock_parser *parser;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	parser = container_of(strp, struct sk_psock_parser, strp);
7768c2ecf20Sopenharmony_ci	return container_of(parser, struct sk_psock, parser);
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic void sk_psock_skb_redirect(struct sk_buff *skb)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	struct sk_psock *psock_other;
7828c2ecf20Sopenharmony_ci	struct sock *sk_other;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	sk_other = tcp_skb_bpf_redirect_fetch(skb);
7858c2ecf20Sopenharmony_ci	/* This error is a buggy BPF program, it returned a redirect
7868c2ecf20Sopenharmony_ci	 * return code, but then didn't set a redirect interface.
7878c2ecf20Sopenharmony_ci	 */
7888c2ecf20Sopenharmony_ci	if (unlikely(!sk_other)) {
7898c2ecf20Sopenharmony_ci		kfree_skb(skb);
7908c2ecf20Sopenharmony_ci		return;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci	psock_other = sk_psock(sk_other);
7938c2ecf20Sopenharmony_ci	/* This error indicates the socket is being torn down or had another
7948c2ecf20Sopenharmony_ci	 * error that caused the pipe to break. We can't send a packet on
7958c2ecf20Sopenharmony_ci	 * a socket that is in this state so we drop the skb.
7968c2ecf20Sopenharmony_ci	 */
7978c2ecf20Sopenharmony_ci	if (!psock_other || sock_flag(sk_other, SOCK_DEAD) ||
7988c2ecf20Sopenharmony_ci	    !sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) {
7998c2ecf20Sopenharmony_ci		kfree_skb(skb);
8008c2ecf20Sopenharmony_ci		return;
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	skb_queue_tail(&psock_other->ingress_skb, skb);
8048c2ecf20Sopenharmony_ci	schedule_work(&psock_other->work);
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic void sk_psock_tls_verdict_apply(struct sk_buff *skb, struct sock *sk, int verdict)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	switch (verdict) {
8108c2ecf20Sopenharmony_ci	case __SK_REDIRECT:
8118c2ecf20Sopenharmony_ci		sk_psock_skb_redirect(skb);
8128c2ecf20Sopenharmony_ci		break;
8138c2ecf20Sopenharmony_ci	case __SK_PASS:
8148c2ecf20Sopenharmony_ci	case __SK_DROP:
8158c2ecf20Sopenharmony_ci	default:
8168c2ecf20Sopenharmony_ci		break;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ciint sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
8238c2ecf20Sopenharmony_ci	int ret = __SK_PASS;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	rcu_read_lock();
8268c2ecf20Sopenharmony_ci	prog = READ_ONCE(psock->progs.skb_verdict);
8278c2ecf20Sopenharmony_ci	if (likely(prog)) {
8288c2ecf20Sopenharmony_ci		skb->sk = psock->sk;
8298c2ecf20Sopenharmony_ci		tcp_skb_bpf_redirect_clear(skb);
8308c2ecf20Sopenharmony_ci		ret = sk_psock_bpf_run(psock, prog, skb);
8318c2ecf20Sopenharmony_ci		ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
8328c2ecf20Sopenharmony_ci		skb->sk = NULL;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci	sk_psock_tls_verdict_apply(skb, psock->sk, ret);
8358c2ecf20Sopenharmony_ci	rcu_read_unlock();
8368c2ecf20Sopenharmony_ci	return ret;
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_tls_strp_read);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic void sk_psock_verdict_apply(struct sk_psock *psock,
8418c2ecf20Sopenharmony_ci				   struct sk_buff *skb, int verdict)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct tcp_skb_cb *tcp;
8448c2ecf20Sopenharmony_ci	struct sock *sk_other;
8458c2ecf20Sopenharmony_ci	int err = -EIO;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	switch (verdict) {
8488c2ecf20Sopenharmony_ci	case __SK_PASS:
8498c2ecf20Sopenharmony_ci		sk_other = psock->sk;
8508c2ecf20Sopenharmony_ci		if (sock_flag(sk_other, SOCK_DEAD) ||
8518c2ecf20Sopenharmony_ci		    !sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
8528c2ecf20Sopenharmony_ci			goto out_free;
8538c2ecf20Sopenharmony_ci		}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci		tcp = TCP_SKB_CB(skb);
8568c2ecf20Sopenharmony_ci		tcp->bpf.flags |= BPF_F_INGRESS;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci		/* If the queue is empty then we can submit directly
8598c2ecf20Sopenharmony_ci		 * into the msg queue. If its not empty we have to
8608c2ecf20Sopenharmony_ci		 * queue work otherwise we may get OOO data. Otherwise,
8618c2ecf20Sopenharmony_ci		 * if sk_psock_skb_ingress errors will be handled by
8628c2ecf20Sopenharmony_ci		 * retrying later from workqueue.
8638c2ecf20Sopenharmony_ci		 */
8648c2ecf20Sopenharmony_ci		if (skb_queue_empty(&psock->ingress_skb)) {
8658c2ecf20Sopenharmony_ci			err = sk_psock_skb_ingress_self(psock, skb);
8668c2ecf20Sopenharmony_ci		}
8678c2ecf20Sopenharmony_ci		if (err < 0) {
8688c2ecf20Sopenharmony_ci			skb_queue_tail(&psock->ingress_skb, skb);
8698c2ecf20Sopenharmony_ci			schedule_work(&psock->work);
8708c2ecf20Sopenharmony_ci		}
8718c2ecf20Sopenharmony_ci		break;
8728c2ecf20Sopenharmony_ci	case __SK_REDIRECT:
8738c2ecf20Sopenharmony_ci		sk_psock_skb_redirect(skb);
8748c2ecf20Sopenharmony_ci		break;
8758c2ecf20Sopenharmony_ci	case __SK_DROP:
8768c2ecf20Sopenharmony_ci	default:
8778c2ecf20Sopenharmony_ciout_free:
8788c2ecf20Sopenharmony_ci		kfree_skb(skb);
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct sk_psock *psock;
8858c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
8868c2ecf20Sopenharmony_ci	int ret = __SK_DROP;
8878c2ecf20Sopenharmony_ci	struct sock *sk;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	rcu_read_lock();
8908c2ecf20Sopenharmony_ci	sk = strp->sk;
8918c2ecf20Sopenharmony_ci	psock = sk_psock(sk);
8928c2ecf20Sopenharmony_ci	if (unlikely(!psock)) {
8938c2ecf20Sopenharmony_ci		kfree_skb(skb);
8948c2ecf20Sopenharmony_ci		goto out;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci	prog = READ_ONCE(psock->progs.skb_verdict);
8978c2ecf20Sopenharmony_ci	if (likely(prog)) {
8988c2ecf20Sopenharmony_ci		skb->sk = sk;
8998c2ecf20Sopenharmony_ci		tcp_skb_bpf_redirect_clear(skb);
9008c2ecf20Sopenharmony_ci		ret = sk_psock_bpf_run(psock, prog, skb);
9018c2ecf20Sopenharmony_ci		ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
9028c2ecf20Sopenharmony_ci		skb->sk = NULL;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci	sk_psock_verdict_apply(psock, skb, ret);
9058c2ecf20Sopenharmony_ciout:
9068c2ecf20Sopenharmony_ci	rcu_read_unlock();
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic int sk_psock_strp_read_done(struct strparser *strp, int err)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	return err;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	struct sk_psock *psock = sk_psock_from_strp(strp);
9178c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
9188c2ecf20Sopenharmony_ci	int ret = skb->len;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	rcu_read_lock();
9218c2ecf20Sopenharmony_ci	prog = READ_ONCE(psock->progs.skb_parser);
9228c2ecf20Sopenharmony_ci	if (likely(prog)) {
9238c2ecf20Sopenharmony_ci		skb->sk = psock->sk;
9248c2ecf20Sopenharmony_ci		ret = sk_psock_bpf_run(psock, prog, skb);
9258c2ecf20Sopenharmony_ci		skb->sk = NULL;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci	rcu_read_unlock();
9288c2ecf20Sopenharmony_ci	return ret;
9298c2ecf20Sopenharmony_ci}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci/* Called with socket lock held. */
9328c2ecf20Sopenharmony_cistatic void sk_psock_strp_data_ready(struct sock *sk)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct sk_psock *psock;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	rcu_read_lock();
9378c2ecf20Sopenharmony_ci	psock = sk_psock(sk);
9388c2ecf20Sopenharmony_ci	if (likely(psock)) {
9398c2ecf20Sopenharmony_ci		if (tls_sw_has_ctx_rx(sk)) {
9408c2ecf20Sopenharmony_ci			psock->parser.saved_data_ready(sk);
9418c2ecf20Sopenharmony_ci		} else {
9428c2ecf20Sopenharmony_ci			write_lock_bh(&sk->sk_callback_lock);
9438c2ecf20Sopenharmony_ci			strp_data_ready(&psock->parser.strp);
9448c2ecf20Sopenharmony_ci			write_unlock_bh(&sk->sk_callback_lock);
9458c2ecf20Sopenharmony_ci		}
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci	rcu_read_unlock();
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb,
9518c2ecf20Sopenharmony_ci				 unsigned int offset, size_t orig_len)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	struct sock *sk = (struct sock *)desc->arg.data;
9548c2ecf20Sopenharmony_ci	struct sk_psock *psock;
9558c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
9568c2ecf20Sopenharmony_ci	int ret = __SK_DROP;
9578c2ecf20Sopenharmony_ci	int len = orig_len;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	/* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */
9608c2ecf20Sopenharmony_ci	skb = skb_clone(skb, GFP_ATOMIC);
9618c2ecf20Sopenharmony_ci	if (!skb) {
9628c2ecf20Sopenharmony_ci		desc->error = -ENOMEM;
9638c2ecf20Sopenharmony_ci		return 0;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	rcu_read_lock();
9678c2ecf20Sopenharmony_ci	psock = sk_psock(sk);
9688c2ecf20Sopenharmony_ci	if (unlikely(!psock)) {
9698c2ecf20Sopenharmony_ci		len = 0;
9708c2ecf20Sopenharmony_ci		kfree_skb(skb);
9718c2ecf20Sopenharmony_ci		goto out;
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci	prog = READ_ONCE(psock->progs.skb_verdict);
9748c2ecf20Sopenharmony_ci	if (likely(prog)) {
9758c2ecf20Sopenharmony_ci		skb->sk = sk;
9768c2ecf20Sopenharmony_ci		tcp_skb_bpf_redirect_clear(skb);
9778c2ecf20Sopenharmony_ci		ret = sk_psock_bpf_run(psock, prog, skb);
9788c2ecf20Sopenharmony_ci		ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb));
9798c2ecf20Sopenharmony_ci		skb->sk = NULL;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci	sk_psock_verdict_apply(psock, skb, ret);
9828c2ecf20Sopenharmony_ciout:
9838c2ecf20Sopenharmony_ci	rcu_read_unlock();
9848c2ecf20Sopenharmony_ci	return len;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic void sk_psock_verdict_data_ready(struct sock *sk)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct socket *sock = sk->sk_socket;
9908c2ecf20Sopenharmony_ci	read_descriptor_t desc;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (unlikely(!sock || !sock->ops || !sock->ops->read_sock))
9938c2ecf20Sopenharmony_ci		return;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	desc.arg.data = sk;
9968c2ecf20Sopenharmony_ci	desc.error = 0;
9978c2ecf20Sopenharmony_ci	desc.count = 1;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	sock->ops->read_sock(sk, &desc, sk_psock_verdict_recv);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic void sk_psock_write_space(struct sock *sk)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	struct sk_psock *psock;
10058c2ecf20Sopenharmony_ci	void (*write_space)(struct sock *sk) = NULL;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	rcu_read_lock();
10088c2ecf20Sopenharmony_ci	psock = sk_psock(sk);
10098c2ecf20Sopenharmony_ci	if (likely(psock)) {
10108c2ecf20Sopenharmony_ci		if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED))
10118c2ecf20Sopenharmony_ci			schedule_work(&psock->work);
10128c2ecf20Sopenharmony_ci		write_space = psock->saved_write_space;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci	rcu_read_unlock();
10158c2ecf20Sopenharmony_ci	if (write_space)
10168c2ecf20Sopenharmony_ci		write_space(sk);
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ciint sk_psock_init_strp(struct sock *sk, struct sk_psock *psock)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	static const struct strp_callbacks cb = {
10228c2ecf20Sopenharmony_ci		.rcv_msg	= sk_psock_strp_read,
10238c2ecf20Sopenharmony_ci		.read_sock_done	= sk_psock_strp_read_done,
10248c2ecf20Sopenharmony_ci		.parse_msg	= sk_psock_strp_parse,
10258c2ecf20Sopenharmony_ci	};
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	psock->parser.enabled = false;
10288c2ecf20Sopenharmony_ci	return strp_init(&psock->parser.strp, sk, &cb);
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_civoid sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct sk_psock_parser *parser = &psock->parser;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (parser->enabled)
10368c2ecf20Sopenharmony_ci		return;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	parser->saved_data_ready = sk->sk_data_ready;
10398c2ecf20Sopenharmony_ci	sk->sk_data_ready = sk_psock_verdict_data_ready;
10408c2ecf20Sopenharmony_ci	sk->sk_write_space = sk_psock_write_space;
10418c2ecf20Sopenharmony_ci	parser->enabled = true;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_civoid sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct sk_psock_parser *parser = &psock->parser;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (parser->enabled)
10498c2ecf20Sopenharmony_ci		return;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	parser->saved_data_ready = sk->sk_data_ready;
10528c2ecf20Sopenharmony_ci	sk->sk_data_ready = sk_psock_strp_data_ready;
10538c2ecf20Sopenharmony_ci	sk->sk_write_space = sk_psock_write_space;
10548c2ecf20Sopenharmony_ci	parser->enabled = true;
10558c2ecf20Sopenharmony_ci}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_civoid sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
10588c2ecf20Sopenharmony_ci{
10598c2ecf20Sopenharmony_ci	struct sk_psock_parser *parser = &psock->parser;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (!parser->enabled)
10628c2ecf20Sopenharmony_ci		return;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	sk->sk_data_ready = parser->saved_data_ready;
10658c2ecf20Sopenharmony_ci	parser->saved_data_ready = NULL;
10668c2ecf20Sopenharmony_ci	strp_stop(&parser->strp);
10678c2ecf20Sopenharmony_ci	parser->enabled = false;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_civoid sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct sk_psock_parser *parser = &psock->parser;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (!parser->enabled)
10758c2ecf20Sopenharmony_ci		return;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	sk->sk_data_ready = parser->saved_data_ready;
10788c2ecf20Sopenharmony_ci	parser->saved_data_ready = NULL;
10798c2ecf20Sopenharmony_ci	parser->enabled = false;
10808c2ecf20Sopenharmony_ci}
1081