diff --git a/components/bt/esp_ble_mesh/mesh_core/transport.c b/components/bt/esp_ble_mesh/mesh_core/transport.c index 82a0ddfae..79f59b0ce 100644 --- a/components/bt/esp_ble_mesh/mesh_core/transport.c +++ b/components/bt/esp_ble_mesh/mesh_core/transport.c @@ -555,7 +555,23 @@ int bt_mesh_trans_resend(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, return err; } -static bool is_replay(struct bt_mesh_net_rx *rx) +static void update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) +{ + rpl->src = rx->ctx.addr; + rpl->seq = rx->seq; + rpl->old_iv = rx->old_iv; + + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { + bt_mesh_store_rpl(rpl); + } +} + +/* 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 + * updated (needed for segmented messages), whereas if a NULL match is given + * the RPL is immediately updated (used for unsegmented messages). + */ +static bool is_replay(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { int i; @@ -564,17 +580,20 @@ static bool is_replay(struct bt_mesh_net_rx *rx) return false; } + /* The RPL is used only for the local node */ + if (!rx->local_match) { + return false; + } + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; /* Empty slot */ if (!rpl->src) { - rpl->src = rx->ctx.addr; - rpl->seq = rx->seq; - rpl->old_iv = rx->old_iv; - - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_rpl(rpl); + if (match) { + *match = rpl; + } else { + update_rpl(rpl, rx); } return false; @@ -597,11 +616,10 @@ static bool is_replay(struct bt_mesh_net_rx *rx) if ((!rx->old_iv && rpl->old_iv) || (rpl->seq < rx->seq) || (rpl->seq > rx->seq + 10)) { #endif /* #if !CONFIG_BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0 */ - rpl->seq = rx->seq; - rpl->old_iv = rx->old_iv; - - if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - bt_mesh_store_rpl(rpl); + if (match) { + *match = rpl; + } else { + update_rpl(rpl, rx); } return false; @@ -950,7 +968,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, return -EINVAL; } - if (rx->local_match && is_replay(rx)) { + if (is_replay(rx, NULL)) { BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, rx->seq); return -EINVAL; @@ -1229,6 +1247,7 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, enum bt_mesh_friend_pdu_type *pdu_type, u64_t *seq_auth) { + struct bt_mesh_rpl *rpl = NULL; struct seg_rx *rx; u8_t *hdr = buf->data; u16_t seq_zero; @@ -1241,6 +1260,12 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, return -EINVAL; } + if (is_replay(net_rx, &rpl)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); + return -EINVAL; + } + BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); net_buf_simple_pull(buf, 1); @@ -1300,6 +1325,11 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); + + if (rpl) { + update_rpl(rpl, net_rx); + } + return -EALREADY; } @@ -1387,12 +1417,8 @@ found_rx: BT_DBG("Complete SDU"); - if (net_rx->local_match && is_replay(net_rx)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", - net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); - /* Clear the segment's bit */ - rx->block &= ~BIT(seg_o); - return -EINVAL; + if (rpl) { + update_rpl(rpl, net_rx); } *pdu_type = BLE_MESH_FRIEND_PDU_COMPLETE;