18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared Memory Communications over RDMA (SMC-R) and RoCE 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * CLC (connection layer control) handshake over initial TCP socket to 68c2ecf20Sopenharmony_ci * prepare for RDMA traffic 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2016, 2018 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/in.h> 148c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 168c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 178c2ecf20Sopenharmony_ci#include <linux/utsname.h> 188c2ecf20Sopenharmony_ci#include <linux/ctype.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <net/addrconf.h> 218c2ecf20Sopenharmony_ci#include <net/sock.h> 228c2ecf20Sopenharmony_ci#include <net/tcp.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "smc.h" 258c2ecf20Sopenharmony_ci#include "smc_core.h" 268c2ecf20Sopenharmony_ci#include "smc_clc.h" 278c2ecf20Sopenharmony_ci#include "smc_ib.h" 288c2ecf20Sopenharmony_ci#include "smc_ism.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68 318c2ecf20Sopenharmony_ci#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48 328c2ecf20Sopenharmony_ci#define SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 78 338c2ecf20Sopenharmony_ci#define SMC_CLC_RECV_BUF_LEN 100 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* eye catcher "SMCR" EBCDIC for CLC messages */ 368c2ecf20Sopenharmony_cistatic const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'}; 378c2ecf20Sopenharmony_ci/* eye catcher "SMCD" EBCDIC for CLC messages */ 388c2ecf20Sopenharmony_cistatic const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic u8 smc_hostname[SMC_MAX_HOSTNAME_LEN]; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* check arriving CLC proposal */ 438c2ecf20Sopenharmony_cistatic bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *pclc_prfx; 468c2ecf20Sopenharmony_ci struct smc_clc_smcd_v2_extension *smcd_v2_ext; 478c2ecf20Sopenharmony_ci struct smc_clc_msg_hdr *hdr = &pclc->hdr; 488c2ecf20Sopenharmony_ci struct smc_clc_v2_extension *v2_ext; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci v2_ext = smc_get_clc_v2_ext(pclc); 518c2ecf20Sopenharmony_ci pclc_prfx = smc_clc_proposal_get_prefix(pclc); 528c2ecf20Sopenharmony_ci if (hdr->version == SMC_V1) { 538c2ecf20Sopenharmony_ci if (hdr->typev1 == SMC_TYPE_N) 548c2ecf20Sopenharmony_ci return false; 558c2ecf20Sopenharmony_ci if (ntohs(hdr->length) != 568c2ecf20Sopenharmony_ci sizeof(*pclc) + ntohs(pclc->iparea_offset) + 578c2ecf20Sopenharmony_ci sizeof(*pclc_prfx) + 588c2ecf20Sopenharmony_ci pclc_prfx->ipv6_prefixes_cnt * 598c2ecf20Sopenharmony_ci sizeof(struct smc_clc_ipv6_prefix) + 608c2ecf20Sopenharmony_ci sizeof(struct smc_clc_msg_trail)) 618c2ecf20Sopenharmony_ci return false; 628c2ecf20Sopenharmony_ci } else { 638c2ecf20Sopenharmony_ci if (ntohs(hdr->length) != 648c2ecf20Sopenharmony_ci sizeof(*pclc) + 658c2ecf20Sopenharmony_ci sizeof(struct smc_clc_msg_smcd) + 668c2ecf20Sopenharmony_ci (hdr->typev1 != SMC_TYPE_N ? 678c2ecf20Sopenharmony_ci sizeof(*pclc_prfx) + 688c2ecf20Sopenharmony_ci pclc_prfx->ipv6_prefixes_cnt * 698c2ecf20Sopenharmony_ci sizeof(struct smc_clc_ipv6_prefix) : 0) + 708c2ecf20Sopenharmony_ci (hdr->typev2 != SMC_TYPE_N ? 718c2ecf20Sopenharmony_ci sizeof(*v2_ext) + 728c2ecf20Sopenharmony_ci v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN : 0) + 738c2ecf20Sopenharmony_ci (smcd_indicated(hdr->typev2) ? 748c2ecf20Sopenharmony_ci sizeof(*smcd_v2_ext) + v2_ext->hdr.ism_gid_cnt * 758c2ecf20Sopenharmony_ci sizeof(struct smc_clc_smcd_gid_chid) : 768c2ecf20Sopenharmony_ci 0) + 778c2ecf20Sopenharmony_ci sizeof(struct smc_clc_msg_trail)) 788c2ecf20Sopenharmony_ci return false; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci return true; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* check arriving CLC accept or confirm */ 848c2ecf20Sopenharmony_cistatic bool 858c2ecf20Sopenharmony_cismc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct smc_clc_msg_hdr *hdr = &clc_v2->hdr; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D) 908c2ecf20Sopenharmony_ci return false; 918c2ecf20Sopenharmony_ci if (hdr->version == SMC_V1) { 928c2ecf20Sopenharmony_ci if ((hdr->typev1 == SMC_TYPE_R && 938c2ecf20Sopenharmony_ci ntohs(hdr->length) != SMCR_CLC_ACCEPT_CONFIRM_LEN) || 948c2ecf20Sopenharmony_ci (hdr->typev1 == SMC_TYPE_D && 958c2ecf20Sopenharmony_ci ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN)) 968c2ecf20Sopenharmony_ci return false; 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci if (hdr->typev1 == SMC_TYPE_D && 998c2ecf20Sopenharmony_ci ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 && 1008c2ecf20Sopenharmony_ci (ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 + 1018c2ecf20Sopenharmony_ci sizeof(struct smc_clc_first_contact_ext))) 1028c2ecf20Sopenharmony_ci return false; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci return true; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void smc_clc_fill_fce(struct smc_clc_first_contact_ext *fce, int *len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci memset(fce, 0, sizeof(*fce)); 1108c2ecf20Sopenharmony_ci fce->os_type = SMC_CLC_OS_LINUX; 1118c2ecf20Sopenharmony_ci fce->release = SMC_RELEASE; 1128c2ecf20Sopenharmony_ci memcpy(fce->hostname, smc_hostname, sizeof(smc_hostname)); 1138c2ecf20Sopenharmony_ci (*len) += sizeof(*fce); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* check if received message has a correct header length and contains valid 1178c2ecf20Sopenharmony_ci * heading and trailing eyecatchers 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct smc_clc_msg_accept_confirm_v2 *clc_v2; 1228c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal *pclc; 1238c2ecf20Sopenharmony_ci struct smc_clc_msg_decline *dclc; 1248c2ecf20Sopenharmony_ci struct smc_clc_msg_trail *trl; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) && 1278c2ecf20Sopenharmony_ci memcmp(clcm->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER))) 1288c2ecf20Sopenharmony_ci return false; 1298c2ecf20Sopenharmony_ci switch (clcm->type) { 1308c2ecf20Sopenharmony_ci case SMC_CLC_PROPOSAL: 1318c2ecf20Sopenharmony_ci pclc = (struct smc_clc_msg_proposal *)clcm; 1328c2ecf20Sopenharmony_ci if (!smc_clc_msg_prop_valid(pclc)) 1338c2ecf20Sopenharmony_ci return false; 1348c2ecf20Sopenharmony_ci trl = (struct smc_clc_msg_trail *) 1358c2ecf20Sopenharmony_ci ((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl)); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case SMC_CLC_ACCEPT: 1388c2ecf20Sopenharmony_ci case SMC_CLC_CONFIRM: 1398c2ecf20Sopenharmony_ci clc_v2 = (struct smc_clc_msg_accept_confirm_v2 *)clcm; 1408c2ecf20Sopenharmony_ci if (!smc_clc_msg_acc_conf_valid(clc_v2)) 1418c2ecf20Sopenharmony_ci return false; 1428c2ecf20Sopenharmony_ci trl = (struct smc_clc_msg_trail *) 1438c2ecf20Sopenharmony_ci ((u8 *)clc_v2 + ntohs(clc_v2->hdr.length) - 1448c2ecf20Sopenharmony_ci sizeof(*trl)); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case SMC_CLC_DECLINE: 1478c2ecf20Sopenharmony_ci dclc = (struct smc_clc_msg_decline *)clcm; 1488c2ecf20Sopenharmony_ci if (ntohs(dclc->hdr.length) != sizeof(*dclc)) 1498c2ecf20Sopenharmony_ci return false; 1508c2ecf20Sopenharmony_ci trl = &dclc->trl; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci default: 1538c2ecf20Sopenharmony_ci return false; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci if (check_trl && 1568c2ecf20Sopenharmony_ci memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) && 1578c2ecf20Sopenharmony_ci memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER))) 1588c2ecf20Sopenharmony_ci return false; 1598c2ecf20Sopenharmony_ci return true; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* find ipv4 addr on device and get the prefix len, fill CLC proposal msg */ 1638c2ecf20Sopenharmony_cistatic int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4, 1648c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct in_device *in_dev = __in_dev_get_rcu(dst->dev); 1678c2ecf20Sopenharmony_ci const struct in_ifaddr *ifa; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!in_dev) 1708c2ecf20Sopenharmony_ci return -ENODEV; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci in_dev_for_each_ifa_rcu(ifa, in_dev) { 1738c2ecf20Sopenharmony_ci if (!inet_ifa_match(ipv4, ifa)) 1748c2ecf20Sopenharmony_ci continue; 1758c2ecf20Sopenharmony_ci prop->prefix_len = inet_mask_len(ifa->ifa_mask); 1768c2ecf20Sopenharmony_ci prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask; 1778c2ecf20Sopenharmony_ci /* prop->ipv6_prefixes_cnt = 0; already done by memset before */ 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci return -ENOENT; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* fill CLC proposal msg with ipv6 prefixes from device */ 1848c2ecf20Sopenharmony_cistatic int smc_clc_prfx_set6_rcu(struct dst_entry *dst, 1858c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop, 1868c2ecf20Sopenharmony_ci struct smc_clc_ipv6_prefix *ipv6_prfx) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 1898c2ecf20Sopenharmony_ci struct inet6_dev *in6_dev = __in6_dev_get(dst->dev); 1908c2ecf20Sopenharmony_ci struct inet6_ifaddr *ifa; 1918c2ecf20Sopenharmony_ci int cnt = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (!in6_dev) 1948c2ecf20Sopenharmony_ci return -ENODEV; 1958c2ecf20Sopenharmony_ci /* use a maximum of 8 IPv6 prefixes from device */ 1968c2ecf20Sopenharmony_ci list_for_each_entry(ifa, &in6_dev->addr_list, if_list) { 1978c2ecf20Sopenharmony_ci if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL) 1988c2ecf20Sopenharmony_ci continue; 1998c2ecf20Sopenharmony_ci ipv6_addr_prefix(&ipv6_prfx[cnt].prefix, 2008c2ecf20Sopenharmony_ci &ifa->addr, ifa->prefix_len); 2018c2ecf20Sopenharmony_ci ipv6_prfx[cnt].prefix_len = ifa->prefix_len; 2028c2ecf20Sopenharmony_ci cnt++; 2038c2ecf20Sopenharmony_ci if (cnt == SMC_CLC_MAX_V6_PREFIX) 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci prop->ipv6_prefixes_cnt = cnt; 2078c2ecf20Sopenharmony_ci if (cnt) 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci#endif 2108c2ecf20Sopenharmony_ci return -ENOENT; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* retrieve and set prefixes in CLC proposal msg */ 2148c2ecf20Sopenharmony_cistatic int smc_clc_prfx_set(struct socket *clcsock, 2158c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop, 2168c2ecf20Sopenharmony_ci struct smc_clc_ipv6_prefix *ipv6_prfx) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct dst_entry *dst = sk_dst_get(clcsock->sk); 2198c2ecf20Sopenharmony_ci struct sockaddr_storage addrs; 2208c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 2218c2ecf20Sopenharmony_ci struct sockaddr_in *addr; 2228c2ecf20Sopenharmony_ci int rc = -ENOENT; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!dst) { 2258c2ecf20Sopenharmony_ci rc = -ENOTCONN; 2268c2ecf20Sopenharmony_ci goto out; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci if (!dst->dev) { 2298c2ecf20Sopenharmony_ci rc = -ENODEV; 2308c2ecf20Sopenharmony_ci goto out_rel; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci /* get address to which the internal TCP socket is bound */ 2338c2ecf20Sopenharmony_ci if (kernel_getsockname(clcsock, (struct sockaddr *)&addrs) < 0) 2348c2ecf20Sopenharmony_ci goto out_rel; 2358c2ecf20Sopenharmony_ci /* analyze IP specific data of net_device belonging to TCP socket */ 2368c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)&addrs; 2378c2ecf20Sopenharmony_ci rcu_read_lock(); 2388c2ecf20Sopenharmony_ci if (addrs.ss_family == PF_INET) { 2398c2ecf20Sopenharmony_ci /* IPv4 */ 2408c2ecf20Sopenharmony_ci addr = (struct sockaddr_in *)&addrs; 2418c2ecf20Sopenharmony_ci rc = smc_clc_prfx_set4_rcu(dst, addr->sin_addr.s_addr, prop); 2428c2ecf20Sopenharmony_ci } else if (ipv6_addr_v4mapped(&addr6->sin6_addr)) { 2438c2ecf20Sopenharmony_ci /* mapped IPv4 address - peer is IPv4 only */ 2448c2ecf20Sopenharmony_ci rc = smc_clc_prfx_set4_rcu(dst, addr6->sin6_addr.s6_addr32[3], 2458c2ecf20Sopenharmony_ci prop); 2468c2ecf20Sopenharmony_ci } else { 2478c2ecf20Sopenharmony_ci /* IPv6 */ 2488c2ecf20Sopenharmony_ci rc = smc_clc_prfx_set6_rcu(dst, prop, ipv6_prfx); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci rcu_read_unlock(); 2518c2ecf20Sopenharmony_ciout_rel: 2528c2ecf20Sopenharmony_ci dst_release(dst); 2538c2ecf20Sopenharmony_ciout: 2548c2ecf20Sopenharmony_ci return rc; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* match ipv4 addrs of dev against addr in CLC proposal */ 2588c2ecf20Sopenharmony_cistatic int smc_clc_prfx_match4_rcu(struct net_device *dev, 2598c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct in_device *in_dev = __in_dev_get_rcu(dev); 2628c2ecf20Sopenharmony_ci const struct in_ifaddr *ifa; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!in_dev) 2658c2ecf20Sopenharmony_ci return -ENODEV; 2668c2ecf20Sopenharmony_ci in_dev_for_each_ifa_rcu(ifa, in_dev) { 2678c2ecf20Sopenharmony_ci if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) && 2688c2ecf20Sopenharmony_ci inet_ifa_match(prop->outgoing_subnet, ifa)) 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return -ENOENT; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* match ipv6 addrs of dev against addrs in CLC proposal */ 2768c2ecf20Sopenharmony_cistatic int smc_clc_prfx_match6_rcu(struct net_device *dev, 2778c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 2808c2ecf20Sopenharmony_ci struct inet6_dev *in6_dev = __in6_dev_get(dev); 2818c2ecf20Sopenharmony_ci struct smc_clc_ipv6_prefix *ipv6_prfx; 2828c2ecf20Sopenharmony_ci struct inet6_ifaddr *ifa; 2838c2ecf20Sopenharmony_ci int i, max; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!in6_dev) 2868c2ecf20Sopenharmony_ci return -ENODEV; 2878c2ecf20Sopenharmony_ci /* ipv6 prefix list starts behind smc_clc_msg_proposal_prefix */ 2888c2ecf20Sopenharmony_ci ipv6_prfx = (struct smc_clc_ipv6_prefix *)((u8 *)prop + sizeof(*prop)); 2898c2ecf20Sopenharmony_ci max = min_t(u8, prop->ipv6_prefixes_cnt, SMC_CLC_MAX_V6_PREFIX); 2908c2ecf20Sopenharmony_ci list_for_each_entry(ifa, &in6_dev->addr_list, if_list) { 2918c2ecf20Sopenharmony_ci if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL) 2928c2ecf20Sopenharmony_ci continue; 2938c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 2948c2ecf20Sopenharmony_ci if (ifa->prefix_len == ipv6_prfx[i].prefix_len && 2958c2ecf20Sopenharmony_ci ipv6_prefix_equal(&ifa->addr, &ipv6_prfx[i].prefix, 2968c2ecf20Sopenharmony_ci ifa->prefix_len)) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci#endif 3018c2ecf20Sopenharmony_ci return -ENOENT; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* check if proposed prefixes match one of our device prefixes */ 3058c2ecf20Sopenharmony_ciint smc_clc_prfx_match(struct socket *clcsock, 3068c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *prop) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct dst_entry *dst = sk_dst_get(clcsock->sk); 3098c2ecf20Sopenharmony_ci int rc; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!dst) { 3128c2ecf20Sopenharmony_ci rc = -ENOTCONN; 3138c2ecf20Sopenharmony_ci goto out; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci if (!dst->dev) { 3168c2ecf20Sopenharmony_ci rc = -ENODEV; 3178c2ecf20Sopenharmony_ci goto out_rel; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci rcu_read_lock(); 3208c2ecf20Sopenharmony_ci if (!prop->ipv6_prefixes_cnt) 3218c2ecf20Sopenharmony_ci rc = smc_clc_prfx_match4_rcu(dst->dev, prop); 3228c2ecf20Sopenharmony_ci else 3238c2ecf20Sopenharmony_ci rc = smc_clc_prfx_match6_rcu(dst->dev, prop); 3248c2ecf20Sopenharmony_ci rcu_read_unlock(); 3258c2ecf20Sopenharmony_ciout_rel: 3268c2ecf20Sopenharmony_ci dst_release(dst); 3278c2ecf20Sopenharmony_ciout: 3288c2ecf20Sopenharmony_ci return rc; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* Wait for data on the tcp-socket, analyze received data 3328c2ecf20Sopenharmony_ci * Returns: 3338c2ecf20Sopenharmony_ci * 0 if success and it was not a decline that we received. 3348c2ecf20Sopenharmony_ci * SMC_CLC_DECL_REPLY if decline received for fallback w/o another decl send. 3358c2ecf20Sopenharmony_ci * clcsock error, -EINTR, -ECONNRESET, -EPROTO otherwise. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ciint smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen, 3388c2ecf20Sopenharmony_ci u8 expected_type, unsigned long timeout) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci long rcvtimeo = smc->clcsock->sk->sk_rcvtimeo; 3418c2ecf20Sopenharmony_ci struct sock *clc_sk = smc->clcsock->sk; 3428c2ecf20Sopenharmony_ci struct smc_clc_msg_hdr *clcm = buf; 3438c2ecf20Sopenharmony_ci struct msghdr msg = {NULL, 0}; 3448c2ecf20Sopenharmony_ci int reason_code = 0; 3458c2ecf20Sopenharmony_ci struct kvec vec = {buf, buflen}; 3468c2ecf20Sopenharmony_ci int len, datlen, recvlen; 3478c2ecf20Sopenharmony_ci bool check_trl = true; 3488c2ecf20Sopenharmony_ci int krflags; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* peek the first few bytes to determine length of data to receive 3518c2ecf20Sopenharmony_ci * so we don't consume any subsequent CLC message or payload data 3528c2ecf20Sopenharmony_ci * in the TCP byte stream 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * Caller must make sure that buflen is no less than 3568c2ecf20Sopenharmony_ci * sizeof(struct smc_clc_msg_hdr) 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci krflags = MSG_PEEK | MSG_WAITALL; 3598c2ecf20Sopenharmony_ci clc_sk->sk_rcvtimeo = timeout; 3608c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, 3618c2ecf20Sopenharmony_ci sizeof(struct smc_clc_msg_hdr)); 3628c2ecf20Sopenharmony_ci len = sock_recvmsg(smc->clcsock, &msg, krflags); 3638c2ecf20Sopenharmony_ci if (signal_pending(current)) { 3648c2ecf20Sopenharmony_ci reason_code = -EINTR; 3658c2ecf20Sopenharmony_ci clc_sk->sk_err = EINTR; 3668c2ecf20Sopenharmony_ci smc->sk.sk_err = EINTR; 3678c2ecf20Sopenharmony_ci goto out; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci if (clc_sk->sk_err) { 3708c2ecf20Sopenharmony_ci reason_code = -clc_sk->sk_err; 3718c2ecf20Sopenharmony_ci if (clc_sk->sk_err == EAGAIN && 3728c2ecf20Sopenharmony_ci expected_type == SMC_CLC_DECLINE) 3738c2ecf20Sopenharmony_ci clc_sk->sk_err = 0; /* reset for fallback usage */ 3748c2ecf20Sopenharmony_ci else 3758c2ecf20Sopenharmony_ci smc->sk.sk_err = clc_sk->sk_err; 3768c2ecf20Sopenharmony_ci goto out; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci if (!len) { /* peer has performed orderly shutdown */ 3798c2ecf20Sopenharmony_ci smc->sk.sk_err = ECONNRESET; 3808c2ecf20Sopenharmony_ci reason_code = -ECONNRESET; 3818c2ecf20Sopenharmony_ci goto out; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci if (len < 0) { 3848c2ecf20Sopenharmony_ci if (len != -EAGAIN || expected_type != SMC_CLC_DECLINE) 3858c2ecf20Sopenharmony_ci smc->sk.sk_err = -len; 3868c2ecf20Sopenharmony_ci reason_code = len; 3878c2ecf20Sopenharmony_ci goto out; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci datlen = ntohs(clcm->length); 3908c2ecf20Sopenharmony_ci if ((len < sizeof(struct smc_clc_msg_hdr)) || 3918c2ecf20Sopenharmony_ci (clcm->version < SMC_V1) || 3928c2ecf20Sopenharmony_ci ((clcm->type != SMC_CLC_DECLINE) && 3938c2ecf20Sopenharmony_ci (clcm->type != expected_type))) { 3948c2ecf20Sopenharmony_ci smc->sk.sk_err = EPROTO; 3958c2ecf20Sopenharmony_ci reason_code = -EPROTO; 3968c2ecf20Sopenharmony_ci goto out; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* receive the complete CLC message */ 4008c2ecf20Sopenharmony_ci memset(&msg, 0, sizeof(struct msghdr)); 4018c2ecf20Sopenharmony_ci if (datlen > buflen) { 4028c2ecf20Sopenharmony_ci check_trl = false; 4038c2ecf20Sopenharmony_ci recvlen = buflen; 4048c2ecf20Sopenharmony_ci } else { 4058c2ecf20Sopenharmony_ci recvlen = datlen; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen); 4088c2ecf20Sopenharmony_ci krflags = MSG_WAITALL; 4098c2ecf20Sopenharmony_ci len = sock_recvmsg(smc->clcsock, &msg, krflags); 4108c2ecf20Sopenharmony_ci if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) { 4118c2ecf20Sopenharmony_ci smc->sk.sk_err = EPROTO; 4128c2ecf20Sopenharmony_ci reason_code = -EPROTO; 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci datlen -= len; 4168c2ecf20Sopenharmony_ci while (datlen) { 4178c2ecf20Sopenharmony_ci u8 tmp[SMC_CLC_RECV_BUF_LEN]; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci vec.iov_base = &tmp; 4208c2ecf20Sopenharmony_ci vec.iov_len = SMC_CLC_RECV_BUF_LEN; 4218c2ecf20Sopenharmony_ci /* receive remaining proposal message */ 4228c2ecf20Sopenharmony_ci recvlen = datlen > SMC_CLC_RECV_BUF_LEN ? 4238c2ecf20Sopenharmony_ci SMC_CLC_RECV_BUF_LEN : datlen; 4248c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen); 4258c2ecf20Sopenharmony_ci len = sock_recvmsg(smc->clcsock, &msg, krflags); 4268c2ecf20Sopenharmony_ci datlen -= len; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci if (clcm->type == SMC_CLC_DECLINE) { 4298c2ecf20Sopenharmony_ci struct smc_clc_msg_decline *dclc; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dclc = (struct smc_clc_msg_decline *)clcm; 4328c2ecf20Sopenharmony_ci reason_code = SMC_CLC_DECL_PEERDECL; 4338c2ecf20Sopenharmony_ci smc->peer_diagnosis = ntohl(dclc->peer_diagnosis); 4348c2ecf20Sopenharmony_ci if (((struct smc_clc_msg_decline *)buf)->hdr.typev2 & 4358c2ecf20Sopenharmony_ci SMC_FIRST_CONTACT_MASK) { 4368c2ecf20Sopenharmony_ci smc->conn.lgr->sync_err = 1; 4378c2ecf20Sopenharmony_ci smc_lgr_terminate_sched(smc->conn.lgr); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciout: 4428c2ecf20Sopenharmony_ci clc_sk->sk_rcvtimeo = rcvtimeo; 4438c2ecf20Sopenharmony_ci return reason_code; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* send CLC DECLINE message across internal TCP socket */ 4478c2ecf20Sopenharmony_ciint smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct smc_clc_msg_decline dclc; 4508c2ecf20Sopenharmony_ci struct msghdr msg; 4518c2ecf20Sopenharmony_ci struct kvec vec; 4528c2ecf20Sopenharmony_ci int len; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci memset(&dclc, 0, sizeof(dclc)); 4558c2ecf20Sopenharmony_ci memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 4568c2ecf20Sopenharmony_ci dclc.hdr.type = SMC_CLC_DECLINE; 4578c2ecf20Sopenharmony_ci dclc.hdr.length = htons(sizeof(struct smc_clc_msg_decline)); 4588c2ecf20Sopenharmony_ci dclc.hdr.version = version; 4598c2ecf20Sopenharmony_ci dclc.os_type = version == SMC_V1 ? 0 : SMC_CLC_OS_LINUX; 4608c2ecf20Sopenharmony_ci dclc.hdr.typev2 = (peer_diag_info == SMC_CLC_DECL_SYNCERR) ? 4618c2ecf20Sopenharmony_ci SMC_FIRST_CONTACT_MASK : 0; 4628c2ecf20Sopenharmony_ci if ((!smc->conn.lgr || !smc->conn.lgr->is_smcd) && 4638c2ecf20Sopenharmony_ci smc_ib_is_valid_local_systemid()) 4648c2ecf20Sopenharmony_ci memcpy(dclc.id_for_peer, local_systemid, 4658c2ecf20Sopenharmony_ci sizeof(local_systemid)); 4668c2ecf20Sopenharmony_ci dclc.peer_diagnosis = htonl(peer_diag_info); 4678c2ecf20Sopenharmony_ci memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 4708c2ecf20Sopenharmony_ci vec.iov_base = &dclc; 4718c2ecf20Sopenharmony_ci vec.iov_len = sizeof(struct smc_clc_msg_decline); 4728c2ecf20Sopenharmony_ci len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, 4738c2ecf20Sopenharmony_ci sizeof(struct smc_clc_msg_decline)); 4748c2ecf20Sopenharmony_ci if (len < 0 || len < sizeof(struct smc_clc_msg_decline)) 4758c2ecf20Sopenharmony_ci len = -EPROTO; 4768c2ecf20Sopenharmony_ci return len > 0 ? 0 : len; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/* send CLC PROPOSAL message across internal TCP socket */ 4808c2ecf20Sopenharmony_ciint smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct smc_clc_smcd_v2_extension *smcd_v2_ext; 4838c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_prefix *pclc_prfx; 4848c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal *pclc_base; 4858c2ecf20Sopenharmony_ci struct smc_clc_smcd_gid_chid *gidchids; 4868c2ecf20Sopenharmony_ci struct smc_clc_msg_proposal_area *pclc; 4878c2ecf20Sopenharmony_ci struct smc_clc_ipv6_prefix *ipv6_prfx; 4888c2ecf20Sopenharmony_ci struct smc_clc_v2_extension *v2_ext; 4898c2ecf20Sopenharmony_ci struct smc_clc_msg_smcd *pclc_smcd; 4908c2ecf20Sopenharmony_ci struct smc_clc_msg_trail *trl; 4918c2ecf20Sopenharmony_ci int len, i, plen, rc; 4928c2ecf20Sopenharmony_ci int reason_code = 0; 4938c2ecf20Sopenharmony_ci struct kvec vec[8]; 4948c2ecf20Sopenharmony_ci struct msghdr msg; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci pclc = kzalloc(sizeof(*pclc), GFP_KERNEL); 4978c2ecf20Sopenharmony_ci if (!pclc) 4988c2ecf20Sopenharmony_ci return -ENOMEM; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci pclc_base = &pclc->pclc_base; 5018c2ecf20Sopenharmony_ci pclc_smcd = &pclc->pclc_smcd; 5028c2ecf20Sopenharmony_ci pclc_prfx = &pclc->pclc_prfx; 5038c2ecf20Sopenharmony_ci ipv6_prfx = pclc->pclc_prfx_ipv6; 5048c2ecf20Sopenharmony_ci v2_ext = &pclc->pclc_v2_ext; 5058c2ecf20Sopenharmony_ci smcd_v2_ext = &pclc->pclc_smcd_v2_ext; 5068c2ecf20Sopenharmony_ci gidchids = pclc->pclc_gidchids; 5078c2ecf20Sopenharmony_ci trl = &pclc->pclc_trl; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci pclc_base->hdr.version = SMC_V2; 5108c2ecf20Sopenharmony_ci pclc_base->hdr.typev1 = ini->smc_type_v1; 5118c2ecf20Sopenharmony_ci pclc_base->hdr.typev2 = ini->smc_type_v2; 5128c2ecf20Sopenharmony_ci plen = sizeof(*pclc_base) + sizeof(*pclc_smcd) + sizeof(*trl); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* retrieve ip prefixes for CLC proposal msg */ 5158c2ecf20Sopenharmony_ci if (ini->smc_type_v1 != SMC_TYPE_N) { 5168c2ecf20Sopenharmony_ci rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx); 5178c2ecf20Sopenharmony_ci if (rc) { 5188c2ecf20Sopenharmony_ci if (ini->smc_type_v2 == SMC_TYPE_N) { 5198c2ecf20Sopenharmony_ci kfree(pclc); 5208c2ecf20Sopenharmony_ci return SMC_CLC_DECL_CNFERR; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci pclc_base->hdr.typev1 = SMC_TYPE_N; 5238c2ecf20Sopenharmony_ci } else { 5248c2ecf20Sopenharmony_ci pclc_base->iparea_offset = htons(sizeof(*pclc_smcd)); 5258c2ecf20Sopenharmony_ci plen += sizeof(*pclc_prfx) + 5268c2ecf20Sopenharmony_ci pclc_prfx->ipv6_prefixes_cnt * 5278c2ecf20Sopenharmony_ci sizeof(ipv6_prfx[0]); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* build SMC Proposal CLC message */ 5328c2ecf20Sopenharmony_ci memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER, 5338c2ecf20Sopenharmony_ci sizeof(SMC_EYECATCHER)); 5348c2ecf20Sopenharmony_ci pclc_base->hdr.type = SMC_CLC_PROPOSAL; 5358c2ecf20Sopenharmony_ci if (smcr_indicated(ini->smc_type_v1)) { 5368c2ecf20Sopenharmony_ci /* add SMC-R specifics */ 5378c2ecf20Sopenharmony_ci memcpy(pclc_base->lcl.id_for_peer, local_systemid, 5388c2ecf20Sopenharmony_ci sizeof(local_systemid)); 5398c2ecf20Sopenharmony_ci memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE); 5408c2ecf20Sopenharmony_ci memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1], 5418c2ecf20Sopenharmony_ci ETH_ALEN); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci if (smcd_indicated(ini->smc_type_v1)) { 5448c2ecf20Sopenharmony_ci /* add SMC-D specifics */ 5458c2ecf20Sopenharmony_ci if (ini->ism_dev[0]) { 5468c2ecf20Sopenharmony_ci pclc_smcd->ism.gid = htonll(ini->ism_dev[0]->local_gid); 5478c2ecf20Sopenharmony_ci pclc_smcd->ism.chid = 5488c2ecf20Sopenharmony_ci htons(smc_ism_get_chid(ini->ism_dev[0])); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci if (ini->smc_type_v2 == SMC_TYPE_N) { 5528c2ecf20Sopenharmony_ci pclc_smcd->v2_ext_offset = 0; 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci u16 v2_ext_offset; 5558c2ecf20Sopenharmony_ci u8 *eid = NULL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci v2_ext_offset = sizeof(*pclc_smcd) - 5588c2ecf20Sopenharmony_ci offsetofend(struct smc_clc_msg_smcd, v2_ext_offset); 5598c2ecf20Sopenharmony_ci if (ini->smc_type_v1 != SMC_TYPE_N) 5608c2ecf20Sopenharmony_ci v2_ext_offset += sizeof(*pclc_prfx) + 5618c2ecf20Sopenharmony_ci pclc_prfx->ipv6_prefixes_cnt * 5628c2ecf20Sopenharmony_ci sizeof(ipv6_prfx[0]); 5638c2ecf20Sopenharmony_ci pclc_smcd->v2_ext_offset = htons(v2_ext_offset); 5648c2ecf20Sopenharmony_ci v2_ext->hdr.eid_cnt = 0; 5658c2ecf20Sopenharmony_ci v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt; 5668c2ecf20Sopenharmony_ci v2_ext->hdr.flag.release = SMC_RELEASE; 5678c2ecf20Sopenharmony_ci v2_ext->hdr.flag.seid = 1; 5688c2ecf20Sopenharmony_ci v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) - 5698c2ecf20Sopenharmony_ci offsetofend(struct smc_clnt_opts_area_hdr, 5708c2ecf20Sopenharmony_ci smcd_v2_ext_offset) + 5718c2ecf20Sopenharmony_ci v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN); 5728c2ecf20Sopenharmony_ci if (ini->ism_dev[0]) 5738c2ecf20Sopenharmony_ci smc_ism_get_system_eid(ini->ism_dev[0], &eid); 5748c2ecf20Sopenharmony_ci else 5758c2ecf20Sopenharmony_ci smc_ism_get_system_eid(ini->ism_dev[1], &eid); 5768c2ecf20Sopenharmony_ci if (eid) 5778c2ecf20Sopenharmony_ci memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN); 5788c2ecf20Sopenharmony_ci plen += sizeof(*v2_ext) + sizeof(*smcd_v2_ext); 5798c2ecf20Sopenharmony_ci if (ini->ism_offered_cnt) { 5808c2ecf20Sopenharmony_ci for (i = 1; i <= ini->ism_offered_cnt; i++) { 5818c2ecf20Sopenharmony_ci gidchids[i - 1].gid = 5828c2ecf20Sopenharmony_ci htonll(ini->ism_dev[i]->local_gid); 5838c2ecf20Sopenharmony_ci gidchids[i - 1].chid = 5848c2ecf20Sopenharmony_ci htons(smc_ism_get_chid(ini->ism_dev[i])); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci plen += ini->ism_offered_cnt * 5878c2ecf20Sopenharmony_ci sizeof(struct smc_clc_smcd_gid_chid); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci pclc_base->hdr.length = htons(plen); 5918c2ecf20Sopenharmony_ci memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* send SMC Proposal CLC message */ 5948c2ecf20Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 5958c2ecf20Sopenharmony_ci i = 0; 5968c2ecf20Sopenharmony_ci vec[i].iov_base = pclc_base; 5978c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*pclc_base); 5988c2ecf20Sopenharmony_ci vec[i].iov_base = pclc_smcd; 5998c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*pclc_smcd); 6008c2ecf20Sopenharmony_ci if (ini->smc_type_v1 != SMC_TYPE_N) { 6018c2ecf20Sopenharmony_ci vec[i].iov_base = pclc_prfx; 6028c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*pclc_prfx); 6038c2ecf20Sopenharmony_ci if (pclc_prfx->ipv6_prefixes_cnt > 0) { 6048c2ecf20Sopenharmony_ci vec[i].iov_base = ipv6_prfx; 6058c2ecf20Sopenharmony_ci vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt * 6068c2ecf20Sopenharmony_ci sizeof(ipv6_prfx[0]); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (ini->smc_type_v2 != SMC_TYPE_N) { 6108c2ecf20Sopenharmony_ci vec[i].iov_base = v2_ext; 6118c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*v2_ext); 6128c2ecf20Sopenharmony_ci vec[i].iov_base = smcd_v2_ext; 6138c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*smcd_v2_ext); 6148c2ecf20Sopenharmony_ci if (ini->ism_offered_cnt) { 6158c2ecf20Sopenharmony_ci vec[i].iov_base = gidchids; 6168c2ecf20Sopenharmony_ci vec[i++].iov_len = ini->ism_offered_cnt * 6178c2ecf20Sopenharmony_ci sizeof(struct smc_clc_smcd_gid_chid); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci vec[i].iov_base = trl; 6218c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(*trl); 6228c2ecf20Sopenharmony_ci /* due to the few bytes needed for clc-handshake this cannot block */ 6238c2ecf20Sopenharmony_ci len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen); 6248c2ecf20Sopenharmony_ci if (len < 0) { 6258c2ecf20Sopenharmony_ci smc->sk.sk_err = smc->clcsock->sk->sk_err; 6268c2ecf20Sopenharmony_ci reason_code = -smc->sk.sk_err; 6278c2ecf20Sopenharmony_ci } else if (len < ntohs(pclc_base->hdr.length)) { 6288c2ecf20Sopenharmony_ci reason_code = -ENETUNREACH; 6298c2ecf20Sopenharmony_ci smc->sk.sk_err = -reason_code; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci kfree(pclc); 6338c2ecf20Sopenharmony_ci return reason_code; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/* build and send CLC CONFIRM / ACCEPT message */ 6378c2ecf20Sopenharmony_cistatic int smc_clc_send_confirm_accept(struct smc_sock *smc, 6388c2ecf20Sopenharmony_ci struct smc_clc_msg_accept_confirm_v2 *clc_v2, 6398c2ecf20Sopenharmony_ci int first_contact, u8 version) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct smc_connection *conn = &smc->conn; 6428c2ecf20Sopenharmony_ci struct smc_clc_msg_accept_confirm *clc; 6438c2ecf20Sopenharmony_ci struct smc_clc_first_contact_ext fce; 6448c2ecf20Sopenharmony_ci struct smc_clc_msg_trail trl; 6458c2ecf20Sopenharmony_ci struct kvec vec[3]; 6468c2ecf20Sopenharmony_ci struct msghdr msg; 6478c2ecf20Sopenharmony_ci int i, len; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* send SMC Confirm CLC msg */ 6508c2ecf20Sopenharmony_ci clc = (struct smc_clc_msg_accept_confirm *)clc_v2; 6518c2ecf20Sopenharmony_ci clc->hdr.version = version; /* SMC version */ 6528c2ecf20Sopenharmony_ci if (first_contact) 6538c2ecf20Sopenharmony_ci clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK; 6548c2ecf20Sopenharmony_ci if (conn->lgr->is_smcd) { 6558c2ecf20Sopenharmony_ci /* SMC-D specific settings */ 6568c2ecf20Sopenharmony_ci memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, 6578c2ecf20Sopenharmony_ci sizeof(SMCD_EYECATCHER)); 6588c2ecf20Sopenharmony_ci clc->hdr.typev1 = SMC_TYPE_D; 6598c2ecf20Sopenharmony_ci clc->d0.gid = conn->lgr->smcd->local_gid; 6608c2ecf20Sopenharmony_ci clc->d0.token = conn->rmb_desc->token; 6618c2ecf20Sopenharmony_ci clc->d0.dmbe_size = conn->rmbe_size_short; 6628c2ecf20Sopenharmony_ci clc->d0.dmbe_idx = 0; 6638c2ecf20Sopenharmony_ci memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE); 6648c2ecf20Sopenharmony_ci if (version == SMC_V1) { 6658c2ecf20Sopenharmony_ci clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); 6668c2ecf20Sopenharmony_ci } else { 6678c2ecf20Sopenharmony_ci u8 *eid = NULL; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci clc_v2->chid = htons(smc_ism_get_chid(conn->lgr->smcd)); 6708c2ecf20Sopenharmony_ci smc_ism_get_system_eid(conn->lgr->smcd, &eid); 6718c2ecf20Sopenharmony_ci if (eid) 6728c2ecf20Sopenharmony_ci memcpy(clc_v2->eid, eid, SMC_MAX_EID_LEN); 6738c2ecf20Sopenharmony_ci len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; 6748c2ecf20Sopenharmony_ci if (first_contact) 6758c2ecf20Sopenharmony_ci smc_clc_fill_fce(&fce, &len); 6768c2ecf20Sopenharmony_ci clc_v2->hdr.length = htons(len); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci memcpy(trl.eyecatcher, SMCD_EYECATCHER, 6798c2ecf20Sopenharmony_ci sizeof(SMCD_EYECATCHER)); 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci struct smc_link *link = conn->lnk; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* SMC-R specific settings */ 6848c2ecf20Sopenharmony_ci link = conn->lnk; 6858c2ecf20Sopenharmony_ci memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER, 6868c2ecf20Sopenharmony_ci sizeof(SMC_EYECATCHER)); 6878c2ecf20Sopenharmony_ci clc->hdr.typev1 = SMC_TYPE_R; 6888c2ecf20Sopenharmony_ci clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN); 6898c2ecf20Sopenharmony_ci memcpy(clc->r0.lcl.id_for_peer, local_systemid, 6908c2ecf20Sopenharmony_ci sizeof(local_systemid)); 6918c2ecf20Sopenharmony_ci memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE); 6928c2ecf20Sopenharmony_ci memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1], 6938c2ecf20Sopenharmony_ci ETH_ALEN); 6948c2ecf20Sopenharmony_ci hton24(clc->r0.qpn, link->roce_qp->qp_num); 6958c2ecf20Sopenharmony_ci clc->r0.rmb_rkey = 6968c2ecf20Sopenharmony_ci htonl(conn->rmb_desc->mr_rx[link->link_idx]->rkey); 6978c2ecf20Sopenharmony_ci clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */ 6988c2ecf20Sopenharmony_ci clc->r0.rmbe_alert_token = htonl(conn->alert_token_local); 6998c2ecf20Sopenharmony_ci switch (clc->hdr.type) { 7008c2ecf20Sopenharmony_ci case SMC_CLC_ACCEPT: 7018c2ecf20Sopenharmony_ci clc->r0.qp_mtu = link->path_mtu; 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci case SMC_CLC_CONFIRM: 7048c2ecf20Sopenharmony_ci clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu); 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci clc->r0.rmbe_size = conn->rmbe_size_short; 7088c2ecf20Sopenharmony_ci clc->r0.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address 7098c2ecf20Sopenharmony_ci (conn->rmb_desc->sgt[link->link_idx].sgl)); 7108c2ecf20Sopenharmony_ci hton24(clc->r0.psn, link->psn_initial); 7118c2ecf20Sopenharmony_ci memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 7158c2ecf20Sopenharmony_ci i = 0; 7168c2ecf20Sopenharmony_ci vec[i].iov_base = clc_v2; 7178c2ecf20Sopenharmony_ci if (version > SMC_V1) 7188c2ecf20Sopenharmony_ci vec[i++].iov_len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 - sizeof(trl); 7198c2ecf20Sopenharmony_ci else 7208c2ecf20Sopenharmony_ci vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ? 7218c2ecf20Sopenharmony_ci SMCD_CLC_ACCEPT_CONFIRM_LEN : 7228c2ecf20Sopenharmony_ci SMCR_CLC_ACCEPT_CONFIRM_LEN) - 7238c2ecf20Sopenharmony_ci sizeof(trl); 7248c2ecf20Sopenharmony_ci if (version > SMC_V1 && first_contact) { 7258c2ecf20Sopenharmony_ci vec[i].iov_base = &fce; 7268c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(fce); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci vec[i].iov_base = &trl; 7298c2ecf20Sopenharmony_ci vec[i++].iov_len = sizeof(trl); 7308c2ecf20Sopenharmony_ci return kernel_sendmsg(smc->clcsock, &msg, vec, 1, 7318c2ecf20Sopenharmony_ci ntohs(clc->hdr.length)); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci/* send CLC CONFIRM message across internal TCP socket */ 7358c2ecf20Sopenharmony_ciint smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, 7368c2ecf20Sopenharmony_ci u8 version) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct smc_clc_msg_accept_confirm_v2 cclc_v2; 7398c2ecf20Sopenharmony_ci int reason_code = 0; 7408c2ecf20Sopenharmony_ci int len; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* send SMC Confirm CLC msg */ 7438c2ecf20Sopenharmony_ci memset(&cclc_v2, 0, sizeof(cclc_v2)); 7448c2ecf20Sopenharmony_ci cclc_v2.hdr.type = SMC_CLC_CONFIRM; 7458c2ecf20Sopenharmony_ci len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact, 7468c2ecf20Sopenharmony_ci version); 7478c2ecf20Sopenharmony_ci if (len < ntohs(cclc_v2.hdr.length)) { 7488c2ecf20Sopenharmony_ci if (len >= 0) { 7498c2ecf20Sopenharmony_ci reason_code = -ENETUNREACH; 7508c2ecf20Sopenharmony_ci smc->sk.sk_err = -reason_code; 7518c2ecf20Sopenharmony_ci } else { 7528c2ecf20Sopenharmony_ci smc->sk.sk_err = smc->clcsock->sk->sk_err; 7538c2ecf20Sopenharmony_ci reason_code = -smc->sk.sk_err; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci return reason_code; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* send CLC ACCEPT message across internal TCP socket */ 7608c2ecf20Sopenharmony_ciint smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact, 7618c2ecf20Sopenharmony_ci u8 version) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct smc_clc_msg_accept_confirm_v2 aclc_v2; 7648c2ecf20Sopenharmony_ci int len; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci memset(&aclc_v2, 0, sizeof(aclc_v2)); 7678c2ecf20Sopenharmony_ci aclc_v2.hdr.type = SMC_CLC_ACCEPT; 7688c2ecf20Sopenharmony_ci len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact, 7698c2ecf20Sopenharmony_ci version); 7708c2ecf20Sopenharmony_ci if (len < ntohs(aclc_v2.hdr.length)) 7718c2ecf20Sopenharmony_ci len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return len > 0 ? 0 : len; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_civoid __init smc_clc_init(void) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct new_utsname *u; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci memset(smc_hostname, _S, sizeof(smc_hostname)); /* ASCII blanks */ 7818c2ecf20Sopenharmony_ci u = utsname(); 7828c2ecf20Sopenharmony_ci memcpy(smc_hostname, u->nodename, 7838c2ecf20Sopenharmony_ci min_t(size_t, strlen(u->nodename), sizeof(smc_hostname))); 7848c2ecf20Sopenharmony_ci} 785