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