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
smc_inet_init_sock(struct sock * sk)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
smc_inet_destroy_sock(struct sock * sk)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
smc_inet_init(void)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
smc_inet_exit(void)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