0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/in.h>
0014 #include <linux/inetdevice.h>
0015 #include <linux/if_ether.h>
0016 #include <linux/sched/signal.h>
0017 #include <linux/utsname.h>
0018 #include <linux/ctype.h>
0019
0020 #include <net/addrconf.h>
0021 #include <net/sock.h>
0022 #include <net/tcp.h>
0023
0024 #include "smc.h"
0025 #include "smc_core.h"
0026 #include "smc_clc.h"
0027 #include "smc_ib.h"
0028 #include "smc_ism.h"
0029 #include "smc_netlink.h"
0030
0031 #define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
0032 #define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
0033 #define SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 78
0034 #define SMCR_CLC_ACCEPT_CONFIRM_LEN_V2 108
0035 #define SMC_CLC_RECV_BUF_LEN 100
0036
0037
0038 static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
0039
0040 static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
0041
0042 static u8 smc_hostname[SMC_MAX_HOSTNAME_LEN];
0043
0044 struct smc_clc_eid_table {
0045 rwlock_t lock;
0046 struct list_head list;
0047 u8 ueid_cnt;
0048 u8 seid_enabled;
0049 };
0050
0051 static struct smc_clc_eid_table smc_clc_eid_table;
0052
0053 struct smc_clc_eid_entry {
0054 struct list_head list;
0055 u8 eid[SMC_MAX_EID_LEN];
0056 };
0057
0058
0059
0060
0061
0062
0063 static bool smc_clc_ueid_valid(char *ueid)
0064 {
0065 char *end = ueid + SMC_MAX_EID_LEN;
0066
0067 while (--end >= ueid && isspace(*end))
0068 ;
0069 if (end < ueid)
0070 return false;
0071 if (!isalnum(*ueid) || islower(*ueid))
0072 return false;
0073 while (ueid <= end) {
0074 if ((!isalnum(*ueid) || islower(*ueid)) && *ueid != '.' &&
0075 *ueid != '-')
0076 return false;
0077 ueid++;
0078 }
0079 return true;
0080 }
0081
0082 static int smc_clc_ueid_add(char *ueid)
0083 {
0084 struct smc_clc_eid_entry *new_ueid, *tmp_ueid;
0085 int rc;
0086
0087 if (!smc_clc_ueid_valid(ueid))
0088 return -EINVAL;
0089
0090
0091 new_ueid = kzalloc(sizeof(*new_ueid), GFP_KERNEL);
0092 if (!new_ueid)
0093 return -ENOMEM;
0094 memcpy(new_ueid->eid, ueid, SMC_MAX_EID_LEN);
0095
0096 write_lock(&smc_clc_eid_table.lock);
0097 if (smc_clc_eid_table.ueid_cnt >= SMC_MAX_UEID) {
0098 rc = -ERANGE;
0099 goto err_out;
0100 }
0101 list_for_each_entry(tmp_ueid, &smc_clc_eid_table.list, list) {
0102 if (!memcmp(tmp_ueid->eid, ueid, SMC_MAX_EID_LEN)) {
0103 rc = -EEXIST;
0104 goto err_out;
0105 }
0106 }
0107 list_add_tail(&new_ueid->list, &smc_clc_eid_table.list);
0108 smc_clc_eid_table.ueid_cnt++;
0109 write_unlock(&smc_clc_eid_table.lock);
0110 return 0;
0111
0112 err_out:
0113 write_unlock(&smc_clc_eid_table.lock);
0114 kfree(new_ueid);
0115 return rc;
0116 }
0117
0118 int smc_clc_ueid_count(void)
0119 {
0120 int count;
0121
0122 read_lock(&smc_clc_eid_table.lock);
0123 count = smc_clc_eid_table.ueid_cnt;
0124 read_unlock(&smc_clc_eid_table.lock);
0125
0126 return count;
0127 }
0128
0129 int smc_nl_add_ueid(struct sk_buff *skb, struct genl_info *info)
0130 {
0131 struct nlattr *nla_ueid = info->attrs[SMC_NLA_EID_TABLE_ENTRY];
0132 char *ueid;
0133
0134 if (!nla_ueid || nla_len(nla_ueid) != SMC_MAX_EID_LEN + 1)
0135 return -EINVAL;
0136 ueid = (char *)nla_data(nla_ueid);
0137
0138 return smc_clc_ueid_add(ueid);
0139 }
0140
0141
0142 static int smc_clc_ueid_remove(char *ueid)
0143 {
0144 struct smc_clc_eid_entry *lst_ueid, *tmp_ueid;
0145 int rc = -ENOENT;
0146
0147
0148 write_lock(&smc_clc_eid_table.lock);
0149 list_for_each_entry_safe(lst_ueid, tmp_ueid, &smc_clc_eid_table.list,
0150 list) {
0151 if (!ueid || !memcmp(lst_ueid->eid, ueid, SMC_MAX_EID_LEN)) {
0152 list_del(&lst_ueid->list);
0153 smc_clc_eid_table.ueid_cnt--;
0154 kfree(lst_ueid);
0155 rc = 0;
0156 }
0157 }
0158 if (!rc && !smc_clc_eid_table.ueid_cnt) {
0159 smc_clc_eid_table.seid_enabled = 1;
0160 rc = -EAGAIN;
0161 }
0162 write_unlock(&smc_clc_eid_table.lock);
0163 return rc;
0164 }
0165
0166 int smc_nl_remove_ueid(struct sk_buff *skb, struct genl_info *info)
0167 {
0168 struct nlattr *nla_ueid = info->attrs[SMC_NLA_EID_TABLE_ENTRY];
0169 char *ueid;
0170
0171 if (!nla_ueid || nla_len(nla_ueid) != SMC_MAX_EID_LEN + 1)
0172 return -EINVAL;
0173 ueid = (char *)nla_data(nla_ueid);
0174
0175 return smc_clc_ueid_remove(ueid);
0176 }
0177
0178 int smc_nl_flush_ueid(struct sk_buff *skb, struct genl_info *info)
0179 {
0180 smc_clc_ueid_remove(NULL);
0181 return 0;
0182 }
0183
0184 static int smc_nl_ueid_dumpinfo(struct sk_buff *skb, u32 portid, u32 seq,
0185 u32 flags, char *ueid)
0186 {
0187 char ueid_str[SMC_MAX_EID_LEN + 1];
0188 void *hdr;
0189
0190 hdr = genlmsg_put(skb, portid, seq, &smc_gen_nl_family,
0191 flags, SMC_NETLINK_DUMP_UEID);
0192 if (!hdr)
0193 return -ENOMEM;
0194 memcpy(ueid_str, ueid, SMC_MAX_EID_LEN);
0195 ueid_str[SMC_MAX_EID_LEN] = 0;
0196 if (nla_put_string(skb, SMC_NLA_EID_TABLE_ENTRY, ueid_str)) {
0197 genlmsg_cancel(skb, hdr);
0198 return -EMSGSIZE;
0199 }
0200 genlmsg_end(skb, hdr);
0201 return 0;
0202 }
0203
0204 static int _smc_nl_ueid_dump(struct sk_buff *skb, u32 portid, u32 seq,
0205 int start_idx)
0206 {
0207 struct smc_clc_eid_entry *lst_ueid;
0208 int idx = 0;
0209
0210 read_lock(&smc_clc_eid_table.lock);
0211 list_for_each_entry(lst_ueid, &smc_clc_eid_table.list, list) {
0212 if (idx++ < start_idx)
0213 continue;
0214 if (smc_nl_ueid_dumpinfo(skb, portid, seq, NLM_F_MULTI,
0215 lst_ueid->eid)) {
0216 --idx;
0217 break;
0218 }
0219 }
0220 read_unlock(&smc_clc_eid_table.lock);
0221 return idx;
0222 }
0223
0224 int smc_nl_dump_ueid(struct sk_buff *skb, struct netlink_callback *cb)
0225 {
0226 struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
0227 int idx;
0228
0229 idx = _smc_nl_ueid_dump(skb, NETLINK_CB(cb->skb).portid,
0230 cb->nlh->nlmsg_seq, cb_ctx->pos[0]);
0231
0232 cb_ctx->pos[0] = idx;
0233 return skb->len;
0234 }
0235
0236 int smc_nl_dump_seid(struct sk_buff *skb, struct netlink_callback *cb)
0237 {
0238 struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
0239 char seid_str[SMC_MAX_EID_LEN + 1];
0240 u8 seid_enabled;
0241 void *hdr;
0242 u8 *seid;
0243
0244 if (cb_ctx->pos[0])
0245 return skb->len;
0246
0247 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
0248 &smc_gen_nl_family, NLM_F_MULTI,
0249 SMC_NETLINK_DUMP_SEID);
0250 if (!hdr)
0251 return -ENOMEM;
0252 if (!smc_ism_is_v2_capable())
0253 goto end;
0254
0255 smc_ism_get_system_eid(&seid);
0256 memcpy(seid_str, seid, SMC_MAX_EID_LEN);
0257 seid_str[SMC_MAX_EID_LEN] = 0;
0258 if (nla_put_string(skb, SMC_NLA_SEID_ENTRY, seid_str))
0259 goto err;
0260 read_lock(&smc_clc_eid_table.lock);
0261 seid_enabled = smc_clc_eid_table.seid_enabled;
0262 read_unlock(&smc_clc_eid_table.lock);
0263 if (nla_put_u8(skb, SMC_NLA_SEID_ENABLED, seid_enabled))
0264 goto err;
0265 end:
0266 genlmsg_end(skb, hdr);
0267 cb_ctx->pos[0]++;
0268 return skb->len;
0269 err:
0270 genlmsg_cancel(skb, hdr);
0271 return -EMSGSIZE;
0272 }
0273
0274 int smc_nl_enable_seid(struct sk_buff *skb, struct genl_info *info)
0275 {
0276 write_lock(&smc_clc_eid_table.lock);
0277 smc_clc_eid_table.seid_enabled = 1;
0278 write_unlock(&smc_clc_eid_table.lock);
0279 return 0;
0280 }
0281
0282 int smc_nl_disable_seid(struct sk_buff *skb, struct genl_info *info)
0283 {
0284 int rc = 0;
0285
0286 write_lock(&smc_clc_eid_table.lock);
0287 if (!smc_clc_eid_table.ueid_cnt)
0288 rc = -ENOENT;
0289 else
0290 smc_clc_eid_table.seid_enabled = 0;
0291 write_unlock(&smc_clc_eid_table.lock);
0292 return rc;
0293 }
0294
0295 static bool _smc_clc_match_ueid(u8 *peer_ueid)
0296 {
0297 struct smc_clc_eid_entry *tmp_ueid;
0298
0299 list_for_each_entry(tmp_ueid, &smc_clc_eid_table.list, list) {
0300 if (!memcmp(tmp_ueid->eid, peer_ueid, SMC_MAX_EID_LEN))
0301 return true;
0302 }
0303 return false;
0304 }
0305
0306 bool smc_clc_match_eid(u8 *negotiated_eid,
0307 struct smc_clc_v2_extension *smc_v2_ext,
0308 u8 *peer_eid, u8 *local_eid)
0309 {
0310 bool match = false;
0311 int i;
0312
0313 negotiated_eid[0] = 0;
0314 read_lock(&smc_clc_eid_table.lock);
0315 if (peer_eid && local_eid &&
0316 smc_clc_eid_table.seid_enabled &&
0317 smc_v2_ext->hdr.flag.seid &&
0318 !memcmp(peer_eid, local_eid, SMC_MAX_EID_LEN)) {
0319 memcpy(negotiated_eid, peer_eid, SMC_MAX_EID_LEN);
0320 match = true;
0321 goto out;
0322 }
0323
0324 for (i = 0; i < smc_v2_ext->hdr.eid_cnt; i++) {
0325 if (_smc_clc_match_ueid(smc_v2_ext->user_eids[i])) {
0326 memcpy(negotiated_eid, smc_v2_ext->user_eids[i],
0327 SMC_MAX_EID_LEN);
0328 match = true;
0329 goto out;
0330 }
0331 }
0332 out:
0333 read_unlock(&smc_clc_eid_table.lock);
0334 return match;
0335 }
0336
0337
0338 static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
0339 {
0340 struct smc_clc_msg_proposal_prefix *pclc_prfx;
0341 struct smc_clc_smcd_v2_extension *smcd_v2_ext;
0342 struct smc_clc_msg_hdr *hdr = &pclc->hdr;
0343 struct smc_clc_v2_extension *v2_ext;
0344
0345 v2_ext = smc_get_clc_v2_ext(pclc);
0346 pclc_prfx = smc_clc_proposal_get_prefix(pclc);
0347 if (hdr->version == SMC_V1) {
0348 if (hdr->typev1 == SMC_TYPE_N)
0349 return false;
0350 if (ntohs(hdr->length) !=
0351 sizeof(*pclc) + ntohs(pclc->iparea_offset) +
0352 sizeof(*pclc_prfx) +
0353 pclc_prfx->ipv6_prefixes_cnt *
0354 sizeof(struct smc_clc_ipv6_prefix) +
0355 sizeof(struct smc_clc_msg_trail))
0356 return false;
0357 } else {
0358 if (ntohs(hdr->length) !=
0359 sizeof(*pclc) +
0360 sizeof(struct smc_clc_msg_smcd) +
0361 (hdr->typev1 != SMC_TYPE_N ?
0362 sizeof(*pclc_prfx) +
0363 pclc_prfx->ipv6_prefixes_cnt *
0364 sizeof(struct smc_clc_ipv6_prefix) : 0) +
0365 (hdr->typev2 != SMC_TYPE_N ?
0366 sizeof(*v2_ext) +
0367 v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN : 0) +
0368 (smcd_indicated(hdr->typev2) ?
0369 sizeof(*smcd_v2_ext) + v2_ext->hdr.ism_gid_cnt *
0370 sizeof(struct smc_clc_smcd_gid_chid) :
0371 0) +
0372 sizeof(struct smc_clc_msg_trail))
0373 return false;
0374 }
0375 return true;
0376 }
0377
0378
0379 static bool
0380 smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2)
0381 {
0382 struct smc_clc_msg_hdr *hdr = &clc_v2->hdr;
0383
0384 if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D)
0385 return false;
0386 if (hdr->version == SMC_V1) {
0387 if ((hdr->typev1 == SMC_TYPE_R &&
0388 ntohs(hdr->length) != SMCR_CLC_ACCEPT_CONFIRM_LEN) ||
0389 (hdr->typev1 == SMC_TYPE_D &&
0390 ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN))
0391 return false;
0392 } else {
0393 if (hdr->typev1 == SMC_TYPE_D &&
0394 ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 &&
0395 (ntohs(hdr->length) != SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 +
0396 sizeof(struct smc_clc_first_contact_ext)))
0397 return false;
0398 if (hdr->typev1 == SMC_TYPE_R &&
0399 ntohs(hdr->length) < SMCR_CLC_ACCEPT_CONFIRM_LEN_V2)
0400 return false;
0401 }
0402 return true;
0403 }
0404
0405
0406 static bool
0407 smc_clc_msg_decl_valid(struct smc_clc_msg_decline *dclc)
0408 {
0409 struct smc_clc_msg_hdr *hdr = &dclc->hdr;
0410
0411 if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D)
0412 return false;
0413 if (hdr->version == SMC_V1) {
0414 if (ntohs(hdr->length) != sizeof(struct smc_clc_msg_decline))
0415 return false;
0416 } else {
0417 if (ntohs(hdr->length) != sizeof(struct smc_clc_msg_decline_v2))
0418 return false;
0419 }
0420 return true;
0421 }
0422
0423 static void smc_clc_fill_fce(struct smc_clc_first_contact_ext *fce, int *len)
0424 {
0425 memset(fce, 0, sizeof(*fce));
0426 fce->os_type = SMC_CLC_OS_LINUX;
0427 fce->release = SMC_RELEASE;
0428 memcpy(fce->hostname, smc_hostname, sizeof(smc_hostname));
0429 (*len) += sizeof(*fce);
0430 }
0431
0432
0433
0434
0435 static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
0436 {
0437 struct smc_clc_msg_accept_confirm_v2 *clc_v2;
0438 struct smc_clc_msg_proposal *pclc;
0439 struct smc_clc_msg_decline *dclc;
0440 struct smc_clc_msg_trail *trl;
0441
0442 if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
0443 memcmp(clcm->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
0444 return false;
0445 switch (clcm->type) {
0446 case SMC_CLC_PROPOSAL:
0447 pclc = (struct smc_clc_msg_proposal *)clcm;
0448 if (!smc_clc_msg_prop_valid(pclc))
0449 return false;
0450 trl = (struct smc_clc_msg_trail *)
0451 ((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl));
0452 break;
0453 case SMC_CLC_ACCEPT:
0454 case SMC_CLC_CONFIRM:
0455 clc_v2 = (struct smc_clc_msg_accept_confirm_v2 *)clcm;
0456 if (!smc_clc_msg_acc_conf_valid(clc_v2))
0457 return false;
0458 trl = (struct smc_clc_msg_trail *)
0459 ((u8 *)clc_v2 + ntohs(clc_v2->hdr.length) -
0460 sizeof(*trl));
0461 break;
0462 case SMC_CLC_DECLINE:
0463 dclc = (struct smc_clc_msg_decline *)clcm;
0464 if (!smc_clc_msg_decl_valid(dclc))
0465 return false;
0466 check_trl = false;
0467 break;
0468 default:
0469 return false;
0470 }
0471 if (check_trl &&
0472 memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
0473 memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
0474 return false;
0475 return true;
0476 }
0477
0478
0479 static int smc_clc_prfx_set4_rcu(struct dst_entry *dst, __be32 ipv4,
0480 struct smc_clc_msg_proposal_prefix *prop)
0481 {
0482 struct in_device *in_dev = __in_dev_get_rcu(dst->dev);
0483 const struct in_ifaddr *ifa;
0484
0485 if (!in_dev)
0486 return -ENODEV;
0487
0488 in_dev_for_each_ifa_rcu(ifa, in_dev) {
0489 if (!inet_ifa_match(ipv4, ifa))
0490 continue;
0491 prop->prefix_len = inet_mask_len(ifa->ifa_mask);
0492 prop->outgoing_subnet = ifa->ifa_address & ifa->ifa_mask;
0493
0494 return 0;
0495 }
0496 return -ENOENT;
0497 }
0498
0499
0500 static int smc_clc_prfx_set6_rcu(struct dst_entry *dst,
0501 struct smc_clc_msg_proposal_prefix *prop,
0502 struct smc_clc_ipv6_prefix *ipv6_prfx)
0503 {
0504 #if IS_ENABLED(CONFIG_IPV6)
0505 struct inet6_dev *in6_dev = __in6_dev_get(dst->dev);
0506 struct inet6_ifaddr *ifa;
0507 int cnt = 0;
0508
0509 if (!in6_dev)
0510 return -ENODEV;
0511
0512 list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
0513 if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
0514 continue;
0515 ipv6_addr_prefix(&ipv6_prfx[cnt].prefix,
0516 &ifa->addr, ifa->prefix_len);
0517 ipv6_prfx[cnt].prefix_len = ifa->prefix_len;
0518 cnt++;
0519 if (cnt == SMC_CLC_MAX_V6_PREFIX)
0520 break;
0521 }
0522 prop->ipv6_prefixes_cnt = cnt;
0523 if (cnt)
0524 return 0;
0525 #endif
0526 return -ENOENT;
0527 }
0528
0529
0530 static int smc_clc_prfx_set(struct socket *clcsock,
0531 struct smc_clc_msg_proposal_prefix *prop,
0532 struct smc_clc_ipv6_prefix *ipv6_prfx)
0533 {
0534 struct dst_entry *dst = sk_dst_get(clcsock->sk);
0535 struct sockaddr_storage addrs;
0536 struct sockaddr_in6 *addr6;
0537 struct sockaddr_in *addr;
0538 int rc = -ENOENT;
0539
0540 if (!dst) {
0541 rc = -ENOTCONN;
0542 goto out;
0543 }
0544 if (!dst->dev) {
0545 rc = -ENODEV;
0546 goto out_rel;
0547 }
0548
0549 if (kernel_getsockname(clcsock, (struct sockaddr *)&addrs) < 0)
0550 goto out_rel;
0551
0552 addr6 = (struct sockaddr_in6 *)&addrs;
0553 rcu_read_lock();
0554 if (addrs.ss_family == PF_INET) {
0555
0556 addr = (struct sockaddr_in *)&addrs;
0557 rc = smc_clc_prfx_set4_rcu(dst, addr->sin_addr.s_addr, prop);
0558 } else if (ipv6_addr_v4mapped(&addr6->sin6_addr)) {
0559
0560 rc = smc_clc_prfx_set4_rcu(dst, addr6->sin6_addr.s6_addr32[3],
0561 prop);
0562 } else {
0563
0564 rc = smc_clc_prfx_set6_rcu(dst, prop, ipv6_prfx);
0565 }
0566 rcu_read_unlock();
0567 out_rel:
0568 dst_release(dst);
0569 out:
0570 return rc;
0571 }
0572
0573
0574 static int smc_clc_prfx_match4_rcu(struct net_device *dev,
0575 struct smc_clc_msg_proposal_prefix *prop)
0576 {
0577 struct in_device *in_dev = __in_dev_get_rcu(dev);
0578 const struct in_ifaddr *ifa;
0579
0580 if (!in_dev)
0581 return -ENODEV;
0582 in_dev_for_each_ifa_rcu(ifa, in_dev) {
0583 if (prop->prefix_len == inet_mask_len(ifa->ifa_mask) &&
0584 inet_ifa_match(prop->outgoing_subnet, ifa))
0585 return 0;
0586 }
0587
0588 return -ENOENT;
0589 }
0590
0591
0592 static int smc_clc_prfx_match6_rcu(struct net_device *dev,
0593 struct smc_clc_msg_proposal_prefix *prop)
0594 {
0595 #if IS_ENABLED(CONFIG_IPV6)
0596 struct inet6_dev *in6_dev = __in6_dev_get(dev);
0597 struct smc_clc_ipv6_prefix *ipv6_prfx;
0598 struct inet6_ifaddr *ifa;
0599 int i, max;
0600
0601 if (!in6_dev)
0602 return -ENODEV;
0603
0604 ipv6_prfx = (struct smc_clc_ipv6_prefix *)((u8 *)prop + sizeof(*prop));
0605 max = min_t(u8, prop->ipv6_prefixes_cnt, SMC_CLC_MAX_V6_PREFIX);
0606 list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
0607 if (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
0608 continue;
0609 for (i = 0; i < max; i++) {
0610 if (ifa->prefix_len == ipv6_prfx[i].prefix_len &&
0611 ipv6_prefix_equal(&ifa->addr, &ipv6_prfx[i].prefix,
0612 ifa->prefix_len))
0613 return 0;
0614 }
0615 }
0616 #endif
0617 return -ENOENT;
0618 }
0619
0620
0621 int smc_clc_prfx_match(struct socket *clcsock,
0622 struct smc_clc_msg_proposal_prefix *prop)
0623 {
0624 struct dst_entry *dst = sk_dst_get(clcsock->sk);
0625 int rc;
0626
0627 if (!dst) {
0628 rc = -ENOTCONN;
0629 goto out;
0630 }
0631 if (!dst->dev) {
0632 rc = -ENODEV;
0633 goto out_rel;
0634 }
0635 rcu_read_lock();
0636 if (!prop->ipv6_prefixes_cnt)
0637 rc = smc_clc_prfx_match4_rcu(dst->dev, prop);
0638 else
0639 rc = smc_clc_prfx_match6_rcu(dst->dev, prop);
0640 rcu_read_unlock();
0641 out_rel:
0642 dst_release(dst);
0643 out:
0644 return rc;
0645 }
0646
0647
0648
0649
0650
0651
0652
0653 int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
0654 u8 expected_type, unsigned long timeout)
0655 {
0656 long rcvtimeo = smc->clcsock->sk->sk_rcvtimeo;
0657 struct sock *clc_sk = smc->clcsock->sk;
0658 struct smc_clc_msg_hdr *clcm = buf;
0659 struct msghdr msg = {NULL, 0};
0660 int reason_code = 0;
0661 struct kvec vec = {buf, buflen};
0662 int len, datlen, recvlen;
0663 bool check_trl = true;
0664 int krflags;
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674 krflags = MSG_PEEK | MSG_WAITALL;
0675 clc_sk->sk_rcvtimeo = timeout;
0676 iov_iter_kvec(&msg.msg_iter, READ, &vec, 1,
0677 sizeof(struct smc_clc_msg_hdr));
0678 len = sock_recvmsg(smc->clcsock, &msg, krflags);
0679 if (signal_pending(current)) {
0680 reason_code = -EINTR;
0681 clc_sk->sk_err = EINTR;
0682 smc->sk.sk_err = EINTR;
0683 goto out;
0684 }
0685 if (clc_sk->sk_err) {
0686 reason_code = -clc_sk->sk_err;
0687 if (clc_sk->sk_err == EAGAIN &&
0688 expected_type == SMC_CLC_DECLINE)
0689 clc_sk->sk_err = 0;
0690 else
0691 smc->sk.sk_err = clc_sk->sk_err;
0692 goto out;
0693 }
0694 if (!len) {
0695 smc->sk.sk_err = ECONNRESET;
0696 reason_code = -ECONNRESET;
0697 goto out;
0698 }
0699 if (len < 0) {
0700 if (len != -EAGAIN || expected_type != SMC_CLC_DECLINE)
0701 smc->sk.sk_err = -len;
0702 reason_code = len;
0703 goto out;
0704 }
0705 datlen = ntohs(clcm->length);
0706 if ((len < sizeof(struct smc_clc_msg_hdr)) ||
0707 (clcm->version < SMC_V1) ||
0708 ((clcm->type != SMC_CLC_DECLINE) &&
0709 (clcm->type != expected_type))) {
0710 smc->sk.sk_err = EPROTO;
0711 reason_code = -EPROTO;
0712 goto out;
0713 }
0714
0715
0716 memset(&msg, 0, sizeof(struct msghdr));
0717 if (datlen > buflen) {
0718 check_trl = false;
0719 recvlen = buflen;
0720 } else {
0721 recvlen = datlen;
0722 }
0723 iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
0724 krflags = MSG_WAITALL;
0725 len = sock_recvmsg(smc->clcsock, &msg, krflags);
0726 if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
0727 smc->sk.sk_err = EPROTO;
0728 reason_code = -EPROTO;
0729 goto out;
0730 }
0731 datlen -= len;
0732 while (datlen) {
0733 u8 tmp[SMC_CLC_RECV_BUF_LEN];
0734
0735 vec.iov_base = &tmp;
0736 vec.iov_len = SMC_CLC_RECV_BUF_LEN;
0737
0738 recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
0739 SMC_CLC_RECV_BUF_LEN : datlen;
0740 iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
0741 len = sock_recvmsg(smc->clcsock, &msg, krflags);
0742 datlen -= len;
0743 }
0744 if (clcm->type == SMC_CLC_DECLINE) {
0745 struct smc_clc_msg_decline *dclc;
0746
0747 dclc = (struct smc_clc_msg_decline *)clcm;
0748 reason_code = SMC_CLC_DECL_PEERDECL;
0749 smc->peer_diagnosis = ntohl(dclc->peer_diagnosis);
0750 if (((struct smc_clc_msg_decline *)buf)->hdr.typev2 &
0751 SMC_FIRST_CONTACT_MASK) {
0752 smc->conn.lgr->sync_err = 1;
0753 smc_lgr_terminate_sched(smc->conn.lgr);
0754 }
0755 }
0756
0757 out:
0758 clc_sk->sk_rcvtimeo = rcvtimeo;
0759 return reason_code;
0760 }
0761
0762
0763 int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info, u8 version)
0764 {
0765 struct smc_clc_msg_decline *dclc_v1;
0766 struct smc_clc_msg_decline_v2 dclc;
0767 struct msghdr msg;
0768 int len, send_len;
0769 struct kvec vec;
0770
0771 dclc_v1 = (struct smc_clc_msg_decline *)&dclc;
0772 memset(&dclc, 0, sizeof(dclc));
0773 memcpy(dclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
0774 dclc.hdr.type = SMC_CLC_DECLINE;
0775 dclc.hdr.version = version;
0776 dclc.os_type = version == SMC_V1 ? 0 : SMC_CLC_OS_LINUX;
0777 dclc.hdr.typev2 = (peer_diag_info == SMC_CLC_DECL_SYNCERR) ?
0778 SMC_FIRST_CONTACT_MASK : 0;
0779 if ((!smc_conn_lgr_valid(&smc->conn) || !smc->conn.lgr->is_smcd) &&
0780 smc_ib_is_valid_local_systemid())
0781 memcpy(dclc.id_for_peer, local_systemid,
0782 sizeof(local_systemid));
0783 dclc.peer_diagnosis = htonl(peer_diag_info);
0784 if (version == SMC_V1) {
0785 memcpy(dclc_v1->trl.eyecatcher, SMC_EYECATCHER,
0786 sizeof(SMC_EYECATCHER));
0787 send_len = sizeof(*dclc_v1);
0788 } else {
0789 memcpy(dclc.trl.eyecatcher, SMC_EYECATCHER,
0790 sizeof(SMC_EYECATCHER));
0791 send_len = sizeof(dclc);
0792 }
0793 dclc.hdr.length = htons(send_len);
0794
0795 memset(&msg, 0, sizeof(msg));
0796 vec.iov_base = &dclc;
0797 vec.iov_len = send_len;
0798 len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, send_len);
0799 if (len < 0 || len < send_len)
0800 len = -EPROTO;
0801 return len > 0 ? 0 : len;
0802 }
0803
0804
0805 int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
0806 {
0807 struct smc_clc_smcd_v2_extension *smcd_v2_ext;
0808 struct smc_clc_msg_proposal_prefix *pclc_prfx;
0809 struct smc_clc_msg_proposal *pclc_base;
0810 struct smc_clc_smcd_gid_chid *gidchids;
0811 struct smc_clc_msg_proposal_area *pclc;
0812 struct smc_clc_ipv6_prefix *ipv6_prfx;
0813 struct smc_clc_v2_extension *v2_ext;
0814 struct smc_clc_msg_smcd *pclc_smcd;
0815 struct smc_clc_msg_trail *trl;
0816 int len, i, plen, rc;
0817 int reason_code = 0;
0818 struct kvec vec[8];
0819 struct msghdr msg;
0820
0821 pclc = kzalloc(sizeof(*pclc), GFP_KERNEL);
0822 if (!pclc)
0823 return -ENOMEM;
0824
0825 pclc_base = &pclc->pclc_base;
0826 pclc_smcd = &pclc->pclc_smcd;
0827 pclc_prfx = &pclc->pclc_prfx;
0828 ipv6_prfx = pclc->pclc_prfx_ipv6;
0829 v2_ext = &pclc->pclc_v2_ext;
0830 smcd_v2_ext = &pclc->pclc_smcd_v2_ext;
0831 gidchids = pclc->pclc_gidchids;
0832 trl = &pclc->pclc_trl;
0833
0834 pclc_base->hdr.version = SMC_V2;
0835 pclc_base->hdr.typev1 = ini->smc_type_v1;
0836 pclc_base->hdr.typev2 = ini->smc_type_v2;
0837 plen = sizeof(*pclc_base) + sizeof(*pclc_smcd) + sizeof(*trl);
0838
0839
0840 if (ini->smc_type_v1 != SMC_TYPE_N) {
0841 rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx);
0842 if (rc) {
0843 if (ini->smc_type_v2 == SMC_TYPE_N) {
0844 kfree(pclc);
0845 return SMC_CLC_DECL_CNFERR;
0846 }
0847 pclc_base->hdr.typev1 = SMC_TYPE_N;
0848 } else {
0849 pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
0850 plen += sizeof(*pclc_prfx) +
0851 pclc_prfx->ipv6_prefixes_cnt *
0852 sizeof(ipv6_prfx[0]);
0853 }
0854 }
0855
0856
0857 memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER,
0858 sizeof(SMC_EYECATCHER));
0859 pclc_base->hdr.type = SMC_CLC_PROPOSAL;
0860 if (smcr_indicated(ini->smc_type_v1)) {
0861
0862 memcpy(pclc_base->lcl.id_for_peer, local_systemid,
0863 sizeof(local_systemid));
0864 memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE);
0865 memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
0866 ETH_ALEN);
0867 }
0868 if (smcd_indicated(ini->smc_type_v1)) {
0869
0870 if (ini->ism_dev[0]) {
0871 pclc_smcd->ism.gid = htonll(ini->ism_dev[0]->local_gid);
0872 pclc_smcd->ism.chid =
0873 htons(smc_ism_get_chid(ini->ism_dev[0]));
0874 }
0875 }
0876 if (ini->smc_type_v2 == SMC_TYPE_N) {
0877 pclc_smcd->v2_ext_offset = 0;
0878 } else {
0879 struct smc_clc_eid_entry *ueident;
0880 u16 v2_ext_offset;
0881
0882 v2_ext->hdr.flag.release = SMC_RELEASE;
0883 v2_ext_offset = sizeof(*pclc_smcd) -
0884 offsetofend(struct smc_clc_msg_smcd, v2_ext_offset);
0885 if (ini->smc_type_v1 != SMC_TYPE_N)
0886 v2_ext_offset += sizeof(*pclc_prfx) +
0887 pclc_prfx->ipv6_prefixes_cnt *
0888 sizeof(ipv6_prfx[0]);
0889 pclc_smcd->v2_ext_offset = htons(v2_ext_offset);
0890 plen += sizeof(*v2_ext);
0891
0892 read_lock(&smc_clc_eid_table.lock);
0893 v2_ext->hdr.eid_cnt = smc_clc_eid_table.ueid_cnt;
0894 plen += smc_clc_eid_table.ueid_cnt * SMC_MAX_EID_LEN;
0895 i = 0;
0896 list_for_each_entry(ueident, &smc_clc_eid_table.list, list) {
0897 memcpy(v2_ext->user_eids[i++], ueident->eid,
0898 sizeof(ueident->eid));
0899 }
0900 read_unlock(&smc_clc_eid_table.lock);
0901 }
0902 if (smcd_indicated(ini->smc_type_v2)) {
0903 u8 *eid = NULL;
0904
0905 v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled;
0906 v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
0907 v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
0908 offsetofend(struct smc_clnt_opts_area_hdr,
0909 smcd_v2_ext_offset) +
0910 v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
0911 smc_ism_get_system_eid(&eid);
0912 if (eid && v2_ext->hdr.flag.seid)
0913 memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN);
0914 plen += sizeof(*smcd_v2_ext);
0915 if (ini->ism_offered_cnt) {
0916 for (i = 1; i <= ini->ism_offered_cnt; i++) {
0917 gidchids[i - 1].gid =
0918 htonll(ini->ism_dev[i]->local_gid);
0919 gidchids[i - 1].chid =
0920 htons(smc_ism_get_chid(ini->ism_dev[i]));
0921 }
0922 plen += ini->ism_offered_cnt *
0923 sizeof(struct smc_clc_smcd_gid_chid);
0924 }
0925 }
0926 if (smcr_indicated(ini->smc_type_v2))
0927 memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
0928
0929 pclc_base->hdr.length = htons(plen);
0930 memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
0931
0932
0933 memset(&msg, 0, sizeof(msg));
0934 i = 0;
0935 vec[i].iov_base = pclc_base;
0936 vec[i++].iov_len = sizeof(*pclc_base);
0937 vec[i].iov_base = pclc_smcd;
0938 vec[i++].iov_len = sizeof(*pclc_smcd);
0939 if (ini->smc_type_v1 != SMC_TYPE_N) {
0940 vec[i].iov_base = pclc_prfx;
0941 vec[i++].iov_len = sizeof(*pclc_prfx);
0942 if (pclc_prfx->ipv6_prefixes_cnt > 0) {
0943 vec[i].iov_base = ipv6_prfx;
0944 vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt *
0945 sizeof(ipv6_prfx[0]);
0946 }
0947 }
0948 if (ini->smc_type_v2 != SMC_TYPE_N) {
0949 vec[i].iov_base = v2_ext;
0950 vec[i++].iov_len = sizeof(*v2_ext) +
0951 (v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
0952 if (smcd_indicated(ini->smc_type_v2)) {
0953 vec[i].iov_base = smcd_v2_ext;
0954 vec[i++].iov_len = sizeof(*smcd_v2_ext);
0955 if (ini->ism_offered_cnt) {
0956 vec[i].iov_base = gidchids;
0957 vec[i++].iov_len = ini->ism_offered_cnt *
0958 sizeof(struct smc_clc_smcd_gid_chid);
0959 }
0960 }
0961 }
0962 vec[i].iov_base = trl;
0963 vec[i++].iov_len = sizeof(*trl);
0964
0965 len = kernel_sendmsg(smc->clcsock, &msg, vec, i, plen);
0966 if (len < 0) {
0967 smc->sk.sk_err = smc->clcsock->sk->sk_err;
0968 reason_code = -smc->sk.sk_err;
0969 } else if (len < ntohs(pclc_base->hdr.length)) {
0970 reason_code = -ENETUNREACH;
0971 smc->sk.sk_err = -reason_code;
0972 }
0973
0974 kfree(pclc);
0975 return reason_code;
0976 }
0977
0978
0979 static int smc_clc_send_confirm_accept(struct smc_sock *smc,
0980 struct smc_clc_msg_accept_confirm_v2 *clc_v2,
0981 int first_contact, u8 version,
0982 u8 *eid, struct smc_init_info *ini)
0983 {
0984 struct smc_connection *conn = &smc->conn;
0985 struct smc_clc_msg_accept_confirm *clc;
0986 struct smc_clc_first_contact_ext fce;
0987 struct smc_clc_fce_gid_ext gle;
0988 struct smc_clc_msg_trail trl;
0989 struct kvec vec[5];
0990 struct msghdr msg;
0991 int i, len;
0992
0993
0994 clc = (struct smc_clc_msg_accept_confirm *)clc_v2;
0995 clc->hdr.version = version;
0996 if (first_contact)
0997 clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK;
0998 if (conn->lgr->is_smcd) {
0999
1000 memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
1001 sizeof(SMCD_EYECATCHER));
1002 clc->hdr.typev1 = SMC_TYPE_D;
1003 clc->d0.gid = conn->lgr->smcd->local_gid;
1004 clc->d0.token = conn->rmb_desc->token;
1005 clc->d0.dmbe_size = conn->rmbe_size_short;
1006 clc->d0.dmbe_idx = 0;
1007 memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
1008 if (version == SMC_V1) {
1009 clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
1010 } else {
1011 clc_v2->d1.chid =
1012 htons(smc_ism_get_chid(conn->lgr->smcd));
1013 if (eid && eid[0])
1014 memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN);
1015 len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2;
1016 if (first_contact)
1017 smc_clc_fill_fce(&fce, &len);
1018 clc_v2->hdr.length = htons(len);
1019 }
1020 memcpy(trl.eyecatcher, SMCD_EYECATCHER,
1021 sizeof(SMCD_EYECATCHER));
1022 } else {
1023 struct smc_link *link = conn->lnk;
1024
1025
1026 memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER,
1027 sizeof(SMC_EYECATCHER));
1028 clc->hdr.typev1 = SMC_TYPE_R;
1029 clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
1030 memcpy(clc->r0.lcl.id_for_peer, local_systemid,
1031 sizeof(local_systemid));
1032 memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE);
1033 memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
1034 ETH_ALEN);
1035 hton24(clc->r0.qpn, link->roce_qp->qp_num);
1036 clc->r0.rmb_rkey =
1037 htonl(conn->rmb_desc->mr[link->link_idx]->rkey);
1038 clc->r0.rmbe_idx = 1;
1039 clc->r0.rmbe_alert_token = htonl(conn->alert_token_local);
1040 switch (clc->hdr.type) {
1041 case SMC_CLC_ACCEPT:
1042 clc->r0.qp_mtu = link->path_mtu;
1043 break;
1044 case SMC_CLC_CONFIRM:
1045 clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu);
1046 break;
1047 }
1048 clc->r0.rmbe_size = conn->rmbe_size_short;
1049 clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ?
1050 cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) :
1051 cpu_to_be64((u64)sg_dma_address
1052 (conn->rmb_desc->sgt[link->link_idx].sgl));
1053 hton24(clc->r0.psn, link->psn_initial);
1054 if (version == SMC_V1) {
1055 clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
1056 } else {
1057 if (eid && eid[0])
1058 memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN);
1059 len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2;
1060 if (first_contact) {
1061 smc_clc_fill_fce(&fce, &len);
1062 fce.v2_direct = !link->lgr->uses_gateway;
1063 memset(&gle, 0, sizeof(gle));
1064 if (ini && clc->hdr.type == SMC_CLC_CONFIRM) {
1065 gle.gid_cnt = ini->smcrv2.gidlist.len;
1066 len += sizeof(gle);
1067 len += gle.gid_cnt * sizeof(gle.gid[0]);
1068 } else {
1069 len += sizeof(gle.reserved);
1070 }
1071 }
1072 clc_v2->hdr.length = htons(len);
1073 }
1074 memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
1075 }
1076
1077 memset(&msg, 0, sizeof(msg));
1078 i = 0;
1079 vec[i].iov_base = clc_v2;
1080 if (version > SMC_V1)
1081 vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
1082 SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 :
1083 SMCR_CLC_ACCEPT_CONFIRM_LEN_V2) -
1084 sizeof(trl);
1085 else
1086 vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ?
1087 SMCD_CLC_ACCEPT_CONFIRM_LEN :
1088 SMCR_CLC_ACCEPT_CONFIRM_LEN) -
1089 sizeof(trl);
1090 if (version > SMC_V1 && first_contact) {
1091 vec[i].iov_base = &fce;
1092 vec[i++].iov_len = sizeof(fce);
1093 if (!conn->lgr->is_smcd) {
1094 if (clc->hdr.type == SMC_CLC_CONFIRM) {
1095 vec[i].iov_base = &gle;
1096 vec[i++].iov_len = sizeof(gle);
1097 vec[i].iov_base = &ini->smcrv2.gidlist.list;
1098 vec[i++].iov_len = gle.gid_cnt *
1099 sizeof(gle.gid[0]);
1100 } else {
1101 vec[i].iov_base = &gle.reserved;
1102 vec[i++].iov_len = sizeof(gle.reserved);
1103 }
1104 }
1105 }
1106 vec[i].iov_base = &trl;
1107 vec[i++].iov_len = sizeof(trl);
1108 return kernel_sendmsg(smc->clcsock, &msg, vec, 1,
1109 ntohs(clc->hdr.length));
1110 }
1111
1112
1113 int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact,
1114 u8 version, u8 *eid, struct smc_init_info *ini)
1115 {
1116 struct smc_clc_msg_accept_confirm_v2 cclc_v2;
1117 int reason_code = 0;
1118 int len;
1119
1120
1121 memset(&cclc_v2, 0, sizeof(cclc_v2));
1122 cclc_v2.hdr.type = SMC_CLC_CONFIRM;
1123 len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact,
1124 version, eid, ini);
1125 if (len < ntohs(cclc_v2.hdr.length)) {
1126 if (len >= 0) {
1127 reason_code = -ENETUNREACH;
1128 smc->sk.sk_err = -reason_code;
1129 } else {
1130 smc->sk.sk_err = smc->clcsock->sk->sk_err;
1131 reason_code = -smc->sk.sk_err;
1132 }
1133 }
1134 return reason_code;
1135 }
1136
1137
1138 int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact,
1139 u8 version, u8 *negotiated_eid)
1140 {
1141 struct smc_clc_msg_accept_confirm_v2 aclc_v2;
1142 int len;
1143
1144 memset(&aclc_v2, 0, sizeof(aclc_v2));
1145 aclc_v2.hdr.type = SMC_CLC_ACCEPT;
1146 len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact,
1147 version, negotiated_eid, NULL);
1148 if (len < ntohs(aclc_v2.hdr.length))
1149 len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err;
1150
1151 return len > 0 ? 0 : len;
1152 }
1153
1154 void smc_clc_get_hostname(u8 **host)
1155 {
1156 *host = &smc_hostname[0];
1157 }
1158
1159 void __init smc_clc_init(void)
1160 {
1161 struct new_utsname *u;
1162
1163 memset(smc_hostname, _S, sizeof(smc_hostname));
1164 u = utsname();
1165 memcpy(smc_hostname, u->nodename,
1166 min_t(size_t, strlen(u->nodename), sizeof(smc_hostname)));
1167
1168 INIT_LIST_HEAD(&smc_clc_eid_table.list);
1169 rwlock_init(&smc_clc_eid_table.lock);
1170 smc_clc_eid_table.ueid_cnt = 0;
1171 smc_clc_eid_table.seid_enabled = 1;
1172 }
1173
1174 void smc_clc_exit(void)
1175 {
1176 smc_clc_ueid_remove(NULL);
1177 }