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
);
104 if (!inet_ifa_match(ipv4
, ifa
))
106 prop
->prefix_len
= inet_mask_len(ifa
->ifa_mask
);
107 prop
->outgoing_subnet
= ifa
->ifa_address
& ifa
->ifa_mask
;
108 /* prop->ipv6_prefixes_cnt = 0; already done by memset before */
110 } endfor_ifa(in_dev
);
114 /* fill CLC proposal msg with ipv6 prefixes from device */
115 static int smc_clc_prfx_set6_rcu(struct dst_entry
*dst
,
116 struct smc_clc_msg_proposal_prefix
*prop
,
117 struct smc_clc_ipv6_prefix
*ipv6_prfx
)
119 #if IS_ENABLED(CONFIG_IPV6)
120 struct inet6_dev
*in6_dev
= __in6_dev_get(dst
->dev
);
121 struct inet6_ifaddr
*ifa
;
126 /* use a maximum of 8 IPv6 prefixes from device */
127 list_for_each_entry(ifa
, &in6_dev
->addr_list
, if_list
) {
128 if (ipv6_addr_type(&ifa
->addr
) & IPV6_ADDR_LINKLOCAL
)
130 ipv6_addr_prefix(&ipv6_prfx
[cnt
].prefix
,
131 &ifa
->addr
, ifa
->prefix_len
);
132 ipv6_prfx
[cnt
].prefix_len
= ifa
->prefix_len
;
134 if (cnt
== SMC_CLC_MAX_V6_PREFIX
)
137 prop
->ipv6_prefixes_cnt
= cnt
;
144 /* retrieve and set prefixes in CLC proposal msg */
145 static int smc_clc_prfx_set(struct socket
*clcsock
,
146 struct smc_clc_msg_proposal_prefix
*prop
,
147 struct smc_clc_ipv6_prefix
*ipv6_prfx
)
149 struct dst_entry
*dst
= sk_dst_get(clcsock
->sk
);
150 struct sockaddr_storage addrs
;
151 struct sockaddr_in6
*addr6
;
152 struct sockaddr_in
*addr
;
155 memset(prop
, 0, sizeof(*prop
));
164 /* get address to which the internal TCP socket is bound */
165 kernel_getsockname(clcsock
, (struct sockaddr
*)&addrs
);
166 /* analyze IP specific data of net_device belonging to TCP socket */
167 addr6
= (struct sockaddr_in6
*)&addrs
;
169 if (addrs
.ss_family
== PF_INET
) {
171 addr
= (struct sockaddr_in
*)&addrs
;
172 rc
= smc_clc_prfx_set4_rcu(dst
, addr
->sin_addr
.s_addr
, prop
);
173 } else if (ipv6_addr_v4mapped(&addr6
->sin6_addr
)) {
174 /* mapped IPv4 address - peer is IPv4 only */
175 rc
= smc_clc_prfx_set4_rcu(dst
, addr6
->sin6_addr
.s6_addr32
[3],
179 rc
= smc_clc_prfx_set6_rcu(dst
, prop
, ipv6_prfx
);
188 /* match ipv4 addrs of dev against addr in CLC proposal */
189 static int smc_clc_prfx_match4_rcu(struct net_device
*dev
,
190 struct smc_clc_msg_proposal_prefix
*prop
)
192 struct in_device
*in_dev
= __in_dev_get_rcu(dev
);
197 if (prop
->prefix_len
== inet_mask_len(ifa
->ifa_mask
) &&
198 inet_ifa_match(prop
->outgoing_subnet
, ifa
))
200 } endfor_ifa(in_dev
);
205 /* match ipv6 addrs of dev against addrs in CLC proposal */
206 static int smc_clc_prfx_match6_rcu(struct net_device
*dev
,
207 struct smc_clc_msg_proposal_prefix
*prop
)
209 #if IS_ENABLED(CONFIG_IPV6)
210 struct inet6_dev
*in6_dev
= __in6_dev_get(dev
);
211 struct smc_clc_ipv6_prefix
*ipv6_prfx
;
212 struct inet6_ifaddr
*ifa
;
217 /* ipv6 prefix list starts behind smc_clc_msg_proposal_prefix */
218 ipv6_prfx
= (struct smc_clc_ipv6_prefix
*)((u8
*)prop
+ sizeof(*prop
));
219 max
= min_t(u8
, prop
->ipv6_prefixes_cnt
, SMC_CLC_MAX_V6_PREFIX
);
220 list_for_each_entry(ifa
, &in6_dev
->addr_list
, if_list
) {
221 if (ipv6_addr_type(&ifa
->addr
) & IPV6_ADDR_LINKLOCAL
)
223 for (i
= 0; i
< max
; i
++) {
224 if (ifa
->prefix_len
== ipv6_prfx
[i
].prefix_len
&&
225 ipv6_prefix_equal(&ifa
->addr
, &ipv6_prfx
[i
].prefix
,
234 /* check if proposed prefixes match one of our device prefixes */
235 int smc_clc_prfx_match(struct socket
*clcsock
,
236 struct smc_clc_msg_proposal_prefix
*prop
)
238 struct dst_entry
*dst
= sk_dst_get(clcsock
->sk
);
250 if (!prop
->ipv6_prefixes_cnt
)
251 rc
= smc_clc_prfx_match4_rcu(dst
->dev
, prop
);
253 rc
= smc_clc_prfx_match6_rcu(dst
->dev
, prop
);
261 /* Wait for data on the tcp-socket, analyze received data
263 * 0 if success and it was not a decline that we received.
264 * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
265 * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
267 int smc_clc_wait_msg(struct smc_sock
*smc
, void *buf
, int buflen
,
268 u8 expected_type
, unsigned long timeout
)
270 long rcvtimeo
= smc
->clcsock
->sk
->sk_rcvtimeo
;
271 struct sock
*clc_sk
= smc
->clcsock
->sk
;
272 struct smc_clc_msg_hdr
*clcm
= buf
;
273 struct msghdr msg
= {NULL
, 0};
275 struct kvec vec
= {buf
, buflen
};
279 /* peek the first few bytes to determine length of data to receive
280 * so we don't consume any subsequent CLC message or payload data
281 * in the TCP byte stream
284 * Caller must make sure that buflen is no less than
285 * sizeof(struct smc_clc_msg_hdr)
287 krflags
= MSG_PEEK
| MSG_WAITALL
;
288 clc_sk
->sk_rcvtimeo
= timeout
;
289 iov_iter_kvec(&msg
.msg_iter
, READ
, &vec
, 1,
290 sizeof(struct smc_clc_msg_hdr
));
291 len
= sock_recvmsg(smc
->clcsock
, &msg
, krflags
);
292 if (signal_pending(current
)) {
293 reason_code
= -EINTR
;
294 clc_sk
->sk_err
= EINTR
;
295 smc
->sk
.sk_err
= EINTR
;
298 if (clc_sk
->sk_err
) {
299 reason_code
= -clc_sk
->sk_err
;
300 if (clc_sk
->sk_err
== EAGAIN
&&
301 expected_type
== SMC_CLC_DECLINE
)
302 clc_sk
->sk_err
= 0; /* reset for fallback usage */
304 smc
->sk
.sk_err
= clc_sk
->sk_err
;
307 if (!len
) { /* peer has performed orderly shutdown */
308 smc
->sk
.sk_err
= ECONNRESET
;
309 reason_code
= -ECONNRESET
;
313 if (len
!= -EAGAIN
|| expected_type
!= SMC_CLC_DECLINE
)
314 smc
->sk
.sk_err
= -len
;
318 datlen
= ntohs(clcm
->length
);
319 if ((len
< sizeof(struct smc_clc_msg_hdr
)) ||
321 (clcm
->version
!= SMC_CLC_V1
) ||
322 (clcm
->path
!= SMC_TYPE_R
&& clcm
->path
!= SMC_TYPE_D
&&
323 clcm
->path
!= SMC_TYPE_B
) ||
324 ((clcm
->type
!= SMC_CLC_DECLINE
) &&
325 (clcm
->type
!= expected_type
))) {
326 smc
->sk
.sk_err
= EPROTO
;
327 reason_code
= -EPROTO
;
331 /* receive the complete CLC message */
332 memset(&msg
, 0, sizeof(struct msghdr
));
333 iov_iter_kvec(&msg
.msg_iter
, READ
, &vec
, 1, datlen
);
334 krflags
= MSG_WAITALL
;
335 len
= sock_recvmsg(smc
->clcsock
, &msg
, krflags
);
336 if (len
< datlen
|| !smc_clc_msg_hdr_valid(clcm
)) {
337 smc
->sk
.sk_err
= EPROTO
;
338 reason_code
= -EPROTO
;
341 if (clcm
->type
== SMC_CLC_DECLINE
) {
342 struct smc_clc_msg_decline
*dclc
;
344 dclc
= (struct smc_clc_msg_decline
*)clcm
;
345 reason_code
= SMC_CLC_DECL_PEERDECL
;
346 smc
->peer_diagnosis
= ntohl(dclc
->peer_diagnosis
);
347 if (((struct smc_clc_msg_decline
*)buf
)->hdr
.flag
) {
348 smc
->conn
.lgr
->sync_err
= 1;
349 smc_lgr_terminate(smc
->conn
.lgr
);
354 clc_sk
->sk_rcvtimeo
= rcvtimeo
;
358 /* send CLC DECLINE message across internal TCP socket */
359 int smc_clc_send_decline(struct smc_sock
*smc
, u32 peer_diag_info
)
361 struct smc_clc_msg_decline dclc
;
366 memset(&dclc
, 0, sizeof(dclc
));
367 memcpy(dclc
.hdr
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
368 dclc
.hdr
.type
= SMC_CLC_DECLINE
;
369 dclc
.hdr
.length
= htons(sizeof(struct smc_clc_msg_decline
));
370 dclc
.hdr
.version
= SMC_CLC_V1
;
371 dclc
.hdr
.flag
= (peer_diag_info
== SMC_CLC_DECL_SYNCERR
) ? 1 : 0;
372 memcpy(dclc
.id_for_peer
, local_systemid
, sizeof(local_systemid
));
373 dclc
.peer_diagnosis
= htonl(peer_diag_info
);
374 memcpy(dclc
.trl
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
376 memset(&msg
, 0, sizeof(msg
));
377 vec
.iov_base
= &dclc
;
378 vec
.iov_len
= sizeof(struct smc_clc_msg_decline
);
379 len
= kernel_sendmsg(smc
->clcsock
, &msg
, &vec
, 1,
380 sizeof(struct smc_clc_msg_decline
));
381 if (len
< 0 || len
< sizeof(struct smc_clc_msg_decline
))
383 return len
> 0 ? 0 : len
;
386 /* send CLC PROPOSAL message across internal TCP socket */
387 int smc_clc_send_proposal(struct smc_sock
*smc
, int smc_type
,
388 struct smc_ib_device
*ibdev
, u8 ibport
, u8 gid
[],
389 struct smcd_dev
*ismdev
)
391 struct smc_clc_ipv6_prefix ipv6_prfx
[SMC_CLC_MAX_V6_PREFIX
];
392 struct smc_clc_msg_proposal_prefix pclc_prfx
;
393 struct smc_clc_msg_smcd pclc_smcd
;
394 struct smc_clc_msg_proposal pclc
;
395 struct smc_clc_msg_trail trl
;
396 int len
, i
, plen
, rc
;
401 /* retrieve ip prefixes for CLC proposal msg */
402 rc
= smc_clc_prfx_set(smc
->clcsock
, &pclc_prfx
, ipv6_prfx
);
404 return SMC_CLC_DECL_CNFERR
; /* configuration error */
406 /* send SMC Proposal CLC message */
407 plen
= sizeof(pclc
) + sizeof(pclc_prfx
) +
408 (pclc_prfx
.ipv6_prefixes_cnt
* sizeof(ipv6_prfx
[0])) +
410 memset(&pclc
, 0, sizeof(pclc
));
411 memcpy(pclc
.hdr
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
412 pclc
.hdr
.type
= SMC_CLC_PROPOSAL
;
413 pclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
414 pclc
.hdr
.path
= smc_type
;
415 if (smc_type
== SMC_TYPE_R
|| smc_type
== SMC_TYPE_B
) {
416 /* add SMC-R specifics */
417 memcpy(pclc
.lcl
.id_for_peer
, local_systemid
,
418 sizeof(local_systemid
));
419 memcpy(&pclc
.lcl
.gid
, gid
, SMC_GID_SIZE
);
420 memcpy(&pclc
.lcl
.mac
, &ibdev
->mac
[ibport
- 1], ETH_ALEN
);
421 pclc
.iparea_offset
= htons(0);
423 if (smc_type
== SMC_TYPE_D
|| smc_type
== SMC_TYPE_B
) {
424 /* add SMC-D specifics */
425 memset(&pclc_smcd
, 0, sizeof(pclc_smcd
));
426 plen
+= sizeof(pclc_smcd
);
427 pclc
.iparea_offset
= htons(SMC_CLC_PROPOSAL_MAX_OFFSET
);
428 pclc_smcd
.gid
= ismdev
->local_gid
;
430 pclc
.hdr
.length
= htons(plen
);
432 memcpy(trl
.eyecatcher
, SMC_EYECATCHER
, sizeof(SMC_EYECATCHER
));
433 memset(&msg
, 0, sizeof(msg
));
435 vec
[i
].iov_base
= &pclc
;
436 vec
[i
++].iov_len
= sizeof(pclc
);
437 if (smc_type
== SMC_TYPE_D
|| smc_type
== SMC_TYPE_B
) {
438 vec
[i
].iov_base
= &pclc_smcd
;
439 vec
[i
++].iov_len
= sizeof(pclc_smcd
);
441 vec
[i
].iov_base
= &pclc_prfx
;
442 vec
[i
++].iov_len
= sizeof(pclc_prfx
);
443 if (pclc_prfx
.ipv6_prefixes_cnt
> 0) {
444 vec
[i
].iov_base
= &ipv6_prfx
[0];
445 vec
[i
++].iov_len
= pclc_prfx
.ipv6_prefixes_cnt
*
446 sizeof(ipv6_prfx
[0]);
448 vec
[i
].iov_base
= &trl
;
449 vec
[i
++].iov_len
= sizeof(trl
);
450 /* due to the few bytes needed for clc-handshake this cannot block */
451 len
= kernel_sendmsg(smc
->clcsock
, &msg
, vec
, i
, plen
);
453 smc
->sk
.sk_err
= smc
->clcsock
->sk
->sk_err
;
454 reason_code
= -smc
->sk
.sk_err
;
455 } else if (len
< (int)sizeof(pclc
)) {
456 reason_code
= -ENETUNREACH
;
457 smc
->sk
.sk_err
= -reason_code
;
463 /* send CLC CONFIRM message across internal TCP socket */
464 int smc_clc_send_confirm(struct smc_sock
*smc
)
466 struct smc_connection
*conn
= &smc
->conn
;
467 struct smc_clc_msg_accept_confirm cclc
;
468 struct smc_link
*link
;
474 /* send SMC Confirm CLC msg */
475 memset(&cclc
, 0, sizeof(cclc
));
476 cclc
.hdr
.type
= SMC_CLC_CONFIRM
;
477 cclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
478 if (smc
->conn
.lgr
->is_smcd
) {
479 /* SMC-D specific settings */
480 memcpy(cclc
.hdr
.eyecatcher
, SMCD_EYECATCHER
,
481 sizeof(SMCD_EYECATCHER
));
482 cclc
.hdr
.path
= SMC_TYPE_D
;
483 cclc
.hdr
.length
= htons(SMCD_CLC_ACCEPT_CONFIRM_LEN
);
484 cclc
.gid
= conn
->lgr
->smcd
->local_gid
;
485 cclc
.token
= conn
->rmb_desc
->token
;
486 cclc
.dmbe_size
= conn
->rmbe_size_short
;
488 memcpy(&cclc
.linkid
, conn
->lgr
->id
, SMC_LGR_ID_SIZE
);
489 memcpy(cclc
.smcd_trl
.eyecatcher
, SMCD_EYECATCHER
,
490 sizeof(SMCD_EYECATCHER
));
492 /* SMC-R specific settings */
493 link
= &conn
->lgr
->lnk
[SMC_SINGLE_LINK
];
494 memcpy(cclc
.hdr
.eyecatcher
, SMC_EYECATCHER
,
495 sizeof(SMC_EYECATCHER
));
496 cclc
.hdr
.path
= SMC_TYPE_R
;
497 cclc
.hdr
.length
= htons(SMCR_CLC_ACCEPT_CONFIRM_LEN
);
498 memcpy(cclc
.lcl
.id_for_peer
, local_systemid
,
499 sizeof(local_systemid
));
500 memcpy(&cclc
.lcl
.gid
, link
->gid
, SMC_GID_SIZE
);
501 memcpy(&cclc
.lcl
.mac
, &link
->smcibdev
->mac
[link
->ibport
- 1],
503 hton24(cclc
.qpn
, link
->roce_qp
->qp_num
);
505 htonl(conn
->rmb_desc
->mr_rx
[SMC_SINGLE_LINK
]->rkey
);
506 cclc
.rmbe_idx
= 1; /* for now: 1 RMB = 1 RMBE */
507 cclc
.rmbe_alert_token
= htonl(conn
->alert_token_local
);
508 cclc
.qp_mtu
= min(link
->path_mtu
, link
->peer_mtu
);
509 cclc
.rmbe_size
= conn
->rmbe_size_short
;
510 cclc
.rmb_dma_addr
= cpu_to_be64((u64
)sg_dma_address
511 (conn
->rmb_desc
->sgt
[SMC_SINGLE_LINK
].sgl
));
512 hton24(cclc
.psn
, link
->psn_initial
);
513 memcpy(cclc
.smcr_trl
.eyecatcher
, SMC_EYECATCHER
,
514 sizeof(SMC_EYECATCHER
));
517 memset(&msg
, 0, sizeof(msg
));
518 vec
.iov_base
= &cclc
;
519 vec
.iov_len
= ntohs(cclc
.hdr
.length
);
520 len
= kernel_sendmsg(smc
->clcsock
, &msg
, &vec
, 1,
521 ntohs(cclc
.hdr
.length
));
522 if (len
< ntohs(cclc
.hdr
.length
)) {
524 reason_code
= -ENETUNREACH
;
525 smc
->sk
.sk_err
= -reason_code
;
527 smc
->sk
.sk_err
= smc
->clcsock
->sk
->sk_err
;
528 reason_code
= -smc
->sk
.sk_err
;
534 /* send CLC ACCEPT message across internal TCP socket */
535 int smc_clc_send_accept(struct smc_sock
*new_smc
, int srv_first_contact
)
537 struct smc_connection
*conn
= &new_smc
->conn
;
538 struct smc_clc_msg_accept_confirm aclc
;
539 struct smc_link
*link
;
544 memset(&aclc
, 0, sizeof(aclc
));
545 aclc
.hdr
.type
= SMC_CLC_ACCEPT
;
546 aclc
.hdr
.version
= SMC_CLC_V1
; /* SMC version */
547 if (srv_first_contact
)
550 if (new_smc
->conn
.lgr
->is_smcd
) {
551 /* SMC-D specific settings */
552 aclc
.hdr
.length
= htons(SMCD_CLC_ACCEPT_CONFIRM_LEN
);
553 memcpy(aclc
.hdr
.eyecatcher
, SMCD_EYECATCHER
,
554 sizeof(SMCD_EYECATCHER
));
555 aclc
.hdr
.path
= SMC_TYPE_D
;
556 aclc
.gid
= conn
->lgr
->smcd
->local_gid
;
557 aclc
.token
= conn
->rmb_desc
->token
;
558 aclc
.dmbe_size
= conn
->rmbe_size_short
;
560 memcpy(&aclc
.linkid
, conn
->lgr
->id
, SMC_LGR_ID_SIZE
);
561 memcpy(aclc
.smcd_trl
.eyecatcher
, SMCD_EYECATCHER
,
562 sizeof(SMCD_EYECATCHER
));
564 /* SMC-R specific settings */
565 aclc
.hdr
.length
= htons(SMCR_CLC_ACCEPT_CONFIRM_LEN
);
566 memcpy(aclc
.hdr
.eyecatcher
, SMC_EYECATCHER
,
567 sizeof(SMC_EYECATCHER
));
568 aclc
.hdr
.path
= SMC_TYPE_R
;
569 link
= &conn
->lgr
->lnk
[SMC_SINGLE_LINK
];
570 memcpy(aclc
.lcl
.id_for_peer
, local_systemid
,
571 sizeof(local_systemid
));
572 memcpy(&aclc
.lcl
.gid
, link
->gid
, SMC_GID_SIZE
);
573 memcpy(&aclc
.lcl
.mac
, link
->smcibdev
->mac
[link
->ibport
- 1],
575 hton24(aclc
.qpn
, link
->roce_qp
->qp_num
);
577 htonl(conn
->rmb_desc
->mr_rx
[SMC_SINGLE_LINK
]->rkey
);
578 aclc
.rmbe_idx
= 1; /* as long as 1 RMB = 1 RMBE */
579 aclc
.rmbe_alert_token
= htonl(conn
->alert_token_local
);
580 aclc
.qp_mtu
= link
->path_mtu
;
581 aclc
.rmbe_size
= conn
->rmbe_size_short
,
582 aclc
.rmb_dma_addr
= cpu_to_be64((u64
)sg_dma_address
583 (conn
->rmb_desc
->sgt
[SMC_SINGLE_LINK
].sgl
));
584 hton24(aclc
.psn
, link
->psn_initial
);
585 memcpy(aclc
.smcr_trl
.eyecatcher
, SMC_EYECATCHER
,
586 sizeof(SMC_EYECATCHER
));
589 memset(&msg
, 0, sizeof(msg
));
590 vec
.iov_base
= &aclc
;
591 vec
.iov_len
= ntohs(aclc
.hdr
.length
);
592 len
= kernel_sendmsg(new_smc
->clcsock
, &msg
, &vec
, 1,
593 ntohs(aclc
.hdr
.length
));
594 if (len
< ntohs(aclc
.hdr
.length
))
595 len
= len
>= 0 ? -EPROTO
: -new_smc
->clcsock
->sk
->sk_err
;
597 return len
> 0 ? 0 : len
;