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#include <linux/utsname.h>
  18#include <linux/ctype.h>
  19
  20#include <net/addrconf.h>
  21#include <net/sock.h>
  22#include <net/tcp.h>
  23
  24#include "smc.h"
  25#include "smc_core.h"
  26#include "smc_clc.h"
  27#include "smc_ib.h"
  28#include "smc_ism.h"
  29
  30#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
  31#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
  32#define SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 78
  33#define SMC_CLC_RECV_BUF_LEN    100
  34
  35/* eye catcher "SMCR" EBCDIC for CLC messages */
  36static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
  37/* eye catcher "SMCD" EBCDIC for CLC messages */
  38static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
  39
  40static u8 smc_hostname[SMC_MAX_HOSTNAME_LEN];
  41
  42/* check arriving CLC proposal */
  43static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
  44{
  45        struct smc_clc_msg_proposal_prefix *pclc_prfx;
  46        struct smc_clc_smcd_v2_extension *smcd_v2_ext;
  47        struct smc_clc_msg_hdr *hdr = &pclc->hdr;
  48        struct smc_clc_v2_extension *v2_ext;
  49
  50        v2_ext = smc_get_clc_v2_ext(pclc);
  51        pclc_prfx = smc_clc_proposal_get_prefix(pclc);
  52        if (hdr->version == SMC_V1) {
  53                if (hdr->typev1 == SMC_TYPE_N)
  54                        return false;
  55                if (ntohs(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(struct smc_clc_msg_trail))
  61                        return false;
  62        } else {
  63                if (ntohs(hdr->length) !=
  64                        sizeof(*pclc) +
  65                        sizeof(struct smc_clc_msg_smcd) +
  66                        (hdr->typev1 != SMC_TYPE_N ?
  67                                sizeof(*pclc_prfx) +
  68                                pclc_prfx->ipv6_prefixes_cnt *
  69                                sizeof(struct smc_clc_ipv6_prefix) : 0) +
  70                        (hdr->typev2 != SMC_TYPE_N ?
  71                                sizeof(*v2_ext) +
  72                                v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN : 0) +
  73                        (smcd_indicated(hdr->typev2) ?
  74                                sizeof(*smcd_v2_ext) + v2_ext->hdr.ism_gid_cnt *
  75                                        sizeof(struct smc_clc_smcd_gid_chid) :
  76                                0) +
  77                        sizeof(struct smc_clc_msg_trail))
  78                        return false;
  79        }
  80        return true;
  81}
  82
  83/* check arriving CLC accept or confirm */
  84static bool
  85smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
  86{
  87        struct smc_clc_msg_hdr *hdr = &clc_v2->hdr;
  88
  89        if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D)
  90                return false;
  91        if (hdr->version == SMC_V1) {
  92                if ((hdr->typev1 == SMC_TYPE_R &&
  93                     ntohs(hdr->length) != SMCR_CLC_ACCEPT_CONFIRM_LEN) ||
  94                    (hdr->typev1 == SMC_TYPE_D &&
  95                     ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN))
  96                        return false;
  97        } else {
  98                if (hdr->typev1 == SMC_TYPE_D &&
  99                    ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 &&
 100                    (ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 +
 101                                sizeof(struct smc_clc_first_contact_ext)))
 102                        return false;
 103        }
 104        return true;
 105}
 106
 107static void smc_clc_fill_fce(struct smc_clc_first_contact_ext *fce, int *len)
 108{
 109        memset(fce, 0, sizeof(*fce));
 110        fce->os_type = SMC_CLC_OS_LINUX;
 111        fce->release = SMC_RELEASE;
 112        memcpy(fce->hostname, smc_hostname, sizeof(smc_hostname));
 113        (*len) += sizeof(*fce);
 114}
 115
 116/* check if received message has a correct header length and contains valid
 117 * heading and trailing eyecatchers
 118 */
 119static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
 120{
 121        struct smc_clc_msg_accept_confirm_v2 *clc_v2;
 122        struct smc_clc_msg_proposal *pclc;
 123        struct smc_clc_msg_decline *dclc;
 124        struct smc_clc_msg_trail *trl;
 125
 126        if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
 127            memcmp(clcm->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
 128                return false;
 129        switch (clcm->type) {
 130        case SMC_CLC_PROPOSAL:
 131                pclc = (struct smc_clc_msg_proposal *)clcm;
 132                if (!smc_clc_msg_prop_valid(pclc))
 133                        return false;
 134                trl = (struct smc_clc_msg_trail *)
 135                        ((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl));
 136                break;
 137        case SMC_CLC_ACCEPT:
 138        case SMC_CLC_CONFIRM:
 139                clc_v2 = (struct smc_clc_msg_accept_confirm_v2 *)clcm;
 140                if (!smc_clc_msg_acc_conf_valid(clc_v2))
 141                        return false;
 142                trl = (struct smc_clc_msg_trail *)
 143                        ((u8 *)clc_v2 + ntohs(clc_v2->hdr.length) -
 144                                                        sizeof(*trl));
 145                break;
 146        case SMC_CLC_DECLINE:
 147                dclc = (struct smc_clc_msg_decline *)clcm;
 148                if (ntohs(dclc->hdr.length) != sizeof(*dclc))
 149                        return false;
 150                trl = &dclc->trl;
 151                break;
 152        default:
 153                return false;
 154        }
 155        if (check_trl &&
 156            memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
 157            memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
 158                return false;
 159        return true;
 160}
 161
 162/* find ipv4 addr on device and get the prefix len, fill CLC proposal msg */
 163static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
 164                                 struct smc_clc_msg_proposal_prefix *prop)
 165{
 166        struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
 167        const struct in_ifaddr *ifa;
 168
 169        if (!in_dev)
 170                return -ENODEV;
 171
 172        in_dev_for_each_ifa_rcu(ifa, in_dev) {
 173                if (!inet_ifa_match(ipv4, ifa))
 174                        continue;
 175                prop->prefix_len = inet_mask_len(ifa->ifa_mask);
 176                prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
 177                /* prop->ipv6_prefixes_cnt = 0; already done by memset before */
 178                return 0;
 179        }
 180        return -ENOENT;
 181}
 182
 183/* fill CLC proposal msg with ipv6 prefixes from device */
 184static int smc_clc_prfx_set6_rcu(struct dst_entry *dst,
 185                                 struct smc_clc_msg_proposal_prefix *prop,
 186                                 struct smc_clc_ipv6_prefix *ipv6_prfx)
 187{
 188#if IS_ENABLED(CONFIG_IPV6)
 189        struct inet6_dev *in6_dev = __in6_dev_get(dst->dev);
 190        struct inet6_ifaddr *ifa;
 191        int cnt = 0;
 192
 193        if (!in6_dev)
 194                return -ENODEV;
 195        /* use a maximum of 8 IPv6 prefixes from device */
 196        list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
 197                if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
 198                        continue;
 199                ipv6_addr_prefix(&ipv6_prfx[cnt].prefix,
 200                                 &ifa->addr, ifa->prefix_len);
 201                ipv6_prfx[cnt].prefix_len = ifa->prefix_len;
 202                cnt++;
 203                if (cnt == SMC_CLC_MAX_V6_PREFIX)
 204                        break;
 205        }
 206        prop->ipv6_prefixes_cnt = cnt;
 207        if (cnt)
 208                return 0;
 209#endif
 210        return -ENOENT;
 211}
 212
 213/* retrieve and set prefixes in CLC proposal msg */
 214static int smc_clc_prfx_set(struct socket *clcsock,
 215                            struct smc_clc_msg_proposal_prefix *prop,
 216                            struct smc_clc_ipv6_prefix *ipv6_prfx)
 217{
 218        struct dst_entry *dst = sk_dst_get(clcsock->sk);
 219        struct sockaddr_storage addrs;
 220        struct sockaddr_in6 *addr6;
 221        struct sockaddr_in *addr;
 222        int rc = -ENOENT;
 223
 224        if (!dst) {
 225                rc = -ENOTCONN;
 226                goto out;
 227        }
 228        if (!dst->dev) {
 229                rc = -ENODEV;
 230                goto out_rel;
 231        }
 232        /* get address to which the internal TCP socket is bound */
 233        kernel_getsockname(clcsock, (struct sockaddr *)&addrs);
 234        /* analyze IP specific data of net_device belonging to TCP socket */
 235        addr6 = (struct sockaddr_in6 *)&addrs;
 236        rcu_read_lock();
 237        if (addrs.ss_family == PF_INET) {
 238                /* IPv4 */
 239                addr = (struct sockaddr_in *)&addrs;
 240                rc = smc_clc_prfx_set4_rcu(dst, addr->sin_addr.s_addr, prop);
 241        } else if (ipv6_addr_v4mapped(&addr6->sin6_addr)) {
 242                /* mapped IPv4 address - peer is IPv4 only */
 243                rc = smc_clc_prfx_set4_rcu(dst, addr6->sin6_addr.s6_addr32[3],
 244                                           prop);
 245        } else {
 246                /* IPv6 */
 247                rc = smc_clc_prfx_set6_rcu(dst, prop, ipv6_prfx);
 248        }
 249        rcu_read_unlock();
 250out_rel:
 251        dst_release(dst);
 252out:
 253        return rc;
 254}
 255
 256/* match ipv4 addrs of dev against addr in CLC proposal */
 257static int smc_clc_prfx_match4_rcu(struct net_device *dev,
 258                                   struct smc_clc_msg_proposal_prefix *prop)
 259{
 260        struct in_device *in_dev = __in_dev_get_rcu(dev);
 261        const struct in_ifaddr *ifa;
 262
 263        if (!in_dev)
 264                return -ENODEV;
 265        in_dev_for_each_ifa_rcu(ifa, in_dev) {
 266                if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) &&
 267                    inet_ifa_match(prop->outgoing_subnet, ifa))
 268                        return 0;
 269        }
 270
 271        return -ENOENT;
 272}
 273
 274/* match ipv6 addrs of dev against addrs in CLC proposal */
 275static int smc_clc_prfx_match6_rcu(struct net_device *dev,
 276                                   struct smc_clc_msg_proposal_prefix *prop)
 277{
 278#if IS_ENABLED(CONFIG_IPV6)
 279        struct inet6_dev *in6_dev = __in6_dev_get(dev);
 280        struct smc_clc_ipv6_prefix *ipv6_prfx;
 281        struct inet6_ifaddr *ifa;
 282        int i, max;
 283
 284        if (!in6_dev)
 285                return -ENODEV;
 286        /* ipv6 prefix list starts behind smc_clc_msg_proposal_prefix */
 287        ipv6_prfx = (struct smc_clc_ipv6_prefix *)((u8 *)prop + sizeof(*prop));
 288        max = min_t(u8, prop->ipv6_prefixes_cnt, SMC_CLC_MAX_V6_PREFIX);
 289        list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
 290                if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
 291                        continue;
 292                for (i = 0; i < max; i++) {
 293                        if (ifa->prefix_len == ipv6_prfx[i].prefix_len &&
 294                            ipv6_prefix_equal(&ifa->addr, &ipv6_prfx[i].prefix,
 295                                              ifa->prefix_len))
 296                                return 0;
 297                }
 298        }
 299#endif
 300        return -ENOENT;
 301}
 302
 303/* check if proposed prefixes match one of our device prefixes */
 304int smc_clc_prfx_match(struct socket *clcsock,
 305                       struct smc_clc_msg_proposal_prefix *prop)
 306{
 307        struct dst_entry *dst = sk_dst_get(clcsock->sk);
 308        int rc;
 309
 310        if (!dst) {
 311                rc = -ENOTCONN;
 312                goto out;
 313        }
 314        if (!dst->dev) {
 315                rc = -ENODEV;
 316                goto out_rel;
 317        }
 318        rcu_read_lock();
 319        if (!prop->ipv6_prefixes_cnt)
 320                rc = smc_clc_prfx_match4_rcu(dst->dev, prop);
 321        else
 322                rc = smc_clc_prfx_match6_rcu(dst->dev, prop);
 323        rcu_read_unlock();
 324out_rel:
 325        dst_release(dst);
 326out:
 327        return rc;
 328}
 329
 330/* Wait for data on the tcp-socket, analyze received data
 331 * Returns:
 332 * 0 if success and it was not a decline that we received.
 333 * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send.
 334 * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise.
 335 */
 336int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
 337                     u8 expected_type, unsigned long timeout)
 338{
 339        long rcvtimeo = smc->clcsock->sk->sk_rcvtimeo;
 340        struct sock *clc_sk = smc->clcsock->sk;
 341        struct smc_clc_msg_hdr *clcm = buf;
 342        struct msghdr msg = {NULL, 0};
 343        int reason_code = 0;
 344        struct kvec vec = {buf, buflen};
 345        int len, datlen, recvlen;
 346        bool check_trl = true;
 347        int krflags;
 348
 349        /* peek the first few bytes to determine length of data to receive
 350         * so we don't consume any subsequent CLC message or payload data
 351         * in the TCP byte stream
 352         */
 353        /*
 354         * Caller must make sure that buflen is no less than
 355         * sizeof(struct smc_clc_msg_hdr)
 356         */
 357        krflags = MSG_PEEK | MSG_WAITALL;
 358        clc_sk->sk_rcvtimeo = timeout;
 359        iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
 360                        sizeof(struct smc_clc_msg_hdr));
 361        len = sock_recvmsg(smc->clcsock, &msg, krflags);
 362        if (signal_pending(current)) {
 363                reason_code = -EINTR;
 364                clc_sk->sk_err = EINTR;
 365                smc->sk.sk_err = EINTR;
 366                goto out;
 367        }
 368        if (clc_sk->sk_err) {
 369                reason_code = -clc_sk->sk_err;
 370                if (clc_sk->sk_err == EAGAIN &&
 371                    expected_type == SMC_CLC_DECLINE)
 372                        clc_sk->sk_err = 0; /* reset for fallback usage */
 373                else
 374                        smc->sk.sk_err = clc_sk->sk_err;
 375                goto out;
 376        }
 377        if (!len) { /* peer has performed orderly shutdown */
 378                smc->sk.sk_err = ECONNRESET;
 379                reason_code = -ECONNRESET;
 380                goto out;
 381        }
 382        if (len < 0) {
 383                if (len != -EAGAIN || expected_type != SMC_CLC_DECLINE)
 384                        smc->sk.sk_err = -len;
 385                reason_code = len;
 386                goto out;
 387        }
 388        datlen = ntohs(clcm->length);
 389        if ((len < sizeof(struct smc_clc_msg_hdr)) ||
 390            (clcm->version < SMC_V1) ||
 391            ((clcm->type != SMC_CLC_DECLINE) &&
 392             (clcm->type != expected_type))) {
 393                smc->sk.sk_err = EPROTO;
 394                reason_code = -EPROTO;
 395                goto out;
 396        }
 397
 398        /* receive the complete CLC message */
 399        memset(&msg, 0, sizeof(struct msghdr));
 400        if (datlen > buflen) {
 401                check_trl = false;
 402                recvlen = buflen;
 403        } else {
 404                recvlen = datlen;
 405        }
 406        iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
 407        krflags = MSG_WAITALL;
 408        len = sock_recvmsg(smc->clcsock, &msg, krflags);
 409        if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
 410                smc->sk.sk_err = EPROTO;
 411                reason_code = -EPROTO;
 412                goto out;
 413        }
 414        datlen -= len;
 415        while (datlen) {
 416                u8 tmp[SMC_CLC_RECV_BUF_LEN];
 417
 418                vec.iov_base = &tmp;
 419                vec.iov_len = SMC_CLC_RECV_BUF_LEN;
 420                /* receive remaining proposal message */
 421                recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
 422                                                SMC_CLC_RECV_BUF_LEN : datlen;
 423                iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
 424                len = sock_recvmsg(smc->clcsock, &msg, krflags);
 425                datlen -= len;
 426        }
 427        if (clcm->type == SMC_CLC_DECLINE) {
 428                struct smc_clc_msg_decline *dclc;
 429
 430                dclc = (struct smc_clc_msg_decline *)clcm;
 431                reason_code = SMC_CLC_DECL_PEERDECL;
 432                smc->peer_diagnosis = ntohl(dclc->peer_diagnosis);
 433                if (((struct smc_clc_msg_decline *)buf)->hdr.typev2 &
 434                                                SMC_FIRST_CONTACT_MASK) {
 435                        smc->conn.lgr->sync_err = 1;
 436                        smc_lgr_terminate_sched(smc->conn.lgr);
 437                }
 438        }
 439
 440out:
 441        clc_sk->sk_rcvtimeo = rcvtimeo;
 442        return reason_code;
 443}
 444
 445/* send CLC DECLINE message across internal TCP socket */
 446int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version)
 447{
 448        struct smc_clc_msg_decline dclc;
 449        struct msghdr msg;
 450        struct kvec vec;
 451        int len;
 452
 453        memset(&dclc, 0, sizeof(dclc));
 454        memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 455        dclc.hdr.type = SMC_CLC_DECLINE;
 456        dclc.hdr.length = htons(sizeof(struct smc_clc_msg_decline));
 457        dclc.hdr.version = version;
 458        dclc.os_type = version == SMC_V1 ? 0 : SMC_CLC_OS_LINUX;
 459        dclc.hdr.typev2 = (peer_diag_info == SMC_CLC_DECL_SYNCERR) ?
 460                                                SMC_FIRST_CONTACT_MASK : 0;
 461        if ((!smc->conn.lgr || !smc->conn.lgr->is_smcd) &&
 462            smc_ib_is_valid_local_systemid())
 463                memcpy(dclc.id_for_peer, local_systemid,
 464                       sizeof(local_systemid));
 465        dclc.peer_diagnosis = htonl(peer_diag_info);
 466        memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 467
 468        memset(&msg, 0, sizeof(msg));
 469        vec.iov_base = &dclc;
 470        vec.iov_len = sizeof(struct smc_clc_msg_decline);
 471        len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
 472                             sizeof(struct smc_clc_msg_decline));
 473        if (len < 0 || len < sizeof(struct smc_clc_msg_decline))
 474                len = -EPROTO;
 475        return len > 0 ? 0 : len;
 476}
 477
 478/* send CLC PROPOSAL message across internal TCP socket */
 479int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
 480{
 481        struct smc_clc_smcd_v2_extension *smcd_v2_ext;
 482        struct smc_clc_msg_proposal_prefix *pclc_prfx;
 483        struct smc_clc_msg_proposal *pclc_base;
 484        struct smc_clc_smcd_gid_chid *gidchids;
 485        struct smc_clc_msg_proposal_area *pclc;
 486        struct smc_clc_ipv6_prefix *ipv6_prfx;
 487        struct smc_clc_v2_extension *v2_ext;
 488        struct smc_clc_msg_smcd *pclc_smcd;
 489        struct smc_clc_msg_trail *trl;
 490        int len, i, plen, rc;
 491        int reason_code = 0;
 492        struct kvec vec[8];
 493        struct msghdr msg;
 494
 495        pclc = kzalloc(sizeof(*pclc), GFP_KERNEL);
 496        if (!pclc)
 497                return -ENOMEM;
 498
 499        pclc_base = &pclc->pclc_base;
 500        pclc_smcd = &pclc->pclc_smcd;
 501        pclc_prfx = &pclc->pclc_prfx;
 502        ipv6_prfx = pclc->pclc_prfx_ipv6;
 503        v2_ext = &pclc->pclc_v2_ext;
 504        smcd_v2_ext = &pclc->pclc_smcd_v2_ext;
 505        gidchids = pclc->pclc_gidchids;
 506        trl = &pclc->pclc_trl;
 507
 508        pclc_base->hdr.version = SMC_V2;
 509        pclc_base->hdr.typev1 = ini->smc_type_v1;
 510        pclc_base->hdr.typev2 = ini->smc_type_v2;
 511        plen = sizeof(*pclc_base) + sizeof(*pclc_smcd) + sizeof(*trl);
 512
 513        /* retrieve ip prefixes for CLC proposal msg */
 514        if (ini->smc_type_v1 != SMC_TYPE_N) {
 515                rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx);
 516                if (rc) {
 517                        if (ini->smc_type_v2 == SMC_TYPE_N) {
 518                                kfree(pclc);
 519                                return SMC_CLC_DECL_CNFERR;
 520                        }
 521                        pclc_base->hdr.typev1 = SMC_TYPE_N;
 522                } else {
 523                        pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
 524                        plen += sizeof(*pclc_prfx) +
 525                                        pclc_prfx->ipv6_prefixes_cnt *
 526                                        sizeof(ipv6_prfx[0]);
 527                }
 528        }
 529
 530        /* build SMC Proposal CLC message */
 531        memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER,
 532               sizeof(SMC_EYECATCHER));
 533        pclc_base->hdr.type = SMC_CLC_PROPOSAL;
 534        if (smcr_indicated(ini->smc_type_v1)) {
 535                /* add SMC-R specifics */
 536                memcpy(pclc_base->lcl.id_for_peer, local_systemid,
 537                       sizeof(local_systemid));
 538                memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE);
 539                memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
 540                       ETH_ALEN);
 541        }
 542        if (smcd_indicated(ini->smc_type_v1)) {
 543                /* add SMC-D specifics */
 544                if (ini->ism_dev[0]) {
 545                        pclc_smcd->ism.gid = htonll(ini->ism_dev[0]->local_gid);
 546                        pclc_smcd->ism.chid =
 547                                htons(smc_ism_get_chid(ini->ism_dev[0]));
 548                }
 549        }
 550        if (ini->smc_type_v2 == SMC_TYPE_N) {
 551                pclc_smcd->v2_ext_offset = 0;
 552        } else {
 553                u16 v2_ext_offset;
 554                u8 *eid = NULL;
 555
 556                v2_ext_offset = sizeof(*pclc_smcd) -
 557                        offsetofend(struct smc_clc_msg_smcd, v2_ext_offset);
 558                if (ini->smc_type_v1 != SMC_TYPE_N)
 559                        v2_ext_offset += sizeof(*pclc_prfx) +
 560                                                pclc_prfx->ipv6_prefixes_cnt *
 561                                                sizeof(ipv6_prfx[0]);
 562                pclc_smcd->v2_ext_offset = htons(v2_ext_offset);
 563                v2_ext->hdr.eid_cnt = 0;
 564                v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
 565                v2_ext->hdr.flag.release = SMC_RELEASE;
 566                v2_ext->hdr.flag.seid = 1;
 567                v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
 568                                offsetofend(struct smc_clnt_opts_area_hdr,
 569                                            smcd_v2_ext_offset) +
 570                                v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
 571                if (ini->ism_dev[0])
 572                        smc_ism_get_system_eid(ini->ism_dev[0], &eid);
 573                else
 574                        smc_ism_get_system_eid(ini->ism_dev[1], &eid);
 575                if (eid)
 576                        memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN);
 577                plen += sizeof(*v2_ext) + sizeof(*smcd_v2_ext);
 578                if (ini->ism_offered_cnt) {
 579                        for (i = 1; i <= ini->ism_offered_cnt; i++) {
 580                                gidchids[i - 1].gid =
 581                                        htonll(ini->ism_dev[i]->local_gid);
 582                                gidchids[i - 1].chid =
 583                                        htons(smc_ism_get_chid(ini->ism_dev[i]));
 584                        }
 585                        plen += ini->ism_offered_cnt *
 586                                sizeof(struct smc_clc_smcd_gid_chid);
 587                }
 588        }
 589        pclc_base->hdr.length = htons(plen);
 590        memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 591
 592        /* send SMC Proposal CLC message */
 593        memset(&msg, 0, sizeof(msg));
 594        i = 0;
 595        vec[i].iov_base = pclc_base;
 596        vec[i++].iov_len = sizeof(*pclc_base);
 597        vec[i].iov_base = pclc_smcd;
 598        vec[i++].iov_len = sizeof(*pclc_smcd);
 599        if (ini->smc_type_v1 != SMC_TYPE_N) {
 600                vec[i].iov_base = pclc_prfx;
 601                vec[i++].iov_len = sizeof(*pclc_prfx);
 602                if (pclc_prfx->ipv6_prefixes_cnt > 0) {
 603                        vec[i].iov_base = ipv6_prfx;
 604                        vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt *
 605                                           sizeof(ipv6_prfx[0]);
 606                }
 607        }
 608        if (ini->smc_type_v2 != SMC_TYPE_N) {
 609                vec[i].iov_base = v2_ext;
 610                vec[i++].iov_len = sizeof(*v2_ext);
 611                vec[i].iov_base = smcd_v2_ext;
 612                vec[i++].iov_len = sizeof(*smcd_v2_ext);
 613                if (ini->ism_offered_cnt) {
 614                        vec[i].iov_base = gidchids;
 615                        vec[i++].iov_len = ini->ism_offered_cnt *
 616                                        sizeof(struct smc_clc_smcd_gid_chid);
 617                }
 618        }
 619        vec[i].iov_base = trl;
 620        vec[i++].iov_len = sizeof(*trl);
 621        /* due to the few bytes needed for clc-handshake this cannot block */
 622        len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen);
 623        if (len < 0) {
 624                smc->sk.sk_err = smc->clcsock->sk->sk_err;
 625                reason_code = -smc->sk.sk_err;
 626        } else if (len < ntohs(pclc_base->hdr.length)) {
 627                reason_code = -ENETUNREACH;
 628                smc->sk.sk_err = -reason_code;
 629        }
 630
 631        kfree(pclc);
 632        return reason_code;
 633}
 634
 635/* build and send CLC CONFIRM / ACCEPT message */
 636static int smc_clc_send_confirm_accept(struct smc_sock *smc,
 637                                       struct smc_clc_msg_accept_confirm_v2 *clc_v2,
 638                                       int first_contact, u8 version)
 639{
 640        struct smc_connection *conn = &smc->conn;
 641        struct smc_clc_msg_accept_confirm *clc;
 642        struct smc_clc_first_contact_ext fce;
 643        struct smc_clc_msg_trail trl;
 644        struct kvec vec[3];
 645        struct msghdr msg;
 646        int i, len;
 647
 648        /* send SMC Confirm CLC msg */
 649        clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
 650        clc->hdr.version = version;     /* SMC version */
 651        if (first_contact)
 652                clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
 653        if (conn->lgr->is_smcd) {
 654                /* SMC-D specific settings */
 655                memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
 656                       sizeof(SMCD_EYECATCHER));
 657                clc->hdr.typev1 = SMC_TYPE_D;
 658                clc->d0.gid = conn->lgr->smcd->local_gid;
 659                clc->d0.token = conn->rmb_desc->token;
 660                clc->d0.dmbe_size = conn->rmbe_size_short;
 661                clc->d0.dmbe_idx = 0;
 662                memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
 663                if (version == SMC_V1) {
 664                        clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
 665                } else {
 666                        u8 *eid = NULL;
 667
 668                        clc_v2->chid = htons(smc_ism_get_chid(conn->lgr->smcd));
 669                        smc_ism_get_system_eid(conn->lgr->smcd, &eid);
 670                        if (eid)
 671                                memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN);
 672                        len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
 673                        if (first_contact)
 674                                smc_clc_fill_fce(&fce, &len);
 675                        clc_v2->hdr.length = htons(len);
 676                }
 677                memcpy(trl.eyecatcher, SMCD_EYECATCHER,
 678                       sizeof(SMCD_EYECATCHER));
 679        } else {
 680                struct smc_link *link = conn->lnk;
 681
 682                /* SMC-R specific settings */
 683                link = conn->lnk;
 684                memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER,
 685                       sizeof(SMC_EYECATCHER));
 686                clc->hdr.typev1 = SMC_TYPE_R;
 687                clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
 688                memcpy(clc->r0.lcl.id_for_peer, local_systemid,
 689                       sizeof(local_systemid));
 690                memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE);
 691                memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
 692                       ETH_ALEN);
 693                hton24(clc->r0.qpn, link->roce_qp->qp_num);
 694                clc->r0.rmb_rkey =
 695                        htonl(conn->rmb_desc->mr_rx[link->link_idx]->rkey);
 696                clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
 697                clc->r0.rmbe_alert_token = htonl(conn->alert_token_local);
 698                switch (clc->hdr.type) {
 699                case SMC_CLC_ACCEPT:
 700                        clc->r0.qp_mtu = link->path_mtu;
 701                        break;
 702                case SMC_CLC_CONFIRM:
 703                        clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu);
 704                        break;
 705                }
 706                clc->r0.rmbe_size = conn->rmbe_size_short;
 707                clc->r0.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
 708                                (conn->rmb_desc->sgt[link->link_idx].sgl));
 709                hton24(clc->r0.psn, link->psn_initial);
 710                memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
 711        }
 712
 713        memset(&msg, 0, sizeof(msg));
 714        i = 0;
 715        vec[i].iov_base = clc_v2;
 716        if (version > SMC_V1)
 717                vec[i++].iov_len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 - sizeof(trl);
 718        else
 719                vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
 720                                                SMCD_CLC_ACCEPT_CONFIRM_LEN :
 721                                                SMCR_CLC_ACCEPT_CONFIRM_LEN) -
 722                                   sizeof(trl);
 723        if (version > SMC_V1 && first_contact) {
 724                vec[i].iov_base = &fce;
 725                vec[i++].iov_len = sizeof(fce);
 726        }
 727        vec[i].iov_base = &trl;
 728        vec[i++].iov_len = sizeof(trl);
 729        return kernel_sendmsg(smc->clcsock, &msg, vec, 1,
 730                              ntohs(clc->hdr.length));
 731}
 732
 733/* send CLC CONFIRM message across internal TCP socket */
 734int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
 735                         u8 version)
 736{
 737        struct smc_clc_msg_accept_confirm_v2 cclc_v2;
 738        int reason_code = 0;
 739        int len;
 740
 741        /* send SMC Confirm CLC msg */
 742        memset(&cclc_v2, 0, sizeof(cclc_v2));
 743        cclc_v2.hdr.type = SMC_CLC_CONFIRM;
 744        len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact,
 745                                          version);
 746        if (len < ntohs(cclc_v2.hdr.length)) {
 747                if (len >= 0) {
 748                        reason_code = -ENETUNREACH;
 749                        smc->sk.sk_err = -reason_code;
 750                } else {
 751                        smc->sk.sk_err = smc->clcsock->sk->sk_err;
 752                        reason_code = -smc->sk.sk_err;
 753                }
 754        }
 755        return reason_code;
 756}
 757
 758/* send CLC ACCEPT message across internal TCP socket */
 759int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
 760                        u8 version)
 761{
 762        struct smc_clc_msg_accept_confirm_v2 aclc_v2;
 763        int len;
 764
 765        memset(&aclc_v2, 0, sizeof(aclc_v2));
 766        aclc_v2.hdr.type = SMC_CLC_ACCEPT;
 767        len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
 768                                          version);
 769        if (len < ntohs(aclc_v2.hdr.length))
 770                len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
 771
 772        return len > 0 ? 0 : len;
 773}
 774
 775void smc_clc_get_hostname(u8 **host)
 776{
 777        *host = &smc_hostname[0];
 778}
 779
 780void __init smc_clc_init(void)
 781{
 782        struct new_utsname *u;
 783
 784        memset(smc_hostname, _S, sizeof(smc_hostname)); /* ASCII blanks */
 785        u = utsname();
 786        memcpy(smc_hostname, u->nodename,
 787               min_t(size_t, strlen(u->nodename), sizeof(smc_hostname)));
 788}
 789