1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Shared Memory Communications over RDMA (SMC-R) and RoCE 4 * 5 * Definitions for the IPPROTO_SMC (socket related) 6 * 7 * Copyright IBM Corp. 2016, 2018 8 * Copyright (c) 2024, Alibaba Inc. 9 * 10 * Author: D. Wythe <alibuda@linux.alibaba.com> 11 */ 12 13 #include <net/protocol.h> 14 #include <net/sock.h> 15 16 #include "smc_inet.h" 17 #include "smc.h" 18 #include "smc_close.h" 19 20 static int smc_inet_init_sock(struct sock *sk); 21 static void smc_inet_destroy_sock(struct sock *sk); 22 23 static struct proto smc_inet_prot = { 24 .name = "INET_SMC", 25 .owner = THIS_MODULE, 26 .init = smc_inet_init_sock, 27 .destroy = smc_inet_destroy_sock, 28 .hash = smc_hash_sk, 29 .unhash = smc_unhash_sk, 30 .release_cb = smc_release_cb, 31 .obj_size = sizeof(struct smc_sock), 32 .h.smc_hash = &smc_v4_hashinfo, 33 .slab_flags = SLAB_TYPESAFE_BY_RCU, 34 }; 35 36 static const struct proto_ops smc_inet_stream_ops = { 37 .family = PF_INET, 38 .owner = THIS_MODULE, 39 .release = smc_release, 40 .bind = smc_bind, 41 .connect = smc_connect, 42 .socketpair = sock_no_socketpair, 43 .accept = smc_accept, 44 .getname = smc_getname, 45 .poll = smc_poll, 46 .ioctl = smc_ioctl, 47 .listen = smc_listen, 48 .shutdown = smc_shutdown, 49 .setsockopt = smc_setsockopt, 50 .getsockopt = smc_getsockopt, 51 .sendmsg = smc_sendmsg, 52 .recvmsg = smc_recvmsg, 53 .mmap = sock_no_mmap, 54 .splice_read = smc_splice_read, 55 }; 56 57 static struct inet_protosw smc_inet_protosw = { 58 .type = SOCK_STREAM, 59 .protocol = IPPROTO_SMC, 60 .prot = &smc_inet_prot, 61 .ops = &smc_inet_stream_ops, 62 }; 63 64 #if IS_ENABLED(CONFIG_IPV6) 65 struct smc6_sock { 66 struct smc_sock smc; 67 struct ipv6_pinfo inet6; 68 }; 69 70 static struct proto smc_inet6_prot = { 71 .name = "INET6_SMC", 72 .owner = THIS_MODULE, 73 .init = smc_inet_init_sock, 74 .destroy = smc_inet_destroy_sock, 75 .hash = smc_hash_sk, 76 .unhash = smc_unhash_sk, 77 .release_cb = smc_release_cb, 78 .obj_size = sizeof(struct smc6_sock), 79 .h.smc_hash = &smc_v6_hashinfo, 80 .slab_flags = SLAB_TYPESAFE_BY_RCU, 81 .ipv6_pinfo_offset = offsetof(struct smc6_sock, inet6), 82 }; 83 84 static const struct proto_ops smc_inet6_stream_ops = { 85 .family = PF_INET6, 86 .owner = THIS_MODULE, 87 .release = smc_release, 88 .bind = smc_bind, 89 .connect = smc_connect, 90 .socketpair = sock_no_socketpair, 91 .accept = smc_accept, 92 .getname = smc_getname, 93 .poll = smc_poll, 94 .ioctl = smc_ioctl, 95 .listen = smc_listen, 96 .shutdown = smc_shutdown, 97 .setsockopt = smc_setsockopt, 98 .getsockopt = smc_getsockopt, 99 .sendmsg = smc_sendmsg, 100 .recvmsg = smc_recvmsg, 101 .mmap = sock_no_mmap, 102 .splice_read = smc_splice_read, 103 }; 104 105 static struct inet_protosw smc_inet6_protosw = { 106 .type = SOCK_STREAM, 107 .protocol = IPPROTO_SMC, 108 .prot = &smc_inet6_prot, 109 .ops = &smc_inet6_stream_ops, 110 }; 111 #endif /* CONFIG_IPV6 */ 112 113 static int smc_inet_init_sock(struct sock *sk) 114 { 115 struct net *net = sock_net(sk); 116 117 /* init common smc sock */ 118 smc_sk_init(net, sk, IPPROTO_SMC); 119 /* create clcsock */ 120 return smc_create_clcsk(net, sk, sk->sk_family); 121 } 122 123 static void smc_inet_destroy_sock(struct sock *sk) 124 { 125 /* The sock is hashed and smc_diag dumps dereference smc->clcsock 126 * without clcsock_release_lock, while sk_common_release() calls 127 * .destroy before .unhash. Unhash first, as __smc_release() does, 128 * so no dump can observe the clcsock being released; the second 129 * unhash is a no-op. 130 */ 131 sk->sk_prot->unhash(sk); 132 smc_clcsock_release(smc_sk(sk)); 133 } 134 135 int __init smc_inet_init(void) 136 { 137 int rc; 138 139 rc = proto_register(&smc_inet_prot, 1); 140 if (rc) { 141 pr_err("%s: proto_register smc_inet_prot fails with %d\n", 142 __func__, rc); 143 return rc; 144 } 145 /* no return value */ 146 inet_register_protosw(&smc_inet_protosw); 147 148 #if IS_ENABLED(CONFIG_IPV6) 149 rc = proto_register(&smc_inet6_prot, 1); 150 if (rc) { 151 pr_err("%s: proto_register smc_inet6_prot fails with %d\n", 152 __func__, rc); 153 goto out_inet6_prot; 154 } 155 rc = inet6_register_protosw(&smc_inet6_protosw); 156 if (rc) { 157 pr_err("%s: inet6_register_protosw smc_inet6_protosw fails with %d\n", 158 __func__, rc); 159 goto out_inet6_protosw; 160 } 161 return rc; 162 out_inet6_protosw: 163 proto_unregister(&smc_inet6_prot); 164 out_inet6_prot: 165 inet_unregister_protosw(&smc_inet_protosw); 166 proto_unregister(&smc_inet_prot); 167 #endif /* CONFIG_IPV6 */ 168 return rc; 169 } 170 171 void smc_inet_exit(void) 172 { 173 #if IS_ENABLED(CONFIG_IPV6) 174 inet6_unregister_protosw(&smc_inet6_protosw); 175 proto_unregister(&smc_inet6_prot); 176 #endif /* CONFIG_IPV6 */ 177 inet_unregister_protosw(&smc_inet_protosw); 178 proto_unregister(&smc_inet_prot); 179 } 180