/* Bluetooth Mesh */ /* * Copyright (c) 2017 Intel Corporation * Copyright (c) 2020 Lingao Meng * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_RPL) #define LOG_MODULE_NAME bt_mesh_rpl #include "common/log.h" #include "mesh.h" #include "adv.h" #include "net.h" #include "rpl.h" #include "settings.h" static struct bt_mesh_rpl replay_list[CONFIG_BT_MESH_CRPL]; void bt_mesh_rpl_update(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_BT_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). */ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { int i; /* Don't bother checking messages from ourselves */ if (rx->net_if == BT_MESH_NET_IF_LOCAL) { return false; } /* The RPL is used only for the local node */ if (!rx->local_match) { return false; } for (i = 0; i < ARRAY_SIZE(replay_list); i++) { struct bt_mesh_rpl *rpl = &replay_list[i]; /* Empty slot */ if (!rpl->src) { if (match) { *match = rpl; } else { bt_mesh_rpl_update(rpl, rx); } return false; } /* Existing slot for given address */ if (rpl->src == rx->ctx.addr) { if (rx->old_iv && !rpl->old_iv) { return true; } if ((!rx->old_iv && rpl->old_iv) || rpl->seq < rx->seq) { if (match) { *match = rpl; } else { bt_mesh_rpl_update(rpl, rx); } return false; } else { return true; } } } BT_ERR("RPL is full!"); return true; } void bt_mesh_rpl_clear(void) { BT_DBG(""); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_clear_rpl(); } else { (void)memset(replay_list, 0, sizeof(replay_list)); } } struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) { int i; for (i = 0; i < ARRAY_SIZE(replay_list); i++) { if (replay_list[i].src == src) { return &replay_list[i]; } } return NULL; } struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) { int i; for (i = 0; i < ARRAY_SIZE(replay_list); i++) { if (!replay_list[i].src) { replay_list[i].src = src; return &replay_list[i]; } } return NULL; } void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data) { int i; for (i = 0; i < ARRAY_SIZE(replay_list); i++) { func(&replay_list[i], user_data); } } void bt_mesh_rpl_reset(void) { int i; /* Discard "old old" IV Index entries from RPL and flag * any other ones (which are valid) as old. */ for (i = 0; i < ARRAY_SIZE(replay_list); i++) { struct bt_mesh_rpl *rpl = &replay_list[i]; if (rpl->src) { if (rpl->old_iv) { (void)memset(rpl, 0, sizeof(*rpl)); } else { rpl->old_iv = true; } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_store_rpl(rpl); } } } }