1ac713874SUrsula Braun /* 2ac713874SUrsula Braun * Shared Memory Communications over RDMA (SMC-R) and RoCE 3ac713874SUrsula Braun * 4ac713874SUrsula Braun * AF_SMC protocol family socket handler keeping the AF_INET sock address type 5ac713874SUrsula Braun * applies to SOCK_STREAM sockets only 6ac713874SUrsula Braun * offers an alternative communication option for TCP-protocol sockets 7ac713874SUrsula Braun * applicable with RoCE-cards only 8ac713874SUrsula Braun * 9a046d57dSUrsula Braun * Initial restrictions: 10a046d57dSUrsula Braun * - support for alternate links postponed 11a046d57dSUrsula Braun * 12aaa4d33fSKarsten Graul * Copyright IBM Corp. 2016, 2018 13ac713874SUrsula Braun * 14ac713874SUrsula Braun * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 15ac713874SUrsula Braun * based on prototype from Frank Blaschka 16ac713874SUrsula Braun */ 17ac713874SUrsula Braun 18ac713874SUrsula Braun #define KMSG_COMPONENT "smc" 19ac713874SUrsula Braun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 20ac713874SUrsula Braun 21ac713874SUrsula Braun #include <linux/module.h> 22ac713874SUrsula Braun #include <linux/socket.h> 23a046d57dSUrsula Braun #include <linux/workqueue.h> 245f08318fSUrsula Braun #include <linux/in.h> 25c3edc401SIngo Molnar #include <linux/sched/signal.h> 26c3edc401SIngo Molnar 27ac713874SUrsula Braun #include <net/sock.h> 28a046d57dSUrsula Braun #include <net/tcp.h> 29f16a7dd5SUrsula Braun #include <net/smc.h> 309b67e26fSUrsula Braun #include <asm/ioctls.h> 31ac713874SUrsula Braun 32ac713874SUrsula Braun #include "smc.h" 33a046d57dSUrsula Braun #include "smc_clc.h" 349bf9abeaSUrsula Braun #include "smc_llc.h" 355f08318fSUrsula Braun #include "smc_cdc.h" 360cfdd8f9SUrsula Braun #include "smc_core.h" 37a4cf0443SUrsula Braun #include "smc_ib.h" 386812baabSThomas Richter #include "smc_pnet.h" 39e6727f39SUrsula Braun #include "smc_tx.h" 40952310ccSUrsula Braun #include "smc_rx.h" 41b38d7324SUrsula Braun #include "smc_close.h" 42ac713874SUrsula Braun 430cfdd8f9SUrsula Braun static DEFINE_MUTEX(smc_create_lgr_pending); /* serialize link group 440cfdd8f9SUrsula Braun * creation 450cfdd8f9SUrsula Braun */ 460cfdd8f9SUrsula Braun 47a046d57dSUrsula Braun static void smc_tcp_listen_work(struct work_struct *); 4824ac3a08SUrsula Braun static void smc_connect_work(struct work_struct *); 49a046d57dSUrsula Braun 50ac713874SUrsula Braun static void smc_set_keepalive(struct sock *sk, int val) 51ac713874SUrsula Braun { 52ac713874SUrsula Braun struct smc_sock *smc = smc_sk(sk); 53ac713874SUrsula Braun 54ac713874SUrsula Braun smc->clcsock->sk->sk_prot->keepalive(smc->clcsock->sk, val); 55ac713874SUrsula Braun } 56ac713874SUrsula Braun 57f16a7dd5SUrsula Braun static struct smc_hashinfo smc_v4_hashinfo = { 58f16a7dd5SUrsula Braun .lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock), 59f16a7dd5SUrsula Braun }; 60f16a7dd5SUrsula Braun 61aaa4d33fSKarsten Graul static struct smc_hashinfo smc_v6_hashinfo = { 62aaa4d33fSKarsten Graul .lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock), 63aaa4d33fSKarsten Graul }; 64aaa4d33fSKarsten Graul 65f16a7dd5SUrsula Braun int smc_hash_sk(struct sock *sk) 66f16a7dd5SUrsula Braun { 67f16a7dd5SUrsula Braun struct smc_hashinfo *h = sk->sk_prot->h.smc_hash; 68f16a7dd5SUrsula Braun struct hlist_head *head; 69f16a7dd5SUrsula Braun 70f16a7dd5SUrsula Braun head = &h->ht; 71f16a7dd5SUrsula Braun 72f16a7dd5SUrsula Braun write_lock_bh(&h->lock); 73f16a7dd5SUrsula Braun sk_add_node(sk, head); 74f16a7dd5SUrsula Braun sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 75f16a7dd5SUrsula Braun write_unlock_bh(&h->lock); 76f16a7dd5SUrsula Braun 77f16a7dd5SUrsula Braun return 0; 78f16a7dd5SUrsula Braun } 79f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_hash_sk); 80f16a7dd5SUrsula Braun 81f16a7dd5SUrsula Braun void smc_unhash_sk(struct sock *sk) 82f16a7dd5SUrsula Braun { 83f16a7dd5SUrsula Braun struct smc_hashinfo *h = sk->sk_prot->h.smc_hash; 84f16a7dd5SUrsula Braun 85f16a7dd5SUrsula Braun write_lock_bh(&h->lock); 86f16a7dd5SUrsula Braun if (sk_del_node_init(sk)) 87f16a7dd5SUrsula Braun sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 88f16a7dd5SUrsula Braun write_unlock_bh(&h->lock); 89f16a7dd5SUrsula Braun } 90f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_unhash_sk); 91f16a7dd5SUrsula Braun 92f16a7dd5SUrsula Braun struct proto smc_proto = { 93ac713874SUrsula Braun .name = "SMC", 94ac713874SUrsula Braun .owner = THIS_MODULE, 95ac713874SUrsula Braun .keepalive = smc_set_keepalive, 96f16a7dd5SUrsula Braun .hash = smc_hash_sk, 97f16a7dd5SUrsula Braun .unhash = smc_unhash_sk, 98ac713874SUrsula Braun .obj_size = sizeof(struct smc_sock), 99f16a7dd5SUrsula Braun .h.smc_hash = &smc_v4_hashinfo, 1005f0d5a3aSPaul E. McKenney .slab_flags = SLAB_TYPESAFE_BY_RCU, 101ac713874SUrsula Braun }; 102f16a7dd5SUrsula Braun EXPORT_SYMBOL_GPL(smc_proto); 103ac713874SUrsula Braun 104aaa4d33fSKarsten Graul struct proto smc_proto6 = { 105aaa4d33fSKarsten Graul .name = "SMC6", 106aaa4d33fSKarsten Graul .owner = THIS_MODULE, 107aaa4d33fSKarsten Graul .keepalive = smc_set_keepalive, 108aaa4d33fSKarsten Graul .hash = smc_hash_sk, 109aaa4d33fSKarsten Graul .unhash = smc_unhash_sk, 110aaa4d33fSKarsten Graul .obj_size = sizeof(struct smc_sock), 111aaa4d33fSKarsten Graul .h.smc_hash = &smc_v6_hashinfo, 112aaa4d33fSKarsten Graul .slab_flags = SLAB_TYPESAFE_BY_RCU, 113aaa4d33fSKarsten Graul }; 114aaa4d33fSKarsten Graul EXPORT_SYMBOL_GPL(smc_proto6); 115aaa4d33fSKarsten Graul 116ac713874SUrsula Braun static int smc_release(struct socket *sock) 117ac713874SUrsula Braun { 118ac713874SUrsula Braun struct sock *sk = sock->sk; 119ac713874SUrsula Braun struct smc_sock *smc; 120b38d7324SUrsula Braun int rc = 0; 121ac713874SUrsula Braun 122ac713874SUrsula Braun if (!sk) 123ac713874SUrsula Braun goto out; 124ac713874SUrsula Braun 125ac713874SUrsula Braun smc = smc_sk(sk); 12624ac3a08SUrsula Braun 12724ac3a08SUrsula Braun /* cleanup for a dangling non-blocking connect */ 12824ac3a08SUrsula Braun flush_work(&smc->connect_work); 12924ac3a08SUrsula Braun kfree(smc->connect_info); 13024ac3a08SUrsula Braun smc->connect_info = NULL; 13124ac3a08SUrsula Braun 132b38d7324SUrsula Braun if (sk->sk_state == SMC_LISTEN) 133b38d7324SUrsula Braun /* smc_close_non_accepted() is called and acquires 134b38d7324SUrsula Braun * sock lock for child sockets again 135b38d7324SUrsula Braun */ 136b38d7324SUrsula Braun lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 137b38d7324SUrsula Braun else 138ac713874SUrsula Braun lock_sock(sk); 139ac713874SUrsula Braun 14051f1de79SUrsula Braun if (!smc->use_fallback) { 141b38d7324SUrsula Braun rc = smc_close_active(smc); 142b38d7324SUrsula Braun sock_set_flag(sk, SOCK_DEAD); 143b38d7324SUrsula Braun sk->sk_shutdown |= SHUTDOWN_MASK; 144b38d7324SUrsula Braun } 145ac713874SUrsula Braun if (smc->clcsock) { 146ac713874SUrsula Braun sock_release(smc->clcsock); 147ac713874SUrsula Braun smc->clcsock = NULL; 148ac713874SUrsula Braun } 14951f1de79SUrsula Braun if (smc->use_fallback) { 150e1bbdd57SUrsula Braun if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT) 15151f1de79SUrsula Braun sock_put(sk); /* passive closing */ 15251f1de79SUrsula Braun sk->sk_state = SMC_CLOSED; 15351f1de79SUrsula Braun sk->sk_state_change(sk); 15451f1de79SUrsula Braun } 155ac713874SUrsula Braun 156ac713874SUrsula Braun /* detach socket */ 157ac713874SUrsula Braun sock_orphan(sk); 158ac713874SUrsula Braun sock->sk = NULL; 15951f1de79SUrsula Braun if (!smc->use_fallback && sk->sk_state == SMC_CLOSED) 160b38d7324SUrsula Braun smc_conn_free(&smc->conn); 161ac713874SUrsula Braun release_sock(sk); 162ac713874SUrsula Braun 16351f1de79SUrsula Braun sk->sk_prot->unhash(sk); 16451f1de79SUrsula Braun sock_put(sk); /* final sock_put */ 165ac713874SUrsula Braun out: 166b38d7324SUrsula Braun return rc; 167ac713874SUrsula Braun } 168ac713874SUrsula Braun 169ac713874SUrsula Braun static void smc_destruct(struct sock *sk) 170ac713874SUrsula Braun { 171ac713874SUrsula Braun if (sk->sk_state != SMC_CLOSED) 172ac713874SUrsula Braun return; 173ac713874SUrsula Braun if (!sock_flag(sk, SOCK_DEAD)) 174ac713874SUrsula Braun return; 175ac713874SUrsula Braun 176ac713874SUrsula Braun sk_refcnt_debug_dec(sk); 177ac713874SUrsula Braun } 178ac713874SUrsula Braun 179aaa4d33fSKarsten Graul static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, 180aaa4d33fSKarsten Graul int protocol) 181ac713874SUrsula Braun { 182ac713874SUrsula Braun struct smc_sock *smc; 183aaa4d33fSKarsten Graul struct proto *prot; 184ac713874SUrsula Braun struct sock *sk; 185ac713874SUrsula Braun 186aaa4d33fSKarsten Graul prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto; 187aaa4d33fSKarsten Graul sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0); 188ac713874SUrsula Braun if (!sk) 189ac713874SUrsula Braun return NULL; 190ac713874SUrsula Braun 191ac713874SUrsula Braun sock_init_data(sock, sk); /* sets sk_refcnt to 1 */ 192ac713874SUrsula Braun sk->sk_state = SMC_INIT; 193ac713874SUrsula Braun sk->sk_destruct = smc_destruct; 194aaa4d33fSKarsten Graul sk->sk_protocol = protocol; 195ac713874SUrsula Braun smc = smc_sk(sk); 196a046d57dSUrsula Braun INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); 19724ac3a08SUrsula Braun INIT_WORK(&smc->connect_work, smc_connect_work); 198be7f3e59SEric Dumazet INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work); 199a046d57dSUrsula Braun INIT_LIST_HEAD(&smc->accept_q); 200a046d57dSUrsula Braun spin_lock_init(&smc->accept_q_lock); 201be7f3e59SEric Dumazet spin_lock_init(&smc->conn.send_lock); 202f16a7dd5SUrsula Braun sk->sk_prot->hash(sk); 203a046d57dSUrsula Braun sk_refcnt_debug_inc(sk); 204ac713874SUrsula Braun 205ac713874SUrsula Braun return sk; 206ac713874SUrsula Braun } 207ac713874SUrsula Braun 208ac713874SUrsula Braun static int smc_bind(struct socket *sock, struct sockaddr *uaddr, 209ac713874SUrsula Braun int addr_len) 210ac713874SUrsula Braun { 211ac713874SUrsula Braun struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; 212ac713874SUrsula Braun struct sock *sk = sock->sk; 213ac713874SUrsula Braun struct smc_sock *smc; 214ac713874SUrsula Braun int rc; 215ac713874SUrsula Braun 216ac713874SUrsula Braun smc = smc_sk(sk); 217ac713874SUrsula Braun 218ac713874SUrsula Braun /* replicate tests from inet_bind(), to be safe wrt. future changes */ 219ac713874SUrsula Braun rc = -EINVAL; 220ac713874SUrsula Braun if (addr_len < sizeof(struct sockaddr_in)) 221ac713874SUrsula Braun goto out; 222ac713874SUrsula Braun 223ac713874SUrsula Braun rc = -EAFNOSUPPORT; 224aaa4d33fSKarsten Graul if (addr->sin_family != AF_INET && 225aaa4d33fSKarsten Graul addr->sin_family != AF_INET6 && 226aaa4d33fSKarsten Graul addr->sin_family != AF_UNSPEC) 227aaa4d33fSKarsten Graul goto out; 228ac713874SUrsula Braun /* accept AF_UNSPEC (mapped to AF_INET) only if s_addr is INADDR_ANY */ 229aaa4d33fSKarsten Graul if (addr->sin_family == AF_UNSPEC && 230aaa4d33fSKarsten Graul addr->sin_addr.s_addr != htonl(INADDR_ANY)) 231ac713874SUrsula Braun goto out; 232ac713874SUrsula Braun 233ac713874SUrsula Braun lock_sock(sk); 234ac713874SUrsula Braun 235ac713874SUrsula Braun /* Check if socket is already active */ 236ac713874SUrsula Braun rc = -EINVAL; 237ac713874SUrsula Braun if (sk->sk_state != SMC_INIT) 238ac713874SUrsula Braun goto out_rel; 239ac713874SUrsula Braun 240ac713874SUrsula Braun smc->clcsock->sk->sk_reuse = sk->sk_reuse; 241ac713874SUrsula Braun rc = kernel_bind(smc->clcsock, uaddr, addr_len); 242ac713874SUrsula Braun 243ac713874SUrsula Braun out_rel: 244ac713874SUrsula Braun release_sock(sk); 245ac713874SUrsula Braun out: 246ac713874SUrsula Braun return rc; 247ac713874SUrsula Braun } 248ac713874SUrsula Braun 249ac713874SUrsula Braun static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, 250ac713874SUrsula Braun unsigned long mask) 251ac713874SUrsula Braun { 252ac713874SUrsula Braun /* options we don't get control via setsockopt for */ 253ac713874SUrsula Braun nsk->sk_type = osk->sk_type; 254ac713874SUrsula Braun nsk->sk_sndbuf = osk->sk_sndbuf; 255ac713874SUrsula Braun nsk->sk_rcvbuf = osk->sk_rcvbuf; 256ac713874SUrsula Braun nsk->sk_sndtimeo = osk->sk_sndtimeo; 257ac713874SUrsula Braun nsk->sk_rcvtimeo = osk->sk_rcvtimeo; 258ac713874SUrsula Braun nsk->sk_mark = osk->sk_mark; 259ac713874SUrsula Braun nsk->sk_priority = osk->sk_priority; 260ac713874SUrsula Braun nsk->sk_rcvlowat = osk->sk_rcvlowat; 261ac713874SUrsula Braun nsk->sk_bound_dev_if = osk->sk_bound_dev_if; 262ac713874SUrsula Braun nsk->sk_err = osk->sk_err; 263ac713874SUrsula Braun 264ac713874SUrsula Braun nsk->sk_flags &= ~mask; 265ac713874SUrsula Braun nsk->sk_flags |= osk->sk_flags & mask; 266ac713874SUrsula Braun } 267ac713874SUrsula Braun 268ac713874SUrsula Braun #define SK_FLAGS_SMC_TO_CLC ((1UL << SOCK_URGINLINE) | \ 269ac713874SUrsula Braun (1UL << SOCK_KEEPOPEN) | \ 270ac713874SUrsula Braun (1UL << SOCK_LINGER) | \ 271ac713874SUrsula Braun (1UL << SOCK_BROADCAST) | \ 272ac713874SUrsula Braun (1UL << SOCK_TIMESTAMP) | \ 273ac713874SUrsula Braun (1UL << SOCK_DBG) | \ 274ac713874SUrsula Braun (1UL << SOCK_RCVTSTAMP) | \ 275ac713874SUrsula Braun (1UL << SOCK_RCVTSTAMPNS) | \ 276ac713874SUrsula Braun (1UL << SOCK_LOCALROUTE) | \ 277ac713874SUrsula Braun (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \ 278ac713874SUrsula Braun (1UL << SOCK_RXQ_OVFL) | \ 279ac713874SUrsula Braun (1UL << SOCK_WIFI_STATUS) | \ 280ac713874SUrsula Braun (1UL << SOCK_NOFCS) | \ 281ac713874SUrsula Braun (1UL << SOCK_FILTER_LOCKED)) 282ac713874SUrsula Braun /* copy only relevant settings and flags of SOL_SOCKET level from smc to 283ac713874SUrsula Braun * clc socket (since smc is not called for these options from net/core) 284ac713874SUrsula Braun */ 285ac713874SUrsula Braun static void smc_copy_sock_settings_to_clc(struct smc_sock *smc) 286ac713874SUrsula Braun { 287ac713874SUrsula Braun smc_copy_sock_settings(smc->clcsock->sk, &smc->sk, SK_FLAGS_SMC_TO_CLC); 288ac713874SUrsula Braun } 289ac713874SUrsula Braun 290ac713874SUrsula Braun #define SK_FLAGS_CLC_TO_SMC ((1UL << SOCK_URGINLINE) | \ 291ac713874SUrsula Braun (1UL << SOCK_KEEPOPEN) | \ 292ac713874SUrsula Braun (1UL << SOCK_LINGER) | \ 293ac713874SUrsula Braun (1UL << SOCK_DBG)) 294ac713874SUrsula Braun /* copy only settings and flags relevant for smc from clc to smc socket */ 295ac713874SUrsula Braun static void smc_copy_sock_settings_to_smc(struct smc_sock *smc) 296ac713874SUrsula Braun { 297ac713874SUrsula Braun smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC); 298ac713874SUrsula Braun } 299ac713874SUrsula Braun 30044aa81ceSKarsten Graul /* register a new rmb, optionally send confirm_rkey msg to register with peer */ 30144aa81ceSKarsten Graul static int smc_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc, 30244aa81ceSKarsten Graul bool conf_rkey) 303e63a5f8cSKarsten Graul { 304e63a5f8cSKarsten Graul /* register memory region for new rmb */ 305a6920d1dSKarsten Graul if (smc_wr_reg_send(link, rmb_desc->mr_rx[SMC_SINGLE_LINK])) { 306a6920d1dSKarsten Graul rmb_desc->regerr = 1; 307e63a5f8cSKarsten Graul return -EFAULT; 308a6920d1dSKarsten Graul } 30944aa81ceSKarsten Graul if (!conf_rkey) 31044aa81ceSKarsten Graul return 0; 31144aa81ceSKarsten Graul /* exchange confirm_rkey msg with peer */ 31244aa81ceSKarsten Graul if (smc_llc_do_confirm_rkey(link, rmb_desc)) { 31344aa81ceSKarsten Graul rmb_desc->regerr = 1; 31444aa81ceSKarsten Graul return -EFAULT; 31544aa81ceSKarsten Graul } 316e63a5f8cSKarsten Graul return 0; 317e63a5f8cSKarsten Graul } 318e63a5f8cSKarsten Graul 3190f627126SStefan Raspl static int smc_clnt_conf_first_link(struct smc_sock *smc) 3209bf9abeaSUrsula Braun { 321877ae5beSKarsten Graul struct net *net = sock_net(smc->clcsock->sk); 3229bf9abeaSUrsula Braun struct smc_link_group *lgr = smc->conn.lgr; 3239bf9abeaSUrsula Braun struct smc_link *link; 3249bf9abeaSUrsula Braun int rest; 3259bf9abeaSUrsula Braun int rc; 3269bf9abeaSUrsula Braun 3279bf9abeaSUrsula Braun link = &lgr->lnk[SMC_SINGLE_LINK]; 3289bf9abeaSUrsula Braun /* receive CONFIRM LINK request from server over RoCE fabric */ 3299bf9abeaSUrsula Braun rest = wait_for_completion_interruptible_timeout( 3309bf9abeaSUrsula Braun &link->llc_confirm, 3319bf9abeaSUrsula Braun SMC_LLC_WAIT_FIRST_TIME); 3329bf9abeaSUrsula Braun if (rest <= 0) { 3339bf9abeaSUrsula Braun struct smc_clc_msg_decline dclc; 3349bf9abeaSUrsula Braun 3359bf9abeaSUrsula Braun rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 3369bf9abeaSUrsula Braun SMC_CLC_DECLINE); 3379bf9abeaSUrsula Braun return rc; 3389bf9abeaSUrsula Braun } 3399bf9abeaSUrsula Braun 34075d320d6SKarsten Graul if (link->llc_confirm_rc) 34175d320d6SKarsten Graul return SMC_CLC_DECL_RMBE_EC; 34275d320d6SKarsten Graul 3439bf9abeaSUrsula Braun rc = smc_ib_modify_qp_rts(link); 3449bf9abeaSUrsula Braun if (rc) 3459bf9abeaSUrsula Braun return SMC_CLC_DECL_INTERR; 3469bf9abeaSUrsula Braun 3479bf9abeaSUrsula Braun smc_wr_remember_qp_attr(link); 348652a1e41SUrsula Braun 34944aa81ceSKarsten Graul if (smc_reg_rmb(link, smc->conn.rmb_desc, false)) 350652a1e41SUrsula Braun return SMC_CLC_DECL_INTERR; 351652a1e41SUrsula Braun 3529bf9abeaSUrsula Braun /* send CONFIRM LINK response over RoCE fabric */ 3539bf9abeaSUrsula Braun rc = smc_llc_send_confirm_link(link, 3549bf9abeaSUrsula Braun link->smcibdev->mac[link->ibport - 1], 3550f627126SStefan Raspl &link->smcibdev->gid[link->ibport - 1], 3560f627126SStefan Raspl SMC_LLC_RESP); 3579bf9abeaSUrsula Braun if (rc < 0) 3589bf9abeaSUrsula Braun return SMC_CLC_DECL_TCL; 3599bf9abeaSUrsula Braun 36052bedf37SKarsten Graul /* receive ADD LINK request from server over RoCE fabric */ 36152bedf37SKarsten Graul rest = wait_for_completion_interruptible_timeout(&link->llc_add, 36252bedf37SKarsten Graul SMC_LLC_WAIT_TIME); 36352bedf37SKarsten Graul if (rest <= 0) { 36452bedf37SKarsten Graul struct smc_clc_msg_decline dclc; 36552bedf37SKarsten Graul 36652bedf37SKarsten Graul rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 36752bedf37SKarsten Graul SMC_CLC_DECLINE); 36852bedf37SKarsten Graul return rc; 36952bedf37SKarsten Graul } 37052bedf37SKarsten Graul 37152bedf37SKarsten Graul /* send add link reject message, only one link supported for now */ 37252bedf37SKarsten Graul rc = smc_llc_send_add_link(link, 37352bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 37452bedf37SKarsten Graul &link->smcibdev->gid[link->ibport - 1], 37552bedf37SKarsten Graul SMC_LLC_RESP); 37652bedf37SKarsten Graul if (rc < 0) 37752bedf37SKarsten Graul return SMC_CLC_DECL_TCL; 37852bedf37SKarsten Graul 379877ae5beSKarsten Graul smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time); 38052bedf37SKarsten Graul 38175d320d6SKarsten Graul return 0; 3829bf9abeaSUrsula Braun } 3839bf9abeaSUrsula Braun 3840cfdd8f9SUrsula Braun static void smc_conn_save_peer_info(struct smc_sock *smc, 3850cfdd8f9SUrsula Braun struct smc_clc_msg_accept_confirm *clc) 3860cfdd8f9SUrsula Braun { 38795d8d263SHans Wippel int bufsize = smc_uncompress_bufsize(clc->rmbe_size); 38895d8d263SHans Wippel 38992a138e3SHans Wippel smc->conn.peer_rmbe_idx = clc->rmbe_idx; 3905f08318fSUrsula Braun smc->conn.local_tx_ctrl.token = ntohl(clc->rmbe_alert_token); 39195d8d263SHans Wippel smc->conn.peer_rmbe_size = bufsize; 392cd6851f3SUrsula Braun atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size); 39395d8d263SHans Wippel smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1); 3940cfdd8f9SUrsula Braun } 3950cfdd8f9SUrsula Braun 3960cfdd8f9SUrsula Braun static void smc_link_save_peer_info(struct smc_link *link, 3970cfdd8f9SUrsula Braun struct smc_clc_msg_accept_confirm *clc) 3980cfdd8f9SUrsula Braun { 3990cfdd8f9SUrsula Braun link->peer_qpn = ntoh24(clc->qpn); 4000cfdd8f9SUrsula Braun memcpy(link->peer_gid, clc->lcl.gid, SMC_GID_SIZE); 4010cfdd8f9SUrsula Braun memcpy(link->peer_mac, clc->lcl.mac, sizeof(link->peer_mac)); 4020cfdd8f9SUrsula Braun link->peer_psn = ntoh24(clc->psn); 4030cfdd8f9SUrsula Braun link->peer_mtu = clc->qp_mtu; 4040cfdd8f9SUrsula Braun } 4050cfdd8f9SUrsula Braun 4063b2dec26SHans Wippel /* fall back during connect */ 4073b2dec26SHans Wippel static int smc_connect_fallback(struct smc_sock *smc) 4083b2dec26SHans Wippel { 4093b2dec26SHans Wippel smc->use_fallback = true; 4103b2dec26SHans Wippel smc_copy_sock_settings_to_clc(smc); 4113b2dec26SHans Wippel if (smc->sk.sk_state == SMC_INIT) 4123b2dec26SHans Wippel smc->sk.sk_state = SMC_ACTIVE; 4133b2dec26SHans Wippel return 0; 4143b2dec26SHans Wippel } 4153b2dec26SHans Wippel 4163b2dec26SHans Wippel /* decline and fall back during connect */ 4173b2dec26SHans Wippel static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code) 4183b2dec26SHans Wippel { 4193b2dec26SHans Wippel int rc; 4203b2dec26SHans Wippel 421e1bbdd57SUrsula Braun if (reason_code < 0) { /* error, fallback is not possible */ 422e1bbdd57SUrsula Braun if (smc->sk.sk_state == SMC_INIT) 423e1bbdd57SUrsula Braun sock_put(&smc->sk); /* passive closing */ 4243b2dec26SHans Wippel return reason_code; 425e1bbdd57SUrsula Braun } 4263b2dec26SHans Wippel if (reason_code != SMC_CLC_DECL_REPLY) { 4273b2dec26SHans Wippel rc = smc_clc_send_decline(smc, reason_code); 428e1bbdd57SUrsula Braun if (rc < 0) { 429e1bbdd57SUrsula Braun if (smc->sk.sk_state == SMC_INIT) 430e1bbdd57SUrsula Braun sock_put(&smc->sk); /* passive closing */ 4313b2dec26SHans Wippel return rc; 4323b2dec26SHans Wippel } 433e1bbdd57SUrsula Braun } 4343b2dec26SHans Wippel return smc_connect_fallback(smc); 4353b2dec26SHans Wippel } 4363b2dec26SHans Wippel 4373b2dec26SHans Wippel /* abort connecting */ 4383b2dec26SHans Wippel static int smc_connect_abort(struct smc_sock *smc, int reason_code, 4393b2dec26SHans Wippel int local_contact) 4403b2dec26SHans Wippel { 4413b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) 4423b2dec26SHans Wippel smc_lgr_forget(smc->conn.lgr); 4433b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 4443b2dec26SHans Wippel smc_conn_free(&smc->conn); 4453b2dec26SHans Wippel return reason_code; 4463b2dec26SHans Wippel } 4473b2dec26SHans Wippel 4483b2dec26SHans Wippel /* check if there is a rdma device available for this connection. */ 4493b2dec26SHans Wippel /* called for connect and listen */ 4503b2dec26SHans Wippel static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev, 4513b2dec26SHans Wippel u8 *ibport) 4523b2dec26SHans Wippel { 4533b2dec26SHans Wippel int reason_code = 0; 4543b2dec26SHans Wippel 4553b2dec26SHans Wippel /* PNET table look up: search active ib_device and port 4563b2dec26SHans Wippel * within same PNETID that also contains the ethernet device 4573b2dec26SHans Wippel * used for the internal TCP socket 4583b2dec26SHans Wippel */ 4593b2dec26SHans Wippel smc_pnet_find_roce_resource(smc->clcsock->sk, ibdev, ibport); 4603b2dec26SHans Wippel if (!(*ibdev)) 4613b2dec26SHans Wippel reason_code = SMC_CLC_DECL_CNFERR; /* configuration error */ 4623b2dec26SHans Wippel 4633b2dec26SHans Wippel return reason_code; 4643b2dec26SHans Wippel } 4653b2dec26SHans Wippel 4663b2dec26SHans Wippel /* CLC handshake during connect */ 4673b2dec26SHans Wippel static int smc_connect_clc(struct smc_sock *smc, 4683b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *aclc, 4693b2dec26SHans Wippel struct smc_ib_device *ibdev, u8 ibport) 4703b2dec26SHans Wippel { 4713b2dec26SHans Wippel int rc = 0; 4723b2dec26SHans Wippel 4733b2dec26SHans Wippel /* do inband token exchange */ 4743b2dec26SHans Wippel rc = smc_clc_send_proposal(smc, ibdev, ibport); 4753b2dec26SHans Wippel if (rc) 4763b2dec26SHans Wippel return rc; 4773b2dec26SHans Wippel /* receive SMC Accept CLC message */ 4783b2dec26SHans Wippel return smc_clc_wait_msg(smc, aclc, sizeof(*aclc), SMC_CLC_ACCEPT); 4793b2dec26SHans Wippel } 4803b2dec26SHans Wippel 481a046d57dSUrsula Braun /* setup for RDMA connection of client */ 4823b2dec26SHans Wippel static int smc_connect_rdma(struct smc_sock *smc, 4833b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *aclc, 4843b2dec26SHans Wippel struct smc_ib_device *ibdev, u8 ibport) 4853b2dec26SHans Wippel { 4863b2dec26SHans Wippel int local_contact = SMC_FIRST_CONTACT; 4873b2dec26SHans Wippel struct smc_link *link; 4883b2dec26SHans Wippel int reason_code = 0; 4893b2dec26SHans Wippel 4903b2dec26SHans Wippel mutex_lock(&smc_create_lgr_pending); 4913b2dec26SHans Wippel local_contact = smc_conn_create(smc, ibdev, ibport, &aclc->lcl, 4923b2dec26SHans Wippel aclc->hdr.flag); 4933b2dec26SHans Wippel if (local_contact < 0) { 4943b2dec26SHans Wippel if (local_contact == -ENOMEM) 4953b2dec26SHans Wippel reason_code = SMC_CLC_DECL_MEM;/* insufficient memory*/ 4963b2dec26SHans Wippel else if (local_contact == -ENOLINK) 4973b2dec26SHans Wippel reason_code = SMC_CLC_DECL_SYNCERR; /* synchr. error */ 4983b2dec26SHans Wippel else 4993b2dec26SHans Wippel reason_code = SMC_CLC_DECL_INTERR; /* other error */ 5003b2dec26SHans Wippel return smc_connect_abort(smc, reason_code, 0); 5013b2dec26SHans Wippel } 5023b2dec26SHans Wippel link = &smc->conn.lgr->lnk[SMC_SINGLE_LINK]; 5033b2dec26SHans Wippel 5043b2dec26SHans Wippel smc_conn_save_peer_info(smc, aclc); 5053b2dec26SHans Wippel 5063b2dec26SHans Wippel /* create send buffer and rmb */ 5073b2dec26SHans Wippel if (smc_buf_create(smc)) 5083b2dec26SHans Wippel return smc_connect_abort(smc, SMC_CLC_DECL_MEM, local_contact); 5093b2dec26SHans Wippel 5103b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) 5113b2dec26SHans Wippel smc_link_save_peer_info(link, aclc); 5123b2dec26SHans Wippel 5133b2dec26SHans Wippel if (smc_rmb_rtoken_handling(&smc->conn, aclc)) 5143b2dec26SHans Wippel return smc_connect_abort(smc, SMC_CLC_DECL_INTERR, 5153b2dec26SHans Wippel local_contact); 5163b2dec26SHans Wippel 5173b2dec26SHans Wippel smc_close_init(smc); 5183b2dec26SHans Wippel smc_rx_init(smc); 5193b2dec26SHans Wippel 5203b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) { 5213b2dec26SHans Wippel if (smc_ib_ready_link(link)) 5223b2dec26SHans Wippel return smc_connect_abort(smc, SMC_CLC_DECL_INTERR, 5233b2dec26SHans Wippel local_contact); 5243b2dec26SHans Wippel } else { 5253b2dec26SHans Wippel if (!smc->conn.rmb_desc->reused && 5263b2dec26SHans Wippel smc_reg_rmb(link, smc->conn.rmb_desc, true)) 5273b2dec26SHans Wippel return smc_connect_abort(smc, SMC_CLC_DECL_INTERR, 5283b2dec26SHans Wippel local_contact); 5293b2dec26SHans Wippel } 5303b2dec26SHans Wippel smc_rmb_sync_sg_for_device(&smc->conn); 5313b2dec26SHans Wippel 5323b2dec26SHans Wippel reason_code = smc_clc_send_confirm(smc); 5333b2dec26SHans Wippel if (reason_code) 5343b2dec26SHans Wippel return smc_connect_abort(smc, reason_code, local_contact); 5353b2dec26SHans Wippel 5363b2dec26SHans Wippel smc_tx_init(smc); 5373b2dec26SHans Wippel 5383b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) { 5393b2dec26SHans Wippel /* QP confirmation over RoCE fabric */ 5403b2dec26SHans Wippel reason_code = smc_clnt_conf_first_link(smc); 5413b2dec26SHans Wippel if (reason_code) 5423b2dec26SHans Wippel return smc_connect_abort(smc, reason_code, 5433b2dec26SHans Wippel local_contact); 5443b2dec26SHans Wippel } 5453b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 5463b2dec26SHans Wippel 5473b2dec26SHans Wippel smc_copy_sock_settings_to_clc(smc); 5483b2dec26SHans Wippel if (smc->sk.sk_state == SMC_INIT) 5493b2dec26SHans Wippel smc->sk.sk_state = SMC_ACTIVE; 5503b2dec26SHans Wippel 5513b2dec26SHans Wippel return 0; 5523b2dec26SHans Wippel } 5533b2dec26SHans Wippel 5543b2dec26SHans Wippel /* perform steps before actually connecting */ 5553b2dec26SHans Wippel static int __smc_connect(struct smc_sock *smc) 556a046d57dSUrsula Braun { 557a046d57dSUrsula Braun struct smc_clc_msg_accept_confirm aclc; 5583b2dec26SHans Wippel struct smc_ib_device *ibdev; 559a046d57dSUrsula Braun int rc = 0; 560a046d57dSUrsula Braun u8 ibport; 561a046d57dSUrsula Braun 56251f1de79SUrsula Braun sock_hold(&smc->sk); /* sock put in passive closing */ 56351f1de79SUrsula Braun 564ee9dfbefSUrsula Braun if (smc->use_fallback) 5653b2dec26SHans Wippel return smc_connect_fallback(smc); 566ee9dfbefSUrsula Braun 5673b2dec26SHans Wippel /* if peer has not signalled SMC-capability, fall back */ 5683b2dec26SHans Wippel if (!tcp_sk(smc->clcsock->sk)->syn_smc) 5693b2dec26SHans Wippel return smc_connect_fallback(smc); 570c5c1cc9cSUrsula Braun 571a046d57dSUrsula Braun /* IPSec connections opt out of SMC-R optimizations */ 5723b2dec26SHans Wippel if (using_ipsec(smc)) 5733b2dec26SHans Wippel return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC); 574a046d57dSUrsula Braun 5753b2dec26SHans Wippel /* check if a RDMA device is available; if not, fall back */ 5763b2dec26SHans Wippel if (smc_check_rdma(smc, &ibdev, &ibport)) 5773b2dec26SHans Wippel return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR); 578a046d57dSUrsula Braun 5793b2dec26SHans Wippel /* perform CLC handshake */ 5803b2dec26SHans Wippel rc = smc_connect_clc(smc, &aclc, ibdev, ibport); 581a046d57dSUrsula Braun if (rc) 5823b2dec26SHans Wippel return smc_connect_decline_fallback(smc, rc); 583a046d57dSUrsula Braun 5843b2dec26SHans Wippel /* connect using rdma */ 5853b2dec26SHans Wippel rc = smc_connect_rdma(smc, &aclc, ibdev, ibport); 5863b2dec26SHans Wippel if (rc) 5873b2dec26SHans Wippel return smc_connect_decline_fallback(smc, rc); 588a046d57dSUrsula Braun 5893b2dec26SHans Wippel return 0; 590a046d57dSUrsula Braun } 591a046d57dSUrsula Braun 59224ac3a08SUrsula Braun static void smc_connect_work(struct work_struct *work) 59324ac3a08SUrsula Braun { 59424ac3a08SUrsula Braun struct smc_sock *smc = container_of(work, struct smc_sock, 59524ac3a08SUrsula Braun connect_work); 59624ac3a08SUrsula Braun int rc; 59724ac3a08SUrsula Braun 59824ac3a08SUrsula Braun lock_sock(&smc->sk); 59924ac3a08SUrsula Braun rc = kernel_connect(smc->clcsock, &smc->connect_info->addr, 60024ac3a08SUrsula Braun smc->connect_info->alen, smc->connect_info->flags); 60124ac3a08SUrsula Braun if (smc->clcsock->sk->sk_err) { 60224ac3a08SUrsula Braun smc->sk.sk_err = smc->clcsock->sk->sk_err; 60324ac3a08SUrsula Braun goto out; 60424ac3a08SUrsula Braun } 60524ac3a08SUrsula Braun if (rc < 0) { 60624ac3a08SUrsula Braun smc->sk.sk_err = -rc; 60724ac3a08SUrsula Braun goto out; 60824ac3a08SUrsula Braun } 60924ac3a08SUrsula Braun 61024ac3a08SUrsula Braun rc = __smc_connect(smc); 61124ac3a08SUrsula Braun if (rc < 0) 61224ac3a08SUrsula Braun smc->sk.sk_err = -rc; 61324ac3a08SUrsula Braun 61424ac3a08SUrsula Braun out: 61524ac3a08SUrsula Braun smc->sk.sk_state_change(&smc->sk); 61624ac3a08SUrsula Braun kfree(smc->connect_info); 61724ac3a08SUrsula Braun smc->connect_info = NULL; 61824ac3a08SUrsula Braun release_sock(&smc->sk); 61924ac3a08SUrsula Braun } 62024ac3a08SUrsula Braun 621ac713874SUrsula Braun static int smc_connect(struct socket *sock, struct sockaddr *addr, 622ac713874SUrsula Braun int alen, int flags) 623ac713874SUrsula Braun { 624ac713874SUrsula Braun struct sock *sk = sock->sk; 625ac713874SUrsula Braun struct smc_sock *smc; 626ac713874SUrsula Braun int rc = -EINVAL; 627ac713874SUrsula Braun 628ac713874SUrsula Braun smc = smc_sk(sk); 629ac713874SUrsula Braun 630ac713874SUrsula Braun /* separate smc parameter checking to be safe */ 631ac713874SUrsula Braun if (alen < sizeof(addr->sa_family)) 632ac713874SUrsula Braun goto out_err; 633aaa4d33fSKarsten Graul if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 634ac713874SUrsula Braun goto out_err; 635ac713874SUrsula Braun 636ac713874SUrsula Braun lock_sock(sk); 637ac713874SUrsula Braun switch (sk->sk_state) { 638ac713874SUrsula Braun default: 639ac713874SUrsula Braun goto out; 640ac713874SUrsula Braun case SMC_ACTIVE: 641ac713874SUrsula Braun rc = -EISCONN; 642ac713874SUrsula Braun goto out; 643ac713874SUrsula Braun case SMC_INIT: 644ac713874SUrsula Braun rc = 0; 645ac713874SUrsula Braun break; 646ac713874SUrsula Braun } 647ac713874SUrsula Braun 648ac713874SUrsula Braun smc_copy_sock_settings_to_clc(smc); 649c5c1cc9cSUrsula Braun tcp_sk(smc->clcsock->sk)->syn_smc = 1; 65024ac3a08SUrsula Braun if (flags & O_NONBLOCK) { 65124ac3a08SUrsula Braun if (smc->connect_info) { 65224ac3a08SUrsula Braun rc = -EALREADY; 65324ac3a08SUrsula Braun goto out; 65424ac3a08SUrsula Braun } 65524ac3a08SUrsula Braun smc->connect_info = kzalloc(alen + 2 * sizeof(int), GFP_KERNEL); 65624ac3a08SUrsula Braun if (!smc->connect_info) { 65724ac3a08SUrsula Braun rc = -ENOMEM; 65824ac3a08SUrsula Braun goto out; 65924ac3a08SUrsula Braun } 66024ac3a08SUrsula Braun smc->connect_info->alen = alen; 66124ac3a08SUrsula Braun smc->connect_info->flags = flags ^ O_NONBLOCK; 66224ac3a08SUrsula Braun memcpy(&smc->connect_info->addr, addr, alen); 66324ac3a08SUrsula Braun schedule_work(&smc->connect_work); 66424ac3a08SUrsula Braun rc = -EINPROGRESS; 66524ac3a08SUrsula Braun } else { 666ac713874SUrsula Braun rc = kernel_connect(smc->clcsock, addr, alen, flags); 667ac713874SUrsula Braun if (rc) 668ac713874SUrsula Braun goto out; 669ac713874SUrsula Braun 6703b2dec26SHans Wippel rc = __smc_connect(smc); 671a046d57dSUrsula Braun if (rc < 0) 672a046d57dSUrsula Braun goto out; 673a046d57dSUrsula Braun else 674a046d57dSUrsula Braun rc = 0; /* success cases including fallback */ 67524ac3a08SUrsula Braun } 676ac713874SUrsula Braun 677ac713874SUrsula Braun out: 678ac713874SUrsula Braun release_sock(sk); 679ac713874SUrsula Braun out_err: 680ac713874SUrsula Braun return rc; 681ac713874SUrsula Braun } 682ac713874SUrsula Braun 683ac713874SUrsula Braun static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc) 684ac713874SUrsula Braun { 6853163c507SUrsula Braun struct socket *new_clcsock = NULL; 6863163c507SUrsula Braun struct sock *lsk = &lsmc->sk; 687ac713874SUrsula Braun struct sock *new_sk; 688ac713874SUrsula Braun int rc; 689ac713874SUrsula Braun 6903163c507SUrsula Braun release_sock(lsk); 691aaa4d33fSKarsten Graul new_sk = smc_sock_alloc(sock_net(lsk), NULL, lsk->sk_protocol); 692ac713874SUrsula Braun if (!new_sk) { 693ac713874SUrsula Braun rc = -ENOMEM; 6943163c507SUrsula Braun lsk->sk_err = ENOMEM; 695ac713874SUrsula Braun *new_smc = NULL; 6963163c507SUrsula Braun lock_sock(lsk); 697ac713874SUrsula Braun goto out; 698ac713874SUrsula Braun } 699ac713874SUrsula Braun *new_smc = smc_sk(new_sk); 700ac713874SUrsula Braun 701ac713874SUrsula Braun rc = kernel_accept(lsmc->clcsock, &new_clcsock, 0); 7023163c507SUrsula Braun lock_sock(lsk); 70335a6b178SUrsula Braun if (rc < 0) 7043163c507SUrsula Braun lsk->sk_err = -rc; 70535a6b178SUrsula Braun if (rc < 0 || lsk->sk_state == SMC_CLOSED) { 706a046d57dSUrsula Braun if (new_clcsock) 707a046d57dSUrsula Braun sock_release(new_clcsock); 708a046d57dSUrsula Braun new_sk->sk_state = SMC_CLOSED; 709a046d57dSUrsula Braun sock_set_flag(new_sk, SOCK_DEAD); 7103163c507SUrsula Braun new_sk->sk_prot->unhash(new_sk); 71151f1de79SUrsula Braun sock_put(new_sk); /* final */ 712ac713874SUrsula Braun *new_smc = NULL; 713ac713874SUrsula Braun goto out; 714ac713874SUrsula Braun } 715ac713874SUrsula Braun 716ac713874SUrsula Braun (*new_smc)->clcsock = new_clcsock; 717ac713874SUrsula Braun out: 718ac713874SUrsula Braun return rc; 719ac713874SUrsula Braun } 720ac713874SUrsula Braun 721a046d57dSUrsula Braun /* add a just created sock to the accept queue of the listen sock as 722a046d57dSUrsula Braun * candidate for a following socket accept call from user space 723a046d57dSUrsula Braun */ 724a046d57dSUrsula Braun static void smc_accept_enqueue(struct sock *parent, struct sock *sk) 725a046d57dSUrsula Braun { 726a046d57dSUrsula Braun struct smc_sock *par = smc_sk(parent); 727a046d57dSUrsula Braun 72851f1de79SUrsula Braun sock_hold(sk); /* sock_put in smc_accept_unlink () */ 729a046d57dSUrsula Braun spin_lock(&par->accept_q_lock); 730a046d57dSUrsula Braun list_add_tail(&smc_sk(sk)->accept_q, &par->accept_q); 731a046d57dSUrsula Braun spin_unlock(&par->accept_q_lock); 732a046d57dSUrsula Braun sk_acceptq_added(parent); 733a046d57dSUrsula Braun } 734a046d57dSUrsula Braun 735a046d57dSUrsula Braun /* remove a socket from the accept queue of its parental listening socket */ 736a046d57dSUrsula Braun static void smc_accept_unlink(struct sock *sk) 737a046d57dSUrsula Braun { 738a046d57dSUrsula Braun struct smc_sock *par = smc_sk(sk)->listen_smc; 739a046d57dSUrsula Braun 740a046d57dSUrsula Braun spin_lock(&par->accept_q_lock); 741a046d57dSUrsula Braun list_del_init(&smc_sk(sk)->accept_q); 742a046d57dSUrsula Braun spin_unlock(&par->accept_q_lock); 743a046d57dSUrsula Braun sk_acceptq_removed(&smc_sk(sk)->listen_smc->sk); 74451f1de79SUrsula Braun sock_put(sk); /* sock_hold in smc_accept_enqueue */ 745a046d57dSUrsula Braun } 746a046d57dSUrsula Braun 747a046d57dSUrsula Braun /* remove a sock from the accept queue to bind it to a new socket created 748a046d57dSUrsula Braun * for a socket accept call from user space 749a046d57dSUrsula Braun */ 750b38d7324SUrsula Braun struct sock *smc_accept_dequeue(struct sock *parent, 751a046d57dSUrsula Braun struct socket *new_sock) 752a046d57dSUrsula Braun { 753a046d57dSUrsula Braun struct smc_sock *isk, *n; 754a046d57dSUrsula Braun struct sock *new_sk; 755a046d57dSUrsula Braun 756a046d57dSUrsula Braun list_for_each_entry_safe(isk, n, &smc_sk(parent)->accept_q, accept_q) { 757a046d57dSUrsula Braun new_sk = (struct sock *)isk; 758a046d57dSUrsula Braun 759a046d57dSUrsula Braun smc_accept_unlink(new_sk); 760a046d57dSUrsula Braun if (new_sk->sk_state == SMC_CLOSED) { 761127f4970SUrsula Braun if (isk->clcsock) { 762127f4970SUrsula Braun sock_release(isk->clcsock); 763127f4970SUrsula Braun isk->clcsock = NULL; 764127f4970SUrsula Braun } 765288c8390SUrsula Braun new_sk->sk_prot->unhash(new_sk); 76651f1de79SUrsula Braun sock_put(new_sk); /* final */ 767a046d57dSUrsula Braun continue; 768a046d57dSUrsula Braun } 769a046d57dSUrsula Braun if (new_sock) 770a046d57dSUrsula Braun sock_graft(new_sk, new_sock); 771a046d57dSUrsula Braun return new_sk; 772a046d57dSUrsula Braun } 773a046d57dSUrsula Braun return NULL; 774a046d57dSUrsula Braun } 775a046d57dSUrsula Braun 776a046d57dSUrsula Braun /* clean up for a created but never accepted sock */ 777b38d7324SUrsula Braun void smc_close_non_accepted(struct sock *sk) 778a046d57dSUrsula Braun { 779a046d57dSUrsula Braun struct smc_sock *smc = smc_sk(sk); 780a046d57dSUrsula Braun 781b38d7324SUrsula Braun lock_sock(sk); 782b38d7324SUrsula Braun if (!sk->sk_lingertime) 783b38d7324SUrsula Braun /* wait for peer closing */ 784b38d7324SUrsula Braun sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT; 78551f1de79SUrsula Braun if (!smc->use_fallback) { 786b38d7324SUrsula Braun smc_close_active(smc); 787288c8390SUrsula Braun sock_set_flag(sk, SOCK_DEAD); 788288c8390SUrsula Braun sk->sk_shutdown |= SHUTDOWN_MASK; 789288c8390SUrsula Braun } 790a046d57dSUrsula Braun if (smc->clcsock) { 791a046d57dSUrsula Braun struct socket *tcp; 792a046d57dSUrsula Braun 793a046d57dSUrsula Braun tcp = smc->clcsock; 794a046d57dSUrsula Braun smc->clcsock = NULL; 795a046d57dSUrsula Braun sock_release(tcp); 796a046d57dSUrsula Braun } 797b38d7324SUrsula Braun if (smc->use_fallback) { 79851f1de79SUrsula Braun sock_put(sk); /* passive closing */ 79951f1de79SUrsula Braun sk->sk_state = SMC_CLOSED; 80051f1de79SUrsula Braun } else { 80151f1de79SUrsula Braun if (sk->sk_state == SMC_CLOSED) 802b38d7324SUrsula Braun smc_conn_free(&smc->conn); 803b38d7324SUrsula Braun } 804b38d7324SUrsula Braun release_sock(sk); 80551f1de79SUrsula Braun sk->sk_prot->unhash(sk); 80651f1de79SUrsula Braun sock_put(sk); /* final sock_put */ 807a046d57dSUrsula Braun } 808a046d57dSUrsula Braun 8099bf9abeaSUrsula Braun static int smc_serv_conf_first_link(struct smc_sock *smc) 8109bf9abeaSUrsula Braun { 811877ae5beSKarsten Graul struct net *net = sock_net(smc->clcsock->sk); 8129bf9abeaSUrsula Braun struct smc_link_group *lgr = smc->conn.lgr; 8139bf9abeaSUrsula Braun struct smc_link *link; 8149bf9abeaSUrsula Braun int rest; 8159bf9abeaSUrsula Braun int rc; 8169bf9abeaSUrsula Braun 8179bf9abeaSUrsula Braun link = &lgr->lnk[SMC_SINGLE_LINK]; 818652a1e41SUrsula Braun 81944aa81ceSKarsten Graul if (smc_reg_rmb(link, smc->conn.rmb_desc, false)) 820652a1e41SUrsula Braun return SMC_CLC_DECL_INTERR; 821652a1e41SUrsula Braun 8229bf9abeaSUrsula Braun /* send CONFIRM LINK request to client over the RoCE fabric */ 8239bf9abeaSUrsula Braun rc = smc_llc_send_confirm_link(link, 8249bf9abeaSUrsula Braun link->smcibdev->mac[link->ibport - 1], 8259bf9abeaSUrsula Braun &link->smcibdev->gid[link->ibport - 1], 8269bf9abeaSUrsula Braun SMC_LLC_REQ); 8279bf9abeaSUrsula Braun if (rc < 0) 8289bf9abeaSUrsula Braun return SMC_CLC_DECL_TCL; 8299bf9abeaSUrsula Braun 8309bf9abeaSUrsula Braun /* receive CONFIRM LINK response from client over the RoCE fabric */ 8319bf9abeaSUrsula Braun rest = wait_for_completion_interruptible_timeout( 8329bf9abeaSUrsula Braun &link->llc_confirm_resp, 8339bf9abeaSUrsula Braun SMC_LLC_WAIT_FIRST_TIME); 8349bf9abeaSUrsula Braun if (rest <= 0) { 8359bf9abeaSUrsula Braun struct smc_clc_msg_decline dclc; 8369bf9abeaSUrsula Braun 8379bf9abeaSUrsula Braun rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 8389bf9abeaSUrsula Braun SMC_CLC_DECLINE); 83975d320d6SKarsten Graul return rc; 8409bf9abeaSUrsula Braun } 8419bf9abeaSUrsula Braun 84275d320d6SKarsten Graul if (link->llc_confirm_resp_rc) 84375d320d6SKarsten Graul return SMC_CLC_DECL_RMBE_EC; 84475d320d6SKarsten Graul 84552bedf37SKarsten Graul /* send ADD LINK request to client over the RoCE fabric */ 84652bedf37SKarsten Graul rc = smc_llc_send_add_link(link, 84752bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 84852bedf37SKarsten Graul &link->smcibdev->gid[link->ibport - 1], 84952bedf37SKarsten Graul SMC_LLC_REQ); 85052bedf37SKarsten Graul if (rc < 0) 85152bedf37SKarsten Graul return SMC_CLC_DECL_TCL; 85252bedf37SKarsten Graul 85352bedf37SKarsten Graul /* receive ADD LINK response from client over the RoCE fabric */ 85452bedf37SKarsten Graul rest = wait_for_completion_interruptible_timeout(&link->llc_add_resp, 85552bedf37SKarsten Graul SMC_LLC_WAIT_TIME); 85652bedf37SKarsten Graul if (rest <= 0) { 85752bedf37SKarsten Graul struct smc_clc_msg_decline dclc; 85852bedf37SKarsten Graul 85952bedf37SKarsten Graul rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc), 86052bedf37SKarsten Graul SMC_CLC_DECLINE); 86152bedf37SKarsten Graul return rc; 86252bedf37SKarsten Graul } 86352bedf37SKarsten Graul 864877ae5beSKarsten Graul smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time); 86552bedf37SKarsten Graul 86675d320d6SKarsten Graul return 0; 8679bf9abeaSUrsula Braun } 8689bf9abeaSUrsula Braun 8693b2dec26SHans Wippel /* listen worker: finish */ 8703b2dec26SHans Wippel static void smc_listen_out(struct smc_sock *new_smc) 871a046d57dSUrsula Braun { 872a046d57dSUrsula Braun struct smc_sock *lsmc = new_smc->listen_smc; 873a046d57dSUrsula Braun struct sock *newsmcsk = &new_smc->sk; 874a046d57dSUrsula Braun 875b38d7324SUrsula Braun lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); 876a046d57dSUrsula Braun if (lsmc->sk.sk_state == SMC_LISTEN) { 877a046d57dSUrsula Braun smc_accept_enqueue(&lsmc->sk, newsmcsk); 878a046d57dSUrsula Braun } else { /* no longer listening */ 879a046d57dSUrsula Braun smc_close_non_accepted(newsmcsk); 880a046d57dSUrsula Braun } 881a046d57dSUrsula Braun release_sock(&lsmc->sk); 882a046d57dSUrsula Braun 883a046d57dSUrsula Braun /* Wake up accept */ 884a046d57dSUrsula Braun lsmc->sk.sk_data_ready(&lsmc->sk); 885a046d57dSUrsula Braun sock_put(&lsmc->sk); /* sock_hold in smc_tcp_listen_work */ 886a046d57dSUrsula Braun } 887a046d57dSUrsula Braun 8883b2dec26SHans Wippel /* listen worker: finish in state connected */ 8893b2dec26SHans Wippel static void smc_listen_out_connected(struct smc_sock *new_smc) 8903b2dec26SHans Wippel { 8913b2dec26SHans Wippel struct sock *newsmcsk = &new_smc->sk; 8923b2dec26SHans Wippel 8933b2dec26SHans Wippel sk_refcnt_debug_inc(newsmcsk); 8943b2dec26SHans Wippel if (newsmcsk->sk_state == SMC_INIT) 8953b2dec26SHans Wippel newsmcsk->sk_state = SMC_ACTIVE; 8963b2dec26SHans Wippel 8973b2dec26SHans Wippel smc_listen_out(new_smc); 8983b2dec26SHans Wippel } 8993b2dec26SHans Wippel 9003b2dec26SHans Wippel /* listen worker: finish in error state */ 9013b2dec26SHans Wippel static void smc_listen_out_err(struct smc_sock *new_smc) 9023b2dec26SHans Wippel { 9033b2dec26SHans Wippel struct sock *newsmcsk = &new_smc->sk; 9043b2dec26SHans Wippel 90551f1de79SUrsula Braun if (newsmcsk->sk_state == SMC_INIT) 90651f1de79SUrsula Braun sock_put(&new_smc->sk); /* passive closing */ 907a046d57dSUrsula Braun newsmcsk->sk_state = SMC_CLOSED; 908b38d7324SUrsula Braun smc_conn_free(&new_smc->conn); 9093b2dec26SHans Wippel 9103b2dec26SHans Wippel smc_listen_out(new_smc); 9113b2dec26SHans Wippel } 9123b2dec26SHans Wippel 9133b2dec26SHans Wippel /* listen worker: decline and fall back if possible */ 9143b2dec26SHans Wippel static void smc_listen_decline(struct smc_sock *new_smc, int reason_code, 9153b2dec26SHans Wippel int local_contact) 9163b2dec26SHans Wippel { 9173b2dec26SHans Wippel /* RDMA setup failed, switch back to TCP */ 9183b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) 9193b2dec26SHans Wippel smc_lgr_forget(new_smc->conn.lgr); 9203b2dec26SHans Wippel if (reason_code < 0) { /* error, no fallback possible */ 9213b2dec26SHans Wippel smc_listen_out_err(new_smc); 9223b2dec26SHans Wippel return; 9233b2dec26SHans Wippel } 9243b2dec26SHans Wippel smc_conn_free(&new_smc->conn); 9253b2dec26SHans Wippel new_smc->use_fallback = true; 9263b2dec26SHans Wippel if (reason_code && reason_code != SMC_CLC_DECL_REPLY) { 9273b2dec26SHans Wippel if (smc_clc_send_decline(new_smc, reason_code) < 0) { 9283b2dec26SHans Wippel smc_listen_out_err(new_smc); 9293b2dec26SHans Wippel return; 9303b2dec26SHans Wippel } 9313b2dec26SHans Wippel } 9323b2dec26SHans Wippel smc_listen_out_connected(new_smc); 9333b2dec26SHans Wippel } 9343b2dec26SHans Wippel 9353b2dec26SHans Wippel /* listen worker: check prefixes */ 9363b2dec26SHans Wippel static int smc_listen_rdma_check(struct smc_sock *new_smc, 9373b2dec26SHans Wippel struct smc_clc_msg_proposal *pclc) 9383b2dec26SHans Wippel { 9393b2dec26SHans Wippel struct smc_clc_msg_proposal_prefix *pclc_prfx; 9403b2dec26SHans Wippel struct socket *newclcsock = new_smc->clcsock; 9413b2dec26SHans Wippel 9423b2dec26SHans Wippel pclc_prfx = smc_clc_proposal_get_prefix(pclc); 9433b2dec26SHans Wippel if (smc_clc_prfx_match(newclcsock, pclc_prfx)) 9443b2dec26SHans Wippel return SMC_CLC_DECL_CNFERR; 9453b2dec26SHans Wippel 9463b2dec26SHans Wippel return 0; 9473b2dec26SHans Wippel } 9483b2dec26SHans Wippel 9493b2dec26SHans Wippel /* listen worker: initialize connection and buffers */ 9503b2dec26SHans Wippel static int smc_listen_rdma_init(struct smc_sock *new_smc, 9513b2dec26SHans Wippel struct smc_clc_msg_proposal *pclc, 9523b2dec26SHans Wippel struct smc_ib_device *ibdev, u8 ibport, 9533b2dec26SHans Wippel int *local_contact) 9543b2dec26SHans Wippel { 9553b2dec26SHans Wippel /* allocate connection / link group */ 9563b2dec26SHans Wippel *local_contact = smc_conn_create(new_smc, ibdev, ibport, &pclc->lcl, 0); 9573b2dec26SHans Wippel if (*local_contact < 0) { 9583b2dec26SHans Wippel if (*local_contact == -ENOMEM) 9593b2dec26SHans Wippel return SMC_CLC_DECL_MEM;/* insufficient memory*/ 9603b2dec26SHans Wippel return SMC_CLC_DECL_INTERR; /* other error */ 9613b2dec26SHans Wippel } 9623b2dec26SHans Wippel 9633b2dec26SHans Wippel /* create send buffer and rmb */ 9643b2dec26SHans Wippel if (smc_buf_create(new_smc)) 9653b2dec26SHans Wippel return SMC_CLC_DECL_MEM; 9663b2dec26SHans Wippel 9673b2dec26SHans Wippel return 0; 9683b2dec26SHans Wippel } 9693b2dec26SHans Wippel 9703b2dec26SHans Wippel /* listen worker: register buffers */ 9713b2dec26SHans Wippel static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact) 9723b2dec26SHans Wippel { 9733b2dec26SHans Wippel struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK]; 9743b2dec26SHans Wippel 9753b2dec26SHans Wippel if (local_contact != SMC_FIRST_CONTACT) { 9763b2dec26SHans Wippel if (!new_smc->conn.rmb_desc->reused) { 9773b2dec26SHans Wippel if (smc_reg_rmb(link, new_smc->conn.rmb_desc, true)) 9783b2dec26SHans Wippel return SMC_CLC_DECL_INTERR; 9793b2dec26SHans Wippel } 9803b2dec26SHans Wippel } 9813b2dec26SHans Wippel smc_rmb_sync_sg_for_device(&new_smc->conn); 9823b2dec26SHans Wippel 9833b2dec26SHans Wippel return 0; 9843b2dec26SHans Wippel } 9853b2dec26SHans Wippel 9863b2dec26SHans Wippel /* listen worker: finish RDMA setup */ 9873b2dec26SHans Wippel static void smc_listen_rdma_finish(struct smc_sock *new_smc, 9883b2dec26SHans Wippel struct smc_clc_msg_accept_confirm *cclc, 9893b2dec26SHans Wippel int local_contact) 9903b2dec26SHans Wippel { 9913b2dec26SHans Wippel struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK]; 9923b2dec26SHans Wippel int reason_code = 0; 9933b2dec26SHans Wippel 9943b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) 9953b2dec26SHans Wippel smc_link_save_peer_info(link, cclc); 9963b2dec26SHans Wippel 9973b2dec26SHans Wippel if (smc_rmb_rtoken_handling(&new_smc->conn, cclc)) { 9983b2dec26SHans Wippel reason_code = SMC_CLC_DECL_INTERR; 9993b2dec26SHans Wippel goto decline; 10003b2dec26SHans Wippel } 10013b2dec26SHans Wippel 10023b2dec26SHans Wippel if (local_contact == SMC_FIRST_CONTACT) { 10033b2dec26SHans Wippel if (smc_ib_ready_link(link)) { 10043b2dec26SHans Wippel reason_code = SMC_CLC_DECL_INTERR; 10053b2dec26SHans Wippel goto decline; 10063b2dec26SHans Wippel } 10073b2dec26SHans Wippel /* QP confirmation over RoCE fabric */ 10083b2dec26SHans Wippel reason_code = smc_serv_conf_first_link(new_smc); 10093b2dec26SHans Wippel if (reason_code) 10103b2dec26SHans Wippel goto decline; 10113b2dec26SHans Wippel } 10123b2dec26SHans Wippel return; 10133b2dec26SHans Wippel 10143b2dec26SHans Wippel decline: 10153b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 10163b2dec26SHans Wippel smc_listen_decline(new_smc, reason_code, local_contact); 10173b2dec26SHans Wippel } 10183b2dec26SHans Wippel 10193b2dec26SHans Wippel /* setup for RDMA connection of server */ 10203b2dec26SHans Wippel static void smc_listen_work(struct work_struct *work) 10213b2dec26SHans Wippel { 10223b2dec26SHans Wippel struct smc_sock *new_smc = container_of(work, struct smc_sock, 10233b2dec26SHans Wippel smc_listen_work); 10243b2dec26SHans Wippel struct socket *newclcsock = new_smc->clcsock; 10253b2dec26SHans Wippel struct smc_clc_msg_accept_confirm cclc; 10263b2dec26SHans Wippel struct smc_clc_msg_proposal *pclc; 10273b2dec26SHans Wippel struct smc_ib_device *ibdev; 10283b2dec26SHans Wippel u8 buf[SMC_CLC_MAX_LEN]; 10293b2dec26SHans Wippel int local_contact = 0; 10303b2dec26SHans Wippel int reason_code = 0; 10313b2dec26SHans Wippel int rc = 0; 10323b2dec26SHans Wippel u8 ibport; 10333b2dec26SHans Wippel 10343b2dec26SHans Wippel if (new_smc->use_fallback) { 10353b2dec26SHans Wippel smc_listen_out_connected(new_smc); 10363b2dec26SHans Wippel return; 10373b2dec26SHans Wippel } 10383b2dec26SHans Wippel 10393b2dec26SHans Wippel /* check if peer is smc capable */ 10403b2dec26SHans Wippel if (!tcp_sk(newclcsock->sk)->syn_smc) { 10413b2dec26SHans Wippel new_smc->use_fallback = true; 10423b2dec26SHans Wippel smc_listen_out_connected(new_smc); 10433b2dec26SHans Wippel return; 10443b2dec26SHans Wippel } 10453b2dec26SHans Wippel 10463b2dec26SHans Wippel /* do inband token exchange - 10473b2dec26SHans Wippel * wait for and receive SMC Proposal CLC message 10483b2dec26SHans Wippel */ 10493b2dec26SHans Wippel pclc = (struct smc_clc_msg_proposal *)&buf; 10503b2dec26SHans Wippel reason_code = smc_clc_wait_msg(new_smc, pclc, SMC_CLC_MAX_LEN, 10513b2dec26SHans Wippel SMC_CLC_PROPOSAL); 10523b2dec26SHans Wippel if (reason_code) { 10533b2dec26SHans Wippel smc_listen_decline(new_smc, reason_code, 0); 10543b2dec26SHans Wippel return; 10553b2dec26SHans Wippel } 10563b2dec26SHans Wippel 10573b2dec26SHans Wippel /* IPSec connections opt out of SMC-R optimizations */ 10583b2dec26SHans Wippel if (using_ipsec(new_smc)) { 10593b2dec26SHans Wippel smc_listen_decline(new_smc, SMC_CLC_DECL_IPSEC, 0); 10603b2dec26SHans Wippel return; 10613b2dec26SHans Wippel } 10623b2dec26SHans Wippel 10633b2dec26SHans Wippel mutex_lock(&smc_create_lgr_pending); 10643b2dec26SHans Wippel smc_close_init(new_smc); 10653b2dec26SHans Wippel smc_rx_init(new_smc); 10663b2dec26SHans Wippel smc_tx_init(new_smc); 10673b2dec26SHans Wippel 10683b2dec26SHans Wippel /* check if RDMA is available */ 10693b2dec26SHans Wippel if (smc_check_rdma(new_smc, &ibdev, &ibport) || 10703b2dec26SHans Wippel smc_listen_rdma_check(new_smc, pclc) || 10713b2dec26SHans Wippel smc_listen_rdma_init(new_smc, pclc, ibdev, ibport, 10723b2dec26SHans Wippel &local_contact) || 10733b2dec26SHans Wippel smc_listen_rdma_reg(new_smc, local_contact)) { 10743b2dec26SHans Wippel /* SMC not supported, decline */ 10753b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 10763b2dec26SHans Wippel smc_listen_decline(new_smc, SMC_CLC_DECL_CNFERR, local_contact); 10773b2dec26SHans Wippel return; 10783b2dec26SHans Wippel } 10793b2dec26SHans Wippel 10803b2dec26SHans Wippel /* send SMC Accept CLC message */ 10813b2dec26SHans Wippel rc = smc_clc_send_accept(new_smc, local_contact); 10823b2dec26SHans Wippel if (rc) { 10833b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 10843b2dec26SHans Wippel smc_listen_decline(new_smc, rc, local_contact); 10853b2dec26SHans Wippel return; 10863b2dec26SHans Wippel } 10873b2dec26SHans Wippel 10883b2dec26SHans Wippel /* receive SMC Confirm CLC message */ 10893b2dec26SHans Wippel reason_code = smc_clc_wait_msg(new_smc, &cclc, sizeof(cclc), 10903b2dec26SHans Wippel SMC_CLC_CONFIRM); 10913b2dec26SHans Wippel if (reason_code) { 10923b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 10933b2dec26SHans Wippel smc_listen_decline(new_smc, reason_code, local_contact); 10943b2dec26SHans Wippel return; 10953b2dec26SHans Wippel } 10963b2dec26SHans Wippel 10973b2dec26SHans Wippel /* finish worker */ 10983b2dec26SHans Wippel smc_listen_rdma_finish(new_smc, &cclc, local_contact); 10993b2dec26SHans Wippel smc_conn_save_peer_info(new_smc, &cclc); 11003b2dec26SHans Wippel mutex_unlock(&smc_create_lgr_pending); 11013b2dec26SHans Wippel smc_listen_out_connected(new_smc); 1102a046d57dSUrsula Braun } 1103a046d57dSUrsula Braun 1104a046d57dSUrsula Braun static void smc_tcp_listen_work(struct work_struct *work) 1105a046d57dSUrsula Braun { 1106a046d57dSUrsula Braun struct smc_sock *lsmc = container_of(work, struct smc_sock, 1107a046d57dSUrsula Braun tcp_listen_work); 11083163c507SUrsula Braun struct sock *lsk = &lsmc->sk; 1109a046d57dSUrsula Braun struct smc_sock *new_smc; 1110a046d57dSUrsula Braun int rc = 0; 1111a046d57dSUrsula Braun 11123163c507SUrsula Braun lock_sock(lsk); 11133163c507SUrsula Braun while (lsk->sk_state == SMC_LISTEN) { 1114a046d57dSUrsula Braun rc = smc_clcsock_accept(lsmc, &new_smc); 1115a046d57dSUrsula Braun if (rc) 1116a046d57dSUrsula Braun goto out; 1117a046d57dSUrsula Braun if (!new_smc) 1118a046d57dSUrsula Braun continue; 1119a046d57dSUrsula Braun 1120a046d57dSUrsula Braun new_smc->listen_smc = lsmc; 1121ee9dfbefSUrsula Braun new_smc->use_fallback = lsmc->use_fallback; 11223163c507SUrsula Braun sock_hold(lsk); /* sock_put in smc_listen_work */ 1123a046d57dSUrsula Braun INIT_WORK(&new_smc->smc_listen_work, smc_listen_work); 1124a046d57dSUrsula Braun smc_copy_sock_settings_to_smc(new_smc); 1125bd58c7e0SUrsula Braun new_smc->sk.sk_sndbuf = lsmc->sk.sk_sndbuf; 1126bd58c7e0SUrsula Braun new_smc->sk.sk_rcvbuf = lsmc->sk.sk_rcvbuf; 112751f1de79SUrsula Braun sock_hold(&new_smc->sk); /* sock_put in passive closing */ 112851f1de79SUrsula Braun if (!schedule_work(&new_smc->smc_listen_work)) 112951f1de79SUrsula Braun sock_put(&new_smc->sk); 1130a046d57dSUrsula Braun } 1131a046d57dSUrsula Braun 1132a046d57dSUrsula Braun out: 11333163c507SUrsula Braun release_sock(lsk); 113451f1de79SUrsula Braun sock_put(&lsmc->sk); /* sock_hold in smc_listen */ 1135a046d57dSUrsula Braun } 1136a046d57dSUrsula Braun 1137ac713874SUrsula Braun static int smc_listen(struct socket *sock, int backlog) 1138ac713874SUrsula Braun { 1139ac713874SUrsula Braun struct sock *sk = sock->sk; 1140ac713874SUrsula Braun struct smc_sock *smc; 1141ac713874SUrsula Braun int rc; 1142ac713874SUrsula Braun 1143ac713874SUrsula Braun smc = smc_sk(sk); 1144ac713874SUrsula Braun lock_sock(sk); 1145ac713874SUrsula Braun 1146ac713874SUrsula Braun rc = -EINVAL; 1147ac713874SUrsula Braun if ((sk->sk_state != SMC_INIT) && (sk->sk_state != SMC_LISTEN)) 1148ac713874SUrsula Braun goto out; 1149ac713874SUrsula Braun 1150ac713874SUrsula Braun rc = 0; 1151ac713874SUrsula Braun if (sk->sk_state == SMC_LISTEN) { 1152ac713874SUrsula Braun sk->sk_max_ack_backlog = backlog; 1153ac713874SUrsula Braun goto out; 1154ac713874SUrsula Braun } 1155ac713874SUrsula Braun /* some socket options are handled in core, so we could not apply 1156ac713874SUrsula Braun * them to the clc socket -- copy smc socket options to clc socket 1157ac713874SUrsula Braun */ 1158ac713874SUrsula Braun smc_copy_sock_settings_to_clc(smc); 1159ee9dfbefSUrsula Braun if (!smc->use_fallback) 1160c5c1cc9cSUrsula Braun tcp_sk(smc->clcsock->sk)->syn_smc = 1; 1161ac713874SUrsula Braun 1162ac713874SUrsula Braun rc = kernel_listen(smc->clcsock, backlog); 1163ac713874SUrsula Braun if (rc) 1164ac713874SUrsula Braun goto out; 1165ac713874SUrsula Braun sk->sk_max_ack_backlog = backlog; 1166ac713874SUrsula Braun sk->sk_ack_backlog = 0; 1167ac713874SUrsula Braun sk->sk_state = SMC_LISTEN; 1168a046d57dSUrsula Braun INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); 116951f1de79SUrsula Braun sock_hold(sk); /* sock_hold in tcp_listen_worker */ 117051f1de79SUrsula Braun if (!schedule_work(&smc->tcp_listen_work)) 117151f1de79SUrsula Braun sock_put(sk); 1172ac713874SUrsula Braun 1173ac713874SUrsula Braun out: 1174ac713874SUrsula Braun release_sock(sk); 1175ac713874SUrsula Braun return rc; 1176ac713874SUrsula Braun } 1177ac713874SUrsula Braun 1178ac713874SUrsula Braun static int smc_accept(struct socket *sock, struct socket *new_sock, 1179cdfbabfbSDavid Howells int flags, bool kern) 1180ac713874SUrsula Braun { 1181a046d57dSUrsula Braun struct sock *sk = sock->sk, *nsk; 1182a046d57dSUrsula Braun DECLARE_WAITQUEUE(wait, current); 1183ac713874SUrsula Braun struct smc_sock *lsmc; 1184a046d57dSUrsula Braun long timeo; 1185a046d57dSUrsula Braun int rc = 0; 1186ac713874SUrsula Braun 1187ac713874SUrsula Braun lsmc = smc_sk(sk); 118851f1de79SUrsula Braun sock_hold(sk); /* sock_put below */ 1189ac713874SUrsula Braun lock_sock(sk); 1190ac713874SUrsula Braun 1191ac713874SUrsula Braun if (lsmc->sk.sk_state != SMC_LISTEN) { 1192ac713874SUrsula Braun rc = -EINVAL; 1193abb190f1SUrsula Braun release_sock(sk); 1194ac713874SUrsula Braun goto out; 1195ac713874SUrsula Braun } 1196ac713874SUrsula Braun 1197a046d57dSUrsula Braun /* Wait for an incoming connection */ 1198a046d57dSUrsula Braun timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 1199a046d57dSUrsula Braun add_wait_queue_exclusive(sk_sleep(sk), &wait); 1200a046d57dSUrsula Braun while (!(nsk = smc_accept_dequeue(sk, new_sock))) { 1201a046d57dSUrsula Braun set_current_state(TASK_INTERRUPTIBLE); 1202a046d57dSUrsula Braun if (!timeo) { 1203a046d57dSUrsula Braun rc = -EAGAIN; 1204a046d57dSUrsula Braun break; 1205a046d57dSUrsula Braun } 1206a046d57dSUrsula Braun release_sock(sk); 1207a046d57dSUrsula Braun timeo = schedule_timeout(timeo); 1208a046d57dSUrsula Braun /* wakeup by sk_data_ready in smc_listen_work() */ 1209a046d57dSUrsula Braun sched_annotate_sleep(); 1210a046d57dSUrsula Braun lock_sock(sk); 1211a046d57dSUrsula Braun if (signal_pending(current)) { 1212a046d57dSUrsula Braun rc = sock_intr_errno(timeo); 1213a046d57dSUrsula Braun break; 1214a046d57dSUrsula Braun } 1215a046d57dSUrsula Braun } 1216a046d57dSUrsula Braun set_current_state(TASK_RUNNING); 1217a046d57dSUrsula Braun remove_wait_queue(sk_sleep(sk), &wait); 1218ac713874SUrsula Braun 1219a046d57dSUrsula Braun if (!rc) 1220a046d57dSUrsula Braun rc = sock_error(nsk); 1221abb190f1SUrsula Braun release_sock(sk); 1222abb190f1SUrsula Braun if (rc) 1223abb190f1SUrsula Braun goto out; 1224abb190f1SUrsula Braun 1225abb190f1SUrsula Braun if (lsmc->sockopt_defer_accept && !(flags & O_NONBLOCK)) { 1226abb190f1SUrsula Braun /* wait till data arrives on the socket */ 1227abb190f1SUrsula Braun timeo = msecs_to_jiffies(lsmc->sockopt_defer_accept * 1228abb190f1SUrsula Braun MSEC_PER_SEC); 1229abb190f1SUrsula Braun if (smc_sk(nsk)->use_fallback) { 1230abb190f1SUrsula Braun struct sock *clcsk = smc_sk(nsk)->clcsock->sk; 1231abb190f1SUrsula Braun 1232abb190f1SUrsula Braun lock_sock(clcsk); 1233abb190f1SUrsula Braun if (skb_queue_empty(&clcsk->sk_receive_queue)) 1234abb190f1SUrsula Braun sk_wait_data(clcsk, &timeo, NULL); 1235abb190f1SUrsula Braun release_sock(clcsk); 1236abb190f1SUrsula Braun } else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) { 1237abb190f1SUrsula Braun lock_sock(nsk); 1238b51fa1b1SStefan Raspl smc_rx_wait(smc_sk(nsk), &timeo, smc_rx_data_available); 1239abb190f1SUrsula Braun release_sock(nsk); 1240abb190f1SUrsula Braun } 1241abb190f1SUrsula Braun } 1242ac713874SUrsula Braun 1243ac713874SUrsula Braun out: 124451f1de79SUrsula Braun sock_put(sk); /* sock_hold above */ 1245ac713874SUrsula Braun return rc; 1246ac713874SUrsula Braun } 1247ac713874SUrsula Braun 1248ac713874SUrsula Braun static int smc_getname(struct socket *sock, struct sockaddr *addr, 12499b2c45d4SDenys Vlasenko int peer) 1250ac713874SUrsula Braun { 1251ac713874SUrsula Braun struct smc_sock *smc; 1252ac713874SUrsula Braun 1253b38d7324SUrsula Braun if (peer && (sock->sk->sk_state != SMC_ACTIVE) && 1254b38d7324SUrsula Braun (sock->sk->sk_state != SMC_APPCLOSEWAIT1)) 1255ac713874SUrsula Braun return -ENOTCONN; 1256ac713874SUrsula Braun 1257ac713874SUrsula Braun smc = smc_sk(sock->sk); 1258ac713874SUrsula Braun 12599b2c45d4SDenys Vlasenko return smc->clcsock->ops->getname(smc->clcsock, addr, peer); 1260ac713874SUrsula Braun } 1261ac713874SUrsula Braun 1262ac713874SUrsula Braun static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 1263ac713874SUrsula Braun { 1264ac713874SUrsula Braun struct sock *sk = sock->sk; 1265ac713874SUrsula Braun struct smc_sock *smc; 1266ac713874SUrsula Braun int rc = -EPIPE; 1267ac713874SUrsula Braun 1268ac713874SUrsula Braun smc = smc_sk(sk); 1269ac713874SUrsula Braun lock_sock(sk); 1270b38d7324SUrsula Braun if ((sk->sk_state != SMC_ACTIVE) && 1271b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT1) && 1272b38d7324SUrsula Braun (sk->sk_state != SMC_INIT)) 1273ac713874SUrsula Braun goto out; 1274ee9dfbefSUrsula Braun 1275ee9dfbefSUrsula Braun if (msg->msg_flags & MSG_FASTOPEN) { 1276ee9dfbefSUrsula Braun if (sk->sk_state == SMC_INIT) { 1277ee9dfbefSUrsula Braun smc->use_fallback = true; 1278ee9dfbefSUrsula Braun } else { 1279ee9dfbefSUrsula Braun rc = -EINVAL; 1280ee9dfbefSUrsula Braun goto out; 1281ee9dfbefSUrsula Braun } 1282ee9dfbefSUrsula Braun } 1283ee9dfbefSUrsula Braun 1284ac713874SUrsula Braun if (smc->use_fallback) 1285ac713874SUrsula Braun rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len); 1286ac713874SUrsula Braun else 1287e6727f39SUrsula Braun rc = smc_tx_sendmsg(smc, msg, len); 1288ac713874SUrsula Braun out: 1289ac713874SUrsula Braun release_sock(sk); 1290ac713874SUrsula Braun return rc; 1291ac713874SUrsula Braun } 1292ac713874SUrsula Braun 1293ac713874SUrsula Braun static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 1294ac713874SUrsula Braun int flags) 1295ac713874SUrsula Braun { 1296ac713874SUrsula Braun struct sock *sk = sock->sk; 1297ac713874SUrsula Braun struct smc_sock *smc; 1298ac713874SUrsula Braun int rc = -ENOTCONN; 1299ac713874SUrsula Braun 1300ac713874SUrsula Braun smc = smc_sk(sk); 1301ac713874SUrsula Braun lock_sock(sk); 1302b38d7324SUrsula Braun if ((sk->sk_state == SMC_INIT) || 1303b38d7324SUrsula Braun (sk->sk_state == SMC_LISTEN) || 1304b38d7324SUrsula Braun (sk->sk_state == SMC_CLOSED)) 1305ac713874SUrsula Braun goto out; 1306ac713874SUrsula Braun 1307b38d7324SUrsula Braun if (sk->sk_state == SMC_PEERFINCLOSEWAIT) { 1308b38d7324SUrsula Braun rc = 0; 1309b38d7324SUrsula Braun goto out; 1310b38d7324SUrsula Braun } 1311b38d7324SUrsula Braun 13129014db20SStefan Raspl if (smc->use_fallback) { 1313ac713874SUrsula Braun rc = smc->clcsock->ops->recvmsg(smc->clcsock, msg, len, flags); 13149014db20SStefan Raspl } else { 13159014db20SStefan Raspl msg->msg_namelen = 0; 13169014db20SStefan Raspl rc = smc_rx_recvmsg(smc, msg, NULL, len, flags); 13179014db20SStefan Raspl } 1318b38d7324SUrsula Braun 1319ac713874SUrsula Braun out: 1320ac713874SUrsula Braun release_sock(sk); 1321ac713874SUrsula Braun return rc; 1322ac713874SUrsula Braun } 1323ac713874SUrsula Braun 1324ade994f4SAl Viro static __poll_t smc_accept_poll(struct sock *parent) 1325a046d57dSUrsula Braun { 13268dce2786SUrsula Braun struct smc_sock *isk = smc_sk(parent); 132763e2480cSAl Viro __poll_t mask = 0; 1328a046d57dSUrsula Braun 13298dce2786SUrsula Braun spin_lock(&isk->accept_q_lock); 13308dce2786SUrsula Braun if (!list_empty(&isk->accept_q)) 1331a9a08845SLinus Torvalds mask = EPOLLIN | EPOLLRDNORM; 13328dce2786SUrsula Braun spin_unlock(&isk->accept_q_lock); 1333a046d57dSUrsula Braun 13348dce2786SUrsula Braun return mask; 1335a046d57dSUrsula Braun } 1336a046d57dSUrsula Braun 1337a11e1d43SLinus Torvalds static __poll_t smc_poll(struct file *file, struct socket *sock, 1338a11e1d43SLinus Torvalds poll_table *wait) 1339ac713874SUrsula Braun { 1340ac713874SUrsula Braun struct sock *sk = sock->sk; 1341e6c8adcaSAl Viro __poll_t mask = 0; 1342ac713874SUrsula Braun struct smc_sock *smc; 1343ac713874SUrsula Braun 13448dce2786SUrsula Braun if (!sk) 1345a9a08845SLinus Torvalds return EPOLLNVAL; 13468dce2786SUrsula Braun 1347ac713874SUrsula Braun smc = smc_sk(sock->sk); 1348a046d57dSUrsula Braun if ((sk->sk_state == SMC_INIT) || smc->use_fallback) { 1349a046d57dSUrsula Braun /* delegate to CLC child sock */ 1350a11e1d43SLinus Torvalds mask = smc->clcsock->ops->poll(file, smc->clcsock, wait); 1351a046d57dSUrsula Braun sk->sk_err = smc->clcsock->sk->sk_err; 135224ac3a08SUrsula Braun if (sk->sk_err) 1353a9a08845SLinus Torvalds mask |= EPOLLERR; 1354a046d57dSUrsula Braun } else { 1355410da1e1SLinus Torvalds if (sk->sk_state != SMC_CLOSED) 1356410da1e1SLinus Torvalds sock_poll_wait(file, sk_sleep(sk), wait); 1357a046d57dSUrsula Braun if (sk->sk_err) 1358a9a08845SLinus Torvalds mask |= EPOLLERR; 13598dce2786SUrsula Braun if ((sk->sk_shutdown == SHUTDOWN_MASK) || 13608dce2786SUrsula Braun (sk->sk_state == SMC_CLOSED)) 1361a9a08845SLinus Torvalds mask |= EPOLLHUP; 13628dce2786SUrsula Braun if (sk->sk_state == SMC_LISTEN) { 13638dce2786SUrsula Braun /* woken up by sk_data_ready in smc_listen_work() */ 13648dce2786SUrsula Braun mask = smc_accept_poll(sk); 13658dce2786SUrsula Braun } else { 1366b38d7324SUrsula Braun if (atomic_read(&smc->conn.sndbuf_space) || 13678dce2786SUrsula Braun sk->sk_shutdown & SEND_SHUTDOWN) { 1368a9a08845SLinus Torvalds mask |= EPOLLOUT | EPOLLWRNORM; 1369e6727f39SUrsula Braun } else { 1370e6727f39SUrsula Braun sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 1371e6727f39SUrsula Braun set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); 1372e6727f39SUrsula Braun } 1373952310ccSUrsula Braun if (atomic_read(&smc->conn.bytes_to_rcv)) 1374a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM; 1375b38d7324SUrsula Braun if (sk->sk_shutdown & RCV_SHUTDOWN) 1376a9a08845SLinus Torvalds mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; 1377b38d7324SUrsula Braun if (sk->sk_state == SMC_APPCLOSEWAIT1) 1378a9a08845SLinus Torvalds mask |= EPOLLIN; 13798dce2786SUrsula Braun } 1380de8474ebSStefan Raspl if (smc->conn.urg_state == SMC_URG_VALID) 1381de8474ebSStefan Raspl mask |= EPOLLPRI; 1382ac713874SUrsula Braun } 1383ac713874SUrsula Braun 1384ac713874SUrsula Braun return mask; 1385ac713874SUrsula Braun } 1386ac713874SUrsula Braun 1387ac713874SUrsula Braun static int smc_shutdown(struct socket *sock, int how) 1388ac713874SUrsula Braun { 1389ac713874SUrsula Braun struct sock *sk = sock->sk; 1390ac713874SUrsula Braun struct smc_sock *smc; 1391ac713874SUrsula Braun int rc = -EINVAL; 1392b38d7324SUrsula Braun int rc1 = 0; 1393ac713874SUrsula Braun 1394ac713874SUrsula Braun smc = smc_sk(sk); 1395ac713874SUrsula Braun 1396ac713874SUrsula Braun if ((how < SHUT_RD) || (how > SHUT_RDWR)) 1397b38d7324SUrsula Braun return rc; 1398ac713874SUrsula Braun 1399ac713874SUrsula Braun lock_sock(sk); 1400ac713874SUrsula Braun 1401ac713874SUrsula Braun rc = -ENOTCONN; 1402caa21e19SUrsula Braun if ((sk->sk_state != SMC_ACTIVE) && 1403b38d7324SUrsula Braun (sk->sk_state != SMC_PEERCLOSEWAIT1) && 1404b38d7324SUrsula Braun (sk->sk_state != SMC_PEERCLOSEWAIT2) && 1405b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT1) && 1406b38d7324SUrsula Braun (sk->sk_state != SMC_APPCLOSEWAIT2) && 1407b38d7324SUrsula Braun (sk->sk_state != SMC_APPFINCLOSEWAIT)) 1408ac713874SUrsula Braun goto out; 1409ac713874SUrsula Braun if (smc->use_fallback) { 1410ac713874SUrsula Braun rc = kernel_sock_shutdown(smc->clcsock, how); 1411ac713874SUrsula Braun sk->sk_shutdown = smc->clcsock->sk->sk_shutdown; 1412ac713874SUrsula Braun if (sk->sk_shutdown == SHUTDOWN_MASK) 1413ac713874SUrsula Braun sk->sk_state = SMC_CLOSED; 1414b38d7324SUrsula Braun goto out; 1415ac713874SUrsula Braun } 1416b38d7324SUrsula Braun switch (how) { 1417b38d7324SUrsula Braun case SHUT_RDWR: /* shutdown in both directions */ 1418b38d7324SUrsula Braun rc = smc_close_active(smc); 1419b38d7324SUrsula Braun break; 1420b38d7324SUrsula Braun case SHUT_WR: 1421b38d7324SUrsula Braun rc = smc_close_shutdown_write(smc); 1422b38d7324SUrsula Braun break; 1423b38d7324SUrsula Braun case SHUT_RD: 1424b38d7324SUrsula Braun rc = 0; 1425b38d7324SUrsula Braun /* nothing more to do because peer is not involved */ 1426b38d7324SUrsula Braun break; 1427b38d7324SUrsula Braun } 14281255fcb2SUrsula Braun if (smc->clcsock) 1429b38d7324SUrsula Braun rc1 = kernel_sock_shutdown(smc->clcsock, how); 1430b38d7324SUrsula Braun /* map sock_shutdown_cmd constants to sk_shutdown value range */ 1431b38d7324SUrsula Braun sk->sk_shutdown |= how + 1; 1432ac713874SUrsula Braun 1433ac713874SUrsula Braun out: 1434ac713874SUrsula Braun release_sock(sk); 1435b38d7324SUrsula Braun return rc ? rc : rc1; 1436ac713874SUrsula Braun } 1437ac713874SUrsula Braun 1438ac713874SUrsula Braun static int smc_setsockopt(struct socket *sock, int level, int optname, 1439ac713874SUrsula Braun char __user *optval, unsigned int optlen) 1440ac713874SUrsula Braun { 1441ac713874SUrsula Braun struct sock *sk = sock->sk; 1442ac713874SUrsula Braun struct smc_sock *smc; 144301d2f7e2SUrsula Braun int val, rc; 1444ac713874SUrsula Braun 1445ac713874SUrsula Braun smc = smc_sk(sk); 1446ac713874SUrsula Braun 1447ac713874SUrsula Braun /* generic setsockopts reaching us here always apply to the 1448ac713874SUrsula Braun * CLC socket 1449ac713874SUrsula Braun */ 1450ee9dfbefSUrsula Braun rc = smc->clcsock->ops->setsockopt(smc->clcsock, level, optname, 1451ac713874SUrsula Braun optval, optlen); 1452ee9dfbefSUrsula Braun if (smc->clcsock->sk->sk_err) { 1453ee9dfbefSUrsula Braun sk->sk_err = smc->clcsock->sk->sk_err; 1454ee9dfbefSUrsula Braun sk->sk_error_report(sk); 1455ee9dfbefSUrsula Braun } 1456ee9dfbefSUrsula Braun if (rc) 1457ee9dfbefSUrsula Braun return rc; 1458ee9dfbefSUrsula Braun 145901d2f7e2SUrsula Braun if (optlen < sizeof(int)) 14603dc9f558SWei Yongjun return -EINVAL; 1461ac0107edSUrsula Braun if (get_user(val, (int __user *)optval)) 1462ac0107edSUrsula Braun return -EFAULT; 146301d2f7e2SUrsula Braun 1464ee9dfbefSUrsula Braun lock_sock(sk); 1465ee9dfbefSUrsula Braun switch (optname) { 1466ee9dfbefSUrsula Braun case TCP_ULP: 1467ee9dfbefSUrsula Braun case TCP_FASTOPEN: 1468ee9dfbefSUrsula Braun case TCP_FASTOPEN_CONNECT: 1469ee9dfbefSUrsula Braun case TCP_FASTOPEN_KEY: 1470ee9dfbefSUrsula Braun case TCP_FASTOPEN_NO_COOKIE: 1471ee9dfbefSUrsula Braun /* option not supported by SMC */ 1472ee9dfbefSUrsula Braun if (sk->sk_state == SMC_INIT) { 1473ee9dfbefSUrsula Braun smc->use_fallback = true; 1474ee9dfbefSUrsula Braun } else { 1475ee9dfbefSUrsula Braun if (!smc->use_fallback) 1476ee9dfbefSUrsula Braun rc = -EINVAL; 1477ee9dfbefSUrsula Braun } 1478ee9dfbefSUrsula Braun break; 147901d2f7e2SUrsula Braun case TCP_NODELAY: 148001d2f7e2SUrsula Braun if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) { 1481569bc643SUrsula Braun if (val && !smc->use_fallback) 148201d2f7e2SUrsula Braun mod_delayed_work(system_wq, &smc->conn.tx_work, 148301d2f7e2SUrsula Braun 0); 148401d2f7e2SUrsula Braun } 148501d2f7e2SUrsula Braun break; 148601d2f7e2SUrsula Braun case TCP_CORK: 148701d2f7e2SUrsula Braun if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) { 1488569bc643SUrsula Braun if (!val && !smc->use_fallback) 148901d2f7e2SUrsula Braun mod_delayed_work(system_wq, &smc->conn.tx_work, 149001d2f7e2SUrsula Braun 0); 149101d2f7e2SUrsula Braun } 149201d2f7e2SUrsula Braun break; 1493abb190f1SUrsula Braun case TCP_DEFER_ACCEPT: 1494abb190f1SUrsula Braun smc->sockopt_defer_accept = val; 1495abb190f1SUrsula Braun break; 1496ee9dfbefSUrsula Braun default: 1497ee9dfbefSUrsula Braun break; 1498ee9dfbefSUrsula Braun } 1499ee9dfbefSUrsula Braun release_sock(sk); 1500ee9dfbefSUrsula Braun 1501ee9dfbefSUrsula Braun return rc; 1502ac713874SUrsula Braun } 1503ac713874SUrsula Braun 1504ac713874SUrsula Braun static int smc_getsockopt(struct socket *sock, int level, int optname, 1505ac713874SUrsula Braun char __user *optval, int __user *optlen) 1506ac713874SUrsula Braun { 1507ac713874SUrsula Braun struct smc_sock *smc; 1508ac713874SUrsula Braun 1509ac713874SUrsula Braun smc = smc_sk(sock->sk); 1510ac713874SUrsula Braun /* socket options apply to the CLC socket */ 1511ac713874SUrsula Braun return smc->clcsock->ops->getsockopt(smc->clcsock, level, optname, 1512ac713874SUrsula Braun optval, optlen); 1513ac713874SUrsula Braun } 1514ac713874SUrsula Braun 1515ac713874SUrsula Braun static int smc_ioctl(struct socket *sock, unsigned int cmd, 1516ac713874SUrsula Braun unsigned long arg) 1517ac713874SUrsula Braun { 1518de8474ebSStefan Raspl union smc_host_cursor cons, urg; 1519de8474ebSStefan Raspl struct smc_connection *conn; 1520ac713874SUrsula Braun struct smc_sock *smc; 15219b67e26fSUrsula Braun int answ; 1522ac713874SUrsula Braun 1523ac713874SUrsula Braun smc = smc_sk(sock->sk); 1524de8474ebSStefan Raspl conn = &smc->conn; 15251992d998SUrsula Braun lock_sock(&smc->sk); 1526*7311d665SUrsula Braun if (smc->use_fallback) { 1527*7311d665SUrsula Braun if (!smc->clcsock) { 1528*7311d665SUrsula Braun release_sock(&smc->sk); 1529*7311d665SUrsula Braun return -EBADF; 1530*7311d665SUrsula Braun } 1531*7311d665SUrsula Braun answ = smc->clcsock->ops->ioctl(smc->clcsock, cmd, arg); 1532*7311d665SUrsula Braun release_sock(&smc->sk); 1533*7311d665SUrsula Braun return answ; 1534*7311d665SUrsula Braun } 15359b67e26fSUrsula Braun switch (cmd) { 15369b67e26fSUrsula Braun case SIOCINQ: /* same as FIONREAD */ 15371992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 15381992d998SUrsula Braun release_sock(&smc->sk); 15399b67e26fSUrsula Braun return -EINVAL; 15401992d998SUrsula Braun } 15412351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 15422351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 15432351abe6SUrsula Braun answ = 0; 15442351abe6SUrsula Braun else 15459b67e26fSUrsula Braun answ = atomic_read(&smc->conn.bytes_to_rcv); 15469b67e26fSUrsula Braun break; 15479b67e26fSUrsula Braun case SIOCOUTQ: 15489b67e26fSUrsula Braun /* output queue size (not send + not acked) */ 15491992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 15501992d998SUrsula Braun release_sock(&smc->sk); 15519b67e26fSUrsula Braun return -EINVAL; 15521992d998SUrsula Braun } 15532351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 15542351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 15552351abe6SUrsula Braun answ = 0; 15562351abe6SUrsula Braun else 155769cb7dc0SHans Wippel answ = smc->conn.sndbuf_desc->len - 15589b67e26fSUrsula Braun atomic_read(&smc->conn.sndbuf_space); 15599b67e26fSUrsula Braun break; 15609b67e26fSUrsula Braun case SIOCOUTQNSD: 15619b67e26fSUrsula Braun /* output queue size (not send only) */ 15621992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 15631992d998SUrsula Braun release_sock(&smc->sk); 15649b67e26fSUrsula Braun return -EINVAL; 15651992d998SUrsula Braun } 15662351abe6SUrsula Braun if (smc->sk.sk_state == SMC_INIT || 15672351abe6SUrsula Braun smc->sk.sk_state == SMC_CLOSED) 15682351abe6SUrsula Braun answ = 0; 15692351abe6SUrsula Braun else 15709b67e26fSUrsula Braun answ = smc_tx_prepared_sends(&smc->conn); 15719b67e26fSUrsula Braun break; 1572de8474ebSStefan Raspl case SIOCATMARK: 15731992d998SUrsula Braun if (smc->sk.sk_state == SMC_LISTEN) { 15741992d998SUrsula Braun release_sock(&smc->sk); 1575de8474ebSStefan Raspl return -EINVAL; 15761992d998SUrsula Braun } 1577de8474ebSStefan Raspl if (smc->sk.sk_state == SMC_INIT || 1578de8474ebSStefan Raspl smc->sk.sk_state == SMC_CLOSED) { 1579de8474ebSStefan Raspl answ = 0; 1580de8474ebSStefan Raspl } else { 1581de8474ebSStefan Raspl smc_curs_write(&cons, 1582de8474ebSStefan Raspl smc_curs_read(&conn->local_tx_ctrl.cons, conn), 1583de8474ebSStefan Raspl conn); 1584de8474ebSStefan Raspl smc_curs_write(&urg, 1585de8474ebSStefan Raspl smc_curs_read(&conn->urg_curs, conn), 1586de8474ebSStefan Raspl conn); 1587de8474ebSStefan Raspl answ = smc_curs_diff(conn->rmb_desc->len, 1588de8474ebSStefan Raspl &cons, &urg) == 1; 1589de8474ebSStefan Raspl } 1590de8474ebSStefan Raspl break; 15919b67e26fSUrsula Braun default: 15921992d998SUrsula Braun release_sock(&smc->sk); 15939b67e26fSUrsula Braun return -ENOIOCTLCMD; 15949b67e26fSUrsula Braun } 15951992d998SUrsula Braun release_sock(&smc->sk); 15969b67e26fSUrsula Braun 15979b67e26fSUrsula Braun return put_user(answ, (int __user *)arg); 1598ac713874SUrsula Braun } 1599ac713874SUrsula Braun 1600ac713874SUrsula Braun static ssize_t smc_sendpage(struct socket *sock, struct page *page, 1601ac713874SUrsula Braun int offset, size_t size, int flags) 1602ac713874SUrsula Braun { 1603ac713874SUrsula Braun struct sock *sk = sock->sk; 1604ac713874SUrsula Braun struct smc_sock *smc; 1605ac713874SUrsula Braun int rc = -EPIPE; 1606ac713874SUrsula Braun 1607ac713874SUrsula Braun smc = smc_sk(sk); 1608ac713874SUrsula Braun lock_sock(sk); 1609bda27ff5SStefan Raspl if (sk->sk_state != SMC_ACTIVE) { 1610bda27ff5SStefan Raspl release_sock(sk); 1611ac713874SUrsula Braun goto out; 1612bda27ff5SStefan Raspl } 1613bda27ff5SStefan Raspl release_sock(sk); 1614ac713874SUrsula Braun if (smc->use_fallback) 1615ac713874SUrsula Braun rc = kernel_sendpage(smc->clcsock, page, offset, 1616ac713874SUrsula Braun size, flags); 1617ac713874SUrsula Braun else 1618ac713874SUrsula Braun rc = sock_no_sendpage(sock, page, offset, size, flags); 1619ac713874SUrsula Braun 1620ac713874SUrsula Braun out: 1621ac713874SUrsula Braun return rc; 1622ac713874SUrsula Braun } 1623ac713874SUrsula Braun 16249014db20SStefan Raspl /* Map the affected portions of the rmbe into an spd, note the number of bytes 16259014db20SStefan Raspl * to splice in conn->splice_pending, and press 'go'. Delays consumer cursor 16269014db20SStefan Raspl * updates till whenever a respective page has been fully processed. 16279014db20SStefan Raspl * Note that subsequent recv() calls have to wait till all splice() processing 16289014db20SStefan Raspl * completed. 16299014db20SStefan Raspl */ 1630ac713874SUrsula Braun static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos, 1631ac713874SUrsula Braun struct pipe_inode_info *pipe, size_t len, 1632ac713874SUrsula Braun unsigned int flags) 1633ac713874SUrsula Braun { 1634ac713874SUrsula Braun struct sock *sk = sock->sk; 1635ac713874SUrsula Braun struct smc_sock *smc; 1636ac713874SUrsula Braun int rc = -ENOTCONN; 1637ac713874SUrsula Braun 1638ac713874SUrsula Braun smc = smc_sk(sk); 1639ac713874SUrsula Braun lock_sock(sk); 16409014db20SStefan Raspl 16419014db20SStefan Raspl if (sk->sk_state == SMC_INIT || 16429014db20SStefan Raspl sk->sk_state == SMC_LISTEN || 16439014db20SStefan Raspl sk->sk_state == SMC_CLOSED) 1644ac713874SUrsula Braun goto out; 16459014db20SStefan Raspl 16469014db20SStefan Raspl if (sk->sk_state == SMC_PEERFINCLOSEWAIT) { 16479014db20SStefan Raspl rc = 0; 16489014db20SStefan Raspl goto out; 16499014db20SStefan Raspl } 16509014db20SStefan Raspl 1651ac713874SUrsula Braun if (smc->use_fallback) { 1652ac713874SUrsula Braun rc = smc->clcsock->ops->splice_read(smc->clcsock, ppos, 1653ac713874SUrsula Braun pipe, len, flags); 1654ac713874SUrsula Braun } else { 16559014db20SStefan Raspl if (*ppos) { 16569014db20SStefan Raspl rc = -ESPIPE; 16579014db20SStefan Raspl goto out; 16589014db20SStefan Raspl } 16599014db20SStefan Raspl if (flags & SPLICE_F_NONBLOCK) 16609014db20SStefan Raspl flags = MSG_DONTWAIT; 16619014db20SStefan Raspl else 16629014db20SStefan Raspl flags = 0; 16639014db20SStefan Raspl rc = smc_rx_recvmsg(smc, NULL, pipe, len, flags); 1664ac713874SUrsula Braun } 1665ac713874SUrsula Braun out: 1666ac713874SUrsula Braun release_sock(sk); 16679014db20SStefan Raspl 1668ac713874SUrsula Braun return rc; 1669ac713874SUrsula Braun } 1670ac713874SUrsula Braun 1671ac713874SUrsula Braun /* must look like tcp */ 1672ac713874SUrsula Braun static const struct proto_ops smc_sock_ops = { 1673ac713874SUrsula Braun .family = PF_SMC, 1674ac713874SUrsula Braun .owner = THIS_MODULE, 1675ac713874SUrsula Braun .release = smc_release, 1676ac713874SUrsula Braun .bind = smc_bind, 1677ac713874SUrsula Braun .connect = smc_connect, 1678ac713874SUrsula Braun .socketpair = sock_no_socketpair, 1679ac713874SUrsula Braun .accept = smc_accept, 1680ac713874SUrsula Braun .getname = smc_getname, 1681a11e1d43SLinus Torvalds .poll = smc_poll, 1682ac713874SUrsula Braun .ioctl = smc_ioctl, 1683ac713874SUrsula Braun .listen = smc_listen, 1684ac713874SUrsula Braun .shutdown = smc_shutdown, 1685ac713874SUrsula Braun .setsockopt = smc_setsockopt, 1686ac713874SUrsula Braun .getsockopt = smc_getsockopt, 1687ac713874SUrsula Braun .sendmsg = smc_sendmsg, 1688ac713874SUrsula Braun .recvmsg = smc_recvmsg, 1689ac713874SUrsula Braun .mmap = sock_no_mmap, 1690ac713874SUrsula Braun .sendpage = smc_sendpage, 1691ac713874SUrsula Braun .splice_read = smc_splice_read, 1692ac713874SUrsula Braun }; 1693ac713874SUrsula Braun 1694ac713874SUrsula Braun static int smc_create(struct net *net, struct socket *sock, int protocol, 1695ac713874SUrsula Braun int kern) 1696ac713874SUrsula Braun { 1697aaa4d33fSKarsten Graul int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET; 1698ac713874SUrsula Braun struct smc_sock *smc; 1699ac713874SUrsula Braun struct sock *sk; 1700ac713874SUrsula Braun int rc; 1701ac713874SUrsula Braun 1702ac713874SUrsula Braun rc = -ESOCKTNOSUPPORT; 1703ac713874SUrsula Braun if (sock->type != SOCK_STREAM) 1704ac713874SUrsula Braun goto out; 1705ac713874SUrsula Braun 1706ac713874SUrsula Braun rc = -EPROTONOSUPPORT; 1707aaa4d33fSKarsten Graul if (protocol != SMCPROTO_SMC && protocol != SMCPROTO_SMC6) 1708ac713874SUrsula Braun goto out; 1709ac713874SUrsula Braun 1710ac713874SUrsula Braun rc = -ENOBUFS; 1711ac713874SUrsula Braun sock->ops = &smc_sock_ops; 1712aaa4d33fSKarsten Graul sk = smc_sock_alloc(net, sock, protocol); 1713ac713874SUrsula Braun if (!sk) 1714ac713874SUrsula Braun goto out; 1715ac713874SUrsula Braun 1716ac713874SUrsula Braun /* create internal TCP socket for CLC handshake and fallback */ 1717ac713874SUrsula Braun smc = smc_sk(sk); 1718a046d57dSUrsula Braun smc->use_fallback = false; /* assume rdma capability first */ 1719aaa4d33fSKarsten Graul rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, 1720aaa4d33fSKarsten Graul &smc->clcsock); 1721a5dcb73bSDavide Caratti if (rc) { 1722ac713874SUrsula Braun sk_common_release(sk); 1723a5dcb73bSDavide Caratti goto out; 1724a5dcb73bSDavide Caratti } 1725cd6851f3SUrsula Braun smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE); 1726cd6851f3SUrsula Braun smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE); 1727ac713874SUrsula Braun 1728ac713874SUrsula Braun out: 1729ac713874SUrsula Braun return rc; 1730ac713874SUrsula Braun } 1731ac713874SUrsula Braun 1732ac713874SUrsula Braun static const struct net_proto_family smc_sock_family_ops = { 1733ac713874SUrsula Braun .family = PF_SMC, 1734ac713874SUrsula Braun .owner = THIS_MODULE, 1735ac713874SUrsula Braun .create = smc_create, 1736ac713874SUrsula Braun }; 1737ac713874SUrsula Braun 1738ac713874SUrsula Braun static int __init smc_init(void) 1739ac713874SUrsula Braun { 1740ac713874SUrsula Braun int rc; 1741ac713874SUrsula Braun 17426812baabSThomas Richter rc = smc_pnet_init(); 17436812baabSThomas Richter if (rc) 17446812baabSThomas Richter return rc; 17456812baabSThomas Richter 17469bf9abeaSUrsula Braun rc = smc_llc_init(); 17479bf9abeaSUrsula Braun if (rc) { 17489bf9abeaSUrsula Braun pr_err("%s: smc_llc_init fails with %d\n", __func__, rc); 17499bf9abeaSUrsula Braun goto out_pnet; 17509bf9abeaSUrsula Braun } 17519bf9abeaSUrsula Braun 17525f08318fSUrsula Braun rc = smc_cdc_init(); 17535f08318fSUrsula Braun if (rc) { 17545f08318fSUrsula Braun pr_err("%s: smc_cdc_init fails with %d\n", __func__, rc); 17555f08318fSUrsula Braun goto out_pnet; 17565f08318fSUrsula Braun } 17575f08318fSUrsula Braun 1758ac713874SUrsula Braun rc = proto_register(&smc_proto, 1); 1759ac713874SUrsula Braun if (rc) { 1760aaa4d33fSKarsten Graul pr_err("%s: proto_register(v4) fails with %d\n", __func__, rc); 17616812baabSThomas Richter goto out_pnet; 1762ac713874SUrsula Braun } 1763ac713874SUrsula Braun 1764aaa4d33fSKarsten Graul rc = proto_register(&smc_proto6, 1); 1765aaa4d33fSKarsten Graul if (rc) { 1766aaa4d33fSKarsten Graul pr_err("%s: proto_register(v6) fails with %d\n", __func__, rc); 1767aaa4d33fSKarsten Graul goto out_proto; 1768aaa4d33fSKarsten Graul } 1769aaa4d33fSKarsten Graul 1770ac713874SUrsula Braun rc = sock_register(&smc_sock_family_ops); 1771ac713874SUrsula Braun if (rc) { 1772ac713874SUrsula Braun pr_err("%s: sock_register fails with %d\n", __func__, rc); 1773aaa4d33fSKarsten Graul goto out_proto6; 1774ac713874SUrsula Braun } 1775f16a7dd5SUrsula Braun INIT_HLIST_HEAD(&smc_v4_hashinfo.ht); 1776aaa4d33fSKarsten Graul INIT_HLIST_HEAD(&smc_v6_hashinfo.ht); 1777ac713874SUrsula Braun 1778a4cf0443SUrsula Braun rc = smc_ib_register_client(); 1779a4cf0443SUrsula Braun if (rc) { 1780a4cf0443SUrsula Braun pr_err("%s: ib_register fails with %d\n", __func__, rc); 1781a4cf0443SUrsula Braun goto out_sock; 1782a4cf0443SUrsula Braun } 1783a4cf0443SUrsula Braun 1784c5c1cc9cSUrsula Braun static_branch_enable(&tcp_have_smc); 1785ac713874SUrsula Braun return 0; 1786ac713874SUrsula Braun 1787a4cf0443SUrsula Braun out_sock: 1788a4cf0443SUrsula Braun sock_unregister(PF_SMC); 1789aaa4d33fSKarsten Graul out_proto6: 1790aaa4d33fSKarsten Graul proto_unregister(&smc_proto6); 1791ac713874SUrsula Braun out_proto: 1792ac713874SUrsula Braun proto_unregister(&smc_proto); 17936812baabSThomas Richter out_pnet: 17946812baabSThomas Richter smc_pnet_exit(); 1795ac713874SUrsula Braun return rc; 1796ac713874SUrsula Braun } 1797ac713874SUrsula Braun 1798ac713874SUrsula Braun static void __exit smc_exit(void) 1799ac713874SUrsula Braun { 18009fda3510SHans Wippel smc_core_exit(); 1801c5c1cc9cSUrsula Braun static_branch_disable(&tcp_have_smc); 1802a4cf0443SUrsula Braun smc_ib_unregister_client(); 1803ac713874SUrsula Braun sock_unregister(PF_SMC); 1804aaa4d33fSKarsten Graul proto_unregister(&smc_proto6); 1805ac713874SUrsula Braun proto_unregister(&smc_proto); 18066812baabSThomas Richter smc_pnet_exit(); 1807ac713874SUrsula Braun } 1808ac713874SUrsula Braun 1809ac713874SUrsula Braun module_init(smc_init); 1810ac713874SUrsula Braun module_exit(smc_exit); 1811ac713874SUrsula Braun 1812ac713874SUrsula Braun MODULE_AUTHOR("Ursula Braun <ubraun@linux.vnet.ibm.com>"); 1813ac713874SUrsula Braun MODULE_DESCRIPTION("smc socket address family"); 1814ac713874SUrsula Braun MODULE_LICENSE("GPL"); 1815ac713874SUrsula Braun MODULE_ALIAS_NETPROTO(PF_SMC); 1816