[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251031031828.111364-1-alibuda@linux.alibaba.com>
Date: Fri, 31 Oct 2025 11:18:28 +0800
From: "D. Wythe" <alibuda@...ux.alibaba.com>
To: mjambigi@...ux.ibm.com,
wenjia@...ux.ibm.com,
wintera@...ux.ibm.com,
dust.li@...ux.alibaba.com,
tonylu@...ux.alibaba.com,
guwen@...ux.alibaba.com
Cc: kuba@...nel.org,
davem@...emloft.net,
netdev@...r.kernel.org,
linux-s390@...r.kernel.org,
linux-rdma@...r.kernel.org,
pabeni@...hat.com,
edumazet@...gle.com,
sidraya@...ux.ibm.com,
jaka@...ux.ibm.com
Subject: [PATCH net] net/smc: fix mismatch between CLC header and proposal extensions
The current CLC proposal message construction uses a mix of
`ini->smc_type_v1/v2` and `pclc_base->hdr.typev1/v2` to decide whether
to include optional extensions (IPv6 prefix extension for v1, and v2
extension). This leads to a critical inconsistency: when
`smc_clc_prfx_set()` fails - for example, in IPv6-only environments with
only link-local addresses, or when the local IP address and the outgoing
interface’s network address are not in the same subnet.
As a result, the proposal message is assembled using the stale
`ini->smc_type_v1` value—causing the IPv6 prefix extension to be
included even though the header indicates v1 is not supported.
The peer then receives a malformed CLC proposal where the header type
does not match the payload, and immediately resets the connection.
Fix this by consistently using `pclc_base->hdr.typev1` and
`pclc_base->hdr.typev2`—the authoritative fields that reflect the
actual capabilities advertised in the CLC header—when deciding whether
to include optional extensions, as required by the SMC-R v2
specification ("V1 IP Subnet Extension and V2 Extension only present if
applicable").
Fixes: 8c3dca341aea ("net/smc: build and send V2 CLC proposal")
Signed-off-by: D. Wythe <alibuda@...ux.alibaba.com>
---
net/smc/smc_clc.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index 157aace169d4..d9ff5f433720 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -922,7 +922,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
htons(smc_ism_get_chid(ini->ism_dev[0]));
}
}
- if (ini->smc_type_v2 == SMC_TYPE_N) {
+ if (pclc_base->hdr.typev2 == SMC_TYPE_N) {
pclc_smcd->v2_ext_offset = 0;
} else {
struct smc_clc_eid_entry *ueident;
@@ -931,7 +931,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
v2_ext->hdr.flag.release = SMC_RELEASE;
v2_ext_offset = sizeof(*pclc_smcd) -
offsetofend(struct smc_clc_msg_smcd, v2_ext_offset);
- if (ini->smc_type_v1 != SMC_TYPE_N)
+ if (pclc_base->hdr.typev1 != SMC_TYPE_N)
v2_ext_offset += sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]);
@@ -949,7 +949,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
}
read_unlock(&smc_clc_eid_table.lock);
}
- if (smcd_indicated(ini->smc_type_v2)) {
+ if (smcd_indicated(pclc_base->hdr.typev2)) {
struct smcd_gid smcd_gid;
u8 *eid = NULL;
int entry = 0;
@@ -987,7 +987,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
}
v2_ext->hdr.ism_gid_cnt = entry;
}
- if (smcr_indicated(ini->smc_type_v2)) {
+ if (smcr_indicated(pclc_base->hdr.typev2)) {
memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE);
v2_ext->max_conns = net->smc.sysctl_max_conns_per_lgr;
v2_ext->max_links = net->smc.sysctl_max_links_per_lgr;
@@ -1003,7 +1003,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
vec[i++].iov_len = sizeof(*pclc_base);
vec[i].iov_base = pclc_smcd;
vec[i++].iov_len = sizeof(*pclc_smcd);
- if (ini->smc_type_v1 != SMC_TYPE_N) {
+ if (pclc_base->hdr.typev1 != SMC_TYPE_N) {
vec[i].iov_base = pclc_prfx;
vec[i++].iov_len = sizeof(*pclc_prfx);
if (pclc_prfx->ipv6_prefixes_cnt > 0) {
@@ -1012,11 +1012,11 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
sizeof(ipv6_prfx[0]);
}
}
- if (ini->smc_type_v2 != SMC_TYPE_N) {
+ if (pclc_base->hdr.typev2 != SMC_TYPE_N) {
vec[i].iov_base = v2_ext;
vec[i++].iov_len = sizeof(*v2_ext) +
(v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
- if (smcd_indicated(ini->smc_type_v2)) {
+ if (smcd_indicated(pclc_base->hdr.typev2)) {
vec[i].iov_base = smcd_v2_ext;
vec[i++].iov_len = sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) {
--
2.45.0
Powered by blists - more mailing lists