Bluetooth: Mesh: store rpl only if incoming data is accepted
Commit prevents updating replay protection list on any frame came from the network layer. Replay protection cache is updated only if - transport handles transport command without errors - access layer handles model message without errors - transport frame has correct length Signed-off-by: Aleksandr Khromykh <aleksandr.khromykh@nordicsemi.no>
This commit is contained in:
parent
7e39db9bce
commit
21eafe6b91
3 changed files with 36 additions and 32 deletions
|
@ -675,7 +675,7 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
|
||||||
|
|
||||||
err = send_friend_poll();
|
err = send_friend_poll();
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Will retry sending later */
|
LOG_WRN("LPN didn't succeed poll sending (err %d)", err);
|
||||||
for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) {
|
for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) {
|
||||||
if (lpn->sub->keys[i].valid) {
|
if (lpn->sub->keys[i].valid) {
|
||||||
bt_mesh_friend_cred_destroy(&lpn->cred[i]);
|
bt_mesh_friend_cred_destroy(&lpn->cred[i]);
|
||||||
|
@ -686,7 +686,6 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
|
||||||
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
|
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
|
||||||
lpn->recv_win = 0U;
|
lpn->recv_win = 0U;
|
||||||
lpn->queue_size = 0U;
|
lpn->queue_size = 0U;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -102,12 +102,12 @@ void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the Replay Protection List for a replay attempt. If non-NULL match
|
/* Check the Replay Protection List for a replay attempt. If non-NULL match
|
||||||
* parameter is given the RPL slot is returned but it is not immediately
|
* parameter is given the RPL slot is returned, but it is not immediately
|
||||||
* updated (needed for segmented messages), whereas if a NULL match is given
|
* updated. This is used to prevent storing data in RPL that has been rejected
|
||||||
* the RPL is immediately updated (used for unsegmented messages).
|
* by upper logic (access, transport commands) and for receiving the segmented messages.
|
||||||
|
* If a NULL match is given the RPL is immediately updated (used for proxy configuration).
|
||||||
*/
|
*/
|
||||||
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
|
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match)
|
||||||
struct bt_mesh_rpl **match)
|
|
||||||
{
|
{
|
||||||
struct bt_mesh_rpl *rpl;
|
struct bt_mesh_rpl *rpl;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -796,23 +796,22 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
LOG_DBG("AKF %u AID 0x%02x", !ctx.crypto.dev_key, AID(&hdr));
|
LOG_DBG("AKF %u AID 0x%02x", !ctx.crypto.dev_key, AID(&hdr));
|
||||||
|
|
||||||
if (!rx->local_match) {
|
if (!rx->local_match) {
|
||||||
return 0;
|
/* if friend_match was set the frame is for LPN which we are friends. */
|
||||||
|
return rx->friend_match ? 0 : -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
||||||
rx, sdu_try_decrypt, &ctx);
|
rx, sdu_try_decrypt, &ctx);
|
||||||
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
||||||
LOG_DBG("No matching AppKey");
|
LOG_DBG("No matching AppKey");
|
||||||
return 0;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
rx->ctx.uuid = ctx.crypto.ad;
|
rx->ctx.uuid = ctx.crypto.ad;
|
||||||
|
|
||||||
LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx);
|
LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx);
|
||||||
|
|
||||||
(void)bt_mesh_model_recv(&rx->ctx, sdu);
|
return bt_mesh_access_recv(&rx->ctx, sdu);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t addr)
|
static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t addr)
|
||||||
|
@ -1027,6 +1026,8 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx,
|
||||||
{
|
{
|
||||||
NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_SDU_UNSEG_MAX);
|
NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_SDU_UNSEG_MAX);
|
||||||
uint8_t hdr;
|
uint8_t hdr;
|
||||||
|
struct bt_mesh_rpl *rpl = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
LOG_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data));
|
LOG_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data));
|
||||||
|
|
||||||
|
@ -1035,7 +1036,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx,
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt_mesh_rpl_check(rx, NULL)) {
|
if (bt_mesh_rpl_check(rx, &rpl)) {
|
||||||
LOG_WRN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst,
|
LOG_WRN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst,
|
||||||
rx->seq);
|
rx->seq);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1044,18 +1045,22 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx,
|
||||||
hdr = net_buf_simple_pull_u8(buf);
|
hdr = net_buf_simple_pull_u8(buf);
|
||||||
|
|
||||||
if (rx->ctl) {
|
if (rx->ctl) {
|
||||||
return ctl_recv(rx, hdr, buf, seq_auth);
|
err = ctl_recv(rx, hdr, buf, seq_auth);
|
||||||
}
|
} else if (buf->len < 1 + APP_MIC_LEN(0)) {
|
||||||
|
|
||||||
if (buf->len < 1 + APP_MIC_LEN(0)) {
|
|
||||||
LOG_ERR("Too short SDU + MIC");
|
LOG_ERR("Too short SDU + MIC");
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
} else {
|
||||||
|
/* Adjust the length to not contain the MIC at the end */
|
||||||
|
buf->len -= APP_MIC_LEN(0);
|
||||||
|
err = sdu_recv(rx, hdr, 0, buf, &sdu, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust the length to not contain the MIC at the end */
|
/* Update rpl only if there is place and upper logic accepted incoming data. */
|
||||||
buf->len -= APP_MIC_LEN(0);
|
if (err == 0 && rpl != NULL) {
|
||||||
|
bt_mesh_rpl_update(rpl, rx);
|
||||||
|
}
|
||||||
|
|
||||||
return sdu_recv(rx, hdr, 0, buf, &sdu, NULL);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data,
|
int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data,
|
||||||
|
@ -1558,17 +1563,6 @@ found_rx:
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("Complete SDU");
|
LOG_DBG("Complete SDU");
|
||||||
|
|
||||||
if (rpl) {
|
|
||||||
bt_mesh_rpl_update(rpl, net_rx);
|
|
||||||
/* Update the seg, unless it has already been surpassed:
|
|
||||||
* This needs to happen after rpl_update to ensure that the IV
|
|
||||||
* update reset logic inside rpl_update doesn't overwrite the
|
|
||||||
* change.
|
|
||||||
*/
|
|
||||||
rpl->seg = MAX(rpl->seg, auth_seqnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
*pdu_type = BT_MESH_FRIEND_PDU_COMPLETE;
|
*pdu_type = BT_MESH_FRIEND_PDU_COMPLETE;
|
||||||
|
|
||||||
/* If this fails, the work handler will either exit early because the
|
/* If this fails, the work handler will either exit early because the
|
||||||
|
@ -1602,6 +1596,17 @@ found_rx:
|
||||||
err = sdu_recv(net_rx, *hdr, ASZMIC(hdr), &seg_buf, &sdu, rx);
|
err = sdu_recv(net_rx, *hdr, ASZMIC(hdr), &seg_buf, &sdu, rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update rpl only if there is place and upper logic accepted incoming data. */
|
||||||
|
if (err == 0 && rpl != NULL) {
|
||||||
|
bt_mesh_rpl_update(rpl, net_rx);
|
||||||
|
/* Update the seg, unless it has already been surpassed:
|
||||||
|
* This needs to happen after rpl_update to ensure that the IV
|
||||||
|
* update reset logic inside rpl_update doesn't overwrite the
|
||||||
|
* change.
|
||||||
|
*/
|
||||||
|
rpl->seg = MAX(rpl->seg, auth_seqnum);
|
||||||
|
}
|
||||||
|
|
||||||
seg_rx_reset(rx, false);
|
seg_rx_reset(rx, false);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue