diff --git a/subsys/bluetooth/host/testing.c b/subsys/bluetooth/host/testing.c index fb582312b5c..3c0f52ef3f0 100644 --- a/subsys/bluetooth/host/testing.c +++ b/subsys/bluetooth/host/testing.c @@ -12,6 +12,7 @@ #if defined(CONFIG_BT_MESH) #include "mesh/net.h" #include "mesh/lpn.h" +#include "mesh/rpl.h" #include "mesh/transport.h" #endif /* CONFIG_BT_MESH */ diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 17c49376d56..17d898cf0be 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH beacon.c net.c transport.c + rpl.c crypto.c access.c cfg_srv.c diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 15eb43386f1..6f761ff5fa7 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -589,6 +589,12 @@ config BT_MESH_DEBUG_NET Use this option to enable Network layer debug logs for the Bluetooth Mesh functionality. +config BT_MESH_DEBUG_RPL + bool "Replay protection list debug" + help + Use this option to enable Replay protection list debug logs + for the Bluetooth Mesh functionality. + config BT_MESH_DEBUG_TRANS bool "Transport layer debug" help diff --git a/subsys/bluetooth/mesh/cdb.c b/subsys/bluetooth/mesh/cdb.c index 551aa1bccbb..5de34ee2a41 100644 --- a/subsys/bluetooth/mesh/cdb.c +++ b/subsys/bluetooth/mesh/cdb.c @@ -15,6 +15,7 @@ #include "mesh.h" #include "net.h" +#include "rpl.h" #include "settings.h" struct bt_mesh_cdb bt_mesh_cdb = { diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index a3584a6fabf..7c75a24ea14 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -27,6 +27,7 @@ #include "mesh.h" #include "adv.h" #include "net.h" +#include "rpl.h" #include "lpn.h" #include "transport.h" #include "crypto.h" diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 6acfce2d986..dc4633f1f37 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -24,6 +24,7 @@ #include "adv.h" #include "prov.h" #include "net.h" +#include "rpl.h" #include "beacon.h" #include "lpn.h" #include "friend.h" diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 4f1acf01d4b..7bcbe7b8b15 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -27,6 +27,7 @@ #include "adv.h" #include "mesh.h" #include "net.h" +#include "rpl.h" #include "lpn.h" #include "friend.h" #include "proxy.h" @@ -559,30 +560,6 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) return false; } -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(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[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); - } - } - } -} - #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST) void bt_mesh_iv_update_test(bool enable) { @@ -658,7 +635,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) if (iv_index > bt_mesh.iv_index + 1) { BT_WARN("Performing IV Index Recovery"); - (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); + bt_mesh_rpl_clear(); bt_mesh.iv_index = iv_index; bt_mesh.seq = 0U; goto do_update; diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index 105cf91d948..3f3c7324ed5 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -74,15 +74,6 @@ struct bt_mesh_subnet { } keys[2]; }; -struct bt_mesh_rpl { - uint16_t src; - bool old_iv; -#if defined(CONFIG_BT_SETTINGS) - bool store; -#endif - uint32_t seq; -}; - #if defined(CONFIG_BT_MESH_FRIEND) #define FRIEND_SEG_RX CONFIG_BT_MESH_FRIEND_SEG_RX #define FRIEND_SUB_LIST_SIZE CONFIG_BT_MESH_FRIEND_SUB_LIST_SIZE @@ -257,8 +248,6 @@ struct bt_mesh_net { struct bt_mesh_app_key app_keys[CONFIG_BT_MESH_APP_KEY_COUNT]; struct bt_mesh_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT]; - - struct bt_mesh_rpl rpl[CONFIG_BT_MESH_CRPL]; }; /* Network interface */ @@ -318,8 +307,6 @@ void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub); int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub); -void bt_mesh_rpl_reset(void); - bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub); diff --git a/subsys/bluetooth/mesh/prov.c b/subsys/bluetooth/mesh/prov.c index 37571a535f5..3d3e3088448 100644 --- a/subsys/bluetooth/mesh/prov.c +++ b/subsys/bluetooth/mesh/prov.c @@ -29,6 +29,7 @@ #include "adv.h" #include "mesh.h" #include "net.h" +#include "rpl.h" #include "beacon.h" #include "access.h" #include "foundation.h" diff --git a/subsys/bluetooth/mesh/proxy.c b/subsys/bluetooth/mesh/proxy.c index 2cdb17c6969..027a0925770 100644 --- a/subsys/bluetooth/mesh/proxy.c +++ b/subsys/bluetooth/mesh/proxy.c @@ -22,6 +22,7 @@ #include "mesh.h" #include "adv.h" #include "net.h" +#include "rpl.h" #include "transport.h" #include "prov.h" #include "beacon.h" diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c new file mode 100644 index 00000000000..a88de870947 --- /dev/null +++ b/subsys/bluetooth/mesh/rpl.c @@ -0,0 +1,175 @@ +/* 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); + } + } + } +} diff --git a/subsys/bluetooth/mesh/rpl.h b/subsys/bluetooth/mesh/rpl.h new file mode 100644 index 00000000000..65daee82458 --- /dev/null +++ b/subsys/bluetooth/mesh/rpl.h @@ -0,0 +1,30 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2020 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +struct bt_mesh_rpl { + uint16_t src; + bool old_iv; +#if defined(CONFIG_BT_SETTINGS) + bool store; +#endif + uint32_t seq; +}; + +typedef void (*bt_mesh_rpl_func_t)(struct bt_mesh_rpl *rpl, + void *user_data); + +void bt_mesh_rpl_reset(void); +bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, + struct bt_mesh_rpl **match); +void bt_mesh_rpl_clear(void); +struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src); +struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src); +void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data); +void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, + struct bt_mesh_net_rx *rx); diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index b34ac8db6ad..92a1f03f989 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -27,6 +27,7 @@ #include "mesh.h" #include "net.h" #include "crypto.h" +#include "rpl.h" #include "transport.h" #include "access.h" #include "foundation.h" @@ -280,33 +281,6 @@ static int seq_set(const char *name, size_t len_rd, settings_read_cb read_cb, return 0; } -static struct bt_mesh_rpl *rpl_find(uint16_t src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - if (bt_mesh.rpl[i].src == src) { - return &bt_mesh.rpl[i]; - } - } - - return NULL; -} - -static struct bt_mesh_rpl *rpl_alloc(uint16_t src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - if (!bt_mesh.rpl[i].src) { - bt_mesh.rpl[i].src = src; - return &bt_mesh.rpl[i]; - } - } - - return NULL; -} - static int rpl_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -321,7 +295,7 @@ static int rpl_set(const char *name, size_t len_rd, } src = strtol(name, NULL, 16); - entry = rpl_find(src); + entry = bt_mesh_rpl_find(src); if (len_rd == 0) { BT_DBG("val (null)"); @@ -335,7 +309,7 @@ static int rpl_set(const char *name, size_t len_rd, } if (!entry) { - entry = rpl_alloc(src); + entry = bt_mesh_rpl_alloc(src); if (!entry) { BT_ERR("Unable to allocate RPL entry for 0x%04x", src); return -ENOMEM; @@ -1349,45 +1323,33 @@ static void store_rpl(struct bt_mesh_rpl *entry) } } -static void clear_rpl(void) +static void clear_rpl(struct bt_mesh_rpl *rpl, void *user_data) { - int i, err; + int err; + char path[18]; - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - char path[18]; - - if (!rpl->src) { - continue; - } - - snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src); - err = settings_delete(path); - if (err) { - BT_ERR("Failed to clear RPL"); - } else { - BT_DBG("Cleared RPL"); - } - - (void)memset(rpl, 0, sizeof(*rpl)); + if (!rpl->src) { + return; } + + snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src); + err = settings_delete(path); + if (err) { + BT_ERR("Failed to clear RPL"); + } else { + BT_DBG("Cleared RPL"); + } + + (void)memset(rpl, 0, sizeof(*rpl)); } -static void store_pending_rpl(void) +static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data) { - int i; - BT_DBG(""); - for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - - if (rpl->store) { - rpl->store = false; - store_rpl(rpl); - } + if (rpl->store) { + rpl->store = false; + store_rpl(rpl); } } @@ -1996,9 +1958,9 @@ static void store_pending(struct k_work *work) if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_rpl(); + bt_mesh_rpl_foreach(store_pending_rpl, NULL); } else { - clear_rpl(); + bt_mesh_rpl_foreach(clear_rpl, NULL); } } diff --git a/subsys/bluetooth/mesh/shell.c b/subsys/bluetooth/mesh/shell.c index cbae6b5ed5a..17e18c530b7 100644 --- a/subsys/bluetooth/mesh/shell.c +++ b/subsys/bluetooth/mesh/shell.c @@ -24,6 +24,7 @@ /* Private includes for raw Network & Transport layer access */ #include "mesh.h" #include "net.h" +#include "rpl.h" #include "transport.h" #include "foundation.h" #include "settings.h" diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 8b5f246259c..48a0b11e843 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -29,6 +29,7 @@ #include "mesh.h" #include "net.h" #include "lpn.h" +#include "rpl.h" #include "friend.h" #include "access.h" #include "foundation.h" @@ -676,75 +677,6 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, return err; } -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_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(bt_mesh.rpl); i++) { - struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; - - /* Empty slot */ - if (!rpl->src) { - if (match) { - *match = rpl; - } else { - update_rpl(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 { - update_rpl(rpl, rx); - } - - return false; - } else { - return true; - } - } - } - - BT_ERR("RPL is full!"); - return true; -} - static void seg_rx_assemble(struct seg_rx *rx, struct net_buf_simple *buf, uint8_t aszmic) { @@ -1587,7 +1519,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, seq_auth, rx->block, rx->obo); if (rpl) { - update_rpl(rpl, net_rx); + bt_mesh_rpl_update(rpl, net_rx); } return -EALREADY; @@ -1700,7 +1632,7 @@ found_rx: BT_DBG("Complete SDU"); if (rpl) { - update_rpl(rpl, net_rx); + bt_mesh_rpl_update(rpl, net_rx); } *pdu_type = BT_MESH_FRIEND_PDU_COMPLETE; @@ -1822,11 +1754,7 @@ void bt_mesh_rx_reset(void) seg_rx_reset(&seg_rx[i], true); } - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_rpl(); - } else { - (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); - } + bt_mesh_rpl_clear(); } void bt_mesh_tx_reset(void) @@ -1853,12 +1781,6 @@ void bt_mesh_trans_init(void) } } -void bt_mesh_rpl_clear(void) -{ - BT_DBG(""); - (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); -} - int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index 1f6516e2208..e7d83e711d8 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -99,10 +99,6 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); void bt_mesh_trans_init(void); -void bt_mesh_rpl_clear(void); - -bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); - int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data); int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx,