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