18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <net/tcp.h>
38c2ecf20Sopenharmony_ci#include <net/strparser.h>
48c2ecf20Sopenharmony_ci#include <net/xfrm.h>
58c2ecf20Sopenharmony_ci#include <net/esp.h>
68c2ecf20Sopenharmony_ci#include <net/espintcp.h>
78c2ecf20Sopenharmony_ci#include <linux/skmsg.h>
88c2ecf20Sopenharmony_ci#include <net/inet_common.h>
98c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
108c2ecf20Sopenharmony_ci#include <net/ipv6_stubs.h>
118c2ecf20Sopenharmony_ci#endif
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic void handle_nonesp(struct espintcp_ctx *ctx, struct sk_buff *skb,
148c2ecf20Sopenharmony_ci			  struct sock *sk)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf ||
178c2ecf20Sopenharmony_ci	    !sk_rmem_schedule(sk, skb, skb->truesize)) {
188c2ecf20Sopenharmony_ci		XFRM_INC_STATS(sock_net(sk), LINUX_MIB_XFRMINERROR);
198c2ecf20Sopenharmony_ci		kfree_skb(skb);
208c2ecf20Sopenharmony_ci		return;
218c2ecf20Sopenharmony_ci	}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	skb_set_owner_r(skb, sk);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	memset(skb->cb, 0, sizeof(skb->cb));
268c2ecf20Sopenharmony_ci	skb_queue_tail(&ctx->ike_queue, skb);
278c2ecf20Sopenharmony_ci	ctx->saved_data_ready(sk);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void handle_esp(struct sk_buff *skb, struct sock *sk)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct tcp_skb_cb *tcp_cb = (struct tcp_skb_cb *)skb->cb;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	skb_reset_transport_header(skb);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* restore IP CB, we need at least IP6CB->nhoff */
378c2ecf20Sopenharmony_ci	memmove(skb->cb, &tcp_cb->header, sizeof(tcp_cb->header));
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	rcu_read_lock();
408c2ecf20Sopenharmony_ci	skb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);
418c2ecf20Sopenharmony_ci	local_bh_disable();
428c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
438c2ecf20Sopenharmony_ci	if (sk->sk_family == AF_INET6)
448c2ecf20Sopenharmony_ci		ipv6_stub->xfrm6_rcv_encap(skb, IPPROTO_ESP, 0, TCP_ENCAP_ESPINTCP);
458c2ecf20Sopenharmony_ci	else
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci		xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, TCP_ENCAP_ESPINTCP);
488c2ecf20Sopenharmony_ci	local_bh_enable();
498c2ecf20Sopenharmony_ci	rcu_read_unlock();
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void espintcp_rcv(struct strparser *strp, struct sk_buff *skb)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = container_of(strp, struct espintcp_ctx,
558c2ecf20Sopenharmony_ci						strp);
568c2ecf20Sopenharmony_ci	struct strp_msg *rxm = strp_msg(skb);
578c2ecf20Sopenharmony_ci	int len = rxm->full_len - 2;
588c2ecf20Sopenharmony_ci	u32 nonesp_marker;
598c2ecf20Sopenharmony_ci	int err;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* keepalive packet? */
628c2ecf20Sopenharmony_ci	if (unlikely(len == 1)) {
638c2ecf20Sopenharmony_ci		u8 data;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		err = skb_copy_bits(skb, rxm->offset + 2, &data, 1);
668c2ecf20Sopenharmony_ci		if (err < 0) {
678c2ecf20Sopenharmony_ci			XFRM_INC_STATS(sock_net(strp->sk), LINUX_MIB_XFRMINHDRERROR);
688c2ecf20Sopenharmony_ci			kfree_skb(skb);
698c2ecf20Sopenharmony_ci			return;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci		if (data == 0xff) {
738c2ecf20Sopenharmony_ci			kfree_skb(skb);
748c2ecf20Sopenharmony_ci			return;
758c2ecf20Sopenharmony_ci		}
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/* drop other short messages */
798c2ecf20Sopenharmony_ci	if (unlikely(len <= sizeof(nonesp_marker))) {
808c2ecf20Sopenharmony_ci		XFRM_INC_STATS(sock_net(strp->sk), LINUX_MIB_XFRMINHDRERROR);
818c2ecf20Sopenharmony_ci		kfree_skb(skb);
828c2ecf20Sopenharmony_ci		return;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	err = skb_copy_bits(skb, rxm->offset + 2, &nonesp_marker,
868c2ecf20Sopenharmony_ci			    sizeof(nonesp_marker));
878c2ecf20Sopenharmony_ci	if (err < 0) {
888c2ecf20Sopenharmony_ci		XFRM_INC_STATS(sock_net(strp->sk), LINUX_MIB_XFRMINHDRERROR);
898c2ecf20Sopenharmony_ci		kfree_skb(skb);
908c2ecf20Sopenharmony_ci		return;
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* remove header, leave non-ESP marker/SPI */
948c2ecf20Sopenharmony_ci	if (!__pskb_pull(skb, rxm->offset + 2)) {
958c2ecf20Sopenharmony_ci		XFRM_INC_STATS(sock_net(strp->sk), LINUX_MIB_XFRMINERROR);
968c2ecf20Sopenharmony_ci		kfree_skb(skb);
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (pskb_trim(skb, rxm->full_len - 2) != 0) {
1018c2ecf20Sopenharmony_ci		XFRM_INC_STATS(sock_net(strp->sk), LINUX_MIB_XFRMINERROR);
1028c2ecf20Sopenharmony_ci		kfree_skb(skb);
1038c2ecf20Sopenharmony_ci		return;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (nonesp_marker == 0)
1078c2ecf20Sopenharmony_ci		handle_nonesp(ctx, skb, strp->sk);
1088c2ecf20Sopenharmony_ci	else
1098c2ecf20Sopenharmony_ci		handle_esp(skb, strp->sk);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int espintcp_parse(struct strparser *strp, struct sk_buff *skb)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct strp_msg *rxm = strp_msg(skb);
1158c2ecf20Sopenharmony_ci	__be16 blen;
1168c2ecf20Sopenharmony_ci	u16 len;
1178c2ecf20Sopenharmony_ci	int err;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (skb->len < rxm->offset + 2)
1208c2ecf20Sopenharmony_ci		return 0;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	err = skb_copy_bits(skb, rxm->offset, &blen, sizeof(blen));
1238c2ecf20Sopenharmony_ci	if (err < 0)
1248c2ecf20Sopenharmony_ci		return err;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	len = be16_to_cpu(blen);
1278c2ecf20Sopenharmony_ci	if (len < 2)
1288c2ecf20Sopenharmony_ci		return -EINVAL;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return len;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int espintcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
1348c2ecf20Sopenharmony_ci			    int nonblock, int flags, int *addr_len)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
1378c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1388c2ecf20Sopenharmony_ci	int err = 0;
1398c2ecf20Sopenharmony_ci	int copied;
1408c2ecf20Sopenharmony_ci	int off = 0;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	flags |= nonblock ? MSG_DONTWAIT : 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	skb = __skb_recv_datagram(sk, &ctx->ike_queue, flags, &off, &err);
1458c2ecf20Sopenharmony_ci	if (!skb) {
1468c2ecf20Sopenharmony_ci		if (err == -EAGAIN && sk->sk_shutdown & RCV_SHUTDOWN)
1478c2ecf20Sopenharmony_ci			return 0;
1488c2ecf20Sopenharmony_ci		return err;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	copied = len;
1528c2ecf20Sopenharmony_ci	if (copied > skb->len)
1538c2ecf20Sopenharmony_ci		copied = skb->len;
1548c2ecf20Sopenharmony_ci	else if (copied < skb->len)
1558c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	err = skb_copy_datagram_msg(skb, 0, msg, copied);
1588c2ecf20Sopenharmony_ci	if (unlikely(err)) {
1598c2ecf20Sopenharmony_ci		kfree_skb(skb);
1608c2ecf20Sopenharmony_ci		return err;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (flags & MSG_TRUNC)
1648c2ecf20Sopenharmony_ci		copied = skb->len;
1658c2ecf20Sopenharmony_ci	kfree_skb(skb);
1668c2ecf20Sopenharmony_ci	return copied;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ciint espintcp_queue_out(struct sock *sk, struct sk_buff *skb)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (skb_queue_len(&ctx->out_queue) >= READ_ONCE(netdev_max_backlog))
1748c2ecf20Sopenharmony_ci		return -ENOBUFS;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	__skb_queue_tail(&ctx->out_queue, skb);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return 0;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(espintcp_queue_out);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/* espintcp length field is 2B and length includes the length field's size */
1838c2ecf20Sopenharmony_ci#define MAX_ESPINTCP_MSG (((1 << 16) - 1) - 2)
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int espintcp_sendskb_locked(struct sock *sk, struct espintcp_msg *emsg,
1868c2ecf20Sopenharmony_ci				   int flags)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	do {
1898c2ecf20Sopenharmony_ci		int ret;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		ret = skb_send_sock_locked(sk, emsg->skb,
1928c2ecf20Sopenharmony_ci					   emsg->offset, emsg->len);
1938c2ecf20Sopenharmony_ci		if (ret < 0)
1948c2ecf20Sopenharmony_ci			return ret;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		emsg->len -= ret;
1978c2ecf20Sopenharmony_ci		emsg->offset += ret;
1988c2ecf20Sopenharmony_ci	} while (emsg->len > 0);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	kfree_skb(emsg->skb);
2018c2ecf20Sopenharmony_ci	memset(emsg, 0, sizeof(*emsg));
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return 0;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int espintcp_sendskmsg_locked(struct sock *sk,
2078c2ecf20Sopenharmony_ci				     struct espintcp_msg *emsg, int flags)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	struct sk_msg *skmsg = &emsg->skmsg;
2108c2ecf20Sopenharmony_ci	struct scatterlist *sg;
2118c2ecf20Sopenharmony_ci	int done = 0;
2128c2ecf20Sopenharmony_ci	int ret;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	flags |= MSG_SENDPAGE_NOTLAST;
2158c2ecf20Sopenharmony_ci	sg = &skmsg->sg.data[skmsg->sg.start];
2168c2ecf20Sopenharmony_ci	do {
2178c2ecf20Sopenharmony_ci		size_t size = sg->length - emsg->offset;
2188c2ecf20Sopenharmony_ci		int offset = sg->offset + emsg->offset;
2198c2ecf20Sopenharmony_ci		struct page *p;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		emsg->offset = 0;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		if (sg_is_last(sg))
2248c2ecf20Sopenharmony_ci			flags &= ~MSG_SENDPAGE_NOTLAST;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		p = sg_page(sg);
2278c2ecf20Sopenharmony_ciretry:
2288c2ecf20Sopenharmony_ci		ret = do_tcp_sendpages(sk, p, offset, size, flags);
2298c2ecf20Sopenharmony_ci		if (ret < 0) {
2308c2ecf20Sopenharmony_ci			emsg->offset = offset - sg->offset;
2318c2ecf20Sopenharmony_ci			skmsg->sg.start += done;
2328c2ecf20Sopenharmony_ci			return ret;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		if (ret != size) {
2368c2ecf20Sopenharmony_ci			offset += ret;
2378c2ecf20Sopenharmony_ci			size -= ret;
2388c2ecf20Sopenharmony_ci			goto retry;
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		done++;
2428c2ecf20Sopenharmony_ci		put_page(p);
2438c2ecf20Sopenharmony_ci		sk_mem_uncharge(sk, sg->length);
2448c2ecf20Sopenharmony_ci		sg = sg_next(sg);
2458c2ecf20Sopenharmony_ci	} while (sg);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	memset(emsg, 0, sizeof(*emsg));
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return 0;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int espintcp_push_msgs(struct sock *sk, int flags)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
2558c2ecf20Sopenharmony_ci	struct espintcp_msg *emsg = &ctx->partial;
2568c2ecf20Sopenharmony_ci	int err;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (!emsg->len)
2598c2ecf20Sopenharmony_ci		return 0;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (ctx->tx_running)
2628c2ecf20Sopenharmony_ci		return -EAGAIN;
2638c2ecf20Sopenharmony_ci	ctx->tx_running = 1;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (emsg->skb)
2668c2ecf20Sopenharmony_ci		err = espintcp_sendskb_locked(sk, emsg, flags);
2678c2ecf20Sopenharmony_ci	else
2688c2ecf20Sopenharmony_ci		err = espintcp_sendskmsg_locked(sk, emsg, flags);
2698c2ecf20Sopenharmony_ci	if (err == -EAGAIN) {
2708c2ecf20Sopenharmony_ci		ctx->tx_running = 0;
2718c2ecf20Sopenharmony_ci		return flags & MSG_DONTWAIT ? -EAGAIN : 0;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	if (!err)
2748c2ecf20Sopenharmony_ci		memset(emsg, 0, sizeof(*emsg));
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ctx->tx_running = 0;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return err;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciint espintcp_push_skb(struct sock *sk, struct sk_buff *skb)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
2848c2ecf20Sopenharmony_ci	struct espintcp_msg *emsg = &ctx->partial;
2858c2ecf20Sopenharmony_ci	unsigned int len;
2868c2ecf20Sopenharmony_ci	int offset;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (sk->sk_state != TCP_ESTABLISHED) {
2898c2ecf20Sopenharmony_ci		kfree_skb(skb);
2908c2ecf20Sopenharmony_ci		return -ECONNRESET;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	offset = skb_transport_offset(skb);
2948c2ecf20Sopenharmony_ci	len = skb->len - offset;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	espintcp_push_msgs(sk, 0);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (emsg->len) {
2998c2ecf20Sopenharmony_ci		kfree_skb(skb);
3008c2ecf20Sopenharmony_ci		return -ENOBUFS;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	skb_set_owner_w(skb, sk);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	emsg->offset = offset;
3068c2ecf20Sopenharmony_ci	emsg->len = len;
3078c2ecf20Sopenharmony_ci	emsg->skb = skb;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	espintcp_push_msgs(sk, 0);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(espintcp_push_skb);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
3188c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
3198c2ecf20Sopenharmony_ci	struct espintcp_msg *emsg = &ctx->partial;
3208c2ecf20Sopenharmony_ci	struct iov_iter pfx_iter;
3218c2ecf20Sopenharmony_ci	struct kvec pfx_iov = {};
3228c2ecf20Sopenharmony_ci	size_t msglen = size + 2;
3238c2ecf20Sopenharmony_ci	char buf[2] = {0};
3248c2ecf20Sopenharmony_ci	int err, end;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (msg->msg_flags & ~MSG_DONTWAIT)
3278c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (size > MAX_ESPINTCP_MSG)
3308c2ecf20Sopenharmony_ci		return -EMSGSIZE;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	if (msg->msg_controllen)
3338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	lock_sock(sk);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	err = espintcp_push_msgs(sk, msg->msg_flags & MSG_DONTWAIT);
3388c2ecf20Sopenharmony_ci	if (err < 0) {
3398c2ecf20Sopenharmony_ci		if (err != -EAGAIN || !(msg->msg_flags & MSG_DONTWAIT))
3408c2ecf20Sopenharmony_ci			err = -ENOBUFS;
3418c2ecf20Sopenharmony_ci		goto unlock;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	sk_msg_init(&emsg->skmsg);
3458c2ecf20Sopenharmony_ci	while (1) {
3468c2ecf20Sopenharmony_ci		/* only -ENOMEM is possible since we don't coalesce */
3478c2ecf20Sopenharmony_ci		err = sk_msg_alloc(sk, &emsg->skmsg, msglen, 0);
3488c2ecf20Sopenharmony_ci		if (!err)
3498c2ecf20Sopenharmony_ci			break;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		err = sk_stream_wait_memory(sk, &timeo);
3528c2ecf20Sopenharmony_ci		if (err)
3538c2ecf20Sopenharmony_ci			goto fail;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	*((__be16 *)buf) = cpu_to_be16(msglen);
3578c2ecf20Sopenharmony_ci	pfx_iov.iov_base = buf;
3588c2ecf20Sopenharmony_ci	pfx_iov.iov_len = sizeof(buf);
3598c2ecf20Sopenharmony_ci	iov_iter_kvec(&pfx_iter, WRITE, &pfx_iov, 1, pfx_iov.iov_len);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	err = sk_msg_memcopy_from_iter(sk, &pfx_iter, &emsg->skmsg,
3628c2ecf20Sopenharmony_ci				       pfx_iov.iov_len);
3638c2ecf20Sopenharmony_ci	if (err < 0)
3648c2ecf20Sopenharmony_ci		goto fail;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	err = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, &emsg->skmsg, size);
3678c2ecf20Sopenharmony_ci	if (err < 0)
3688c2ecf20Sopenharmony_ci		goto fail;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	end = emsg->skmsg.sg.end;
3718c2ecf20Sopenharmony_ci	emsg->len = size;
3728c2ecf20Sopenharmony_ci	sk_msg_iter_var_prev(end);
3738c2ecf20Sopenharmony_ci	sg_mark_end(sk_msg_elem(&emsg->skmsg, end));
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	tcp_rate_check_app_limited(sk);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	err = espintcp_push_msgs(sk, msg->msg_flags & MSG_DONTWAIT);
3788c2ecf20Sopenharmony_ci	/* this message could be partially sent, keep it */
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	release_sock(sk);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return size;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cifail:
3858c2ecf20Sopenharmony_ci	sk_msg_free(sk, &emsg->skmsg);
3868c2ecf20Sopenharmony_ci	memset(emsg, 0, sizeof(*emsg));
3878c2ecf20Sopenharmony_ciunlock:
3888c2ecf20Sopenharmony_ci	release_sock(sk);
3898c2ecf20Sopenharmony_ci	return err;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic struct proto espintcp_prot __ro_after_init;
3938c2ecf20Sopenharmony_cistatic struct proto_ops espintcp_ops __ro_after_init;
3948c2ecf20Sopenharmony_cistatic struct proto espintcp6_prot;
3958c2ecf20Sopenharmony_cistatic struct proto_ops espintcp6_ops;
3968c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(tcpv6_prot_mutex);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic void espintcp_data_ready(struct sock *sk)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	strp_data_ready(&ctx->strp);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void espintcp_tx_work(struct work_struct *work)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = container_of(work,
4088c2ecf20Sopenharmony_ci						struct espintcp_ctx, work);
4098c2ecf20Sopenharmony_ci	struct sock *sk = ctx->strp.sk;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	lock_sock(sk);
4128c2ecf20Sopenharmony_ci	if (!ctx->tx_running)
4138c2ecf20Sopenharmony_ci		espintcp_push_msgs(sk, 0);
4148c2ecf20Sopenharmony_ci	release_sock(sk);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic void espintcp_write_space(struct sock *sk)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	schedule_work(&ctx->work);
4228c2ecf20Sopenharmony_ci	ctx->saved_write_space(sk);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void espintcp_destruct(struct sock *sk)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	ctx->saved_destruct(sk);
4308c2ecf20Sopenharmony_ci	kfree(ctx);
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cibool tcp_is_ulp_esp(struct sock *sk)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	return sk->sk_prot == &espintcp_prot || sk->sk_prot == &espintcp6_prot;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tcp_is_ulp_esp);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic void build_protos(struct proto *espintcp_prot,
4408c2ecf20Sopenharmony_ci			 struct proto_ops *espintcp_ops,
4418c2ecf20Sopenharmony_ci			 const struct proto *orig_prot,
4428c2ecf20Sopenharmony_ci			 const struct proto_ops *orig_ops);
4438c2ecf20Sopenharmony_cistatic int espintcp_init_sk(struct sock *sk)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct inet_connection_sock *icsk = inet_csk(sk);
4468c2ecf20Sopenharmony_ci	struct strp_callbacks cb = {
4478c2ecf20Sopenharmony_ci		.rcv_msg = espintcp_rcv,
4488c2ecf20Sopenharmony_ci		.parse_msg = espintcp_parse,
4498c2ecf20Sopenharmony_ci	};
4508c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx;
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* sockmap is not compatible with espintcp */
4548c2ecf20Sopenharmony_ci	if (sk->sk_user_data)
4558c2ecf20Sopenharmony_ci		return -EBUSY;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
4588c2ecf20Sopenharmony_ci	if (!ctx)
4598c2ecf20Sopenharmony_ci		return -ENOMEM;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	err = strp_init(&ctx->strp, sk, &cb);
4628c2ecf20Sopenharmony_ci	if (err)
4638c2ecf20Sopenharmony_ci		goto free;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	__sk_dst_reset(sk);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	strp_check_rcv(&ctx->strp);
4688c2ecf20Sopenharmony_ci	skb_queue_head_init(&ctx->ike_queue);
4698c2ecf20Sopenharmony_ci	skb_queue_head_init(&ctx->out_queue);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (sk->sk_family == AF_INET) {
4728c2ecf20Sopenharmony_ci		sk->sk_prot = &espintcp_prot;
4738c2ecf20Sopenharmony_ci		sk->sk_socket->ops = &espintcp_ops;
4748c2ecf20Sopenharmony_ci	} else {
4758c2ecf20Sopenharmony_ci		mutex_lock(&tcpv6_prot_mutex);
4768c2ecf20Sopenharmony_ci		if (!espintcp6_prot.recvmsg)
4778c2ecf20Sopenharmony_ci			build_protos(&espintcp6_prot, &espintcp6_ops, sk->sk_prot, sk->sk_socket->ops);
4788c2ecf20Sopenharmony_ci		mutex_unlock(&tcpv6_prot_mutex);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		sk->sk_prot = &espintcp6_prot;
4818c2ecf20Sopenharmony_ci		sk->sk_socket->ops = &espintcp6_ops;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci	ctx->saved_data_ready = sk->sk_data_ready;
4848c2ecf20Sopenharmony_ci	ctx->saved_write_space = sk->sk_write_space;
4858c2ecf20Sopenharmony_ci	ctx->saved_destruct = sk->sk_destruct;
4868c2ecf20Sopenharmony_ci	sk->sk_data_ready = espintcp_data_ready;
4878c2ecf20Sopenharmony_ci	sk->sk_write_space = espintcp_write_space;
4888c2ecf20Sopenharmony_ci	sk->sk_destruct = espintcp_destruct;
4898c2ecf20Sopenharmony_ci	rcu_assign_pointer(icsk->icsk_ulp_data, ctx);
4908c2ecf20Sopenharmony_ci	INIT_WORK(&ctx->work, espintcp_tx_work);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* avoid using task_frag */
4938c2ecf20Sopenharmony_ci	sk->sk_allocation = GFP_ATOMIC;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cifree:
4988c2ecf20Sopenharmony_ci	kfree(ctx);
4998c2ecf20Sopenharmony_ci	return err;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic void espintcp_release(struct sock *sk)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
5058c2ecf20Sopenharmony_ci	struct sk_buff_head queue;
5068c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	__skb_queue_head_init(&queue);
5098c2ecf20Sopenharmony_ci	skb_queue_splice_init(&ctx->out_queue, &queue);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	while ((skb = __skb_dequeue(&queue)))
5128c2ecf20Sopenharmony_ci		espintcp_push_skb(sk, skb);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	tcp_release_cb(sk);
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic void espintcp_close(struct sock *sk, long timeout)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
5208c2ecf20Sopenharmony_ci	struct espintcp_msg *emsg = &ctx->partial;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	strp_stop(&ctx->strp);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	sk->sk_prot = &tcp_prot;
5258c2ecf20Sopenharmony_ci	barrier();
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	cancel_work_sync(&ctx->work);
5288c2ecf20Sopenharmony_ci	strp_done(&ctx->strp);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	skb_queue_purge(&ctx->out_queue);
5318c2ecf20Sopenharmony_ci	skb_queue_purge(&ctx->ike_queue);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (emsg->len) {
5348c2ecf20Sopenharmony_ci		if (emsg->skb)
5358c2ecf20Sopenharmony_ci			kfree_skb(emsg->skb);
5368c2ecf20Sopenharmony_ci		else
5378c2ecf20Sopenharmony_ci			sk_msg_free(sk, &emsg->skmsg);
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	tcp_close(sk, timeout);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic __poll_t espintcp_poll(struct file *file, struct socket *sock,
5448c2ecf20Sopenharmony_ci			      poll_table *wait)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	__poll_t mask = datagram_poll(file, sock, wait);
5478c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
5488c2ecf20Sopenharmony_ci	struct espintcp_ctx *ctx = espintcp_getctx(sk);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&ctx->ike_queue))
5518c2ecf20Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return mask;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic void build_protos(struct proto *espintcp_prot,
5578c2ecf20Sopenharmony_ci			 struct proto_ops *espintcp_ops,
5588c2ecf20Sopenharmony_ci			 const struct proto *orig_prot,
5598c2ecf20Sopenharmony_ci			 const struct proto_ops *orig_ops)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	memcpy(espintcp_prot, orig_prot, sizeof(struct proto));
5628c2ecf20Sopenharmony_ci	memcpy(espintcp_ops, orig_ops, sizeof(struct proto_ops));
5638c2ecf20Sopenharmony_ci	espintcp_prot->sendmsg = espintcp_sendmsg;
5648c2ecf20Sopenharmony_ci	espintcp_prot->recvmsg = espintcp_recvmsg;
5658c2ecf20Sopenharmony_ci	espintcp_prot->close = espintcp_close;
5668c2ecf20Sopenharmony_ci	espintcp_prot->release_cb = espintcp_release;
5678c2ecf20Sopenharmony_ci	espintcp_ops->poll = espintcp_poll;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic struct tcp_ulp_ops espintcp_ulp __read_mostly = {
5718c2ecf20Sopenharmony_ci	.name = "espintcp",
5728c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
5738c2ecf20Sopenharmony_ci	.init = espintcp_init_sk,
5748c2ecf20Sopenharmony_ci};
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_civoid __init espintcp_init(void)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	build_protos(&espintcp_prot, &espintcp_ops, &tcp_prot, &inet_stream_ops);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	tcp_register_ulp(&espintcp_ulp);
5818c2ecf20Sopenharmony_ci}
582