1 // SPDX-License-Identifier: GPL-2.0
3 * Shared Memory Communications over RDMA (SMC-R) and RoCE
5 * CLC (connection layer control) handshake over initial TCP socket to
6 * prepare for RDMA traffic
8 * Copyright IBM Corp. 2016, 2018
10 * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com>
14 #include <linux/inetdevice.h>
15 #include <linux/if_ether.h>
16 #include <linux/sched/signal.h>
18 #include <net/addrconf.h>
28 #define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
29 #define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
31 /* eye catcher "SMCR" EBCDIC for CLC messages */
32 static const char SMC_EYECATCHER
[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
33 /* eye catcher "SMCD" EBCDIC for CLC messages */
34 static const char SMCD_EYECATCHER
[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
36 /* check if received message has a correct header length and contains valid
37 * heading and trailing eyecatchers
39 static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr
*clcm
)
41 struct smc_clc_msg_proposal_prefix
*pclc_prfx
;
42 struct smc_clc_msg_accept_confirm
*clc
;
43 struct smc_clc_msg_proposal
*pclc
;
44 struct smc_clc_msg_decline
*dclc
;
45 struct smc_clc_msg_trail
*trl
;
47 if (memcmp(clcm
->eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
)) &&
48 memcmp(clcm
->eyecatcher
, SMCD_EYECATCHER
, sizeof(SMCD_EYECATCHER
)))
51 case SMC_CLC_PROPOSAL
:
52 if (clcm
->path
!= SMC_TYPE_R
&& clcm
->path
!= SMC_TYPE_D
&&
53 clcm
->path
!= SMC_TYPE_B
)
55 pclc
= (struct smc_clc_msg_proposal
*)clcm
;
56 pclc_prfx
= smc_clc_proposal_get_prefix(pclc
);
57 if (ntohs(pclc
->hdr
.length
) !=
58 sizeof(*pclc
) + ntohs(pclc
->iparea_offset
) +
60 pclc_prfx
->ipv6_prefixes_cnt
*
61 sizeof(struct smc_clc_ipv6_prefix
) +
64 trl
= (struct smc_clc_msg_trail
*)
65 ((u8
*)pclc
+ ntohs(pclc
->hdr
.length
) - sizeof(*trl
));
69 if (clcm
->path
!= SMC_TYPE_R
&& clcm
->path
!= SMC_TYPE_D
)
71 clc
= (struct smc_clc_msg_accept_confirm
*)clcm
;
72 if ((clcm
->path
== SMC_TYPE_R
&&
73 ntohs(clc
->hdr
.length
) != SMCR_CLC_ACCEPT_CONFIRM_LEN
) ||
74 (clcm
->path
== SMC_TYPE_D
&&
75 ntohs(clc
->hdr
.length
) != SMCD_CLC_ACCEPT_CONFIRM_LEN
))
77 trl
= (struct smc_clc_msg_trail
*)
78 ((u8
*)clc
+ ntohs(clc
->hdr
.length
) - sizeof(*trl
));
81 dclc
= (struct smc_clc_msg_decline
*)clcm
;
82 if (ntohs(dclc
->hdr
.length
) != sizeof(*dclc
))
89 if (memcmp(trl
->eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
)) &&
90 memcmp(trl
->eyecatcher
, SMCD_EYECATCHER
, sizeof(SMCD_EYECATCHER
)))
95 /* find ipv4 addr on device and get the prefix len, fill CLC proposal msg */
96 static int smc_clc_prfx_set4_rcu(struct dst_entry
*dst
, __be32 ipv4
,
97 struct smc_clc_msg_proposal_prefix
*prop
)
99 struct in_device
*in_dev
= __in_dev_get_rcu(dst
->dev
);
100 const struct in_ifaddr
*ifa
;
105 in_dev_for_each_ifa_rcu(ifa
, in_dev
) {
106 if (!inet_ifa_match(ipv4
, ifa
))
108 prop
->prefix_len
= inet_mask_len(ifa
->ifa_mask
);
109 prop
->outgoing_subnet
= ifa
->ifa_address
& ifa
->ifa_mask
;
110 /* prop->ipv6_prefixes_cnt = 0; already done by memset before */
116 /* fill CLC proposal msg with ipv6 prefixes from device */
117 static int smc_clc_prfx_set6_rcu(struct dst_entry
*dst
,
118 struct smc_clc_msg_proposal_prefix
*prop
,
119 struct smc_clc_ipv6_prefix
*ipv6_prfx
)
121 #if IS_ENABLED(CONFIG_IPV6)
122 struct inet6_dev
*in6_dev
= __in6_dev_get(dst
->dev
);
123 struct inet6_ifaddr
*ifa
;
128 /* use a maximum of 8 IPv6 prefixes from device */
129 list_for_each_entry(ifa
, &in6_dev
->addr_list
, if_list
) {
130 if (ipv6_addr_type(&ifa
->addr
) & IPV6_ADDR_LINKLOCAL
)
132 ipv6_addr_prefix(&ipv6_prfx
[cnt
].prefix
,
133 &ifa
->addr
, ifa
->prefix_len
);
134 ipv6_prfx
[cnt
].prefix_len
= ifa
->prefix_len
;
136 if (cnt
== SMC_CLC_MAX_V6_PREFIX
)
139 prop
->ipv6_prefixes_cnt
= cnt
;
146 /* retrieve and set prefixes in CLC proposal msg */
147 static int smc_clc_prfx_set(struct socket
*clcsock
,
148 struct smc_clc_msg_proposal_prefix
*prop
,
149 struct smc_clc_ipv6_prefix
*ipv6_prfx
)
151 struct dst_entry
*dst
= sk_dst_get(clcsock
->sk
);
152 struct sockaddr_storage addrs
;
153 struct sockaddr_in6
*addr6
;
154 struct sockaddr_in
*addr
;
157 memset(prop
, 0, sizeof(*prop
));
166 /* get address to which the internal TCP socket is bound */
167 kernel_getsockname(clcsock
, (struct sockaddr
*)&addrs
);
168 /* analyze IP specific data of net_device belonging to TCP socket */
169 addr6
= (struct sockaddr_in6
*)&addrs
;
171 if (addrs
.ss_family
== PF_INET
) {
173 addr
= (struct sockaddr_in
*)&addrs
;
174 rc
= smc_clc_prfx_set4_rcu(dst
, addr
->sin_addr
.s_addr
, prop
);
175 } else if (ipv6_addr_v4mapped(&addr6
->sin6_addr
)) {
176 /* mapped IPv4 address - peer is IPv4 only */
177 rc
= smc_clc_prfx_set4_rcu(dst
, addr6
->sin6_addr
.s6_addr32
[3],
181 rc
= smc_clc_prfx_set6_rcu(dst
, prop
, ipv6_prfx
);
190 /* match ipv4 addrs of dev against addr in CLC proposal */
191 static int smc_clc_prfx_match4_rcu(struct net_device
*dev
,
192 struct smc_clc_msg_proposal_prefix
*prop
)
194 struct in_device
*in_dev
= __in_dev_get_rcu(dev
);
195 const struct in_ifaddr
*ifa
;
199 in_dev_for_each_ifa_rcu(ifa
, in_dev
) {
200 if (prop
->prefix_len
== inet_mask_len(ifa
->ifa_mask
) &&
201 inet_ifa_match(prop
->outgoing_subnet
, ifa
))
208 /* match ipv6 addrs of dev against addrs in CLC proposal */
209 static int smc_clc_prfx_match6_rcu(struct net_device
*dev
,
210 struct smc_clc_msg_proposal_prefix
*prop
)
212 #if IS_ENABLED(CONFIG_IPV6)
213 struct inet6_dev
*in6_dev
= __in6_dev_get(dev
);
214 struct smc_clc_ipv6_prefix
*ipv6_prfx
;
215 struct inet6_ifaddr
*ifa
;
220 /* ipv6 prefix list starts behind smc_clc_msg_proposal_prefix */
221 ipv6_prfx
= (struct smc_clc_ipv6_prefix
*)((u8
*)prop
+ sizeof(*prop
));
222 max
= min_t(u8
, prop
->ipv6_prefixes_cnt
, SMC_CLC_MAX_V6_PREFIX
);
223 list_for_each_entry(ifa
, &in6_dev
->addr_list
, if_list
) {
224 if (ipv6_addr_type(&ifa
->addr
) & IPV6_ADDR_LINKLOCAL
)
226 for (i
= 0; i
< max
; i
++) {
227 if (ifa
->prefix_len
== ipv6_prfx
[i
].prefix_len
&&
228 ipv6_prefix_equal(&ifa
->addr
, &ipv6_prfx
[i
].prefix
,
237 /* check if proposed prefixes match one of our device prefixes */
238 int smc_clc_prfx_match(struct socket
*clcsock
,
239 struct smc_clc_msg_proposal_prefix
*prop
)
241 struct dst_entry
*dst
= sk_dst_get(clcsock
->sk
);
253 if (!prop
->ipv6_prefixes_cnt
)
254 rc
= smc_clc_prfx_match4_rcu(dst
->dev
, prop
);
256 rc
= smc_clc_prfx_match6_rcu(dst
->dev
, prop
);
264 /* Wait for data on the tcp-socket, analyze received data
266 * 0 if success and it was not a decline that we received.
267 * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
268 * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
270 int smc_clc_wait_msg(struct smc_sock
*smc
, void *buf
, int buflen
,
271 u8 expected_type
, unsigned long timeout
)
273 long rcvtimeo
= smc
->clcsock
->sk
->sk_rcvtimeo
;
274 struct sock
*clc_sk
= smc
->clcsock
->sk
;
275 struct smc_clc_msg_hdr
*clcm
= buf
;
276 struct msghdr msg
= {NULL
, 0};
278 struct kvec vec
= {buf
, buflen
};
282 /* peek the first few bytes to determine length of data to receive
283 * so we don't consume any subsequent CLC message or payload data
284 * in the TCP byte stream
287 * Caller must make sure that buflen is no less than
288 * sizeof(struct smc_clc_msg_hdr)
290 krflags
= MSG_PEEK
| MSG_WAITALL
;
291 clc_sk
->sk_rcvtimeo
= timeout
;
292 iov_iter_kvec(&msg
.msg_iter
, READ
, &vec
, 1,
293 sizeof(struct smc_clc_msg_hdr
));
294 len
= sock_recvmsg(smc
->clcsock
, &msg
, krflags
);
295 if (signal_pending(current
)) {
296 reason_code
= -EINTR
;
297 clc_sk
->sk_err
= EINTR
;
298 smc
->sk
.sk_err
= EINTR
;
301 if (clc_sk
->sk_err
) {
302 reason_code
= -clc_sk
->sk_err
;
303 if (clc_sk
->sk_err
== EAGAIN
&&
304 expected_type
== SMC_CLC_DECLINE
)
305 clc_sk
->sk_err
= 0; /* reset for fallback usage */
307 smc
->sk
.sk_err
= clc_sk
->sk_err
;
310 if (!len
) { /* peer has performed orderly shutdown */
311 smc
->sk
.sk_err
= ECONNRESET
;
312 reason_code
= -ECONNRESET
;
316 if (len
!= -EAGAIN
|| expected_type
!= SMC_CLC_DECLINE
)
317 smc
->sk
.sk_err
= -len
;
321 datlen
= ntohs(clcm
->length
);
322 if ((len
< sizeof(struct smc_clc_msg_hdr
)) ||
324 (clcm
->version
!= SMC_CLC_V1
) ||
325 (clcm
->path
!= SMC_TYPE_R
&& clcm
->path
!= SMC_TYPE_D
&&
326 clcm
->path
!= SMC_TYPE_B
) ||
327 ((clcm
->type
!= SMC_CLC_DECLINE
) &&
328 (clcm
->type
!= expected_type
))) {
329 smc
->sk
.sk_err
= EPROTO
;
330 reason_code
= -EPROTO
;
334 /* receive the complete CLC message */
335 memset(&msg
, 0, sizeof(struct msghdr
));
336 iov_iter_kvec(&msg
.msg_iter
, READ
, &vec
, 1, datlen
);
337 krflags
= MSG_WAITALL
;
338 len
= sock_recvmsg(smc
->clcsock
, &msg
, krflags
);
339 if (len
< datlen
|| !smc_clc_msg_hdr_valid(clcm
)) {
340 smc
->sk
.sk_err
= EPROTO
;
341 reason_code
= -EPROTO
;
344 if (clcm
->type
== SMC_CLC_DECLINE
) {
345 struct smc_clc_msg_decline
*dclc
;
347 dclc
= (struct smc_clc_msg_decline
*)clcm
;
348 reason_code
= SMC_CLC_DECL_PEERDECL
;
349 smc
->peer_diagnosis
= ntohl(dclc
->peer_diagnosis
);
350 if (((struct smc_clc_msg_decline
*)buf
)->hdr
.flag
) {
351 smc
->conn
.lgr
->sync_err
= 1;
352 smc_lgr_terminate(smc
->conn
.lgr
);
357 clc_sk
->sk_rcvtimeo
= rcvtimeo
;
361 /* send CLC DECLINE message across internal TCP socket */
362 int smc_clc_send_decline(struct smc_sock
*smc
, u32 peer_diag_info
)
364 struct smc_clc_msg_decline dclc
;
369 memset(&dclc
, 0, sizeof(dclc
));
370 memcpy(dclc
.hdr
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
371 dclc
.hdr
.type
= SMC_CLC_DECLINE
;
372 dclc
.hdr
.length
= htons(sizeof(struct smc_clc_msg_decline
));
373 dclc
.hdr
.version
= SMC_CLC_V1
;
374 dclc
.hdr
.flag
= (peer_diag_info
== SMC_CLC_DECL_SYNCERR
) ? 1 : 0;
375 memcpy(dclc
.id_for_peer
, local_systemid
, sizeof(local_systemid
));
376 dclc
.peer_diagnosis
= htonl(peer_diag_info
);
377 memcpy(dclc
.trl
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
379 memset(&msg
, 0, sizeof(msg
));
380 vec
.iov_base
= &dclc
;
381 vec
.iov_len
= sizeof(struct smc_clc_msg_decline
);
382 len
= kernel_sendmsg(smc
->clcsock
, &msg
, &vec
, 1,
383 sizeof(struct smc_clc_msg_decline
));
384 if (len
< 0 || len
< sizeof(struct smc_clc_msg_decline
))
386 return len
> 0 ? 0 : len
;
389 /* send CLC PROPOSAL message across internal TCP socket */
390 int smc_clc_send_proposal(struct smc_sock
*smc
, int smc_type
,
391 struct smc_init_info
*ini
)
393 struct smc_clc_ipv6_prefix ipv6_prfx
[SMC_CLC_MAX_V6_PREFIX
];
394 struct smc_clc_msg_proposal_prefix pclc_prfx
;
395 struct smc_clc_msg_smcd pclc_smcd
;
396 struct smc_clc_msg_proposal pclc
;
397 struct smc_clc_msg_trail trl
;
398 int len
, i
, plen
, rc
;
403 /* retrieve ip prefixes for CLC proposal msg */
404 rc
= smc_clc_prfx_set(smc
->clcsock
, &pclc_prfx
, ipv6_prfx
);
406 return SMC_CLC_DECL_CNFERR
; /* configuration error */
408 /* send SMC Proposal CLC message */
409 plen
= sizeof(pclc
) + sizeof(pclc_prfx
) +
410 (pclc_prfx
.ipv6_prefixes_cnt
* sizeof(ipv6_prfx
[0])) +
412 memset(&pclc
, 0, sizeof(pclc
));
413 memcpy(pclc
.hdr
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
414 pclc
.hdr
.type
= SMC_CLC_PROPOSAL
;
415 pclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
416 pclc
.hdr
.path
= smc_type
;
417 if (smc_type
== SMC_TYPE_R
|| smc_type
== SMC_TYPE_B
) {
418 /* add SMC-R specifics */
419 memcpy(pclc
.lcl
.id_for_peer
, local_systemid
,
420 sizeof(local_systemid
));
421 memcpy(&pclc
.lcl
.gid
, ini
->ib_gid
, SMC_GID_SIZE
);
422 memcpy(&pclc
.lcl
.mac
, &ini
->ib_dev
->mac
[ini
->ib_port
- 1],
424 pclc
.iparea_offset
= htons(0);
426 if (smc_type
== SMC_TYPE_D
|| smc_type
== SMC_TYPE_B
) {
427 /* add SMC-D specifics */
428 memset(&pclc_smcd
, 0, sizeof(pclc_smcd
));
429 plen
+= sizeof(pclc_smcd
);
430 pclc
.iparea_offset
= htons(SMC_CLC_PROPOSAL_MAX_OFFSET
);
431 pclc_smcd
.gid
= ini
->ism_dev
->local_gid
;
433 pclc
.hdr
.length
= htons(plen
);
435 memcpy(trl
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
436 memset(&msg
, 0, sizeof(msg
));
438 vec
[i
].iov_base
= &pclc
;
439 vec
[i
++].iov_len
= sizeof(pclc
);
440 if (smc_type
== SMC_TYPE_D
|| smc_type
== SMC_TYPE_B
) {
441 vec
[i
].iov_base
= &pclc_smcd
;
442 vec
[i
++].iov_len
= sizeof(pclc_smcd
);
444 vec
[i
].iov_base
= &pclc_prfx
;
445 vec
[i
++].iov_len
= sizeof(pclc_prfx
);
446 if (pclc_prfx
.ipv6_prefixes_cnt
> 0) {
447 vec
[i
].iov_base
= &ipv6_prfx
[0];
448 vec
[i
++].iov_len
= pclc_prfx
.ipv6_prefixes_cnt
*
449 sizeof(ipv6_prfx
[0]);
451 vec
[i
].iov_base
= &trl
;
452 vec
[i
++].iov_len
= sizeof(trl
);
453 /* due to the few bytes needed for clc-handshake this cannot block */
454 len
= kernel_sendmsg(smc
->clcsock
, &msg
, vec
, i
, plen
);
456 smc
->sk
.sk_err
= smc
->clcsock
->sk
->sk_err
;
457 reason_code
= -smc
->sk
.sk_err
;
458 } else if (len
< (int)sizeof(pclc
)) {
459 reason_code
= -ENETUNREACH
;
460 smc
->sk
.sk_err
= -reason_code
;
466 /* send CLC CONFIRM message across internal TCP socket */
467 int smc_clc_send_confirm(struct smc_sock
*smc
)
469 struct smc_connection
*conn
= &smc
->conn
;
470 struct smc_clc_msg_accept_confirm cclc
;
471 struct smc_link
*link
;
477 /* send SMC Confirm CLC msg */
478 memset(&cclc
, 0, sizeof(cclc
));
479 cclc
.hdr
.type
= SMC_CLC_CONFIRM
;
480 cclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
481 if (smc
->conn
.lgr
->is_smcd
) {
482 /* SMC-D specific settings */
483 memcpy(cclc
.hdr
.eyecatcher
, SMCD_EYECATCHER
,
484 sizeof(SMCD_EYECATCHER
));
485 cclc
.hdr
.path
= SMC_TYPE_D
;
486 cclc
.hdr
.length
= htons(SMCD_CLC_ACCEPT_CONFIRM_LEN
);
487 cclc
.gid
= conn
->lgr
->smcd
->local_gid
;
488 cclc
.token
= conn
->rmb_desc
->token
;
489 cclc
.dmbe_size
= conn
->rmbe_size_short
;
491 memcpy(&cclc
.linkid
, conn
->lgr
->id
, SMC_LGR_ID_SIZE
);
492 memcpy(cclc
.smcd_trl
.eyecatcher
, SMCD_EYECATCHER
,
493 sizeof(SMCD_EYECATCHER
));
495 /* SMC-R specific settings */
496 link
= &conn
->lgr
->lnk
[SMC_SINGLE_LINK
];
497 memcpy(cclc
.hdr
.eyecatcher
, SMC_EYECATCHER
,
498 sizeof(SMC_EYECATCHER
));
499 cclc
.hdr
.path
= SMC_TYPE_R
;
500 cclc
.hdr
.length
= htons(SMCR_CLC_ACCEPT_CONFIRM_LEN
);
501 memcpy(cclc
.lcl
.id_for_peer
, local_systemid
,
502 sizeof(local_systemid
));
503 memcpy(&cclc
.lcl
.gid
, link
->gid
, SMC_GID_SIZE
);
504 memcpy(&cclc
.lcl
.mac
, &link
->smcibdev
->mac
[link
->ibport
- 1],
506 hton24(cclc
.qpn
, link
->roce_qp
->qp_num
);
508 htonl(conn
->rmb_desc
->mr_rx
[SMC_SINGLE_LINK
]->rkey
);
509 cclc
.rmbe_idx
= 1; /* for now: 1 RMB = 1 RMBE */
510 cclc
.rmbe_alert_token
= htonl(conn
->alert_token_local
);
511 cclc
.qp_mtu
= min(link
->path_mtu
, link
->peer_mtu
);
512 cclc
.rmbe_size
= conn
->rmbe_size_short
;
513 cclc
.rmb_dma_addr
= cpu_to_be64((u64
)sg_dma_address
514 (conn
->rmb_desc
->sgt
[SMC_SINGLE_LINK
].sgl
));
515 hton24(cclc
.psn
, link
->psn_initial
);
516 memcpy(cclc
.smcr_trl
.eyecatcher
, SMC_EYECATCHER
,
517 sizeof(SMC_EYECATCHER
));
520 memset(&msg
, 0, sizeof(msg
));
521 vec
.iov_base
= &cclc
;
522 vec
.iov_len
= ntohs(cclc
.hdr
.length
);
523 len
= kernel_sendmsg(smc
->clcsock
, &msg
, &vec
, 1,
524 ntohs(cclc
.hdr
.length
));
525 if (len
< ntohs(cclc
.hdr
.length
)) {
527 reason_code
= -ENETUNREACH
;
528 smc
->sk
.sk_err
= -reason_code
;
530 smc
->sk
.sk_err
= smc
->clcsock
->sk
->sk_err
;
531 reason_code
= -smc
->sk
.sk_err
;
537 /* send CLC ACCEPT message across internal TCP socket */
538 int smc_clc_send_accept(struct smc_sock
*new_smc
, int srv_first_contact
)
540 struct smc_connection
*conn
= &new_smc
->conn
;
541 struct smc_clc_msg_accept_confirm aclc
;
542 struct smc_link
*link
;
547 memset(&aclc
, 0, sizeof(aclc
));
548 aclc
.hdr
.type
= SMC_CLC_ACCEPT
;
549 aclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
550 if (srv_first_contact
)
553 if (new_smc
->conn
.lgr
->is_smcd
) {
554 /* SMC-D specific settings */
555 aclc
.hdr
.length
= htons(SMCD_CLC_ACCEPT_CONFIRM_LEN
);
556 memcpy(aclc
.hdr
.eyecatcher
, SMCD_EYECATCHER
,
557 sizeof(SMCD_EYECATCHER
));
558 aclc
.hdr
.path
= SMC_TYPE_D
;
559 aclc
.gid
= conn
->lgr
->smcd
->local_gid
;
560 aclc
.token
= conn
->rmb_desc
->token
;
561 aclc
.dmbe_size
= conn
->rmbe_size_short
;
563 memcpy(&aclc
.linkid
, conn
->lgr
->id
, SMC_LGR_ID_SIZE
);
564 memcpy(aclc
.smcd_trl
.eyecatcher
, SMCD_EYECATCHER
,
565 sizeof(SMCD_EYECATCHER
));
567 /* SMC-R specific settings */
568 aclc
.hdr
.length
= htons(SMCR_CLC_ACCEPT_CONFIRM_LEN
);
569 memcpy(aclc
.hdr
.eyecatcher
, SMC_EYECATCHER
,
570 sizeof(SMC_EYECATCHER
));
571 aclc
.hdr
.path
= SMC_TYPE_R
;
572 link
= &conn
->lgr
->lnk
[SMC_SINGLE_LINK
];
573 memcpy(aclc
.lcl
.id_for_peer
, local_systemid
,
574 sizeof(local_systemid
));
575 memcpy(&aclc
.lcl
.gid
, link
->gid
, SMC_GID_SIZE
);
576 memcpy(&aclc
.lcl
.mac
, link
->smcibdev
->mac
[link
->ibport
- 1],
578 hton24(aclc
.qpn
, link
->roce_qp
->qp_num
);
580 htonl(conn
->rmb_desc
->mr_rx
[SMC_SINGLE_LINK
]->rkey
);
581 aclc
.rmbe_idx
= 1; /* as long as 1 RMB = 1 RMBE */
582 aclc
.rmbe_alert_token
= htonl(conn
->alert_token_local
);
583 aclc
.qp_mtu
= link
->path_mtu
;
584 aclc
.rmbe_size
= conn
->rmbe_size_short
,
585 aclc
.rmb_dma_addr
= cpu_to_be64((u64
)sg_dma_address
586 (conn
->rmb_desc
->sgt
[SMC_SINGLE_LINK
].sgl
));
587 hton24(aclc
.psn
, link
->psn_initial
);
588 memcpy(aclc
.smcr_trl
.eyecatcher
, SMC_EYECATCHER
,
589 sizeof(SMC_EYECATCHER
));
592 memset(&msg
, 0, sizeof(msg
));
593 vec
.iov_base
= &aclc
;
594 vec
.iov_len
= ntohs(aclc
.hdr
.length
);
595 len
= kernel_sendmsg(new_smc
->clcsock
, &msg
, &vec
, 1,
596 ntohs(aclc
.hdr
.length
));
597 if (len
< ntohs(aclc
.hdr
.length
))
598 len
= len
>= 0 ? -EPROTO
: -new_smc
->clcsock
->sk
->sk_err
;
600 return len
> 0 ? 0 : len
;