From 648378b29253e036951edbd52f5f17afd81a4f67 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 18:43:12 +0200 Subject: [PATCH] Bluetooth: Mesh: Add full virtual addresses support This commit adds the following features related to virtual addresses support: - Allows to store Label UUIDs which virtual addresses collide; - Allows to decrypt messages encrypted with a virtual address with collision; - Allows to publish a message to a specific Label UUID to avoid virtual addresses collision by adding a pointer to Label UUID to struct bt_mesh_msg_ctx and struct bt_mesh_model_pub; - Allows to differentiate Label UUIDs in the model's Subscription List by storing all subscribed UUIDs in struct bt_mesh_model.uuids field. Signed-off-by: Pavel Vasilyev --- include/zephyr/bluetooth/mesh/access.h | 18 + include/zephyr/bluetooth/mesh/main.h | 17 + include/zephyr/bluetooth/mesh/msg.h | 12 +- subsys/bluetooth/mesh/CMakeLists.txt | 1 + subsys/bluetooth/mesh/access.c | 293 +++++++++++++--- subsys/bluetooth/mesh/access.h | 1 + subsys/bluetooth/mesh/cfg_srv.c | 215 +++++++----- subsys/bluetooth/mesh/friend.c | 34 +- subsys/bluetooth/mesh/lpn.c | 2 +- subsys/bluetooth/mesh/lpn.h | 2 +- subsys/bluetooth/mesh/settings.c | 1 + subsys/bluetooth/mesh/transport.c | 270 ++------------- subsys/bluetooth/mesh/transport.h | 9 - subsys/bluetooth/mesh/transport_legacy.c | 271 ++------------- subsys/bluetooth/mesh/va.c | 319 ++++++++++++++++++ subsys/bluetooth/mesh/va.h | 79 +++++ tests/bsim/bluetooth/mesh/src/mesh_test.c | 26 +- tests/bsim/bluetooth/mesh/src/mesh_test.h | 6 +- .../bsim/bluetooth/mesh/src/test_friendship.c | 120 ++++--- tests/bsim/bluetooth/mesh/src/test_iv_index.c | 3 +- tests/bsim/bluetooth/mesh/src/test_scanner.c | 2 +- .../bsim/bluetooth/mesh/src/test_transport.c | 68 ++-- 22 files changed, 1047 insertions(+), 722 deletions(-) create mode 100644 subsys/bluetooth/mesh/va.c create mode 100644 subsys/bluetooth/mesh/va.h diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 58219437958..d033d9e8849 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -17,10 +17,18 @@ /* Internal macros used to initialize array members */ #define BT_MESH_KEY_UNUSED_ELT_(IDX, _) BT_MESH_KEY_UNUSED #define BT_MESH_ADDR_UNASSIGNED_ELT_(IDX, _) BT_MESH_ADDR_UNASSIGNED +#define BT_MESH_UUID_UNASSIGNED_ELT_(IDX, _) NULL #define BT_MESH_MODEL_KEYS_UNUSED(_keys) \ { LISTIFY(_keys, BT_MESH_KEY_UNUSED_ELT_, (,)) } #define BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps) \ { LISTIFY(_grps, BT_MESH_ADDR_UNASSIGNED_ELT_, (,)) } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +#define BT_MESH_MODEL_UUIDS_UNASSIGNED() \ + .uuids = (const uint8_t *[]){ LISTIFY(CONFIG_BT_MESH_LABEL_COUNT, \ + BT_MESH_UUID_UNASSIGNED_ELT_, (,)) }, +#else +#define BT_MESH_MODEL_UUIDS_UNASSIGNED() +#endif /** * @brief Access layer @@ -286,6 +294,7 @@ struct bt_mesh_model_op { .keys_cnt = _keys, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ .user_data = _user_data, \ @@ -319,6 +328,7 @@ struct bt_mesh_model_op { .keys_cnt = _keys, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .user_data = _user_data, \ .cb = _cb, \ } @@ -364,6 +374,7 @@ struct bt_mesh_model_op { .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ .user_data = _user_data, \ @@ -418,6 +429,7 @@ struct bt_mesh_model_op { .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .user_data = _user_data, \ .cb = _cb, \ .metadata = _metadata, \ @@ -545,6 +557,7 @@ struct bt_mesh_model_pub { struct bt_mesh_model *mod; uint16_t addr; /**< Publish Address. */ + const uint8_t *uuid; /**< Label UUID if Publish Address is Virtual Address. */ uint16_t key:12, /**< Publish AppKey Index. */ cred:1, /**< Friendship Credentials Flag. */ send_rel:1, /**< Force reliable sending (segment acks) */ @@ -744,6 +757,11 @@ struct bt_mesh_model { uint16_t * const groups; const uint16_t groups_cnt; +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /** List of Label UUIDs the model is subscribed to. */ + const uint8_t ** const uuids; +#endif + /** Opcode handler list */ const struct bt_mesh_model_op * const op; diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 96f2b343a70..5d37b581f4d 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -854,6 +854,23 @@ int bt_mesh_friend_terminate(uint16_t lpn_addr); */ void bt_mesh_rpl_pending_store(uint16_t addr); +/** @brief Iterate stored Label UUIDs. + * + * When @c addr is @ref BT_MESH_ADDR_UNASSIGNED, this function iterates over all available addresses + * starting with @c uuid. In this case, use @c retaddr to get virtual address representation of + * the returned Label UUID. When @c addr is a virtual address, this function returns next Label + * UUID corresponding to the @c addr. When @c uuid is NULL, this function returns the first + * available UUID. If @c uuid is previously returned uuid, this function returns following uuid. + * + * @param addr Virtual address to search for, or @ref BT_MESH_ADDR_UNASSIGNED. + * @param uuid Pointer to the previously returned Label UUID or NULL. + * @param retaddr Pointer to a memory where virtual address representation of the returning UUID is + * to be stored to. + * + * @return Pointer to Label UUID, or NULL if no more entries found. + */ +const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/mesh/msg.h b/include/zephyr/bluetooth/mesh/msg.h index ff2e3ffeba4..e52ca85e3a4 100644 --- a/include/zephyr/bluetooth/mesh/msg.h +++ b/include/zephyr/bluetooth/mesh/msg.h @@ -86,6 +86,9 @@ struct bt_mesh_msg_ctx { /** Destination address of a received message. Not used for sending. */ uint16_t recv_dst; + /** Label UUID if Remote address is Virtual address, or NULL otherwise. */ + const uint8_t *uuid; + /** RSSI of received packet. Not used for sending. */ int8_t recv_rssi; @@ -102,6 +105,8 @@ struct bt_mesh_msg_ctx { /** * @brief Helper for bt_mesh_msg_ctx structure initialization. * + * @note If @c dst is a Virtual Address, Label UUID shall be initialized separately. + * * @param net_key_idx NetKey Index of the subnet to send the message on. Only used if * @c app_key_idx points to devkey. * @param app_key_idx AppKey Index to encrypt the message with. @@ -141,7 +146,12 @@ struct bt_mesh_msg_ctx { * @param pub Pointer to a model publication context. */ #define BT_MESH_MSG_CTX_INIT_PUB(pub) \ - BT_MESH_MSG_CTX_INIT(0, (pub)->key, (pub)->addr, (pub)->ttl) + { \ + .app_idx = (pub)->key, \ + .addr = (pub)->addr, \ + .send_ttl = (pub)->ttl, \ + .uuid = (pub)->uuid, \ + } /** @brief Initialize a model message. * diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index e4aa8f8933d..a1a5b1de93a 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH msg.c cfg_srv.c health_srv.c + va.c ) if (CONFIG_BT_MESH_V1d1) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 7df72d698fe..483e7dcc028 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -27,6 +27,7 @@ #include "foundation.h" #include "op_agg.h" #include "settings.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL #include @@ -34,13 +35,16 @@ LOG_MODULE_REGISTER(bt_mesh_access); /* Model publication information for persistent storage. */ struct mod_pub_val { - uint16_t addr; - uint16_t key; - uint8_t ttl; - uint8_t retransmit; - uint8_t period; - uint8_t period_div:4, - cred:1; + struct { + uint16_t addr; + uint16_t key; + uint8_t ttl; + uint8_t retransmit; + uint8_t period; + uint8_t period_div:4, + cred:1; + } base; + uint16_t uuidx; }; struct comp_foreach_model_arg { @@ -1002,6 +1006,69 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) return ctx.entry; } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +static const uint8_t **model_uuid_get(struct bt_mesh_model *mod, const uint8_t *uuid) +{ + int i; + + for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] == uuid) { + /* If we are looking for a new entry, ensure that we find a model where + * there is empty entry in both, uuids and groups list. + */ + if (uuid == NULL && !model_group_get(mod, BT_MESH_ADDR_UNASSIGNED)) { + continue; + } + + return &mod->uuids[i]; + } + } + + return NULL; +} + +struct find_uuid_visitor_ctx { + const uint8_t **entry; + struct bt_mesh_model *mod; + const uint8_t *uuid; +}; + +static enum bt_mesh_walk find_uuid_mod_visitor(struct bt_mesh_model *mod, void *user_data) +{ + struct find_uuid_visitor_ctx *ctx = user_data; + + if (mod->elem_idx != ctx->mod->elem_idx) { + return BT_MESH_WALK_CONTINUE; + } + + ctx->entry = model_uuid_get(mod, ctx->uuid); + if (ctx->entry) { + ctx->mod = mod; + return BT_MESH_WALK_STOP; + } + + return BT_MESH_WALK_CONTINUE; +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ + +const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + struct find_uuid_visitor_ctx ctx = { + .mod = *mod, + .entry = NULL, + .uuid = uuid, + }; + + bt_mesh_model_extensions_walk(*mod, find_uuid_mod_visitor, &ctx); + + *mod = ctx.mod; + return ctx.entry; +#else + return NULL; +#endif +} + static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, uint16_t group_addr) { @@ -1117,11 +1184,13 @@ bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) return false; } -static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst) +static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) { if (BT_MESH_ADDR_IS_UNICAST(dst)) { return (dev_comp->elem[mod->elem_idx].addr == dst); - } else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst) || + } else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { + return !!bt_mesh_model_find_uuid(&mod, uuid); + } else if (BT_MESH_ADDR_IS_GROUP(dst) || (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) { return !!bt_mesh_model_find_group(&mod, dst); } @@ -1217,8 +1286,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode) CODE_UNREACHABLE; } -static int element_model_recv(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, uint16_t addr, +static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, struct bt_mesh_elem *elem, uint32_t opcode) { const struct bt_mesh_model_op *op; @@ -1237,8 +1305,8 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, return ACCESS_STATUS_WRONG_KEY; } - if (!model_has_dst(model, addr)) { - LOG_ERR("Invalid address 0x%02x", addr); + if (!model_has_dst(model, ctx->recv_dst, ctx->uuid)) { + LOG_ERR("Invalid address 0x%02x", ctx->recv_dst); return ACCESS_STATUS_INVALID_ADDRESS; } @@ -1291,13 +1359,13 @@ int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) } else { struct bt_mesh_elem *elem = &dev_comp->elem[index]; - err = element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode); + err = element_model_recv(ctx, buf, elem, opcode); } } else { for (index = 0; index < dev_comp->elem_count; index++) { struct bt_mesh_elem *elem = &dev_comp->elem[index]; - (void)element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode); + (void)element_model_recv(ctx, buf, elem, opcode); } } @@ -1581,6 +1649,64 @@ static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd, LOG_HEXDUMP_DBG(mod->groups, len, "val"); LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0])); + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /* If uuids[0] is NULL, then either the model is not subscribed to virtual addresses or + * uuids are not yet recovered. + */ + if (mod->uuids[0] == NULL) { + int i, j = 0; + + for (i = 0; i < mod->groups_cnt && j < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { + /* Recover from implementation where uuid was not stored for + * virtual address. It is safe to pick first matched label because + * previously the stack wasn't able to store virtual addresses with + * collisions. + */ + mod->uuids[j] = bt_mesh_va_uuid_get(mod->groups[i], NULL, NULL); + j++; + } + } + } +#endif + return 0; +} + +static int mod_set_sub_va(struct bt_mesh_model *mod, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT]; + ssize_t len; + int i; + int count; + + /* Start with empty array regardless of cleared or set value */ + (void)memset(mod->uuids, 0, CONFIG_BT_MESH_LABEL_COUNT * sizeof(mod->uuids[0])); + + if (len_rd == 0) { + LOG_DBG("Cleared subscriptions for model"); + return 0; + } + + len = read_cb(cb_arg, uuidxs, sizeof(uuidxs)); + if (len < 0) { + LOG_ERR("Failed to read value (err %zd)", len); + return len; + } + + LOG_HEXDUMP_DBG(uuidxs, len, "val"); + + for (i = 0, count = 0; i < len / sizeof(uint16_t); i++) { + mod->uuids[count] = bt_mesh_va_get_uuid_by_idx(uuidxs[i]); + if (mod->uuids[count] != NULL) { + count++; + } + } + + LOG_DBG("Decoded %zu subscribed virtual addresses for model", count); +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ return 0; } @@ -1603,6 +1729,7 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, mod->pub->period = 0U; mod->pub->retransmit = 0U; mod->pub->count = 0U; + mod->pub->uuid = NULL; LOG_DBG("Cleared publication for model"); return 0; @@ -1612,22 +1739,41 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, return 0; } - err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); - if (err) { - LOG_ERR("Failed to set \'model-pub\'"); - return err; + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub.base)); + if (!err) { + /* Recover from implementation where uuid was not stored for virtual address. It + * is safe to pick first matched label because previously the stack wasn't able + * to store virtual addresses with collisions. + */ + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { + mod->pub->uuid = bt_mesh_va_uuid_get(pub.base.addr, NULL, NULL); + } + + goto pub_base_set; + } else { + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); + if (err) { + LOG_ERR("Failed to set \'model-pub\'"); + return err; + } } - mod->pub->addr = pub.addr; - mod->pub->key = pub.key; - mod->pub->cred = pub.cred; - mod->pub->ttl = pub.ttl; - mod->pub->period = pub.period; - mod->pub->retransmit = pub.retransmit; - mod->pub->period_div = pub.period_div; + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { + mod->pub->uuid = bt_mesh_va_get_uuid_by_idx(pub.uuidx); + } + +pub_base_set: + mod->pub->addr = pub.base.addr; + mod->pub->key = pub.base.key; + mod->pub->cred = pub.base.cred; + mod->pub->ttl = pub.base.ttl; + mod->pub->period = pub.base.period; + mod->pub->retransmit = pub.base.retransmit; + mod->pub->period_div = pub.base.period_div; mod->pub->count = 0U; - LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.addr, pub.key); + LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.base.addr, + pub.base.key); return 0; } @@ -1675,26 +1821,35 @@ static int mod_set(bool vnd, const char *name, size_t len_rd, } len = settings_name_next(name, &next); - if (!next) { LOG_ERR("Insufficient number of arguments"); return -ENOENT; } - if (!strncmp(next, "bind", len)) { - return mod_set_bind(mod, len_rd, read_cb, cb_arg); - } + /* `len` contains length of model id string representation. Call settings_name_next() again + * to get length of `next`. + */ + switch (settings_name_next(next, NULL)) { + case 4: + if (!strncmp(next, "bind", 4)) { + return mod_set_bind(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "subv", 4)) { + return mod_set_sub_va(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "data", 4)) { + return mod_data_set(mod, next, len_rd, read_cb, cb_arg); + } - if (!strncmp(next, "sub", len)) { - return mod_set_sub(mod, len_rd, read_cb, cb_arg); - } + break; + case 3: + if (!strncmp(next, "sub", 3)) { + return mod_set_sub(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "pub", 3)) { + return mod_set_pub(mod, len_rd, read_cb, cb_arg); + } - if (!strncmp(next, "pub", len)) { - return mod_set_pub(mod, len_rd, read_cb, cb_arg); - } - - if (!strncmp(next, "data", len)) { - return mod_data_set(mod, next, len_rd, read_cb, cb_arg); + break; + default: + break; } LOG_WRN("Unknown module key %s", next); @@ -1786,8 +1941,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) encode_mod_path(mod, vnd, "sub", path, sizeof(path)); if (count) { - err = settings_save_one(path, groups, - count * sizeof(groups[0])); + err = settings_save_one(path, groups, count * sizeof(groups[0])); } else { err = settings_delete(path); } @@ -1799,6 +1953,38 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) } } +static void store_pending_mod_sub_va(struct bt_mesh_model *mod, bool vnd) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT]; + char path[20]; + int i, count, err; + + for (i = 0, count = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] != NULL) { + err = bt_mesh_va_get_idx_by_uuid(mod->uuids[i], &uuidxs[count]); + if (!err) { + count++; + } + } + } + + encode_mod_path(mod, vnd, "subv", path, sizeof(path)); + + if (count) { + err = settings_save_one(path, uuidxs, count * sizeof(uuidxs[0])); + } else { + err = settings_delete(path); + } + + if (err) { + LOG_ERR("Failed to store %s value", path); + } else { + LOG_DBG("Stored %s value", path); + } +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ +} + static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) { struct mod_pub_val pub = {0}; @@ -1810,15 +1996,21 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { err = settings_delete(path); } else { - pub.addr = mod->pub->addr; - pub.key = mod->pub->key; - pub.ttl = mod->pub->ttl; - pub.retransmit = mod->pub->retransmit; - pub.period = mod->pub->period; - pub.period_div = mod->pub->period_div; - pub.cred = mod->pub->cred; + pub.base.addr = mod->pub->addr; + pub.base.key = mod->pub->key; + pub.base.ttl = mod->pub->ttl; + pub.base.retransmit = mod->pub->retransmit; + pub.base.period = mod->pub->period; + pub.base.period_div = mod->pub->period_div; + pub.base.cred = mod->pub->cred; - err = settings_save_one(path, &pub, sizeof(pub)); + if (BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr)) { + (void)bt_mesh_va_get_idx_by_uuid(mod->pub->uuid, &pub.uuidx); + } + + err = settings_save_one(path, &pub, + BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr) ? sizeof(pub) : + sizeof(pub.base)); } if (err) { @@ -1844,6 +2036,7 @@ static void store_pending_mod(struct bt_mesh_model *mod, if (mod->flags & BT_MESH_MOD_SUB_PENDING) { mod->flags &= ~BT_MESH_MOD_SUB_PENDING; store_pending_mod_sub(mod, vnd); + store_pending_mod_sub_va(mod, vnd); } if (mod->flags & BT_MESH_MOD_PUB_PENDING) { diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 43ec1839160..43d5ad43913 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -41,6 +41,7 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *root, void *user_data); uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); +const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid); void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 7dbba2e8b58..512f2eb57f9 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -35,6 +35,7 @@ #include "friend.h" #include "settings.h" #include "cfg.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL #include @@ -130,7 +131,7 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, } } -static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, +static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, const uint8_t *uuid, uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, uint8_t retransmit, bool store) { @@ -158,6 +159,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->period = 0U; model->pub->retransmit = 0U; model->pub->count = 0U; + model->pub->uuid = NULL; if (model->pub->update) { /* If this fails, the timer will check pub->addr and @@ -179,11 +181,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, #if CONFIG_BT_MESH_LABEL_COUNT > 0 if (BT_MESH_ADDR_IS_VIRTUAL(model->pub->addr)) { - uint8_t *uuid = bt_mesh_va_label_get(model->pub->addr); - - if (uuid) { - bt_mesh_va_del(uuid, NULL); - } + (void)bt_mesh_va_del(model->pub->uuid); } #endif @@ -193,6 +191,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->ttl = ttl; model->pub->period = period; model->pub->retransmit = retransmit; + model->pub->uuid = uuid; if (model->pub->update) { int32_t period_ms; @@ -273,7 +272,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st } if (model->pub && model->pub->key == key_idx) { - _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, + _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, NULL, 0, 0, 0, 0, 0, store); } } @@ -803,7 +802,7 @@ static int mod_pub_set(struct bt_mesh_model *model, goto send_status; } - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, + status = _mod_pub_set(mod, pub_addr, NULL, pub_app_idx, cred_flag, pub_ttl, pub_period, retransmit, true); send_status: @@ -813,32 +812,31 @@ send_status: static size_t mod_sub_list_clear(struct bt_mesh_model *mod) { - uint8_t *label_uuid; size_t clear_count; int i; - /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < mod->groups_cnt; i++) { - if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - } + /* mod->groups contains both, group and virtual addrs. Virtual addrs deletion will + * be handled separately. + */ + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; + clear_count++; + } + } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /* Unref stored labels related to this model */ + for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] == NULL) { continue; } - label_uuid = bt_mesh_va_label_get(mod->groups[i]); - - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - - if (label_uuid) { - bt_mesh_va_del(label_uuid, NULL); - } else { - LOG_ERR("Label UUID not found"); - } + (void)bt_mesh_va_del(mod->uuids[i]); + mod->uuids[i] = NULL; + /* No need to increment `clear_count` as `groups` contains virtual addresses. */ } +#endif return clear_count; } @@ -847,11 +845,13 @@ static int mod_pub_va_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + const struct bt_mesh_va *va; uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; - uint16_t elem_addr, pub_addr, pub_app_idx; + uint16_t elem_addr, pub_app_idx; + uint16_t pub_addr = 0U; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; bool vnd; @@ -866,7 +866,7 @@ static int mod_pub_va_set(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); pub_app_idx = net_buf_simple_pull_le16(buf); cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); pub_app_idx &= BIT_MASK(12); @@ -890,27 +890,27 @@ static int mod_pub_va_set(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - pub_addr = 0U; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - pub_addr = 0U; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_add(label_uuid, &pub_addr); + status = bt_mesh_va_add(uuid, &va); if (status != STATUS_SUCCESS) { goto send_status; } - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, + pub_addr = va->addr; + + status = _mod_pub_set(mod, pub_addr, va->uuid, pub_app_idx, cred_flag, pub_ttl, pub_period, retransmit, true); if (status != STATUS_SUCCESS) { - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); } send_status: @@ -1383,12 +1383,14 @@ static int mod_sub_va_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - uint16_t elem_addr, sub_addr; + const struct bt_mesh_va *va; + uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; - uint16_t *entry; + uint16_t *group_entry; + const uint8_t **label_entry; uint8_t status; bool vnd; @@ -1403,7 +1405,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1412,42 +1414,59 @@ static int mod_sub_va_add(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_add(label_uuid, &sub_addr); + status = bt_mesh_va_add(uuid, &va); if (status != STATUS_SUCCESS) { goto send_status; } - if (bt_mesh_model_find_group(&mod, sub_addr)) { + if (bt_mesh_model_find_uuid(&mod, va->uuid)) { /* Tried to add existing subscription */ status = STATUS_SUCCESS; - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); goto send_status; } - - entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED); - if (!entry) { + label_entry = bt_mesh_model_find_uuid(&mod, NULL); + if (!label_entry) { status = STATUS_INSUFF_RESOURCES; - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); goto send_status; } - *entry = sub_addr; + group_entry = NULL; - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); + for (int i = 0; i < mod->groups_cnt; i++) { + if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) { + group_entry = &mod->groups[i]; + break; + } + } + + /* bt_mesh_model_find_uuid() should find a model where both, uuids and groups lists have + * empty entry. + */ + if (!group_entry) { + status = STATUS_INSUFF_RESOURCES; + (void)bt_mesh_va_del(va->uuid); + goto send_status; + } + + *group_entry = va->addr; + *label_entry = va->uuid; + + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_add(va->addr); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { @@ -1455,6 +1474,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model, } status = STATUS_SUCCESS; + sub_addr = va->addr; send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, @@ -1465,12 +1485,13 @@ static int mod_sub_va_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - uint16_t elem_addr, sub_addr; + const struct bt_mesh_va *va; + uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; - uint16_t *match; + const uint8_t **label_match; uint8_t status; bool vnd; @@ -1485,7 +1506,7 @@ static int mod_sub_va_del(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1495,40 +1516,50 @@ static int mod_sub_va_del(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_del(label_uuid, &sub_addr); - if (sub_addr == BT_MESH_ADDR_UNASSIGNED) { + va = bt_mesh_va_find(uuid); + if (!va) { + status = STATUS_CANNOT_REMOVE; goto send_status; } - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_del(&sub_addr, 1); + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_del(&va->addr, 1); } - match = bt_mesh_model_find_group(&mod, sub_addr); - if (match) { - *match = BT_MESH_ADDR_UNASSIGNED; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_model_sub_store(mod); - } - - status = STATUS_SUCCESS; - } else { + label_match = bt_mesh_model_find_uuid(&mod, va->uuid); + if (!label_match) { status = STATUS_CANNOT_REMOVE; + goto send_status; } + for (int i = 0; i < mod->groups_cnt; i++) { + if (mod->groups[i] == va->addr) { + mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; + break; + } + } + + *label_match = NULL; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_model_sub_store(mod); + } + + sub_addr = va->addr; + (void)bt_mesh_va_del(va->uuid); + status = STATUS_SUCCESS; + send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); @@ -1538,10 +1569,11 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; uint8_t status; bool vnd; @@ -1557,7 +1589,7 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1577,26 +1609,33 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, goto send_status; } - - if (mod->groups_cnt > 0) { - - status = bt_mesh_va_add(label_uuid, &sub_addr); - if (status == STATUS_SUCCESS) { - bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); - mod->groups[0] = sub_addr; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_model_sub_store(mod); - } - - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - } - } else { + if (CONFIG_BT_MESH_LABEL_COUNT == 0 || mod->groups_cnt == 0) { + (void)va; status = STATUS_INSUFF_RESOURCES; + goto send_status; } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + status = bt_mesh_va_add(uuid, &va); + if (status != STATUS_SUCCESS) { + goto send_status; + } + + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); + mod->groups[0] = va->addr; + mod->uuids[0] = va->uuid; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_model_sub_store(mod); + } + + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_add(va->addr); + } + + sub_addr = va->addr; +#endif send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 5a1a51801e1..e14fc1e91a2 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -21,6 +21,7 @@ #include "access.h" #include "foundation.h" #include "friend.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_FRIEND_LOG_LEVEL #include @@ -60,9 +61,15 @@ struct friend_pdu_info { uint32_t iv_index; }; +BUILD_ASSERT(CONFIG_BT_MESH_LABEL_COUNT <= 0xFFFU, "Friend doesn't support more than 4096 labels."); + struct friend_adv { uint16_t app_idx; - bool seg; + struct { + /* CONFIG_BT_MESH_LABEL_COUNT max value is 4096. */ + uint16_t uuidx:15, + seg:1; + }; }; NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BT_MESH_ADV_DATA_SIZE, @@ -309,6 +316,7 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) if (empty_idx != INT_MAX) { frnd->sub_list[empty_idx] = addr; + LOG_DBG("%04x added %04x to subscription list", frnd->lpn, addr); } else { LOG_WRN("No space in friend subscription list"); } @@ -320,6 +328,7 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { + LOG_DBG("%04x removed %04x from subscription list", frnd->lpn, addr); frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED; return; } @@ -370,6 +379,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta *meta) { uint16_t app_idx = FRIEND_ADV(buf)->app_idx; + uint16_t uuidx = FRIEND_ADV(buf)->uuidx; struct bt_mesh_net_rx net = { .ctx = { .app_idx = app_idx, @@ -393,10 +403,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, meta->crypto.aszmic = 0; if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) { - meta->crypto.ad = bt_mesh_va_label_get(meta->crypto.dst); - if (!meta->crypto.ad) { - return -ENOENT; - } + meta->crypto.ad = bt_mesh_va_get_uuid_by_idx(uuidx); } else { meta->crypto.ad = NULL; } @@ -1504,11 +1511,26 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, * when encrypting in transport and network. */ FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx; + + /* When reencrypting a virtual address message, we need to know uuid as well. */ + if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { + uint16_t uuidx; + int err; + + err = bt_mesh_va_get_idx_by_uuid(tx->ctx->uuid, &uuidx); + if (err) { + net_buf_unref(buf); + return; + } + + FRIEND_ADV(buf)->uuidx = uuidx; + } } enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - LOG_DBG("Queued message for LPN 0x%04x", frnd->lpn); + LOG_DBG("Queued message for LPN 0x%04x, dst: %04x, uuid: %p", frnd->lpn, tx->ctx->addr, + tx->ctx->uuid); } static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 03ff672338f..2b655f729f3 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -966,7 +966,7 @@ void bt_mesh_lpn_group_add(uint16_t group) sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); } -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) +void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count) { int i; diff --git a/subsys/bluetooth/mesh/lpn.h b/subsys/bluetooth/mesh/lpn.h index 7d909e06d0b..6fbea59b975 100644 --- a/subsys/bluetooth/mesh/lpn.h +++ b/subsys/bluetooth/mesh/lpn.h @@ -45,7 +45,7 @@ static inline bool bt_mesh_lpn_waiting_update(void) void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); void bt_mesh_lpn_group_add(uint16_t group); -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count); +void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count); void bt_mesh_lpn_disable(bool force); void bt_mesh_lpn_friendship_end(void); diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index ef4eec6f6a7..771aad9b946 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -30,6 +30,7 @@ #include "settings.h" #include "cfg.h" #include "solicitation.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL #include diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 1501c88217b..4cacf8d526c 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -35,6 +35,7 @@ #include "settings.h" #include "heartbeat.h" #include "transport.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL #include @@ -59,20 +60,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport); /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT -struct virtual_addr { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - -/* Virtual Address information for persistent storage. */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - #define ACK_DELAY(seg_n) \ (MIN(2 * seg_n + 1, BT_MESH_SAR_RX_ACK_DELAY_INC_X2) * \ BT_MESH_SAR_RX_SEG_INT_MS / 2) @@ -131,8 +118,6 @@ static struct seg_rx { K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); -static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) @@ -652,7 +637,7 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k }; if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - crypto.ad = bt_mesh_va_label_get(tx->ctx->addr); + crypto.ad = tx->ctx->uuid; } return bt_mesh_app_encrypt(key, &crypto, msg); @@ -759,15 +744,35 @@ struct decrypt_ctx { static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { - const struct decrypt_ctx *ctx = cb_data; + struct decrypt_ctx *ctx = cb_data; + int err; - if (ctx->seg) { - seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); + ctx->crypto.ad = NULL; + + do { + if (ctx->seg) { + seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); + } + + if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + ctx->crypto.ad = bt_mesh_va_uuid_get(rx->ctx.recv_dst, ctx->crypto.ad, + NULL); + + if (!ctx->crypto.ad) { + return -ENOENT; + } + } + + net_buf_simple_reset(ctx->sdu); + + err = bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + } while (err && ctx->crypto.ad != NULL); + + if (!err && BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + rx->ctx.uuid = ctx->crypto.ad; } - net_buf_simple_reset(ctx->sdu); - - return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + return err; } static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, @@ -794,10 +799,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst); - } - rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr), rx, sdu_try_decrypt, &ctx); if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) { @@ -805,6 +806,8 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } + rx->ctx.uuid = ctx.crypto.ad; + LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx); (void)bt_mesh_model_recv(&rx->ctx, sdu); @@ -1683,11 +1686,6 @@ void bt_mesh_rx_reset(void) } } -static void store_va_label(void) -{ - bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); -} - void bt_mesh_trans_reset(void) { int i; @@ -1700,18 +1698,8 @@ void bt_mesh_trans_reset(void) seg_tx_reset(&seg_tx[i]); } - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref) { - virtual_addrs[i].ref = 0U; - virtual_addrs[i].changed = 1U; - } - } - bt_mesh_rpl_clear(); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } + bt_mesh_va_clear(); } void bt_mesh_trans_init(void) @@ -1727,199 +1715,3 @@ void bt_mesh_trans_init(void) k_work_init_delayable(&seg_rx[i].discard, seg_discard); } } - -static inline void va_store(struct virtual_addr *store) -{ - store->changed = 1U; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } -} - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - int err; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (!virtual_addrs[i].ref) { - if (!va) { - va = &virtual_addrs[i]; - } - - continue; - } - - if (!memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - *addr = virtual_addrs[i].addr; - virtual_addrs[i].ref++; - va_store(&virtual_addrs[i]); - return STATUS_SUCCESS; - } - } - - if (!va) { - return STATUS_INSUFF_RESOURCES; - } - - memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); - err = bt_mesh_virtual_addr(uuid, &va->addr); - if (err) { - va->addr = BT_MESH_ADDR_UNASSIGNED; - return STATUS_UNSPECIFIED; - } - - va->ref = 1; - va_store(va); - - *addr = va->addr; - - return STATUS_SUCCESS; -} - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - va = &virtual_addrs[i]; - break; - } - } - - if (!va) { - return STATUS_CANNOT_REMOVE; - } - - va->ref--; - if (addr) { - *addr = va->addr; - } - - va_store(va); - return STATUS_SUCCESS; -} - -uint8_t *bt_mesh_va_label_get(uint16_t addr) -{ - int i; - - LOG_DBG("addr 0x%04x", addr); - - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) { - LOG_DBG("Found Label UUID for 0x%04x: %s", addr, - bt_hex(virtual_addrs[i].uuid, 16)); - return virtual_addrs[i].uuid; - } - } - - LOG_WRN("No matching Label UUID for 0x%04x", addr); - - return NULL; -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static struct virtual_addr *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; - } - - return &virtual_addrs[index]; -} - -static int va_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct va_val va; - struct virtual_addr *lab; - uint16_t index; - int err; - - if (!name) { - LOG_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - index = strtol(name, NULL, 16); - - if (len_rd == 0) { - LOG_WRN("Mesh Virtual Address length = 0"); - return 0; - } - - err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); - if (err) { - LOG_ERR("Failed to set \'virtual address\'"); - return err; - } - - if (va.ref == 0) { - LOG_WRN("Ignore Mesh Virtual Address ref = 0"); - return 0; - } - - lab = bt_mesh_va_get(index); - if (lab == NULL) { - LOG_WRN("Out of labels buffers"); - return -ENOBUFS; - } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); - - return 0; -} - -BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -void bt_mesh_va_pending_store(void) -{ - struct virtual_addr *lab; - struct va_val va; - char path[18]; - uint16_t i; - int err; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - err = settings_delete(path); - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - err = settings_save_one(path, &va, sizeof(va)); - } - - if (err) { - LOG_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} -#else -void bt_mesh_va_pending_store(void) -{ - /* Do nothing. */ -} -#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index ec540bd118a..2ac840d3923 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -101,13 +101,4 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, 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_trans_reset(void); - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr); - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr); - -uint8_t *bt_mesh_va_label_get(uint16_t addr); - -void bt_mesh_va_pending_store(void); diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index f619473c606..c63ad1dac85 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -34,6 +34,7 @@ #include "settings.h" #include "heartbeat.h" #include "transport.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL #include @@ -78,20 +79,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport); /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT -struct virtual_addr { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - -/* Virtual Address information for persistent storage. */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - static struct seg_tx { struct bt_mesh_subnet *sub; void *seg[BT_MESH_TX_SEG_MAX]; @@ -138,8 +125,6 @@ static struct seg_rx { K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); -static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) @@ -613,7 +598,10 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k }; if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - crypto.ad = bt_mesh_va_label_get(tx->ctx->addr); + crypto.ad = tx->ctx->uuid; + if (crypto.ad == NULL) { + return -ENOENT; + } } return bt_mesh_app_encrypt(key, &crypto, msg); @@ -720,15 +708,35 @@ struct decrypt_ctx { static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { - const struct decrypt_ctx *ctx = cb_data; + struct decrypt_ctx *ctx = cb_data; + int err; - if (ctx->seg) { - seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); + ctx->crypto.ad = NULL; + + do { + if (ctx->seg) { + seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); + } + + if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + ctx->crypto.ad = bt_mesh_va_uuid_get(rx->ctx.recv_dst, ctx->crypto.ad, + NULL); + + if (!ctx->crypto.ad) { + return -ENOENT; + } + } + + net_buf_simple_reset(ctx->sdu); + + err = bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + } while (err && ctx->crypto.ad != NULL); + + if (!err && BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { + rx->ctx.uuid = ctx->crypto.ad; } - net_buf_simple_reset(ctx->sdu); - - return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + return err; } static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, @@ -755,10 +763,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst); - } - rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr), rx, sdu_try_decrypt, &ctx); if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) { @@ -1625,11 +1629,6 @@ void bt_mesh_rx_reset(void) } } -static void store_va_label(void) -{ - bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); -} - void bt_mesh_trans_reset(void) { int i; @@ -1642,18 +1641,8 @@ void bt_mesh_trans_reset(void) seg_tx_reset(&seg_tx[i]); } - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref) { - virtual_addrs[i].ref = 0U; - virtual_addrs[i].changed = 1U; - } - } - bt_mesh_rpl_clear(); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } + bt_mesh_va_clear(); } void bt_mesh_trans_init(void) @@ -1668,199 +1657,3 @@ void bt_mesh_trans_init(void) k_work_init_delayable(&seg_rx[i].ack, seg_ack); } } - -static inline void va_store(struct virtual_addr *store) -{ - store->changed = 1U; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } -} - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - int err; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (!virtual_addrs[i].ref) { - if (!va) { - va = &virtual_addrs[i]; - } - - continue; - } - - if (!memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - *addr = virtual_addrs[i].addr; - virtual_addrs[i].ref++; - va_store(&virtual_addrs[i]); - return STATUS_SUCCESS; - } - } - - if (!va) { - return STATUS_INSUFF_RESOURCES; - } - - memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); - err = bt_mesh_virtual_addr(uuid, &va->addr); - if (err) { - va->addr = BT_MESH_ADDR_UNASSIGNED; - return STATUS_UNSPECIFIED; - } - - va->ref = 1; - va_store(va); - - *addr = va->addr; - - return STATUS_SUCCESS; -} - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - va = &virtual_addrs[i]; - break; - } - } - - if (!va) { - return STATUS_CANNOT_REMOVE; - } - - va->ref--; - if (addr) { - *addr = va->addr; - } - - va_store(va); - return STATUS_SUCCESS; -} - -uint8_t *bt_mesh_va_label_get(uint16_t addr) -{ - int i; - - LOG_DBG("addr 0x%04x", addr); - - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) { - LOG_DBG("Found Label UUID for 0x%04x: %s", addr, - bt_hex(virtual_addrs[i].uuid, 16)); - return virtual_addrs[i].uuid; - } - } - - LOG_WRN("No matching Label UUID for 0x%04x", addr); - - return NULL; -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static struct virtual_addr *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; - } - - return &virtual_addrs[index]; -} - -static int va_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct va_val va; - struct virtual_addr *lab; - uint16_t index; - int err; - - if (!name) { - LOG_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - index = strtol(name, NULL, 16); - - if (len_rd == 0) { - LOG_WRN("Mesh Virtual Address length = 0"); - return 0; - } - - err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); - if (err) { - LOG_ERR("Failed to set \'virtual address\'"); - return err; - } - - if (va.ref == 0) { - LOG_WRN("Ignore Mesh Virtual Address ref = 0"); - return 0; - } - - lab = bt_mesh_va_get(index); - if (lab == NULL) { - LOG_WRN("Out of labels buffers"); - return -ENOBUFS; - } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); - - return 0; -} - -BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -void bt_mesh_va_pending_store(void) -{ - struct virtual_addr *lab; - struct va_val va; - char path[18]; - uint16_t i; - int err; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - err = settings_delete(path); - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - err = settings_save_one(path, &va, sizeof(va)); - } - - if (err) { - LOG_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} -#else -void bt_mesh_va_pending_store(void) -{ - /* Do nothing. */ -} -#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/subsys/bluetooth/mesh/va.c b/subsys/bluetooth/mesh/va.c new file mode 100644 index 00000000000..0392208951a --- /dev/null +++ b/subsys/bluetooth/mesh/va.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "common/bt_str.h" + +#include "va.h" +#include "foundation.h" +#include "msg.h" +#include "net.h" +#include "crypto.h" +#include "settings.h" + +#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_va); + +static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; + +/* Virtual Address information for persistent storage. */ +struct va_val { + uint16_t ref; + uint16_t addr; + uint8_t uuid[16]; +} __packed; + +static void va_store(struct bt_mesh_va *store) +{ + store->changed = 1U; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); + } +} + +uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry) +{ + struct bt_mesh_va *va = NULL; + int err; + + for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (!virtual_addrs[i].ref) { + if (!va) { + va = &virtual_addrs[i]; + } + + continue; + } + + if (!memcmp(uuid, virtual_addrs[i].uuid, + ARRAY_SIZE(virtual_addrs[i].uuid))) { + if (entry) { + *entry = &virtual_addrs[i]; + } + virtual_addrs[i].ref++; + va_store(&virtual_addrs[i]); + return STATUS_SUCCESS; + } + } + + if (!va) { + return STATUS_INSUFF_RESOURCES; + } + + memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); + err = bt_mesh_virtual_addr(uuid, &va->addr); + if (err) { + va->addr = BT_MESH_ADDR_UNASSIGNED; + return STATUS_UNSPECIFIED; + } + + va->ref = 1; + va_store(va); + + if (entry) { + *entry = va; + } + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_va_del(const uint8_t *uuid) +{ + struct bt_mesh_va *va; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return STATUS_CANNOT_REMOVE; + } + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + + if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) { + return STATUS_CANNOT_REMOVE; + } + + va->ref--; + va_store(va); + + return STATUS_SUCCESS; +} + +const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr) +{ + int i = 0; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return NULL; + } + + if (uuid != NULL) { + struct bt_mesh_va *va; + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + i = ARRAY_INDEX(virtual_addrs, va); + } + + for (; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref && + (virtual_addrs[i].addr == addr || addr == BT_MESH_ADDR_UNASSIGNED)) { + if (!uuid) { + LOG_DBG("Found Label UUID for 0x%04x: %s", addr, + bt_hex(virtual_addrs[i].uuid, 16)); + + if (retaddr) { + *retaddr = virtual_addrs[i].addr; + } + + return virtual_addrs[i].uuid; + } else if (uuid == virtual_addrs[i].uuid) { + uuid = NULL; + } + } + } + + LOG_WRN("No matching Label UUID for 0x%04x", addr); + + return NULL; +} + +bool bt_mesh_va_collision_check(uint16_t addr) +{ + size_t count = 0; + const uint8_t *uuid = NULL; + + do { + uuid = bt_mesh_va_uuid_get(addr, uuid, NULL); + } while (uuid && ++count); + + return count > 1; +} + +const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref && !memcmp(virtual_addrs[i].uuid, uuid, 16)) { + return &virtual_addrs[i]; + } + } + + return NULL; +} + +static struct bt_mesh_va *va_get_by_idx(uint16_t index) +{ + if (index >= ARRAY_SIZE(virtual_addrs)) { + return NULL; + } + + return &virtual_addrs[index]; +} + +const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx) +{ + struct bt_mesh_va *va; + + va = va_get_by_idx(idx); + return (va && va->ref > 0) ? va->uuid : NULL; +} + +int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx) +{ + struct bt_mesh_va *va; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return -ENOENT; + } + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + + if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) { + return -ENOENT; + } + + *uuidx = ARRAY_INDEX(virtual_addrs, va); + return 0; +} + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +static int va_set(const char *name, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + struct va_val va; + struct bt_mesh_va *lab; + uint16_t index; + int err; + + if (!name) { + LOG_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + index = strtol(name, NULL, 16); + + if (len_rd == 0) { + LOG_WRN("Mesh Virtual Address length = 0"); + return 0; + } + + err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); + if (err) { + LOG_ERR("Failed to set \'virtual address\'"); + return err; + } + + if (va.ref == 0) { + LOG_WRN("Ignore Mesh Virtual Address ref = 0"); + return 0; + } + + lab = va_get_by_idx(index); + if (lab == NULL) { + LOG_WRN("Out of labels buffers"); + return -ENOBUFS; + } + + memcpy(lab->uuid, va.uuid, 16); + lab->addr = va.addr; + lab->ref = va.ref; + + LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); + + return 0; +} + +BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); + +#define IS_VA_DEL(_label) ((_label)->ref == 0) +void bt_mesh_va_pending_store(void) +{ + struct bt_mesh_va *lab; + struct va_val va; + char path[18]; + uint16_t i; + int err; + + for (i = 0; (lab = va_get_by_idx(i)) != NULL; i++) { + if (!lab->changed) { + continue; + } + + lab->changed = 0U; + + snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); + + if (IS_VA_DEL(lab)) { + err = settings_delete(path); + } else { + va.ref = lab->ref; + va.addr = lab->addr; + memcpy(va.uuid, lab->uuid, 16); + + err = settings_save_one(path, &va, sizeof(va)); + } + + if (err) { + LOG_ERR("Failed to %s %s value (err %d)", + IS_VA_DEL(lab) ? "delete" : "store", path, err); + } else { + LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); + } + } +} +#else +void bt_mesh_va_pending_store(void) +{ + /* Do nothing. */ +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ + +void bt_mesh_va_clear(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref) { + virtual_addrs[i].ref = 0U; + virtual_addrs[i].changed = 1U; + } + } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); + } +} diff --git a/subsys/bluetooth/mesh/va.h b/subsys/bluetooth/mesh/va.h new file mode 100644 index 00000000000..958b99af6c0 --- /dev/null +++ b/subsys/bluetooth/mesh/va.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** Virtual address entry. */ +struct bt_mesh_va { + uint16_t ref:15, + changed:1; + uint16_t addr; + uint8_t uuid[16]; +}; + +/** @brief Store Label UUID. + * + * @param uuid Label UUID to be stored. + * @param entry Pointer to a memory where a new or updated entry will be stored, or NULL. + * + * @return STATUS_SUCCESS if entry is stored or updated, error code otherwise. + */ +uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry); + +/** @brief Delete Label UUID. + * + * @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid + * pointer. + * + * @param uuid Label UUID to delete. + * + * @return STATUS_SUCCESS if entry is deleted, error code otherwise. + */ +uint8_t bt_mesh_va_del(const uint8_t *uuid); + +/** @brief Find virtual address entry by Label UUID. + * + * @c uuid can be a user data. + * + * @param uuid pointer to memory with Label UUID to be found. + * + * @return Pointer to a valid entry, NULL otherwise. + */ +const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid); + +/** @brief Check if there are more than one Label UUID which hash has the specificed virtual + * address. + * + * @param addr Virtual address to check + * + * @return True if there is collision, false otherwise. + */ +bool bt_mesh_va_collision_check(uint16_t addr); + +/* Needed for storing va as indexes in persistent storage. */ +/** @brief Get Label UUID by index. + * + * @param idx Index of virtual address entry. + * + * @return Pointer to a valid Label UUID, or NULL if entry is not found. + */ +const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx); + +/** @brief Get virtual address entry index by Label UUID. + * + * @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid + * pointer. + * + * @param uuid Label UUID which index to find + * @param uuidx Pointer to a memory where to store index. + * + * @return 0 if entry is found, error code otherwise. + */ +int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx); + +/** @brief Store pending virtual address entries in the persistent storage.*/ +void bt_mesh_va_pending_store(void); + +/** @brief Remove all stored virtual addresses and remove them from the persistent storage. */ +void bt_mesh_va_clear(void); diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index 583e8eb86a5..cbbc7ac28a7 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -15,6 +15,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); +#include "common/bt_str.h" + /* Max number of messages that can be pending on RX at the same time */ #define RECV_QUEUE_SIZE 32 @@ -303,7 +305,7 @@ static struct bt_mesh_test_msg *blocking_recv(k_timeout_t timeout) return k_queue_get(&recv, timeout); } -int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout) +int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout) { struct bt_mesh_test_msg *msg = blocking_recv(timeout); @@ -321,6 +323,19 @@ int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout) return -EINVAL; } + if (BT_MESH_ADDR_IS_VIRTUAL(msg->ctx.recv_dst) && + ((uuid != NULL && msg->ctx.uuid == NULL) || + (uuid == NULL && msg->ctx.uuid != NULL) || + memcmp(uuid, msg->ctx.uuid, 16))) { + LOG_ERR("Recv: Label UUID mismatch for virtual address 0x%04x"); + if (uuid && msg->ctx.uuid) { + LOG_ERR("Got: %s", bt_hex(msg->ctx.uuid, 16)); + LOG_ERR("Expected: %s", bt_hex(uuid, 16)); + } + + return -EINVAL; + } + k_mem_slab_free(&msg_pool, (void **)&msg); return 0; @@ -390,7 +405,7 @@ static void tx_ended(int err, void *data) k_sem_give(&send_ctx->sem); } -int bt_mesh_test_send_async(uint16_t addr, size_t len, +int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, const struct bt_mesh_send_cb *send_cb, void *cb_data) @@ -403,6 +418,7 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len, test_send_ctx.addr = addr; test_send_ctx.send_rel = (flags & FORCE_SEGMENTATION); test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT; + test_send_ctx.uuid = uuid; BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_1, BT_MESH_TX_SDU_MAX); bt_mesh_model_msg_init(&buf, TEST_MSG_OP_1); @@ -441,11 +457,11 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len, return 0; } -int bt_mesh_test_send(uint16_t addr, size_t len, +int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, k_timeout_t timeout) { if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - return bt_mesh_test_send_async(addr, len, flags, NULL, NULL); + return bt_mesh_test_send_async(addr, uuid, len, flags, NULL, NULL); } static const struct bt_mesh_send_cb send_cb = { @@ -457,7 +473,7 @@ int bt_mesh_test_send(uint16_t addr, size_t len, int err; k_sem_init(&send_ctx.sem, 0, 1); - err = bt_mesh_test_send_async(addr, len, flags, &send_cb, &send_ctx); + err = bt_mesh_test_send_async(addr, uuid, len, flags, &send_cb, &send_ctx); if (err) { return err; } diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index ca28964dce3..d36f5cddeaf 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -141,13 +141,13 @@ void bt_mesh_test_timeout(bs_time_t HW_device_time); void bt_mesh_device_setup(const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp); -int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout); +int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout); int bt_mesh_test_recv_msg(struct bt_mesh_test_msg *msg, k_timeout_t timeout); int bt_mesh_test_recv_clear(void); -int bt_mesh_test_send(uint16_t addr, size_t len, +int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, k_timeout_t timeout); -int bt_mesh_test_send_async(uint16_t addr, size_t len, +int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, const struct bt_mesh_send_cb *send_cb, void *cb_data); diff --git a/tests/bsim/bluetooth/mesh/src/test_friendship.c b/tests/bsim/bluetooth/mesh/src/test_friendship.c index 3411be4b5c6..4e54aa74af6 100644 --- a/tests/bsim/bluetooth/mesh/src/test_friendship.c +++ b/tests/bsim/bluetooth/mesh/src/test_friendship.c @@ -6,6 +6,7 @@ #include "mesh_test.h" #include "mesh/net.h" #include "mesh/transport.h" +#include "mesh/va.h" #include #include "argparse.h" @@ -156,7 +157,7 @@ static void test_friend_msg(void) /* Send unsegmented message from friend to LPN: */ LOG_INF("Sending unsegmented message"); - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_SECONDS(1)), "Unseg send failed"); @@ -164,7 +165,7 @@ static void test_friend_msg(void) friend_wait_for_polls(2); /* Send segmented message */ - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 13, 0, + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 13, 0, K_SECONDS(1)), "Unseg send failed"); @@ -178,23 +179,23 @@ static void test_friend_msg(void) * transport and network parts of the second packet. * Ensures coverage for the regression reported in #32033. */ - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)), "Unseg send failed"); - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)), "Unseg send failed"); /* Two messages require 2 polls plus the "no more messages" msg */ friend_wait_for_polls(3); - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(10)), + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(10)), "Receive from LPN failed"); /* Receive a segmented message from the LPN. LPN should poll for the ack * after sending the segments. */ - ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_SECONDS(10))); /* 4 polls (2 if legacy transport layer is used): * - The first one triggered manually by transport when sending segmented message; * - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages); @@ -227,13 +228,13 @@ static void test_friend_overflow(void) /* Fill the queue */ for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) { - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); } /* Add one more message, which should overflow the queue and cause the * first message to be discarded. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -246,12 +247,12 @@ static void test_friend_overflow(void) /* Make room in the Friend Queue for only one unsegmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 1), 0, K_SECONDS(1)), - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); /* This message should preempt the segmented one. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -266,17 +267,17 @@ static void test_friend_overflow(void) * message won't preempt this segmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2), 0, K_SECONDS(1)); - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); /* This segmented message should preempt the previous segmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2), 0, K_SECONDS(1)); /* This message should fit in Friend Queue as well. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -295,7 +296,7 @@ static void test_friend_overflow(void) */ static void test_friend_group(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; bt_mesh_test_setup(); @@ -306,7 +307,7 @@ static void test_friend_group(void) "Friendship not established"); bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED); - ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr)); + ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va)); /* The other mesh device will send its messages in the first poll */ ASSERT_OK(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, @@ -317,10 +318,10 @@ static void test_friend_group(void) bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED); /* Send a group message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Send a virtual message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Wait for the LPN to poll for each message, then for adding the @@ -331,7 +332,7 @@ static void test_friend_group(void) /* Send a group message to an address the LPN added after the friendship * was established. */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(10)); @@ -410,7 +411,7 @@ static void test_lpn_msg_frnd(void) /* Receive unsegmented message */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1)), "Failed to receive message"); /* Give friend time to prepare the message */ @@ -418,7 +419,7 @@ static void test_lpn_msg_frnd(void) /* Receive segmented message */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); - ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, K_SECONDS(2)), + ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, NULL, K_SECONDS(2)), "Failed to receive message"); /* Give friend time to prepare the messages */ @@ -427,10 +428,10 @@ static void test_lpn_msg_frnd(void) /* Receive two unsegmented messages */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr, - K_SECONDS(2)), + NULL, K_SECONDS(2)), "Failed to receive message"); ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr, - K_SECONDS(2)), + NULL, K_SECONDS(2)), "Failed to receive message"); k_sleep(K_SECONDS(3)); @@ -438,7 +439,7 @@ static void test_lpn_msg_frnd(void) /* Send an unsegmented message to the friend. * Should not be affected by the LPN mode at all. */ - ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 5, 0, K_MSEC(500)), + ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 5, 0, K_MSEC(500)), "Send to friend failed"); k_sleep(K_SECONDS(5)); @@ -446,7 +447,7 @@ static void test_lpn_msg_frnd(void) /* Send a segmented message to the friend. Should trigger a poll for the * ack. */ - ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 15, 0, K_SECONDS(5)), + ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 15, 0, K_SECONDS(5)), "Send to friend failed"); PASS(); @@ -472,17 +473,18 @@ static void test_lpn_msg_mesh(void) /* Send an unsegmented message to a third mesh node. * Should not be affected by the LPN mode at all. */ - ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 5, 0, K_NO_WAIT), "Send to mesh failed"); + ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_NO_WAIT), + "Send to mesh failed"); /* Receive an unsegmented message back */ - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_FOREVER)); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER)); /* Send a segmented message to the mesh node. */ - ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 15, 0, K_FOREVER), + ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 15, 0, K_FOREVER), "Send to other failed"); /* Receive a segmented message back */ - ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_FOREVER)); + ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER)); /* Send an unsegmented message with friend credentials to a third mesh * node. The friend shall relay it. @@ -664,6 +666,7 @@ static void test_lpn_overflow(void) static void test_lpn_group(void) { struct bt_mesh_test_msg msg; + const struct bt_mesh_va *va; uint16_t vaddr; uint8_t status = 0; int err; @@ -683,6 +686,10 @@ static void test_lpn_group(void) FAIL("VA addr add failed with err %d status 0x%x", err, status); } + va = bt_mesh_va_find(test_va_uuid); + ASSERT_TRUE(va != NULL); + ASSERT_EQUAL(vaddr, va->addr); + bt_mesh_lpn_set(true); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED, K_SECONDS(5)), "LPN not established"); @@ -693,7 +700,7 @@ static void test_lpn_group(void) * start up first. */ k_sleep(K_MSEC(10)); - ASSERT_OK(bt_mesh_test_send(other_cfg.addr, 5, 0, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_SECONDS(1))); k_sleep(K_SECONDS(5)); ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); @@ -706,7 +713,8 @@ static void test_lpn_group(void) } ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1))); - if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != other_cfg.addr) { + if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != other_cfg.addr || + msg.ctx.uuid != va->uuid) { FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr, msg.ctx.recv_dst); } @@ -722,7 +730,7 @@ static void test_lpn_group(void) } ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1))); - if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != friend_cfg.addr) { + if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != friend_cfg.addr) { FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr, msg.ctx.recv_dst); } @@ -763,6 +771,7 @@ static void test_lpn_group(void) static void test_lpn_loopback(void) { struct bt_mesh_test_msg msg; + const struct bt_mesh_va *va; uint16_t vaddr; uint8_t status = 0; int err; @@ -782,6 +791,10 @@ static void test_lpn_loopback(void) FAIL("VA addr add failed with err %d status 0x%x", err, status); } + va = bt_mesh_va_find(test_va_uuid); + ASSERT_TRUE(va != NULL); + ASSERT_EQUAL(vaddr, va->addr); + bt_mesh_lpn_set(true); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED, K_SECONDS(5)), @@ -791,12 +804,16 @@ static void test_lpn_loopback(void) k_sleep(K_SECONDS(1)); /* Loopback on unicast, shouldn't even leave the device */ - ASSERT_OK(bt_mesh_test_send_async(cfg->addr, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(cfg->addr, NULL, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1))); /* Loopback on group address, should not come back from the friend */ - ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, NULL, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, NULL, K_SECONDS(1))); + + /* Loopback on virtual address, should not come back from the friend */ + ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1))); ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); err = bt_mesh_test_recv_msg(&msg, K_SECONDS(2)); @@ -805,8 +822,8 @@ static void test_lpn_loopback(void) } /* Loopback on virtual address, should not come back from the friend */ - ASSERT_OK(bt_mesh_test_send_async(vaddr, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, vaddr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1))); k_sleep(K_SECONDS(2)); @@ -844,27 +861,32 @@ static void test_other_msg(void) } /* Receive an unsegmented message from the LPN. */ - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); /* Minor delay that allows LPN's adv to complete sending. */ k_sleep(K_SECONDS(2)); /* Send an unsegmented message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 5, 0, K_NO_WAIT), "Failed to send to LPN"); + ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 5, 0, K_NO_WAIT), + "Failed to send to LPN"); /* Receive a segmented message from the LPN. */ - ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); /* Minor delay that allows LPN's adv to complete sending. */ k_sleep(K_SECONDS(2)); /* Send a segmented message to the friend. */ - ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 15, 0, K_FOREVER), "Send to LPN failed"); + ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 15, 0, K_FOREVER), + "Send to LPN failed"); /* Receive an unsegmented message from the LPN, originally sent with * friend credentials. */ - ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); PASS(); } @@ -874,20 +896,20 @@ static void test_other_msg(void) */ static void test_other_group(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr)); + ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va)); /* Wait for LPN to send us a message after establishing the friendship */ - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1))); /* Send a group message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Send a virtual message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); PASS(); diff --git a/tests/bsim/bluetooth/mesh/src/test_iv_index.c b/tests/bsim/bluetooth/mesh/src/test_iv_index.c index 8c0dde73071..466f0fb7b56 100644 --- a/tests/bsim/bluetooth/mesh/src/test_iv_index.c +++ b/tests/bsim/bluetooth/mesh/src/test_iv_index.c @@ -134,7 +134,8 @@ static void test_ivu_deferring(void) atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; - ASSERT_OK(bt_mesh_test_send_async(0x0002, 20, FORCE_SEGMENTATION, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(0x0002, NULL, 20, FORCE_SEGMENTATION, &async_send_cb, + &sem)); ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE)); ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); diff --git a/tests/bsim/bluetooth/mesh/src/test_scanner.c b/tests/bsim/bluetooth/mesh/src/test_scanner.c index aaccd84cec4..12557b7e1b2 100644 --- a/tests/bsim/bluetooth/mesh/src/test_scanner.c +++ b/tests/bsim/bluetooth/mesh/src/test_scanner.c @@ -185,7 +185,7 @@ static void test_rx_invalid_packet(void) } /* Verify that test data is received correct. */ - err = bt_mesh_test_recv(10, cfg->addr, K_SECONDS(10)); + err = bt_mesh_test_recv(10, cfg->addr, NULL, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed receiving with valid ad_type"); PASS(); diff --git a/tests/bsim/bluetooth/mesh/src/test_transport.c b/tests/bsim/bluetooth/mesh/src/test_transport.c index a6be16c58c9..8da83c0df3b 100644 --- a/tests/bsim/bluetooth/mesh/src/test_transport.c +++ b/tests/bsim/bluetooth/mesh/src/test_transport.c @@ -6,8 +6,18 @@ #include "mesh_test.h" #include "mesh/net.h" #include "mesh/transport.h" +#include "mesh/va.h" #include +#include "mesh/crypto.h" + +#define LOG_MODULE_NAME test_transport + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include "common/bt_str.h" + /* * Transport layer tests: * This file contains tests for sending and receiving messages end-to-end in @@ -121,7 +131,7 @@ static void test_tx_unicast(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(rx_cfg.addr, test_vector[i].len, + err = bt_mesh_test_send(rx_cfg.addr, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -138,7 +148,7 @@ static void test_tx_group(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len, + err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -150,19 +160,19 @@ static void test_tx_group(void) */ static void test_tx_va(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; int err; bt_mesh_test_setup(); - err = bt_mesh_va_add(test_va_uuid, &virtual_addr); + err = bt_mesh_va_add(test_va_uuid, &va); ASSERT_OK_MSG(err, "Virtual addr add failed (err %d)", err); /* Wait for the receiver to subscribe on address. */ k_sleep(K_SECONDS(1)); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(virtual_addr, test_vector[i].len, + err = bt_mesh_test_send(va->addr, va->uuid, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -179,10 +189,10 @@ static void test_tx_loopback(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(cfg->addr, test_vector[i].len, test_vector[i].flags, + err = bt_mesh_test_send(cfg->addr, NULL, test_vector[i].len, test_vector[i].flags, K_NO_WAIT); ASSERT_OK_MSG(err, "Failed sending vector %d", i); - bt_mesh_test_recv(test_vector[i].len, cfg->addr, K_SECONDS(1)); + bt_mesh_test_recv(test_vector[i].len, cfg->addr, NULL, K_SECONDS(1)); if (test_stats.received != i + 1) { FAIL("Didn't receive message %d", i); @@ -219,10 +229,10 @@ static void test_tx_unknown_app(void) test_send_ctx.app_idx = 1; - ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 5, 0, K_SECONDS(1)), "Failed sending unsegmented"); - ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 25, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 25, 0, K_SECONDS(1)), "Failed sending segmented"); PASS(); @@ -247,7 +257,7 @@ static void test_tx_loopback_group(void) err, status); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len, + err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); @@ -255,7 +265,7 @@ static void test_tx_loopback_group(void) k_sleep(K_SECONDS(1)); ASSERT_OK_MSG(bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR, - K_SECONDS(1)), + NULL, K_SECONDS(1)), "Failed receiving loopback %d", i); if (test_stats.received != i + 1) { @@ -277,11 +287,11 @@ static void test_tx_seg_block(void) bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT)); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT)); /* Send some more to the same address before the first is finished. */ - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT)); - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT)); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_SECONDS(10))); if (test_stats.sent != 3) { FAIL("Not all messages completed (%u/3)", test_stats.sent); @@ -303,10 +313,10 @@ static void test_tx_seg_concurrent(void) k_sem_init(&sem, 0, 1); bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 20, 0, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 20, 0, &async_send_cb, &sem)); /* Send some more to the same address before the first is finished. */ - ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, 20, 0, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, NULL, 20, 0, K_SECONDS(10))); /* Ensure that the first message finishes as well */ ASSERT_OK(k_sem_take(&sem, K_SECONDS(1))); @@ -336,7 +346,7 @@ static void test_tx_seg_ivu(void) iv_index = BT_MESH_NET_IVI_TX; - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb, + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb, &sem)); /* Start IV update */ bt_mesh_iv_update(); @@ -347,7 +357,7 @@ static void test_tx_seg_ivu(void) k_sem_take(&sem, K_SECONDS(20)); - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb, + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb, &sem)); /* End IV update */ @@ -377,7 +387,7 @@ static void test_tx_seg_fail(void) bt_mesh_test_setup(); expected_send_err = -ETIMEDOUT; - ASSERT_OK(bt_mesh_test_send_async(0x0fff, 20, 0, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(0x0fff, NULL, 20, 0, &async_send_cb, &sem)); ASSERT_OK(k_sem_take(&sem, K_SECONDS(10))); PASS(); @@ -396,7 +406,7 @@ static void test_rx_unicast(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, cfg->addr, - K_SECONDS(10)); + NULL, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -418,7 +428,7 @@ static void test_rx_group(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR, - K_SECONDS(20)); + NULL, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -441,7 +451,7 @@ static void test_rx_va(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, virtual_addr, - K_SECONDS(20)); + test_va_uuid, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -471,9 +481,9 @@ static void test_rx_seg_block(void) { bt_mesh_test_setup(); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); PASS(); } @@ -496,8 +506,8 @@ static void test_rx_seg_concurrent(void) * Note: The receive order is technically irrelevant, but the test_recv * function fails if the order is wrong. */ - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, NULL, K_SECONDS(2)), "RX fail"); PASS(); } @@ -509,8 +519,8 @@ static void test_rx_seg_ivu(void) bt_mesh_test_setup(); rx_sar_conf(); - ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail"); PASS(); }