get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1168604/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1168604,
    "url": "http://patchwork.ozlabs.org/api/patches/1168604/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/3dfe273fef4ba475268d409de6dd7279960a00ba.1569491461.git.sd@queasysnail.net/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<3dfe273fef4ba475268d409de6dd7279960a00ba.1569491461.git.sd@queasysnail.net>",
    "list_archive_url": null,
    "date": "2019-09-27T14:59:01",
    "name": "[ipsec-next,v3,6/6] xfrm: add espintcp (RFC 8229)",
    "commit_ref": null,
    "pull_url": null,
    "state": "awaiting-upstream",
    "archived": false,
    "hash": "558fceccb626747f4923f980c0f7f228e4a8839d",
    "submitter": {
        "id": 47767,
        "url": "http://patchwork.ozlabs.org/api/people/47767/?format=api",
        "name": "Sabrina Dubroca",
        "email": "sd@queasysnail.net"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/3dfe273fef4ba475268d409de6dd7279960a00ba.1569491461.git.sd@queasysnail.net/mbox/",
    "series": [
        {
            "id": 132948,
            "url": "http://patchwork.ozlabs.org/api/series/132948/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=132948",
            "date": "2019-09-27T14:58:55",
            "name": "ipsec: add TCP encapsulation support (RFC 8229)",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/132948/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1168604/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1168604/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming-netdev@ozlabs.org",
        "Delivered-To": "patchwork-incoming-netdev@ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dmarc=none (p=none dis=none)\n\theader.from=queasysnail.net"
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 46fw0h0cCZz9sNf\n\tfor <patchwork-incoming-netdev@ozlabs.org>;\n\tSat, 28 Sep 2019 00:58:44 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1726843AbfI0O6m (ORCPT\n\t<rfc822;patchwork-incoming-netdev@ozlabs.org>);\n\tFri, 27 Sep 2019 10:58:42 -0400",
            "from mx1.redhat.com ([209.132.183.28]:33028 \"EHLO mx1.redhat.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1727836AbfI0O6m (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tFri, 27 Sep 2019 10:58:42 -0400",
            "from smtp.corp.redhat.com\n\t(int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id 2C7ED1895A45;\n\tFri, 27 Sep 2019 14:58:41 +0000 (UTC)",
            "from hog.localdomain, (unknown [10.40.206.20])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id E06338DC00;\n\tFri, 27 Sep 2019 14:58:39 +0000 (UTC)"
        ],
        "From": "Sabrina Dubroca <sd@queasysnail.net>",
        "To": "netdev@vger.kernel.org",
        "Cc": "Herbert Xu <herbert@gondor.apana.org.au>,\n\tSteffen Klassert <steffen.klassert@secunet.com>,\n\tSabrina Dubroca <sd@queasysnail.net>",
        "Subject": "[PATCH ipsec-next v3 6/6] xfrm: add espintcp (RFC 8229)",
        "Date": "Fri, 27 Sep 2019 16:59:01 +0200",
        "Message-Id": "<3dfe273fef4ba475268d409de6dd7279960a00ba.1569491461.git.sd@queasysnail.net>",
        "In-Reply-To": "<cover.1569491461.git.sd@queasysnail.net>",
        "References": "<cover.1569491461.git.sd@queasysnail.net>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.13",
        "X-Greylist": "Sender IP whitelisted, not delayed by milter-greylist-4.6.2\n\t(mx1.redhat.com [10.5.110.62]);\n\tFri, 27 Sep 2019 14:58:41 +0000 (UTC)",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "TCP encapsulation of IKE and IPsec messages (RFC 8229) is implemented\nas a TCP ULP, overriding in particular the sendmsg and recvmsg\noperations. A Stream Parser is used to extract messages out of the TCP\nstream using the first 2 bytes as length marker. Received IKE messages\nare put on \"ike_queue\", waiting to be dequeued by the custom recvmsg\nimplementation. Received ESP messages are sent to XFRM, like with UDP\nencapsulation.\n\nSome of this code is taken from the original submission by Herbert\nXu. Currently, only IPv4 is supported, like for UDP encapsulation.\n\nCo-developed-by: Herbert Xu <herbert@gondor.apana.org.au>\nSigned-off-by: Herbert Xu <herbert@gondor.apana.org.au>\nSigned-off-by: Sabrina Dubroca <sd@queasysnail.net>\n---\nv3: rename config option to INET_ESPINTCP and move it to net/ipv4/Kconfig\nv2:\n  - remove unneeded goto and improve error handling in\n    esp_output_tcp_finish\n  - clean up the ifdefs by providing dummy implementations of those\n    functions\n  - fix Kconfig select, missing NET_SOCK_MSG\n\n include/net/espintcp.h   |  38 +++\n include/net/xfrm.h       |   1 +\n include/uapi/linux/udp.h |   1 +\n net/ipv4/Kconfig         |  11 +\n net/ipv4/esp4.c          | 191 ++++++++++++++-\n net/xfrm/Makefile        |   1 +\n net/xfrm/espintcp.c      | 505 +++++++++++++++++++++++++++++++++++++++\n net/xfrm/xfrm_policy.c   |   7 +\n net/xfrm/xfrm_state.c    |   3 +\n 9 files changed, 755 insertions(+), 3 deletions(-)\n create mode 100644 include/net/espintcp.h\n create mode 100644 net/xfrm/espintcp.c",
    "diff": "diff --git a/include/net/espintcp.h b/include/net/espintcp.h\nnew file mode 100644\nindex 000000000000..02fc28c82d30\n--- /dev/null\n+++ b/include/net/espintcp.h\n@@ -0,0 +1,38 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef _NET_ESPINTCP_H\n+#define _NET_ESPINTCP_H\n+\n+#include <net/strparser.h>\n+#include <linux/skmsg.h>\n+\n+void __init espintcp_init(void);\n+\n+int espintcp_push_skb(struct sock *sk, struct sk_buff *skb);\n+int espintcp_queue_out(struct sock *sk, struct sk_buff *skb);\n+bool tcp_is_ulp_esp(struct sock *sk);\n+\n+struct espintcp_msg {\n+\tstruct sk_buff *skb;\n+\tstruct sk_msg skmsg;\n+\tint offset;\n+\tint len;\n+};\n+\n+struct espintcp_ctx {\n+\tstruct strparser strp;\n+\tstruct sk_buff_head ike_queue;\n+\tstruct sk_buff_head out_queue;\n+\tstruct espintcp_msg partial;\n+\tvoid (*saved_data_ready)(struct sock *sk);\n+\tvoid (*saved_write_space)(struct sock *sk);\n+\tstruct work_struct work;\n+\tbool tx_running;\n+};\n+\n+static inline struct espintcp_ctx *espintcp_getctx(const struct sock *sk)\n+{\n+\tstruct inet_connection_sock *icsk = inet_csk(sk);\n+\n+\treturn icsk->icsk_ulp_data;\n+}\n+#endif\ndiff --git a/include/net/xfrm.h b/include/net/xfrm.h\nindex a0199f8251ec..e49b5fe8a66b 100644\n--- a/include/net/xfrm.h\n+++ b/include/net/xfrm.h\n@@ -193,6 +193,7 @@ struct xfrm_state {\n \n \t/* Data for encapsulator */\n \tstruct xfrm_encap_tmpl\t*encap;\n+\tstruct sock __rcu\t*encap_sk;\n \n \t/* Data for care-of address */\n \txfrm_address_t\t*coaddr;\ndiff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h\nindex 30baccb6c9c4..4828794efcf8 100644\n--- a/include/uapi/linux/udp.h\n+++ b/include/uapi/linux/udp.h\n@@ -42,5 +42,6 @@ struct udphdr {\n #define UDP_ENCAP_GTP0\t\t4 /* GSM TS 09.60 */\n #define UDP_ENCAP_GTP1U\t\t5 /* 3GPP TS 29.060 */\n #define UDP_ENCAP_RXRPC\t\t6\n+#define TCP_ENCAP_ESPINTCP\t7 /* Yikes, this is really xfrm encap types. */\n \n #endif /* _UAPI_LINUX_UDP_H */\ndiff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig\nindex 974de4d20f25..40bbeef4c62c 100644\n--- a/net/ipv4/Kconfig\n+++ b/net/ipv4/Kconfig\n@@ -378,6 +378,17 @@ config INET_ESP_OFFLOAD\n \n \t  If unsure, say N.\n \n+config INET_ESPINTCP\n+\tbool \"IP: ESP in TCP encapsulation (RFC 8229)\"\n+\tdepends on XFRM && INET_ESP\n+\tselect STREAM_PARSER\n+\tselect NET_SOCK_MSG\n+\thelp\n+\t  Support for RFC 8229 encapsulation of ESP and IKE over\n+\t  TCP/IPv4 sockets.\n+\n+\t  If unsure, say N.\n+\n config INET_IPCOMP\n \ttristate \"IP: IPComp transformation\"\n \tselect INET_XFRM_TUNNEL\ndiff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c\nindex 033c61d27148..103c7d599a3c 100644\n--- a/net/ipv4/esp4.c\n+++ b/net/ipv4/esp4.c\n@@ -18,6 +18,8 @@\n #include <net/icmp.h>\n #include <net/protocol.h>\n #include <net/udp.h>\n+#include <net/tcp.h>\n+#include <net/espintcp.h>\n \n #include <linux/highmem.h>\n \n@@ -117,6 +119,132 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)\n \t\t\tput_page(sg_page(sg));\n }\n \n+#ifdef CONFIG_INET_ESPINTCP\n+struct esp_tcp_sk {\n+\tstruct sock *sk;\n+\tstruct rcu_head rcu;\n+};\n+\n+static void esp_free_tcp_sk(struct rcu_head *head)\n+{\n+\tstruct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);\n+\n+\tsock_put(esk->sk);\n+\tkfree(esk);\n+}\n+\n+static struct sock *esp_find_tcp_sk(struct xfrm_state *x)\n+{\n+\tstruct xfrm_encap_tmpl *encap = x->encap;\n+\tstruct esp_tcp_sk *esk;\n+\t__be16 sport, dport;\n+\tstruct sock *nsk;\n+\tstruct sock *sk;\n+\n+\tsk = rcu_dereference(x->encap_sk);\n+\tif (sk && sk->sk_state == TCP_ESTABLISHED)\n+\t\treturn sk;\n+\n+\tspin_lock_bh(&x->lock);\n+\tsport = encap->encap_sport;\n+\tdport = encap->encap_dport;\n+\tnsk = rcu_dereference_protected(x->encap_sk,\n+\t\t\t\t\tlockdep_is_held(&x->lock));\n+\tif (sk && sk == nsk) {\n+\t\tesk = kmalloc(sizeof(*esk), GFP_ATOMIC);\n+\t\tif (!esk) {\n+\t\t\tspin_unlock_bh(&x->lock);\n+\t\t\treturn ERR_PTR(-ENOMEM);\n+\t\t}\n+\t\tRCU_INIT_POINTER(x->encap_sk, NULL);\n+\t\tesk->sk = sk;\n+\t\tcall_rcu(&esk->rcu, esp_free_tcp_sk);\n+\t}\n+\tspin_unlock_bh(&x->lock);\n+\n+\tsk = inet_lookup_established(xs_net(x), &tcp_hashinfo, x->id.daddr.a4,\n+\t\t\t\t     dport, x->props.saddr.a4, sport, 0);\n+\tif (!sk)\n+\t\treturn ERR_PTR(-ENOENT);\n+\n+\tif (!tcp_is_ulp_esp(sk)) {\n+\t\tsock_put(sk);\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tspin_lock_bh(&x->lock);\n+\tnsk = rcu_dereference_protected(x->encap_sk,\n+\t\t\t\t\tlockdep_is_held(&x->lock));\n+\tif (encap->encap_sport != sport ||\n+\t    encap->encap_dport != dport) {\n+\t\tsock_put(sk);\n+\t\tsk = nsk ?: ERR_PTR(-EREMCHG);\n+\t} else if (sk == nsk) {\n+\t\tsock_put(sk);\n+\t} else {\n+\t\trcu_assign_pointer(x->encap_sk, sk);\n+\t}\n+\tspin_unlock_bh(&x->lock);\n+\n+\treturn sk;\n+}\n+\n+static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)\n+{\n+\tstruct sock *sk;\n+\tint err;\n+\n+\trcu_read_lock();\n+\n+\tsk = esp_find_tcp_sk(x);\n+\terr = PTR_ERR_OR_ZERO(sk);\n+\tif (err)\n+\t\tgoto out;\n+\n+\tbh_lock_sock(sk);\n+\tif (sock_owned_by_user(sk))\n+\t\terr = espintcp_queue_out(sk, skb);\n+\telse\n+\t\terr = espintcp_push_skb(sk, skb);\n+\tbh_unlock_sock(sk);\n+\n+out:\n+\trcu_read_unlock();\n+\treturn err;\n+}\n+\n+static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,\n+\t\t\t\t   struct sk_buff *skb)\n+{\n+\tstruct dst_entry *dst = skb_dst(skb);\n+\tstruct xfrm_state *x = dst->xfrm;\n+\n+\treturn esp_output_tcp_finish(x, skb);\n+}\n+\n+static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)\n+{\n+\tint err;\n+\n+\tlocal_bh_disable();\n+\terr = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);\n+\tlocal_bh_enable();\n+\n+\t/* EINPROGRESS just happens to do the right thing.  It\n+\t * actually means that the skb has been consumed and\n+\t * isn't coming back.\n+\t */\n+\treturn err ?: -EINPROGRESS;\n+}\n+#else\n+static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)\n+{\n+\tkfree_skb(skb);\n+\n+\treturn -EOPNOTSUPP;\n+}\n+#endif\n+\n static void esp_output_done(struct crypto_async_request *base, int err)\n {\n \tstruct sk_buff *skb = base->data;\n@@ -147,7 +275,11 @@ static void esp_output_done(struct crypto_async_request *base, int err)\n \t\tsecpath_reset(skb);\n \t\txfrm_dev_resume(skb);\n \t} else {\n-\t\txfrm_output_resume(skb, err);\n+\t\tif (!err &&\n+\t\t    x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)\n+\t\t\tesp_output_tail_tcp(x, skb);\n+\t\telse\n+\t\t\txfrm_output_resume(skb, err);\n \t}\n }\n \n@@ -236,7 +368,7 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,\n \tunsigned int len;\n \n \tlen = skb->len + esp->tailen - skb_transport_offset(skb);\n-\tif (len + sizeof(struct iphdr) >= IP_MAX_MTU)\n+\tif (len + sizeof(struct iphdr) > IP_MAX_MTU)\n \t\treturn ERR_PTR(-EMSGSIZE);\n \n \tuh = (struct udphdr *)esp->esph;\n@@ -256,6 +388,41 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,\n \treturn (struct ip_esp_hdr *)(uh + 1);\n }\n \n+#ifdef CONFIG_INET_ESPINTCP\n+static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,\n+\t\t\t\t\t\t    struct sk_buff *skb,\n+\t\t\t\t\t\t    struct esp_info *esp)\n+{\n+\t__be16 *lenp = (void *)esp->esph;\n+\tstruct ip_esp_hdr *esph;\n+\tunsigned int len;\n+\tstruct sock *sk;\n+\n+\tlen = skb->len + esp->tailen - skb_transport_offset(skb);\n+\tif (len > IP_MAX_MTU)\n+\t\treturn ERR_PTR(-EMSGSIZE);\n+\n+\trcu_read_lock();\n+\tsk = esp_find_tcp_sk(x);\n+\trcu_read_unlock();\n+\n+\tif (IS_ERR(sk))\n+\t\treturn ERR_CAST(sk);\n+\n+\t*lenp = htons(len);\n+\tesph = (struct ip_esp_hdr *)(lenp + 1);\n+\n+\treturn esph;\n+}\n+#else\n+static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,\n+\t\t\t\t\t\t    struct sk_buff *skb,\n+\t\t\t\t\t\t    struct esp_info *esp)\n+{\n+\treturn ERR_PTR(-EOPNOTSUPP);\n+}\n+#endif\n+\n static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,\n \t\t\t    struct esp_info *esp)\n {\n@@ -276,6 +443,9 @@ static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,\n \tcase UDP_ENCAP_ESPINUDP_NON_IKE:\n \t\tesph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);\n \t\tbreak;\n+\tcase TCP_ENCAP_ESPINTCP:\n+\t\tesph = esp_output_tcp_encap(x, skb, esp);\n+\t\tbreak;\n \t}\n \n \tif (IS_ERR(esph))\n@@ -296,7 +466,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *\n \tstruct sk_buff *trailer;\n \tint tailen = esp->tailen;\n \n-\t/* this is non-NULL only with UDP Encapsulation */\n+\t/* this is non-NULL only with TCP/UDP Encapsulation */\n \tif (x->encap) {\n \t\tint err = esp_output_encap(x, skb, esp);\n \n@@ -491,6 +661,9 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *\n \tif (sg != dsg)\n \t\tesp_ssg_unref(x, tmp);\n \n+\tif (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)\n+\t\terr = esp_output_tail_tcp(x, skb);\n+\n error_free:\n \tkfree(tmp);\n error:\n@@ -617,10 +790,14 @@ int esp_input_done2(struct sk_buff *skb, int err)\n \n \tif (x->encap) {\n \t\tstruct xfrm_encap_tmpl *encap = x->encap;\n+\t\tstruct tcphdr *th = (void *)(skb_network_header(skb) + ihl);\n \t\tstruct udphdr *uh = (void *)(skb_network_header(skb) + ihl);\n \t\t__be16 source;\n \n \t\tswitch (x->encap->encap_type) {\n+\t\tcase TCP_ENCAP_ESPINTCP:\n+\t\t\tsource = th->source;\n+\t\t\tbreak;\n \t\tcase UDP_ENCAP_ESPINUDP:\n \t\tcase UDP_ENCAP_ESPINUDP_NON_IKE:\n \t\t\tsource = uh->source;\n@@ -1017,6 +1194,14 @@ static int esp_init_state(struct xfrm_state *x)\n \t\tcase UDP_ENCAP_ESPINUDP_NON_IKE:\n \t\t\tx->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);\n \t\t\tbreak;\n+#ifdef CONFIG_INET_ESPINTCP\n+\t\tcase TCP_ENCAP_ESPINTCP:\n+\t\t\t/* only the length field, TCP encap is done by\n+\t\t\t * the socket\n+\t\t\t */\n+\t\t\tx->props.header_len += 2;\n+\t\t\tbreak;\n+#endif\n \t\t}\n \t}\n \ndiff --git a/net/xfrm/Makefile b/net/xfrm/Makefile\nindex fbc4552d17b8..212a4fcb4a88 100644\n--- a/net/xfrm/Makefile\n+++ b/net/xfrm/Makefile\n@@ -11,3 +11,4 @@ obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o\n obj-$(CONFIG_XFRM_USER) += xfrm_user.o\n obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o\n obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o\n+obj-$(CONFIG_INET_ESPINTCP) += espintcp.o\ndiff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c\nnew file mode 100644\nindex 000000000000..1d561a00c4b0\n--- /dev/null\n+++ b/net/xfrm/espintcp.c\n@@ -0,0 +1,505 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include <net/tcp.h>\n+#include <net/strparser.h>\n+#include <net/xfrm.h>\n+#include <net/esp.h>\n+#include <net/espintcp.h>\n+#include <linux/skmsg.h>\n+#include <net/inet_common.h>\n+\n+static void handle_nonesp(struct espintcp_ctx *ctx, struct sk_buff *skb,\n+\t\t\t  struct sock *sk)\n+{\n+\tif (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf ||\n+\t    !sk_rmem_schedule(sk, skb, skb->truesize)) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\n+\tskb_set_owner_r(skb, sk);\n+\n+\tmemset(skb->cb, 0, sizeof(skb->cb));\n+\tskb_queue_tail(&ctx->ike_queue, skb);\n+\tctx->saved_data_ready(sk);\n+}\n+\n+static void handle_esp(struct sk_buff *skb, struct sock *sk)\n+{\n+\tskb_reset_transport_header(skb);\n+\tmemset(skb->cb, 0, sizeof(skb->cb));\n+\n+\trcu_read_lock();\n+\tskb->dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif);\n+\tlocal_bh_disable();\n+\txfrm4_rcv_encap(skb, IPPROTO_ESP, 0, TCP_ENCAP_ESPINTCP);\n+\tlocal_bh_enable();\n+\trcu_read_unlock();\n+}\n+\n+static void espintcp_rcv(struct strparser *strp, struct sk_buff *skb)\n+{\n+\tstruct espintcp_ctx *ctx = container_of(strp, struct espintcp_ctx,\n+\t\t\t\t\t\tstrp);\n+\tstruct strp_msg *rxm = strp_msg(skb);\n+\tu32 nonesp_marker;\n+\tint err;\n+\n+\terr = skb_copy_bits(skb, rxm->offset + 2, &nonesp_marker,\n+\t\t\t    sizeof(nonesp_marker));\n+\tif (err < 0) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\n+\t/* remove header, leave non-ESP marker/SPI */\n+\tif (!__pskb_pull(skb, rxm->offset + 2)) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\n+\tif (pskb_trim(skb, rxm->full_len - 2) != 0) {\n+\t\tkfree_skb(skb);\n+\t\treturn;\n+\t}\n+\n+\tif (nonesp_marker == 0)\n+\t\thandle_nonesp(ctx, skb, strp->sk);\n+\telse\n+\t\thandle_esp(skb, strp->sk);\n+}\n+\n+static int espintcp_parse(struct strparser *strp, struct sk_buff *skb)\n+{\n+\tstruct strp_msg *rxm = strp_msg(skb);\n+\t__be16 blen;\n+\tu16 len;\n+\tint err;\n+\n+\tif (skb->len < rxm->offset + 2)\n+\t\treturn 0;\n+\n+\terr = skb_copy_bits(skb, rxm->offset, &blen, sizeof(blen));\n+\tif (err < 0)\n+\t\treturn err;\n+\n+\tlen = be16_to_cpu(blen);\n+\tif (len < 6)\n+\t\treturn -EINVAL;\n+\n+\treturn len;\n+}\n+\n+static int espintcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,\n+\t\t\t    int nonblock, int flags, int *addr_len)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct sk_buff *skb;\n+\tint err = 0;\n+\tint copied;\n+\tint off = 0;\n+\n+\tflags |= nonblock ? MSG_DONTWAIT : 0;\n+\n+\tskb = __skb_recv_datagram(sk, &ctx->ike_queue, flags, NULL, &off, &err);\n+\tif (!skb)\n+\t\treturn err;\n+\n+\tcopied = len;\n+\tif (copied > skb->len)\n+\t\tcopied = skb->len;\n+\telse if (copied < skb->len)\n+\t\tmsg->msg_flags |= MSG_TRUNC;\n+\n+\terr = skb_copy_datagram_msg(skb, 0, msg, copied);\n+\tif (unlikely(err)) {\n+\t\tkfree_skb(skb);\n+\t\treturn err;\n+\t}\n+\n+\tif (flags & MSG_TRUNC)\n+\t\tcopied = skb->len;\n+\tkfree_skb(skb);\n+\treturn copied;\n+}\n+\n+int espintcp_queue_out(struct sock *sk, struct sk_buff *skb)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\n+\tif (skb_queue_len(&ctx->out_queue) >= netdev_max_backlog)\n+\t\treturn -ENOBUFS;\n+\n+\t__skb_queue_tail(&ctx->out_queue, skb);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(espintcp_queue_out);\n+\n+/* espintcp length field is 2B and length includes the length field's size */\n+#define MAX_ESPINTCP_MSG (((1 << 16) - 1) - 2)\n+\n+static int espintcp_sendskb_locked(struct sock *sk, struct espintcp_msg *emsg,\n+\t\t\t\t   int flags)\n+{\n+\tdo {\n+\t\tint ret;\n+\n+\t\tret = skb_send_sock_locked(sk, emsg->skb,\n+\t\t\t\t\t   emsg->offset, emsg->len);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\temsg->len -= ret;\n+\t\temsg->offset += ret;\n+\t} while (emsg->len > 0);\n+\n+\tkfree_skb(emsg->skb);\n+\tmemset(emsg, 0, sizeof(*emsg));\n+\n+\treturn 0;\n+}\n+\n+static int espintcp_sendskmsg_locked(struct sock *sk,\n+\t\t\t\t     struct espintcp_msg *emsg, int flags)\n+{\n+\tstruct sk_msg *skmsg = &emsg->skmsg;\n+\tstruct scatterlist *sg;\n+\tint done = 0;\n+\tint ret;\n+\n+\tflags |= MSG_SENDPAGE_NOTLAST;\n+\tsg = &skmsg->sg.data[skmsg->sg.start];\n+\tdo {\n+\t\tsize_t size = sg->length - emsg->offset;\n+\t\tint offset = sg->offset + emsg->offset;\n+\t\tstruct page *p;\n+\n+\t\temsg->offset = 0;\n+\n+\t\tif (sg_is_last(sg))\n+\t\t\tflags &= ~MSG_SENDPAGE_NOTLAST;\n+\n+\t\tp = sg_page(sg);\n+retry:\n+\t\tret = do_tcp_sendpages(sk, p, offset, size, flags);\n+\t\tif (ret < 0) {\n+\t\t\temsg->offset = offset - sg->offset;\n+\t\t\tskmsg->sg.start += done;\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tif (ret != size) {\n+\t\t\toffset += ret;\n+\t\t\tsize -= ret;\n+\t\t\tgoto retry;\n+\t\t}\n+\n+\t\tdone++;\n+\t\tput_page(p);\n+\t\tsk_mem_uncharge(sk, sg->length);\n+\t\tsg = sg_next(sg);\n+\t} while (sg);\n+\n+\tmemset(emsg, 0, sizeof(*emsg));\n+\n+\treturn 0;\n+}\n+\n+static int espintcp_push_msgs(struct sock *sk)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct espintcp_msg *emsg = &ctx->partial;\n+\tint err;\n+\n+\tif (!emsg->len)\n+\t\treturn 0;\n+\n+\tif (ctx->tx_running)\n+\t\treturn -EAGAIN;\n+\tctx->tx_running = 1;\n+\n+\tif (emsg->skb)\n+\t\terr = espintcp_sendskb_locked(sk, emsg, 0);\n+\telse\n+\t\terr = espintcp_sendskmsg_locked(sk, emsg, 0);\n+\tif (err == -EAGAIN) {\n+\t\tctx->tx_running = 0;\n+\t\treturn 0;\n+\t}\n+\tif (!err)\n+\t\tmemset(emsg, 0, sizeof(*emsg));\n+\n+\tctx->tx_running = 0;\n+\n+\treturn err;\n+}\n+\n+int espintcp_push_skb(struct sock *sk, struct sk_buff *skb)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct espintcp_msg *emsg = &ctx->partial;\n+\tunsigned int len;\n+\tint offset;\n+\n+\tif (sk->sk_state != TCP_ESTABLISHED) {\n+\t\tkfree_skb(skb);\n+\t\treturn -ECONNRESET;\n+\t}\n+\n+\toffset = skb_transport_offset(skb);\n+\tlen = skb->len - offset;\n+\n+\tespintcp_push_msgs(sk);\n+\n+\tif (emsg->len) {\n+\t\tkfree_skb(skb);\n+\t\treturn -ENOBUFS;\n+\t}\n+\n+\tskb_set_owner_w(skb, sk);\n+\n+\temsg->offset = offset;\n+\temsg->len = len;\n+\temsg->skb = skb;\n+\n+\tespintcp_push_msgs(sk);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(espintcp_push_skb);\n+\n+static int espintcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)\n+{\n+\tlong timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct espintcp_msg *emsg = &ctx->partial;\n+\tstruct iov_iter pfx_iter;\n+\tstruct kvec pfx_iov = {};\n+\tsize_t msglen = size + 2;\n+\tchar buf[2] = {0};\n+\tint err, end;\n+\n+\tif (msg->msg_flags)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tif (size > MAX_ESPINTCP_MSG)\n+\t\treturn -EMSGSIZE;\n+\n+\tif (msg->msg_controllen)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tlock_sock(sk);\n+\n+\terr = espintcp_push_msgs(sk);\n+\tif (err < 0) {\n+\t\terr = -ENOBUFS;\n+\t\tgoto unlock;\n+\t}\n+\n+\tsk_msg_init(&emsg->skmsg);\n+\twhile (1) {\n+\t\t/* only -ENOMEM is possible since we don't coalesce */\n+\t\terr = sk_msg_alloc(sk, &emsg->skmsg, msglen, 0);\n+\t\tif (!err)\n+\t\t\tbreak;\n+\n+\t\terr = sk_stream_wait_memory(sk, &timeo);\n+\t\tif (err)\n+\t\t\tgoto fail;\n+\t}\n+\n+\t*((__be16 *)buf) = cpu_to_be16(msglen);\n+\tpfx_iov.iov_base = buf;\n+\tpfx_iov.iov_len = sizeof(buf);\n+\tiov_iter_kvec(&pfx_iter, WRITE, &pfx_iov, 1, pfx_iov.iov_len);\n+\n+\terr = sk_msg_memcopy_from_iter(sk, &pfx_iter, &emsg->skmsg,\n+\t\t\t\t       pfx_iov.iov_len);\n+\tif (err < 0)\n+\t\tgoto fail;\n+\n+\terr = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, &emsg->skmsg, size);\n+\tif (err < 0)\n+\t\tgoto fail;\n+\n+\tend = emsg->skmsg.sg.end;\n+\temsg->len = size;\n+\tsk_msg_iter_var_prev(end);\n+\tsg_mark_end(sk_msg_elem(&emsg->skmsg, end));\n+\n+\ttcp_rate_check_app_limited(sk);\n+\n+\terr = espintcp_push_msgs(sk);\n+\t/* this message could be partially sent, keep it */\n+\tif (err < 0)\n+\t\tgoto unlock;\n+\trelease_sock(sk);\n+\n+\treturn size;\n+\n+fail:\n+\tsk_msg_free(sk, &emsg->skmsg);\n+\tmemset(emsg, 0, sizeof(*emsg));\n+unlock:\n+\trelease_sock(sk);\n+\treturn err;\n+}\n+\n+static struct proto espintcp_prot __ro_after_init;\n+static struct proto_ops espintcp_ops __ro_after_init;\n+\n+static void espintcp_data_ready(struct sock *sk)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\n+\tstrp_data_ready(&ctx->strp);\n+}\n+\n+static void espintcp_tx_work(struct work_struct *work)\n+{\n+\tstruct espintcp_ctx *ctx = container_of(work,\n+\t\t\t\t\t\tstruct espintcp_ctx, work);\n+\tstruct sock *sk = ctx->strp.sk;\n+\n+\tlock_sock(sk);\n+\tif (!ctx->tx_running)\n+\t\tespintcp_push_msgs(sk);\n+\trelease_sock(sk);\n+}\n+\n+static void espintcp_write_space(struct sock *sk)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\n+\tschedule_work(&ctx->work);\n+\tctx->saved_write_space(sk);\n+}\n+\n+static void espintcp_destruct(struct sock *sk)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\n+\tkfree(ctx);\n+}\n+\n+bool tcp_is_ulp_esp(struct sock *sk)\n+{\n+\treturn sk->sk_prot == &espintcp_prot;\n+}\n+EXPORT_SYMBOL_GPL(tcp_is_ulp_esp);\n+\n+static int espintcp_init_sk(struct sock *sk)\n+{\n+\tstruct inet_connection_sock *icsk = inet_csk(sk);\n+\tstruct strp_callbacks cb = {\n+\t\t.rcv_msg = espintcp_rcv,\n+\t\t.parse_msg = espintcp_parse,\n+\t};\n+\tstruct espintcp_ctx *ctx;\n+\tint err;\n+\n+\tctx = kzalloc(sizeof(*ctx), GFP_KERNEL);\n+\tif (!ctx)\n+\t\treturn -ENOMEM;\n+\n+\terr = strp_init(&ctx->strp, sk, &cb);\n+\tif (err)\n+\t\tgoto free;\n+\n+\t__sk_dst_reset(sk);\n+\n+\tstrp_check_rcv(&ctx->strp);\n+\tskb_queue_head_init(&ctx->ike_queue);\n+\tskb_queue_head_init(&ctx->out_queue);\n+\tsk->sk_prot = &espintcp_prot;\n+\tsk->sk_socket->ops = &espintcp_ops;\n+\tctx->saved_data_ready = sk->sk_data_ready;\n+\tctx->saved_write_space = sk->sk_write_space;\n+\tsk->sk_data_ready = espintcp_data_ready;\n+\tsk->sk_write_space = espintcp_write_space;\n+\tsk->sk_destruct = espintcp_destruct;\n+\ticsk->icsk_ulp_data = ctx;\n+\tINIT_WORK(&ctx->work, espintcp_tx_work);\n+\n+\t/* avoid using task_frag */\n+\tsk->sk_allocation = GFP_ATOMIC;\n+\n+\treturn 0;\n+\n+free:\n+\tkfree(ctx);\n+\treturn err;\n+}\n+\n+static void espintcp_release(struct sock *sk)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct sk_buff_head queue;\n+\tstruct sk_buff *skb;\n+\n+\t__skb_queue_head_init(&queue);\n+\tskb_queue_splice_init(&ctx->out_queue, &queue);\n+\n+\twhile ((skb = __skb_dequeue(&queue)))\n+\t\tespintcp_push_skb(sk, skb);\n+\n+\ttcp_release_cb(sk);\n+}\n+\n+static void espintcp_close(struct sock *sk, long timeout)\n+{\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\tstruct espintcp_msg *emsg = &ctx->partial;\n+\n+\tstrp_stop(&ctx->strp);\n+\n+\tsk->sk_prot = &tcp_prot;\n+\tbarrier();\n+\n+\tcancel_work_sync(&ctx->work);\n+\tstrp_done(&ctx->strp);\n+\n+\tskb_queue_purge(&ctx->out_queue);\n+\tskb_queue_purge(&ctx->ike_queue);\n+\n+\tif (emsg->len) {\n+\t\tif (emsg->skb)\n+\t\t\tkfree_skb(emsg->skb);\n+\t\telse\n+\t\t\tsk_msg_free(sk, &emsg->skmsg);\n+\t}\n+\n+\ttcp_close(sk, timeout);\n+}\n+\n+static __poll_t espintcp_poll(struct file *file, struct socket *sock,\n+\t\t\t      poll_table *wait)\n+{\n+\t__poll_t mask = datagram_poll(file, sock, wait);\n+\tstruct sock *sk = sock->sk;\n+\tstruct espintcp_ctx *ctx = espintcp_getctx(sk);\n+\n+\tif (!skb_queue_empty(&ctx->ike_queue))\n+\t\tmask |= EPOLLIN | EPOLLRDNORM;\n+\n+\treturn mask;\n+}\n+\n+static struct tcp_ulp_ops espintcp_ulp __read_mostly = {\n+\t.name = \"espintcp\",\n+\t.owner = THIS_MODULE,\n+\t.init = espintcp_init_sk,\n+};\n+\n+void __init espintcp_init(void)\n+{\n+\tmemcpy(&espintcp_prot, &tcp_prot, sizeof(tcp_prot));\n+\tmemcpy(&espintcp_ops, &inet_stream_ops, sizeof(inet_stream_ops));\n+\tespintcp_prot.sendmsg = espintcp_sendmsg;\n+\tespintcp_prot.recvmsg = espintcp_recvmsg;\n+\tespintcp_prot.close = espintcp_close;\n+\tespintcp_prot.release_cb = espintcp_release;\n+\tespintcp_ops.poll = espintcp_poll;\n+\n+\ttcp_register_ulp(&espintcp_ulp);\n+}\ndiff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c\nindex 21e939235b39..4af04f74bf30 100644\n--- a/net/xfrm/xfrm_policy.c\n+++ b/net/xfrm/xfrm_policy.c\n@@ -39,6 +39,9 @@\n #ifdef CONFIG_XFRM_STATISTICS\n #include <net/snmp.h>\n #endif\n+#ifdef CONFIG_INET_ESPINTCP\n+#include <net/espintcp.h>\n+#endif\n \n #include \"xfrm_hash.h\"\n \n@@ -4157,6 +4160,10 @@ void __init xfrm_init(void)\n \tseqcount_init(&xfrm_policy_hash_generation);\n \txfrm_input_init();\n \n+#ifdef CONFIG_INET_ESPINTCP\n+\tespintcp_init();\n+#endif\n+\n \tRCU_INIT_POINTER(xfrm_if_cb, NULL);\n \tsynchronize_rcu();\n }\ndiff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c\nindex c6f3c4a1bd99..acef2d54f869 100644\n--- a/net/xfrm/xfrm_state.c\n+++ b/net/xfrm/xfrm_state.c\n@@ -668,6 +668,9 @@ int __xfrm_state_delete(struct xfrm_state *x)\n \t\tnet->xfrm.state_num--;\n \t\tspin_unlock(&net->xfrm.xfrm_state_lock);\n \n+\t\tif (x->encap_sk)\n+\t\t\tsock_put(rcu_dereference_raw(x->encap_sk));\n+\n \t\txfrm_dev_state_delete(x);\n \n \t\t/* All xfrm_state objects are created by xfrm_state_alloc.\n",
    "prefixes": [
        "ipsec-next",
        "v3",
        "6/6"
    ]
}