diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index de367510813b..a27406e09e24 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -1001,13 +1001,21 @@ static void smc_llc_save_add_link_rkeys(struct smc_link *link, struct smc_link *link_new, u8 *llc_msg) { + const u32 rt_off = offsetof(struct smc_llc_msg_add_link_v2_ext, rt); struct smc_llc_msg_add_link_v2_ext *ext; struct smc_link_group *lgr = link->lgr; int max, i; + /* Without a shared v2 receive buffer the extension is not copied + * into the queue entry, so not even ext->num_rkeys is there. + */ + if (!smc_link_shared_v2_rxbuf(link)) + return; ext = (struct smc_llc_msg_add_link_v2_ext *)(llc_msg + SMC_WR_TX_SIZE); max = min_t(u8, ext->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2); + max = min_t(u32, max, (SMC_WR_BUF_V2_SIZE - SMC_WR_TX_SIZE - rt_off) / + sizeof(ext->rt[0])); down_write(&lgr->rmbs_lock); for (i = 0; i < max; i++) { smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, @@ -1812,17 +1820,25 @@ static void smc_llc_rmt_delete_rkey(struct smc_link_group *lgr) link = qentry->link; if (lgr->smc_version == SMC_V2) { + const u32 rkey_off = + offsetof(struct smc_llc_msg_delete_rkey_v2, rkey); struct smc_llc_msg_delete_rkey_v2 *llcv2; + u32 buf_len; if (smc_link_shared_v2_rxbuf(link)) { memcpy(lgr->wr_rx_buf_v2, llc, sizeof(*llc)); llcv2 = (struct smc_llc_msg_delete_rkey_v2 *)lgr->wr_rx_buf_v2; + buf_len = SMC_WR_BUF_V2_SIZE; } else { llcv2 = (struct smc_llc_msg_delete_rkey_v2 *)llc; + buf_len = sizeof(qentry->msg); } llcv2->num_inval_rkeys = 0; max = min_t(u8, llcv2->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2); + /* bound by the buffer llcv2 points at */ + max = min_t(u32, max, (buf_len - rkey_off) / + sizeof(llcv2->rkey[0])); for (i = 0; i < max; i++) { if (smc_rtoken_delete(link, llcv2->rkey[i])) llcv2->num_inval_rkeys++;