linux/net/smc/smc_clc.c
<<
>>
Prefs
   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, 2018
   9 *
  10 *  Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
  11 */
  12
  13#include <linux/in.h>
  14#include <linux/inetdevice.h>
  15#include <linux/if_ether.h>
  16#include <linux/sched/signal.h>
  17
  18#include <net/addrconf.h>
  19#include <net/sock.h>
  20#include <net/tcp.h>
  21
  22#include "smc.h"
  23#include "smc_core.h"
  24#include "smc_clc.h"
  25#include "smc_ib.h"
  26#include "smc_ism.h"
  27
  28#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
  29#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
  30#define SMC_CLC_RECV_BUF_LEN    100
  31
  32/* eye catcher "SMCR" EBCDIC for CLC messages */
  33static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
  34/* eye catcher "SMCD" EBCDIC for CLC messages */
  35static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
  36
  37/* check if received message has a correct header length and contains valid
  38 * heading and trailing eyecatchers
  39 */
  40static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
  41{
  42        struct smc_clc_msg_proposal_prefix *pclc_prfx;
  43        struct smc_clc_msg_accept_confirm *clc;
  44        struct smc_clc_msg_proposal *pclc;
  45        struct smc_clc_msg_decline *dclc;
  46        struct smc_clc_msg_trail *trl;
  47
  48        if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
  49            memcmp(clcm->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
  50                return false;
  51        switch (clcm->type) {
  52        case SMC_CLC_PROPOSAL:
  53                pclc = (struct smc_clc_msg_proposal *)clcm;
  54                pclc_prfx = smc_clc_proposal_get_prefix(pclc);
  55                if (ntohs(pclc->hdr.length) <
  56                        sizeof(*pclc) + ntohs(pclc->iparea_offset) +
  57                        sizeof(*pclc_prfx) +
  58                        pclc_prfx->ipv6_prefixes_cnt *
  59                                sizeof(struct smc_clc_ipv6_prefix) +
  60                        sizeof(*trl))
  61                        return false;
  62                trl = (struct smc_clc_msg_trail *)
  63                        ((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl));
  64                break;
  65        case SMC_CLC_ACCEPT:
  66        case SMC_CLC_CONFIRM:
  67                if (clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D)
  68                        return false;
  69                clc = (struct smc_clc_msg_accept_confirm *)clcm;
  70                if ((clcm->path == SMC_TYPE_R &&
  71                     ntohs(clc->hdr.length) != SMCR_CLC_ACCEPT_CONFIRM_LEN) ||
  72                    (clcm->path == SMC_TYPE_D &&
  73                     ntohs(clc->hdr.length) != SMCD_CLC_ACCEPT_CONFIRM_LEN))
  74                        return false;
  75                trl = (struct smc_clc_msg_trail *)
  76                        ((u8 *)clc + ntohs(clc->hdr.length) - sizeof(*trl));
  77                break;
  78        case SMC_CLC_DECLINE:
  79                dclc = (struct smc_clc_msg_decline *)clcm;
  80                if (ntohs(dclc->hdr.length) != sizeof(*dclc))
  81                        return false;
  82                trl = &dclc->trl;
  83                break;
  84        default:
  85                return false;
  86        }
  87        if (check_trl &&
  88            memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
  89            memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
  90                return false;
  91        return true;
  92}
  93
  94/* find ipv4 addr on device and get the prefix len, fill CLC proposal msg */
  95static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
  96                                 struct smc_clc_msg_proposal_prefix *prop)
  97{
  98        struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
  99        const struct in_ifaddr *ifa;
 100
 101        if (!in_dev)
 102                return -ENODEV;
 103
 104        in_dev_for_each_ifa_rcu(ifa, in_dev) {
 105                if (!inet_ifa_match(ipv4, ifa))
 106                        continue;
 107                prop->prefix_len = inet_mask_len(ifa->ifa_mask);
 108                prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
 109                /* prop->ipv6_prefixes_cnt = 0; already done by memset before */
 110                return 0;
 111        }
 112        return -ENOENT;
 113}
 114
 115/* fill CLC proposal msg with ipv6 prefixes from device */
 116static int smc_clc_prfx_set6_rcu(struct dst_entry *dst,
 117                                 struct smc_clc_msg_proposal_prefix *prop,
 118                                 struct smc_clc_ipv6_prefix *ipv6_prfx)
 119{
 120#if IS_ENABLED(CONFIG_IPV6)
 121        struct inet6_dev *in6_dev = __in6_dev_get(dst->dev);
 122        struct inet6_ifaddr *ifa;
 123        int cnt = 0;
 124
 125        if (!in6_dev)
 126                return -ENODEV;
 127        /* use a maximum of 8 IPv6 prefixes from device */
 128        list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
 129                if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
 130                        continue;
 131                ipv6_addr_prefix(&ipv6_prfx[cnt].prefix,
 132                                 &ifa->addr, ifa->prefix_len);
 133                ipv6_prfx[cnt].prefix_len = ifa->prefix_len;
 134                cnt++;
 135                if (cnt == SMC_CLC_MAX_V6_PREFIX)
 136                        break;
 137        }
 138        prop->ipv6_prefixes_cnt = cnt;
 139        if (cnt)
 140                return 0;
 141#endif
 142        return -ENOENT;
 143}
 144
 145/* retrieve and set prefixes in CLC proposal msg */
 146static int smc_clc_prfx_set(struct socket *clcsock,
 147                            struct smc_clc_msg_proposal_prefix *prop,
 148                            struct smc_clc_ipv6_prefix *ipv6_prfx)
 149{
 150        struct dst_entry *dst = sk_dst_get(clcsock->sk);
 151        struct sockaddr_storage addrs;
 152        struct sockaddr_in6 *addr6;
 153        struct sockaddr_in *addr;
 154        int rc = -ENOENT;
 155
 156        memset(prop, 0, sizeof(*prop));
 157        if (!dst) {
 158                rc = -ENOTCONN;
 159                goto out;
 160        }
 161        if (!dst->dev) {
 162                rc = -ENODEV;
 163                goto out_rel;
 164        }
 165        /* get address to which the internal TCP socket is bound */
 166        kernel_getsockname(clcsock, (struct sockaddr *)&addrs);
 167        /* analyze IP specific data of net_device belonging to TCP socket */
 168        addr6 = (struct sockaddr_in6 *)&addrs;
 169        rcu_read_lock();
 170        if (addrs.ss_family == PF_INET) {
 171                /* IPv4 */
 172                addr = (struct sockaddr_in *)&addrs;
 173                rc = smc_clc_prfx_set4_rcu(dst, addr->sin_addr.s_addr, prop);
 174        } else if (ipv6_addr_v4mapped(&addr6->sin6_addr)) {
 175                /* mapped IPv4 address - peer is IPv4 only */
 176                rc = smc_clc_prfx_set4_rcu(dst, addr6->sin6_addr.s6_addr32[3],
 177                                           prop);
 178        } else {
 179                /* IPv6 */
 180                rc = smc_clc_prfx_set6_rcu(dst, prop, ipv6_prfx);
 181        }
 182        rcu_read_unlock();
 183out_rel:
 184        dst_release(dst);
 185out:
 186        return rc;
 187}
 188
 189/* match ipv4 addrs of dev against addr in CLC proposal */
 190static int smc_clc_prfx_match4_rcu(struct net_device *dev,
 191                                   struct smc_clc_msg_proposal_prefix *prop)
 192{
 193        struct in_device *in_dev = __in_dev_get_rcu(dev);
 194        const struct in_ifaddr *ifa;
 195
 196        if (!in_dev)
 197                return -ENODEV;
 198        in_dev_for_each_ifa_rcu(ifa, in_dev) {
 199                if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) &&
 200                    inet_ifa_match(prop->outgoing_subnet, ifa))
 201                        return 0;
 202        }
 203
 204        return -ENOENT;
 205}
 206
 207/* match ipv6 addrs of dev against addrs in CLC proposal */
 208static int smc_clc_prfx_match6_rcu(struct net_device *dev,
 209                                   struct smc_clc_msg_proposal_prefix *prop)
 210{
 211#if IS_ENABLED(CONFIG_IPV6)
 212        struct inet6_dev *in6_dev = __in6_dev_get(dev);
 213        struct smc_clc_ipv6_prefix *ipv6_prfx;
 214        struct inet6_ifaddr *ifa;
 215        int i, max;
 216
 217        if (!in6_dev)
 218                return -ENODEV;
 219        /* ipv6 prefix list starts behind smc_clc_msg_proposal_prefix */
 220        ipv6_prfx = (struct smc_clc_ipv6_prefix *)((u8 *)prop + sizeof(*prop));
 221        max = min_t(u8, prop->ipv6_prefixes_cnt, SMC_CLC_MAX_V6_PREFIX);
 222        list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
 223                if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
 224                        continue;
 225                for (i = 0; i < max; i++) {
 226                        if (ifa->prefix_len == ipv6_prfx[i].prefix_len &&
 227                            ipv6_prefix_equal(&ifa->addr, &ipv6_prfx[i].prefix,
 228                                              ifa->prefix_len))
 229                                return 0;
 230                }
 231        }
 232#endif
 233        return -ENOENT;
 234}
 235
 236/* check if proposed prefixes match one of our device prefixes */
 237int smc_clc_prfx_match(struct socket *clcsock,
 238                       struct smc_clc_msg_proposal_prefix *prop)
 239{
 240        struct dst_entry *dst = sk_dst_get(clcsock->sk);
 241        int rc;
 242
 243        if (!dst) {
 244                rc = -ENOTCONN;
 245                goto out;
 246        }
 247        if (!dst->dev) {
 248                rc = -ENODEV;
 249                goto out_rel;
 250        }
 251        rcu_read_lock();
 252        if (!prop->ipv6_prefixes_cnt)
 253                rc = smc_clc_prfx_match4_rcu(dst->dev, prop);
 254        else
 255                rc = smc_clc_prfx_match6_rcu(dst->dev, prop);
 256        rcu_read_unlock();
 257out_rel:
 258        dst_release(dst);
 259out:
 260        return rc;
 261}
 262
 263/* Wait for data on the tcp-socket, analyze received data
 264 * Returns:
 265 * 0 if success and it was not a decline that we received.
 266 * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
 267 * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
 268 */
 269int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
 270                     u8 expected_type, unsigned long timeout)
 271{
 272        long rcvtimeo = smc->clcsock->sk->sk_rcvtimeo;
 273        struct sock *clc_sk = smc->clcsock->sk;
 274        struct smc_clc_msg_hdr *clcm = buf;
 275        struct msghdr msg = {NULL, 0};
 276        int reason_code = 0;
 277        struct kvec vec = {buf, buflen};
 278        int len, datlen, recvlen;
 279        bool check_trl = true;
 280        int krflags;
 281
 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
 285         */
 286        /*
 287         * Caller must make sure that buflen is no less than
 288         * sizeof(struct smc_clc_msg_hdr)
 289         */
 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;
 299                goto out;
 300        }
 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 */
 306                else
 307                        smc->sk.sk_err = clc_sk->sk_err;
 308                goto out;
 309        }
 310        if (!len) { /* peer has performed orderly shutdown */
 311                smc->sk.sk_err = ECONNRESET;
 312                reason_code = -ECONNRESET;
 313                goto out;
 314        }
 315        if (len < 0) {
 316                if (len != -EAGAIN || expected_type != SMC_CLC_DECLINE)
 317                        smc->sk.sk_err = -len;
 318                reason_code = len;
 319                goto out;
 320        }
 321        datlen = ntohs(clcm->length);
 322        if ((len < sizeof(struct smc_clc_msg_hdr)) ||
 323            (clcm->version < SMC_CLC_V1) ||
 324            ((clcm->type != SMC_CLC_DECLINE) &&
 325             (clcm->type != expected_type))) {
 326                smc->sk.sk_err = EPROTO;
 327                reason_code = -EPROTO;
 328                goto out;
 329        }
 330
 331        if (clcm->type == SMC_CLC_PROPOSAL && clcm->path == SMC_TYPE_N)
 332                reason_code = SMC_CLC_DECL_VERSMISMAT; /* just V2 offered */
 333
 334        /* receive the complete CLC message */
 335        memset(&msg, 0, sizeof(struct msghdr));
 336        if (datlen > buflen) {
 337                check_trl = false;
 338                recvlen = buflen;
 339        } else {
 340                recvlen = datlen;
 341        }
 342        iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
 343        krflags = MSG_WAITALL;
 344        len = sock_recvmsg(smc->clcsock, &msg, krflags);
 345        if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
 346                smc->sk.sk_err = EPROTO;
 347                reason_code = -EPROTO;
 348                goto out;
 349        }
 350        datlen -= len;
 351        while (datlen) {
 352                u8 tmp[SMC_CLC_RECV_BUF_LEN];
 353
 354                vec.iov_base = &tmp;
 355                vec.iov_len = SMC_CLC_RECV_BUF_LEN;
 356                /* receive remaining proposal message */
 357                recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
 358                                                SMC_CLC_RECV_BUF_LEN : datlen;
 359                iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
 360                len = sock_recvmsg(smc->clcsock, &msg, krflags);
 361                datlen -= len;
 362        }
 363        if (clcm->type == SMC_CLC_DECLINE) {
 364                struct smc_clc_msg_decline *dclc;
 365
 366                dclc = (struct smc_clc_msg_decline *)clcm;
 367                reason_code = SMC_CLC_DECL_PEERDECL;
 368                smc->peer_diagnosis = ntohl(dclc->peer_diagnosis);
 369                if (((struct smc_clc_msg_decline *)buf)->hdr.flag) {
 370                        smc->conn.lgr->sync_err = 1;
 371                        smc_lgr_terminate_sched(smc->conn.lgr);
 372                }
 373        }
 374
 375out:
 376        clc_sk->sk_rcvtimeo = rcvtimeo;
 377        return reason_code;
 378}
 379
 380/* send CLC DECLINE message across internal TCP socket */
 381int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info)
 382{
 383        struct smc_clc_msg_decline dclc;
 384        struct msghdr msg;
 385        struct kvec vec;
 386        int len;
 387
 388        memset(&dclc, 0, sizeof(dclc));
 389        memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 390        dclc.hdr.type = SMC_CLC_DECLINE;
 391        dclc.hdr.length = htons(sizeof(struct smc_clc_msg_decline));
 392        dclc.hdr.version = SMC_CLC_V1;
 393        dclc.hdr.flag = (peer_diag_info == SMC_CLC_DECL_SYNCERR) ? 1 : 0;
 394        if ((!smc->conn.lgr || !smc->conn.lgr->is_smcd) &&
 395            smc_ib_is_valid_local_systemid())
 396                memcpy(dclc.id_for_peer, local_systemid,
 397                       sizeof(local_systemid));
 398        dclc.peer_diagnosis = htonl(peer_diag_info);
 399        memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 400
 401        memset(&msg, 0, sizeof(msg));
 402        vec.iov_base = &dclc;
 403        vec.iov_len = sizeof(struct smc_clc_msg_decline);
 404        len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
 405                             sizeof(struct smc_clc_msg_decline));
 406        if (len < 0 || len < sizeof(struct smc_clc_msg_decline))
 407                len = -EPROTO;
 408        return len > 0 ? 0 : len;
 409}
 410
 411/* send CLC PROPOSAL message across internal TCP socket */
 412int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
 413                          struct smc_init_info *ini)
 414{
 415        struct smc_clc_ipv6_prefix ipv6_prfx[SMC_CLC_MAX_V6_PREFIX];
 416        struct smc_clc_msg_proposal_prefix pclc_prfx;
 417        struct smc_clc_msg_smcd pclc_smcd;
 418        struct smc_clc_msg_proposal pclc;
 419        struct smc_clc_msg_trail trl;
 420        int len, i, plen, rc;
 421        int reason_code = 0;
 422        struct kvec vec[5];
 423        struct msghdr msg;
 424
 425        /* retrieve ip prefixes for CLC proposal msg */
 426        rc = smc_clc_prfx_set(smc->clcsock, &pclc_prfx, ipv6_prfx);
 427        if (rc)
 428                return SMC_CLC_DECL_CNFERR; /* configuration error */
 429
 430        /* send SMC Proposal CLC message */
 431        plen = sizeof(pclc) + sizeof(pclc_prfx) +
 432               (pclc_prfx.ipv6_prefixes_cnt * sizeof(ipv6_prfx[0])) +
 433               sizeof(trl);
 434        memset(&pclc, 0, sizeof(pclc));
 435        memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 436        pclc.hdr.type = SMC_CLC_PROPOSAL;
 437        pclc.hdr.version = SMC_CLC_V1;          /* SMC version */
 438        pclc.hdr.path = smc_type;
 439        if (smc_type == SMC_TYPE_R || smc_type == SMC_TYPE_B) {
 440                /* add SMC-R specifics */
 441                memcpy(pclc.lcl.id_for_peer, local_systemid,
 442                       sizeof(local_systemid));
 443                memcpy(&pclc.lcl.gid, ini->ib_gid, SMC_GID_SIZE);
 444                memcpy(&pclc.lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
 445                       ETH_ALEN);
 446                pclc.iparea_offset = htons(0);
 447        }
 448        if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
 449                /* add SMC-D specifics */
 450                memset(&pclc_smcd, 0, sizeof(pclc_smcd));
 451                plen += sizeof(pclc_smcd);
 452                pclc.iparea_offset = htons(SMC_CLC_PROPOSAL_MAX_OFFSET);
 453                pclc_smcd.gid = ini->ism_dev->local_gid;
 454        }
 455        pclc.hdr.length = htons(plen);
 456
 457        memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 458        memset(&msg, 0, sizeof(msg));
 459        i = 0;
 460        vec[i].iov_base = &pclc;
 461        vec[i++].iov_len = sizeof(pclc);
 462        if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
 463                vec[i].iov_base = &pclc_smcd;
 464                vec[i++].iov_len = sizeof(pclc_smcd);
 465        }
 466        vec[i].iov_base = &pclc_prfx;
 467        vec[i++].iov_len = sizeof(pclc_prfx);
 468        if (pclc_prfx.ipv6_prefixes_cnt > 0) {
 469                vec[i].iov_base = &ipv6_prfx[0];
 470                vec[i++].iov_len = pclc_prfx.ipv6_prefixes_cnt *
 471                                   sizeof(ipv6_prfx[0]);
 472        }
 473        vec[i].iov_base = &trl;
 474        vec[i++].iov_len = sizeof(trl);
 475        /* due to the few bytes needed for clc-handshake this cannot block */
 476        len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen);
 477        if (len < 0) {
 478                smc->sk.sk_err = smc->clcsock->sk->sk_err;
 479                reason_code = -smc->sk.sk_err;
 480        } else if (len < (int)sizeof(pclc)) {
 481                reason_code = -ENETUNREACH;
 482                smc->sk.sk_err = -reason_code;
 483        }
 484
 485        return reason_code;
 486}
 487
 488/* send CLC CONFIRM message across internal TCP socket */
 489int smc_clc_send_confirm(struct smc_sock *smc)
 490{
 491        struct smc_connection *conn = &smc->conn;
 492        struct smc_clc_msg_accept_confirm cclc;
 493        struct smc_link *link;
 494        int reason_code = 0;
 495        struct msghdr msg;
 496        struct kvec vec;
 497        int len;
 498
 499        /* send SMC Confirm CLC msg */
 500        memset(&cclc, 0, sizeof(cclc));
 501        cclc.hdr.type = SMC_CLC_CONFIRM;
 502        cclc.hdr.version = SMC_CLC_V1;          /* SMC version */
 503        if (smc->conn.lgr->is_smcd) {
 504                /* SMC-D specific settings */
 505                memcpy(cclc.hdr.eyecatcher, SMCD_EYECATCHER,
 506                       sizeof(SMCD_EYECATCHER));
 507                cclc.hdr.path = SMC_TYPE_D;
 508                cclc.hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
 509                cclc.gid = conn->lgr->smcd->local_gid;
 510                cclc.token = conn->rmb_desc->token;
 511                cclc.dmbe_size = conn->rmbe_size_short;
 512                cclc.dmbe_idx = 0;
 513                memcpy(&cclc.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
 514                memcpy(cclc.smcd_trl.eyecatcher, SMCD_EYECATCHER,
 515                       sizeof(SMCD_EYECATCHER));
 516        } else {
 517                /* SMC-R specific settings */
 518                link = conn->lnk;
 519                memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER,
 520                       sizeof(SMC_EYECATCHER));
 521                cclc.hdr.path = SMC_TYPE_R;
 522                cclc.hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
 523                memcpy(cclc.lcl.id_for_peer, local_systemid,
 524                       sizeof(local_systemid));
 525                memcpy(&cclc.lcl.gid, link->gid, SMC_GID_SIZE);
 526                memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
 527                       ETH_ALEN);
 528                hton24(cclc.qpn, link->roce_qp->qp_num);
 529                cclc.rmb_rkey =
 530                        htonl(conn->rmb_desc->mr_rx[link->link_idx]->rkey);
 531                cclc.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
 532                cclc.rmbe_alert_token = htonl(conn->alert_token_local);
 533                cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
 534                cclc.rmbe_size = conn->rmbe_size_short;
 535                cclc.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
 536                                (conn->rmb_desc->sgt[link->link_idx].sgl));
 537                hton24(cclc.psn, link->psn_initial);
 538                memcpy(cclc.smcr_trl.eyecatcher, SMC_EYECATCHER,
 539                       sizeof(SMC_EYECATCHER));
 540        }
 541
 542        memset(&msg, 0, sizeof(msg));
 543        vec.iov_base = &cclc;
 544        vec.iov_len = ntohs(cclc.hdr.length);
 545        len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
 546                             ntohs(cclc.hdr.length));
 547        if (len < ntohs(cclc.hdr.length)) {
 548                if (len >= 0) {
 549                        reason_code = -ENETUNREACH;
 550                        smc->sk.sk_err = -reason_code;
 551                } else {
 552                        smc->sk.sk_err = smc->clcsock->sk->sk_err;
 553                        reason_code = -smc->sk.sk_err;
 554                }
 555        }
 556        return reason_code;
 557}
 558
 559/* send CLC ACCEPT message across internal TCP socket */
 560int smc_clc_send_accept(struct smc_sock *new_smc, int srv_first_contact)
 561{
 562        struct smc_connection *conn = &new_smc->conn;
 563        struct smc_clc_msg_accept_confirm aclc;
 564        struct smc_link *link;
 565        struct msghdr msg;
 566        struct kvec vec;
 567        int len;
 568
 569        memset(&aclc, 0, sizeof(aclc));
 570        aclc.hdr.type = SMC_CLC_ACCEPT;
 571        aclc.hdr.version = SMC_CLC_V1;          /* SMC version */
 572        if (srv_first_contact)
 573                aclc.hdr.flag = 1;
 574
 575        if (new_smc->conn.lgr->is_smcd) {
 576                /* SMC-D specific settings */
 577                aclc.hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
 578                memcpy(aclc.hdr.eyecatcher, SMCD_EYECATCHER,
 579                       sizeof(SMCD_EYECATCHER));
 580                aclc.hdr.path = SMC_TYPE_D;
 581                aclc.gid = conn->lgr->smcd->local_gid;
 582                aclc.token = conn->rmb_desc->token;
 583                aclc.dmbe_size = conn->rmbe_size_short;
 584                aclc.dmbe_idx = 0;
 585                memcpy(&aclc.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
 586                memcpy(aclc.smcd_trl.eyecatcher, SMCD_EYECATCHER,
 587                       sizeof(SMCD_EYECATCHER));
 588        } else {
 589                /* SMC-R specific settings */
 590                aclc.hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
 591                memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER,
 592                       sizeof(SMC_EYECATCHER));
 593                aclc.hdr.path = SMC_TYPE_R;
 594                link = conn->lnk;
 595                memcpy(aclc.lcl.id_for_peer, local_systemid,
 596                       sizeof(local_systemid));
 597                memcpy(&aclc.lcl.gid, link->gid, SMC_GID_SIZE);
 598                memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1],
 599                       ETH_ALEN);
 600                hton24(aclc.qpn, link->roce_qp->qp_num);
 601                aclc.rmb_rkey =
 602                        htonl(conn->rmb_desc->mr_rx[link->link_idx]->rkey);
 603                aclc.rmbe_idx = 1;              /* as long as 1 RMB = 1 RMBE */
 604                aclc.rmbe_alert_token = htonl(conn->alert_token_local);
 605                aclc.qp_mtu = link->path_mtu;
 606                aclc.rmbe_size = conn->rmbe_size_short,
 607                aclc.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
 608                                (conn->rmb_desc->sgt[link->link_idx].sgl));
 609                hton24(aclc.psn, link->psn_initial);
 610                memcpy(aclc.smcr_trl.eyecatcher, SMC_EYECATCHER,
 611                       sizeof(SMC_EYECATCHER));
 612        }
 613
 614        memset(&msg, 0, sizeof(msg));
 615        vec.iov_base = &aclc;
 616        vec.iov_len = ntohs(aclc.hdr.length);
 617        len = kernel_sendmsg(new_smc->clcsock, &msg, &vec, 1,
 618                             ntohs(aclc.hdr.length));
 619        if (len < ntohs(aclc.hdr.length))
 620                len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
 621
 622        return len > 0 ? 0 : len;
 623}
 624