License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[linux-2.6-block.git] / net / smc / smc_clc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Shared Memory Communications over RDMA (SMC-R) and RoCE
4  *
5  *  CLC (connection layer control) handshake over initial TCP socket to
6  *  prepare for RDMA traffic
7  *
8  *  Copyright IBM Corp. 2016
9  *
10  *  Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
11  */
12
13 #include <linux/in.h>
14 #include <linux/if_ether.h>
15 #include <linux/sched/signal.h>
16
17 #include <net/sock.h>
18 #include <net/tcp.h>
19
20 #include "smc.h"
21 #include "smc_core.h"
22 #include "smc_clc.h"
23 #include "smc_ib.h"
24
25 /* Wait for data on the tcp-socket, analyze received data
26  * Returns:
27  * 0 if success and it was not a decline that we received.
28  * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
29  * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
30  */
31 int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
32                      u8 expected_type)
33 {
34         struct sock *clc_sk = smc->clcsock->sk;
35         struct smc_clc_msg_hdr *clcm = buf;
36         struct msghdr msg = {NULL, 0};
37         int reason_code = 0;
38         struct kvec vec;
39         int len, datlen;
40         int krflags;
41
42         /* peek the first few bytes to determine length of data to receive
43          * so we don't consume any subsequent CLC message or payload data
44          * in the TCP byte stream
45          */
46         vec.iov_base = buf;
47         vec.iov_len = buflen;
48         krflags = MSG_PEEK | MSG_WAITALL;
49         smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
50         len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1,
51                              sizeof(struct smc_clc_msg_hdr), krflags);
52         if (signal_pending(current)) {
53                 reason_code = -EINTR;
54                 clc_sk->sk_err = EINTR;
55                 smc->sk.sk_err = EINTR;
56                 goto out;
57         }
58         if (clc_sk->sk_err) {
59                 reason_code = -clc_sk->sk_err;
60                 smc->sk.sk_err = clc_sk->sk_err;
61                 goto out;
62         }
63         if (!len) { /* peer has performed orderly shutdown */
64                 smc->sk.sk_err = ECONNRESET;
65                 reason_code = -ECONNRESET;
66                 goto out;
67         }
68         if (len < 0) {
69                 smc->sk.sk_err = -len;
70                 reason_code = len;
71                 goto out;
72         }
73         datlen = ntohs(clcm->length);
74         if ((len < sizeof(struct smc_clc_msg_hdr)) ||
75             (datlen < sizeof(struct smc_clc_msg_decline)) ||
76             (datlen > sizeof(struct smc_clc_msg_accept_confirm)) ||
77             memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) ||
78             ((clcm->type != SMC_CLC_DECLINE) &&
79              (clcm->type != expected_type))) {
80                 smc->sk.sk_err = EPROTO;
81                 reason_code = -EPROTO;
82                 goto out;
83         }
84
85         /* receive the complete CLC message */
86         vec.iov_base = buf;
87         vec.iov_len = buflen;
88         memset(&msg, 0, sizeof(struct msghdr));
89         krflags = MSG_WAITALL;
90         smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
91         len = kernel_recvmsg(smc->clcsock, &msg, &vec, 1, datlen, krflags);
92         if (len < datlen) {
93                 smc->sk.sk_err = EPROTO;
94                 reason_code = -EPROTO;
95                 goto out;
96         }
97         if (clcm->type == SMC_CLC_DECLINE) {
98                 reason_code = SMC_CLC_DECL_REPLY;
99                 if (((struct smc_clc_msg_decline *)buf)->hdr.flag) {
100                         smc->conn.lgr->sync_err = true;
101                         smc_lgr_terminate(smc->conn.lgr);
102                 }
103         }
104
105 out:
106         return reason_code;
107 }
108
109 /* send CLC DECLINE message across internal TCP socket */
110 int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info)
111 {
112         struct smc_clc_msg_decline dclc;
113         struct msghdr msg;
114         struct kvec vec;
115         int len;
116
117         memset(&dclc, 0, sizeof(dclc));
118         memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
119         dclc.hdr.type = SMC_CLC_DECLINE;
120         dclc.hdr.length = htons(sizeof(struct smc_clc_msg_decline));
121         dclc.hdr.version = SMC_CLC_V1;
122         dclc.hdr.flag = (peer_diag_info == SMC_CLC_DECL_SYNCERR) ? 1 : 0;
123         memcpy(dclc.id_for_peer, local_systemid, sizeof(local_systemid));
124         dclc.peer_diagnosis = htonl(peer_diag_info);
125         memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
126
127         memset(&msg, 0, sizeof(msg));
128         vec.iov_base = &dclc;
129         vec.iov_len = sizeof(struct smc_clc_msg_decline);
130         len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
131                              sizeof(struct smc_clc_msg_decline));
132         if (len < sizeof(struct smc_clc_msg_decline))
133                 smc->sk.sk_err = EPROTO;
134         if (len < 0)
135                 smc->sk.sk_err = -len;
136         return len;
137 }
138
139 /* send CLC PROPOSAL message across internal TCP socket */
140 int smc_clc_send_proposal(struct smc_sock *smc,
141                           struct smc_ib_device *smcibdev,
142                           u8 ibport)
143 {
144         struct smc_clc_msg_proposal pclc;
145         int reason_code = 0;
146         struct msghdr msg;
147         struct kvec vec;
148         int len, rc;
149
150         /* send SMC Proposal CLC message */
151         memset(&pclc, 0, sizeof(pclc));
152         memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
153         pclc.hdr.type = SMC_CLC_PROPOSAL;
154         pclc.hdr.length = htons(sizeof(pclc));
155         pclc.hdr.version = SMC_CLC_V1;          /* SMC version */
156         memcpy(pclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
157         memcpy(&pclc.lcl.gid, &smcibdev->gid[ibport - 1], SMC_GID_SIZE);
158         memcpy(&pclc.lcl.mac, &smcibdev->mac[ibport - 1], ETH_ALEN);
159
160         /* determine subnet and mask from internal TCP socket */
161         rc = smc_netinfo_by_tcpsk(smc->clcsock, &pclc.outgoing_subnet,
162                                   &pclc.prefix_len);
163         if (rc)
164                 return SMC_CLC_DECL_CNFERR; /* configuration error */
165         memcpy(pclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
166         memset(&msg, 0, sizeof(msg));
167         vec.iov_base = &pclc;
168         vec.iov_len = sizeof(pclc);
169         /* due to the few bytes needed for clc-handshake this cannot block */
170         len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(pclc));
171         if (len < sizeof(pclc)) {
172                 if (len >= 0) {
173                         reason_code = -ENETUNREACH;
174                         smc->sk.sk_err = -reason_code;
175                 } else {
176                         smc->sk.sk_err = smc->clcsock->sk->sk_err;
177                         reason_code = -smc->sk.sk_err;
178                 }
179         }
180
181         return reason_code;
182 }
183
184 /* send CLC CONFIRM message across internal TCP socket */
185 int smc_clc_send_confirm(struct smc_sock *smc)
186 {
187         struct smc_connection *conn = &smc->conn;
188         struct smc_clc_msg_accept_confirm cclc;
189         struct smc_link *link;
190         int reason_code = 0;
191         struct msghdr msg;
192         struct kvec vec;
193         int len;
194
195         link = &conn->lgr->lnk[SMC_SINGLE_LINK];
196         /* send SMC Confirm CLC msg */
197         memset(&cclc, 0, sizeof(cclc));
198         memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
199         cclc.hdr.type = SMC_CLC_CONFIRM;
200         cclc.hdr.length = htons(sizeof(cclc));
201         cclc.hdr.version = SMC_CLC_V1;          /* SMC version */
202         memcpy(cclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
203         memcpy(&cclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
204                SMC_GID_SIZE);
205         memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
206         hton24(cclc.qpn, link->roce_qp->qp_num);
207         cclc.rmb_rkey =
208                 htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
209         cclc.conn_idx = 1; /* for now: 1 RMB = 1 RMBE */
210         cclc.rmbe_alert_token = htonl(conn->alert_token_local);
211         cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
212         cclc.rmbe_size = conn->rmbe_size_short;
213         cclc.rmb_dma_addr = cpu_to_be64(
214                 (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
215         hton24(cclc.psn, link->psn_initial);
216
217         memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
218
219         memset(&msg, 0, sizeof(msg));
220         vec.iov_base = &cclc;
221         vec.iov_len = sizeof(cclc);
222         len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(cclc));
223         if (len < sizeof(cclc)) {
224                 if (len >= 0) {
225                         reason_code = -ENETUNREACH;
226                         smc->sk.sk_err = -reason_code;
227                 } else {
228                         smc->sk.sk_err = smc->clcsock->sk->sk_err;
229                         reason_code = -smc->sk.sk_err;
230                 }
231         }
232         return reason_code;
233 }
234
235 /* send CLC ACCEPT message across internal TCP socket */
236 int smc_clc_send_accept(struct smc_sock *new_smc, int srv_first_contact)
237 {
238         struct smc_connection *conn = &new_smc->conn;
239         struct smc_clc_msg_accept_confirm aclc;
240         struct smc_link *link;
241         struct msghdr msg;
242         struct kvec vec;
243         int rc = 0;
244         int len;
245
246         link = &conn->lgr->lnk[SMC_SINGLE_LINK];
247         memset(&aclc, 0, sizeof(aclc));
248         memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
249         aclc.hdr.type = SMC_CLC_ACCEPT;
250         aclc.hdr.length = htons(sizeof(aclc));
251         aclc.hdr.version = SMC_CLC_V1;          /* SMC version */
252         if (srv_first_contact)
253                 aclc.hdr.flag = 1;
254         memcpy(aclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
255         memcpy(&aclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
256                SMC_GID_SIZE);
257         memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
258         hton24(aclc.qpn, link->roce_qp->qp_num);
259         aclc.rmb_rkey =
260                 htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
261         aclc.conn_idx = 1;                      /* as long as 1 RMB = 1 RMBE */
262         aclc.rmbe_alert_token = htonl(conn->alert_token_local);
263         aclc.qp_mtu = link->path_mtu;
264         aclc.rmbe_size = conn->rmbe_size_short,
265         aclc.rmb_dma_addr = cpu_to_be64(
266                 (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
267         hton24(aclc.psn, link->psn_initial);
268         memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
269
270         memset(&msg, 0, sizeof(msg));
271         vec.iov_base = &aclc;
272         vec.iov_len = sizeof(aclc);
273         len = kernel_sendmsg(new_smc->clcsock, &msg, &vec, 1, sizeof(aclc));
274         if (len < sizeof(aclc)) {
275                 if (len >= 0)
276                         new_smc->sk.sk_err = EPROTO;
277                 else
278                         new_smc->sk.sk_err = new_smc->clcsock->sk->sk_err;
279                 rc = sock_error(&new_smc->sk);
280         }
281
282         return rc;
283 }