diff --git a/include/bluetooth/mesh.h b/include/bluetooth/mesh.h index 0a461383f6e..aa5e06987aa 100644 --- a/include/bluetooth/mesh.h +++ b/include/bluetooth/mesh.h @@ -22,5 +22,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */ diff --git a/include/bluetooth/mesh/access.h b/include/bluetooth/mesh/access.h index cb31b9b8f2a..48770c238eb 100644 --- a/include/bluetooth/mesh/access.h +++ b/include/bluetooth/mesh/access.h @@ -41,6 +41,7 @@ extern "C" { #define BT_MESH_ADDR_RELAYS 0xfffe #define BT_MESH_KEY_UNUSED 0xffff +#define BT_MESH_KEY_ANY 0xffff #define BT_MESH_KEY_DEV 0xfffe #define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV #define BT_MESH_KEY_DEV_REMOTE 0xfffd diff --git a/include/bluetooth/mesh/cfg.h b/include/bluetooth/mesh/cfg.h new file mode 100644 index 00000000000..0355ebb927c --- /dev/null +++ b/include/bluetooth/mesh/cfg.h @@ -0,0 +1,320 @@ +/** @file + * @brief Bluetooth Mesh Runtime Configuration APIs. + */ + +/* + * Copyright (c) 2020 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_CFG_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_CFG_H_ + +#include +#include +#include + +/** + * @brief Bluetooth Mesh Runtime Configuration API + * @defgroup bt_mesh_cfg Bluetooth Mesh Runtime Configuration + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Bluetooth Mesh Feature states */ +enum bt_mesh_feat_state { + /** Feature is supported, but disabled. */ + BT_MESH_FEATURE_DISABLED, + /** Feature is supported and enabled. */ + BT_MESH_FEATURE_ENABLED, + /** Feature is not supported, and cannot be enabled. */ + BT_MESH_FEATURE_NOT_SUPPORTED, +}; + +/** + * @brief Bluetooth Mesh Subnet Configuration + * @defgroup bt_mesh_cfg_subnet Bluetooth Mesh Subnet Configuration + * @{ + */ + +/** @brief Add a Subnet. + * + * Adds a subnet with the given network index and network key to the list of + * known Subnets. All messages sent on the given Subnet will be processed by + * this node, and the node may send and receive Network Beacons on the given + * Subnet. + * + * @param net_idx Network index. + * @param key Root network key of the Subnet. All other keys are derived + * from this. + * + * @retval STATUS_SUCCESS The Subnet was successfully added. + * @retval STATUS_INSUFF_RESOURCES No room for this Subnet. + * @retval STATUS_UNSPECIFIED The Subnet couldn't be created for some reason. + */ +uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]); + +/** @brief Update the given Subnet. + * + * Starts the Key Refresh procedure for this Subnet by adding a second set of + * encryption keys. The Subnet will continue sending with the old key (but + * receiving messages using both) until the Subnet enters Key Refresh phase 2. + * + * This allows a network configurator to replace old network and application + * keys for the entire network, effectively removing access for all nodes that + * aren't given the new keys. + * + * @param net_idx Network index. + * @param key New root network key of the Subnet. + * + * @retval STATUS_SUCCESS The Subnet was updated with a second key. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_IDX_ALREADY_STORED The @c key value is the same as the + * current key. + * @retval STATUS_CANNOT_UPDATE The Subnet cannot be updated for some reason. + */ +uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]); + +/** @brief Delete a Subnet. + * + * Removes the Subnet with the given network index from the node. The node will + * stop sending Network Beacons with the given Subnet, and can no longer + * process messages on this Subnet. + * + * All Applications bound to this Subnet are also deleted. + * + * @param net_idx Network index. + * + * @retval STATUS_SUCCESS The Subnet was deleted. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + */ +uint8_t bt_mesh_subnet_del(uint16_t net_idx); + +/** @brief Check whether a Subnet is known. + * + * @param net_idx Network index + * + * @return true if a Subnet with the given index exists, false otherwise. + */ +bool bt_mesh_subnet_exists(uint16_t net_idx); + +/** @brief Set the Subnet's Key Refresh phase. + * + * The Key Refresh procedure is started by updating the Subnet keys through + * @ref bt_mesh_subnet_update. This puts the Subnet in Key Refresh Phase 1. + * Once all nodes have received the new Subnet key, Key Refresh Phase 2 can be + * activated through this function to start transmitting with the new network + * key. Finally, to revoke the old key, set the Key Refresh Phase to 3. This + * removes the old keys from the node, and returns the Subnet back to normal + * single-key operation with the new key set. + * + * @param net_idx Network index. + * @param phase Pointer to the new Key Refresh phase. Will return the actual + * Key Refresh phase after updating. + * + * @retval STATUS_SUCCESS The Key Refresh phase of the Subnet was successfully + * changed. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_CANNOT_UPDATE The given phase change is invalid. + */ +uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase); + +/** @brief Get the Subnet's Key Refresh phase. + * + * @param net_idx Network index. + * @param phase Pointer to the Key Refresh variable to fill. + * + * @retval STATUS_SUCCESS Successfully populated the @c phase variable. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + */ +uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase); + +/** @brief Set the Node Identity state of the Subnet. + * + * The Node Identity state of a Subnet determines whether the Subnet advertises + * connectable Node Identity beacons for Proxy Clients to connect to. + * Once started, the Node Identity beacon runs for 60 seconds, or until it is + * stopped. + * + * This function serves the same purpose as @ref bt_mesh_proxy_identity_enable, + * but only acts on a single Subnet. + * + * GATT Proxy support must be enabled through + * @option{CONFIG_BT_MESH_GATT_PROXY}. + * + * @param net_idx Network index. + * @param node_id New Node Identity state, must be either @ref + * BT_MESH_FEATURE_ENABLED or @ref BT_MESH_FEATURE_DISABLED. + * + * @retval STATUS_SUCCESS Successfully set the Node Identity state of the + * Subnet. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_FEAT_NOT_SUPP The Node Identity feature is not supported. + * @retval STATUS_CANNOT_SET Couldn't set the Node Identity state. + */ +uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx, + enum bt_mesh_feat_state node_id); + +/** @brief Get the Node Identity state of the Subnet. + * + * @param net_idx Network index. + * @param node_id Node Identity variable to fill. + * + * @retval STATUS_SUCCESS Successfully populated the @c node_id variable. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + */ +uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx, + enum bt_mesh_feat_state *node_id); + +/** @brief Get a list of all known Subnet indexes. + * + * Builds a list of all known Subnet indexes in the @c net_idxs array. + * If the @c net_idxs array is smaller than the list of known Subnets, this + * function fills all available entries and returns @c -ENOMEM. In this + * case, the next @c max entries of the list can be read out by calling + * @code + * bt_mesh_subnets_get(list, max, max); + * @endcode + * + * Note that any changes to the Subnet list between calls to this function + * could change the order and number of entries in the list. + * + * @param net_idxs Array to fill. + * @param max Max number of indexes to return. + * @param skip Number of indexes to skip. Enables batched processing of the + * list. + * + * @return The number of indexes added to the @c net_idxs array, or @c -ENOMEM + * if the number of known Subnets exceeds the @c max parameter. + */ +ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip); + +/** + * @} + */ + +/** + * @brief Bluetooth Mesh Application Configuration + * @defgroup bt_mesh_cfg_app Bluetooth Mesh Application Configuration + * @{ + */ + +/** @brief Add an Application key. + * + * Adds the Application with the given index to the list of known applications. + * Allows the node to send and receive model messages encrypted with this + * Application key. + * + * Every Application is bound to a specific Subnet. The node must know the + * Subnet the Application is bound to before it can add the Application. + * + * @param app_idx Application index. + * @param net_idx Network index the Application is bound to. + * @param key Application key value. + * + * @retval STATUS_SUCCESS The Application was successfully added. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_INSUFF_RESOURCES There's no room for storing this + * Application. + * @retval STATUS_INVALID_BINDING This AppIdx is already bound to another + * Subnet. + * @retval STATUS_IDX_ALREADY_STORED This AppIdx is already stored with a + * different key value. + * @retval STATUS_CANNOT_SET Cannot set the Application key for some reason. + */ +uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, + const uint8_t key[16]); + +/** @brief Update an Application key. + * + * Update an Application with a second Application key, as part of the + * Key Refresh procedure of the bound Subnet. The node will continue + * transmitting with the old application key (but receiving on both) until the + * Subnet enters Key Refresh phase 2. Once the Subnet enters Key Refresh phase + * 3, the old application key will be deleted. + * + * @note The Application key can only be updated if the bound Subnet is in Key + * Refresh phase 1. + * + * @param app_idx Application index. + * @param net_idx Network index the Application is bound to, or + * @ref BT_MESH_KEY_ANY to skip the binding check. + * @param key New key value. + * + * @retval STATUS_SUCCESS The Application key was successfully updated. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx. + * @retval STATUS_CANNOT_UPDATE The Application key cannot be updated for some + * reason. + * @retval STATUS_IDX_ALREADY_STORED This AppIdx is already updated with a + * different key value. + */ +uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, + const uint8_t key[16]); + +/** @brief Delete an Application key. + * + * All models bound to this application will remove this binding. + * All models publishing with this application will stop publishing. + * + * @param app_idx Application index. + * @param net_idx Network index. + * + * @retval STATUS_SUCCESS The Application key was successfully deleted. + * @retval STATUS_INVALID_NETKEY The NetIdx is unknown. + * @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx. + */ +uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx); + +/** @brief Check if an Application key is known. + * + * @param app_idx Application index. + * + * @return true if the Application is known, false otherwise. + */ +bool bt_mesh_app_key_exists(uint16_t app_idx); + +/** @brief Get a list of all known Application key indexes. + * + * Builds a list of all Application indexes for the given network index in the + * @c app_idxs array. If the @c app_idxs array cannot fit all bound + * Applications, this function fills all available entries and returns @c + * -ENOMEM. In this case, the next @c max entries of the list can be read out + * by calling + * @code + * bt_mesh_app_keys_get(net_idx, list, max, max); + * @endcode + * + * Note that any changes to the Application key list between calls to this + * function could change the order and number of entries in the list. + * + * @param net_idx Network Index to get the Applications of, or @ref + * BT_MESH_KEY_ANY to get all Applications. + * @param app_idxs Array to fill. + * @param max Max number of indexes to return. + * @param skip Number of indexes to skip. Enables batched processing of the + * list. + * + * @return The number of indexes added to the @c app_idxs array, or @c -ENOMEM + * if the number of known Applications exceeds the @c max parameter. + */ +ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, + off_t skip); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CFG_H_ */ diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index d819a9e2239..d1c7b342f5f 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -102,6 +102,11 @@ Z_ITERABLE_SECTION_ROM(bt_gatt_service_static, 4) +#if defined(CONFIG_BT_MESH) + Z_ITERABLE_SECTION_ROM(bt_mesh_subnet_cb, 4) + Z_ITERABLE_SECTION_ROM(bt_mesh_app_key_cb, 4) +#endif + #if defined(CONFIG_EC_HOST_CMD) Z_ITERABLE_SECTION_ROM(ec_host_cmd_handler, 4) #endif diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 17d898cf0be..0c18a5c38ce 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -8,6 +8,8 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH adv.c beacon.c net.c + subnet.c + app_keys.c transport.c rpl.c crypto.c diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 4c57e25342a..1449e1e1472 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -642,6 +642,12 @@ config BT_MESH_DEBUG_CRYPTO Use this option to enable cryptographic debug logs for the Bluetooth Mesh functionality. +config BT_MESH_DEBUG_KEYS + bool "Key management debug" + help + Use this option to enable key management debug logs for the + Bluetooth Mesh functionality. + config BT_MESH_DEBUG_PROV bool "Provisioning debug" help diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 8beb9df3666..4d8086a9a37 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -158,28 +158,17 @@ static int publish_retransmit(struct bt_mesh_model *mod) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = mod->pub; - struct bt_mesh_app_key *key; struct bt_mesh_msg_ctx ctx = { .addr = pub->addr, .send_ttl = pub->ttl, + .app_idx = pub->key, }; struct bt_mesh_net_tx tx = { .ctx = &ctx, .src = bt_mesh_model_elem(mod)->addr, - .xmit = bt_mesh_net_transmit_get(), .friend_cred = pub->cred, }; - key = bt_mesh_app_key_find(pub->key); - if (!key) { - return -EADDRNOTAVAIL; - } - - tx.sub = bt_mesh_subnet_get(key->net_idx); - - ctx.net_idx = key->net_idx; - ctx.app_idx = key->app_idx; - net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len); pub->count--; @@ -695,24 +684,9 @@ int bt_mesh_model_send(struct bt_mesh_model *model, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { - struct bt_mesh_app_key *app_key; - - if (!BT_MESH_IS_DEV_KEY(ctx->app_idx)) { - app_key = bt_mesh_app_key_find(ctx->app_idx); - if (!app_key) { - BT_ERR("Unknown app_idx 0x%04x", ctx->app_idx); - return -EINVAL; - } - - ctx->net_idx = app_key->net_idx; - } - struct bt_mesh_net_tx tx = { - .sub = bt_mesh_subnet_get(ctx->net_idx), .ctx = ctx, .src = bt_mesh_model_elem(model)->addr, - .xmit = bt_mesh_net_transmit_get(), - .friend_cred = 0, }; return model_send(model, &tx, false, msg, cb, cb_data); @@ -722,13 +696,15 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = model->pub; - struct bt_mesh_app_key *key; struct bt_mesh_msg_ctx ctx = { + .addr = pub->addr, + .send_ttl = pub->ttl, + .send_rel = pub->send_rel, + .app_idx = pub->key, }; struct bt_mesh_net_tx tx = { .ctx = &ctx, .src = bt_mesh_model_elem(model)->addr, - .xmit = bt_mesh_net_transmit_get(), }; int err; @@ -742,11 +718,6 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) return -EADDRNOTAVAIL; } - key = bt_mesh_app_key_find(pub->key); - if (!key) { - return -EADDRNOTAVAIL; - } - if (pub->msg->len + 4 > BT_MESH_TX_SDU_MAX) { BT_ERR("Message does not fit maximum SDU size"); return -EMSGSIZE; @@ -759,14 +730,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len); - ctx.addr = pub->addr; - ctx.send_ttl = pub->ttl; - ctx.send_rel = pub->send_rel; - ctx.net_idx = key->net_idx; - ctx.app_idx = key->app_idx; - tx.friend_cred = pub->cred; - tx.sub = bt_mesh_subnet_get(ctx.net_idx), pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); diff --git a/subsys/bluetooth/mesh/app_keys.c b/subsys/bluetooth/mesh/app_keys.c new file mode 100644 index 00000000000..86994f3bd38 --- /dev/null +++ b/subsys/bluetooth/mesh/app_keys.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "mesh.h" +#include "net.h" +#include "app_keys.h" +#include "rpl.h" +#include "settings.h" +#include "crypto.h" +#include "adv.h" +#include "proxy.h" +#include "friend.h" +#include "foundation.h" +#include "access.h" + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_KEYS) +#define LOG_MODULE_NAME bt_mesh_app_keys +#include "common/log.h" + +static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { + [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { + .app_idx = BT_MESH_KEY_UNUSED, + .net_idx = BT_MESH_KEY_UNUSED, + } +}; + +static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt) +{ + Z_STRUCT_SECTION_FOREACH(bt_mesh_app_key_cb, cb) { + cb->evt_handler(app->app_idx, app->net_idx, evt); + } +} + +static struct bt_mesh_app_key *app_get(uint16_t app_idx) +{ + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + if (apps[i].app_idx == app_idx) { + return &apps[i]; + } + } + + return NULL; +} + +static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) +{ + struct bt_mesh_app_key *app = NULL; + + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + /* Check for already existing app_key */ + if (apps[i].app_idx == app_idx) { + return &apps[i]; + } + + if (!app && apps[i].app_idx == BT_MESH_KEY_UNUSED) { + app = &apps[i]; + } + } + + return app; +} + +static void app_key_del(struct bt_mesh_app_key *app) +{ + BT_DBG("AppIdx 0x%03x", app->app_idx); + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_clear_app_key(app->app_idx); + } + + app_key_evt(app, BT_MESH_KEY_DELETED); + + app->net_idx = BT_MESH_KEY_UNUSED; + app->app_idx = BT_MESH_KEY_UNUSED; + (void)memset(app->keys, 0, sizeof(app->keys)); +} + +static void app_key_revoke(struct bt_mesh_app_key *app) +{ + if (!app->updated) { + return; + } + + memcpy(&app->keys[0], &app->keys[1], sizeof(app->keys[0])); + memset(&app->keys[1], 0, sizeof(app->keys[1])); + app->updated = false; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_app_key(app->app_idx); + } + + app_key_evt(app, BT_MESH_KEY_REVOKED); +} + +uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, + const uint8_t key[16]) +{ + struct bt_mesh_app_key *app; + + BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, + bt_hex(key, 16)); + + if (!bt_mesh_subnet_get(net_idx)) { + return STATUS_INVALID_NETKEY; + } + + app = app_key_alloc(app_idx); + if (!app) { + return STATUS_INSUFF_RESOURCES; + } + + if (app->app_idx == app_idx) { + if (app->net_idx != net_idx) { + return STATUS_INVALID_BINDING; + } + + if (memcmp(key, app->keys[0].val, 16)) { + return STATUS_IDX_ALREADY_STORED; + } + + return STATUS_SUCCESS; + } + + if (bt_mesh_app_id(key, &app->keys[0].id)) { + return STATUS_CANNOT_SET; + } + + BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id); + + app->net_idx = net_idx; + app->app_idx = app_idx; + app->updated = false; + memcpy(app->keys[0].val, key, 16); + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + BT_DBG("Storing AppKey persistently"); + bt_mesh_store_app_key(app->app_idx); + } + + app_key_evt(app, BT_MESH_KEY_ADDED); + + return STATUS_SUCCESS; +} + +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) +{ + struct bt_mesh_app_key *app; + + app = app_get(app_idx); + if (app) { + return app; + } + + return NULL; +} + +uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, + const uint8_t key[16]) +{ + struct bt_mesh_app_key *app; + struct bt_mesh_subnet *sub; + + BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, + bt_hex(key, 16)); + + app = app_get(app_idx); + if (!app) { + return STATUS_INVALID_APPKEY; + } + + if (net_idx != BT_MESH_KEY_UNUSED && app->net_idx != net_idx) { + return STATUS_INVALID_BINDING; + } + + sub = bt_mesh_subnet_get(app->net_idx); + if (!sub) { + return STATUS_INVALID_NETKEY; + } + + /* The AppKey Update message shall generate an error when node + * is in normal operation, Phase 2, or Phase 3 or in Phase 1 + * when the AppKey Update message on a valid AppKeyIndex when + * the AppKey value is different. + */ + if (sub->kr_phase != BT_MESH_KR_PHASE_1) { + return STATUS_CANNOT_UPDATE; + } + + if (app->updated) { + if (memcmp(app->keys[1].val, key, 16)) { + return STATUS_IDX_ALREADY_STORED; + } + + return STATUS_SUCCESS; + } + + if (bt_mesh_app_id(key, &app->keys[1].id)) { + return STATUS_CANNOT_UPDATE; + } + + BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, app->keys[1].id); + + app->updated = true; + memcpy(app->keys[1].val, key, 16); + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + BT_DBG("Storing AppKey persistently"); + bt_mesh_store_app_key(app->app_idx); + } + + app_key_evt(app, BT_MESH_KEY_UPDATED); + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) +{ + struct bt_mesh_app_key *app; + + BT_DBG("AppIdx 0x%03x", app_idx); + + if (net_idx != BT_MESH_KEY_UNUSED && !bt_mesh_subnet_get(net_idx)) { + return STATUS_INVALID_NETKEY; + } + + app = app_get(app_idx); + if (!app) { + /* This could be a retry of a previous attempt that had its + * response lost, so pretend that it was a success. + */ + return STATUS_SUCCESS; + } + + if (net_idx != BT_MESH_KEY_UNUSED && net_idx != app->net_idx) { + return STATUS_INVALID_BINDING; + } + + app_key_del(app); + + return STATUS_SUCCESS; +} + +int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, + const uint8_t old_key[16], const uint8_t new_key[16]) +{ + struct bt_mesh_app_key *app; + + app = app_key_alloc(app_idx); + if (!app) { + return -ENOMEM; + } + + if (app->app_idx == app_idx) { + return 0; + } + + BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id); + + memcpy(app->keys[0].val, old_key, 16); + if (bt_mesh_app_id(old_key, &app->keys[0].id)) { + return -EIO; + } + + if (new_key) { + memcpy(app->keys[1].val, new_key, 16); + if (bt_mesh_app_id(new_key, &app->keys[1].id)) { + return -EIO; + } + } + + app->net_idx = net_idx; + app->app_idx = app_idx; + app->updated = !!new_key; + + return 0; +} + +bool bt_mesh_app_key_exists(uint16_t app_idx) +{ + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + if (apps[i].app_idx == app_idx) { + return true; + } + } + + return false; +} + +ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, + off_t skip) +{ + size_t count = 0; + + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + struct bt_mesh_app_key *app = &apps[i]; + + if (app->app_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (net_idx != BT_MESH_KEY_ANY && app->net_idx != net_idx) { + continue; + } + + if (skip) { + skip--; + continue; + } + + if (count >= max) { + return -ENOMEM; + } + + app_idxs[count++] = app->app_idx; + } + + return count; +} + +int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_subnet **sub, + const uint8_t *app_key[16], uint8_t *aid) +{ + struct bt_mesh_app_key *app = NULL; + + if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) { + /* With device keys, the application has to decide which subnet + * to send on. + */ + *sub = bt_mesh_subnet_get(ctx->net_idx); + if (!*sub) { + BT_WARN("Unknown NetKey 0x%03x", ctx->net_idx); + return -EINVAL; + } + + if (ctx->app_idx == BT_MESH_KEY_DEV_REMOTE && + !bt_mesh_elem_find(ctx->addr)) { + struct bt_mesh_cdb_node *node; + + if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) { + BT_WARN("No DevKey for 0x%04x", ctx->addr); + return -EINVAL; + } + + node = bt_mesh_cdb_node_get(ctx->addr); + if (!node) { + BT_WARN("No DevKey for 0x%04x", ctx->addr); + return -EINVAL; + } + + *app_key = node->dev_key; + } else { + *app_key = bt_mesh.dev_key; + } + + *aid = 0; + return 0; + } + + app = app_get(ctx->app_idx); + if (!app) { + BT_WARN("Unknown AppKey 0x%03x", ctx->app_idx); + return -EINVAL; + } + + *sub = bt_mesh_subnet_get(app->net_idx); + if (!*sub) { + BT_WARN("Unknown NetKey 0x%03x", app->net_idx); + return -EINVAL; + } + + if ((*sub)->kr_phase == BT_MESH_KR_PHASE_2 && app->updated) { + *aid = app->keys[1].id; + *app_key = app->keys[1].val; + } else { + *aid = app->keys[0].id; + *app_key = app->keys[0].val; + } + + return 0; +} + +uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, + struct bt_mesh_net_rx *rx, + int (*cb)(struct bt_mesh_net_rx *rx, + const uint8_t key[16], void *cb_data), + void *cb_data) +{ + int err, i; + + if (dev_key) { + /* Attempt remote dev key first, as that is only available for + * provisioner devices, which normally don't interact with nodes + * that know their local dev key. + */ + if (IS_ENABLED(CONFIG_BT_MESH_CDB) && + rx->net_if != BT_MESH_NET_IF_LOCAL) { + struct bt_mesh_cdb_node *node; + + node = bt_mesh_cdb_node_get(rx->ctx.addr); + if (node && !cb(rx, node->dev_key, cb_data)) { + return BT_MESH_KEY_DEV_REMOTE; + } + } + + /** Bluetooth Mesh Specification v1.0.1, section 3.4.3: + * The Device key is only valid for unicast addresses. + */ + if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { + err = cb(rx, bt_mesh.dev_key, cb_data); + if (!err) { + return BT_MESH_KEY_DEV_LOCAL; + } + } + + return BT_MESH_KEY_UNUSED; + } + + for (i = 0; i < ARRAY_SIZE(apps); i++) { + const struct bt_mesh_app_key *app = &apps[i]; + const struct bt_mesh_app_cred *cred; + + if (app->app_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (app->net_idx != rx->sub->net_idx) { + continue; + } + + if (rx->new_key && app->updated) { + cred = &app->keys[1]; + } else { + cred = &app->keys[0]; + } + + if (cred->id != aid) { + continue; + } + + err = cb(rx, cred->val, cb_data); + if (err) { + continue; + } + + return app->app_idx; + } + + return BT_MESH_KEY_UNUSED; +} + +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + if (evt == BT_MESH_KEY_UPDATED || evt == BT_MESH_KEY_ADDED) { + return; + } + + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + struct bt_mesh_app_key *app = &apps[i]; + + if (app->app_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (app->net_idx != sub->net_idx) { + continue; + } + + if (evt == BT_MESH_KEY_DELETED) { + app_key_del(app); + } else if (evt == BT_MESH_KEY_REVOKED) { + app_key_revoke(app); + } else if (evt == BT_MESH_KEY_SWAPPED && app->updated) { + app_key_evt(app, BT_MESH_KEY_SWAPPED); + } + } +} + +BT_MESH_SUBNET_CB_DEFINE(subnet_evt); + +void bt_mesh_app_keys_reset(void) +{ + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + struct bt_mesh_app_key *app = &apps[i]; + + if (app->app_idx != BT_MESH_KEY_UNUSED) { + app_key_del(app); + } + } +} diff --git a/subsys/bluetooth/mesh/app_keys.h b/subsys/bluetooth/mesh/app_keys.h new file mode 100644 index 00000000000..b9f6862b4af --- /dev/null +++ b/subsys/bluetooth/mesh/app_keys.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_APP_KEYS_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_APP_KEYS_H_ + +#include +#include "subnet.h" + +/** Mesh Application. */ +struct bt_mesh_app_key { + uint16_t net_idx; + uint16_t app_idx; + bool updated; + struct bt_mesh_app_cred { + uint8_t id; + uint8_t val[16]; + } keys[2]; +}; + +/** @brief Reset the app keys module. */ +void bt_mesh_app_keys_reset(void); + +/** @brief Get the application key with the given AppIdx. + * + * @param app_idx App index. + * + * @return The matching application, or NULL if the application isn't known. + */ +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); + +/** @brief Initialize a new application key with the given parameters. + * + * @param app_idx AppIndex. + * @param net_idx NetIndex the application is bound to. + * @param old_key Current application key. + * @param new_key Updated application key, or NULL if not known. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, + const uint8_t old_key[16], const uint8_t new_key[16]); + +/** @brief Resolve the message encryption keys, given a message context. + * + * Will use the @c ctx::app_idx and @c ctx::net_idx fields to find a pair of + * message encryption keys. If @c ctx::app_idx represents a device key, the + * @c ctx::net_idx will be used to determine the net key. Otherwise, the + * @c ctx::net_idx parameter will be ignored. + * + * @param ctx Message context. + * @param sub Subnet return parameter. + * @param app_key Application return parameter. + * @param aid Application ID return parameter. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_subnet **sub, + const uint8_t *app_key[16], uint8_t *aid); + +/** @brief Iterate through all matching application keys and call @c cb on each. + * + * @param dev_key Whether to return device keys. + * @param aid 7 bit application ID to match. + * @param rx RX structure to match against. + * @param cb Callback to call for every valid app key. + * @param cb_data Callback data to pass to the callback. + * + * @return The AppIdx that yielded a 0-return from the callback. + */ +uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, + struct bt_mesh_net_rx *rx, + int (*cb)(struct bt_mesh_net_rx *rx, + const uint8_t key[16], void *cb_data), + void *cb_data); + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_APP_KEYS_H_ */ diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index 951dd7caecd..4faf7c1c99b 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -40,23 +40,9 @@ static struct k_delayed_work beacon_timer; -static struct bt_mesh_subnet *cache_check(uint8_t data[21]) +static int cache_check(struct bt_mesh_subnet *sub, void *beacon_data) { - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (!memcmp(sub->beacon_cache, data, 21)) { - return sub; - } - } - - return NULL; + return !memcmp(sub->beacon_cache, beacon_data, 21); } static void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub) @@ -81,11 +67,7 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); - if (sub->kr_flag) { - keys = &sub->keys[1]; - } else { - keys = &sub->keys[0]; - } + keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)]; net_buf_simple_add_u8(buf, flags); @@ -107,44 +89,34 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, #define BEACON_THRESHOLD(sub) \ ((10 * ((sub)->beacons_last + 1)) * MSEC_PER_SEC - (5 * MSEC_PER_SEC)) -static int secure_beacon_send(void) +static int secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data) { static const struct bt_mesh_send_cb send_cb = { .end = beacon_complete, }; uint32_t now = k_uptime_get_32(); - int i; + struct net_buf *buf; + uint32_t time_diff; BT_DBG(""); - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - struct net_buf *buf; - uint32_t time_diff; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - time_diff = now - sub->beacon_sent; - if (time_diff < (600 * MSEC_PER_SEC) && - time_diff < BEACON_THRESHOLD(sub)) { - continue; - } - - buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT, - K_NO_WAIT); - if (!buf) { - BT_ERR("Unable to allocate beacon buffer"); - return -ENOBUFS; - } - - bt_mesh_beacon_create(sub, &buf->b); - - bt_mesh_adv_send(buf, &send_cb, sub); - net_buf_unref(buf); + time_diff = now - sub->beacon_sent; + if (time_diff < (600 * MSEC_PER_SEC) && + time_diff < BEACON_THRESHOLD(sub)) { + return 0; } + buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT, K_NO_WAIT); + if (!buf) { + BT_ERR("Unable to allocate beacon buffer"); + return -ENOMEM; + } + + bt_mesh_beacon_create(sub, &buf->b); + + bt_mesh_adv_send(buf, &send_cb, sub); + net_buf_unref(buf); + return 0; } @@ -236,10 +208,15 @@ static void unprovisioned_beacon_recv(struct net_buf_simple *buf) } } +static void sub_update_beacon_observation(struct bt_mesh_subnet *sub) +{ + sub->beacons_last = sub->beacons_cur; + sub->beacons_cur = 0U; +} + static void update_beacon_observation(void) { static bool first_half; - int i; /* Observation period is 20 seconds, whereas the beacon timer * runs every 10 seconds. We process what's happened during the @@ -250,16 +227,7 @@ static void update_beacon_observation(void) return; } - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - sub->beacons_last = sub->beacons_cur; - sub->beacons_cur = 0U; - } + bt_mesh_subnet_foreach(sub_update_beacon_observation); } static void beacon_send(struct k_work *work) @@ -274,7 +242,7 @@ static void beacon_send(struct k_work *work) if (bt_mesh_is_provisioned()) { update_beacon_observation(); - secure_beacon_send(); + (void)bt_mesh_subnet_find(secure_beacon_send, NULL); /* Only resubmit if beaconing is still enabled */ if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED || @@ -292,20 +260,62 @@ static void beacon_send(struct k_work *work) } } +struct beacon_params { + const uint8_t *net_id; + const uint8_t *auth; + uint32_t iv_index; + uint8_t flags; + + bool new_key; +}; + +static bool auth_match(struct bt_mesh_subnet_keys *keys, + const struct beacon_params *params) +{ + uint8_t net_auth[8]; + + if (memcmp(params->net_id, keys->net_id, 8)) { + return false; + } + + bt_mesh_beacon_auth(keys->beacon, params->flags, keys->net_id, + params->iv_index, net_auth); + + if (memcmp(params->auth, net_auth, 8)) { + BT_WARN("Authentication Value %s != %s", + bt_hex(params->auth, 8), bt_hex(net_auth, 8)); + return false; + } + + return true; +} + +static int subnet_by_id(struct bt_mesh_subnet *sub, void *cb_data) +{ + struct beacon_params *params = cb_data; + + for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) { + if (sub->keys[i].valid && auth_match(&sub->keys[i], params)) { + params->new_key = (i > 0); + return true; + } + } + + return false; +} + static void secure_beacon_recv(struct net_buf_simple *buf) { - uint8_t *data, *net_id, *auth; + struct beacon_params params; struct bt_mesh_subnet *sub; - uint32_t iv_index; - bool new_key, kr_change, iv_change; - uint8_t flags; + uint8_t *data; if (buf->len < 21) { BT_ERR("Too short secure beacon (len %u)", buf->len); return; } - sub = cache_check(buf->data); + sub = bt_mesh_subnet_find(cache_check, buf->data); if (sub) { /* We've seen this beacon before - just update the stats */ goto update_stats; @@ -314,33 +324,29 @@ static void secure_beacon_recv(struct net_buf_simple *buf) /* So we can add to the cache if auth matches */ data = buf->data; - flags = net_buf_simple_pull_u8(buf); - net_id = net_buf_simple_pull_mem(buf, 8); - iv_index = net_buf_simple_pull_be32(buf); - auth = buf->data; + params.flags = net_buf_simple_pull_u8(buf); + params.net_id = net_buf_simple_pull_mem(buf, 8); + params.iv_index = net_buf_simple_pull_be32(buf); + params.auth = buf->data; BT_DBG("flags 0x%02x id %s iv_index 0x%08x", - flags, bt_hex(net_id, 8), iv_index); + params.flags, bt_hex(params.net_id, 8), params.iv_index); - sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key); + sub = bt_mesh_subnet_find(subnet_by_id, ¶ms); if (!sub) { BT_DBG("No subnet that matched beacon"); return; } - if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) { + if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params.new_key) { BT_WARN("Ignoring Phase 2 KR Update secured using old key"); return; } cache_add(data, sub); - kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key); - if (kr_change) { - bt_mesh_net_beacon_update(sub); - /* Key Refresh without IV Update only impacts one subnet */ - bt_mesh_net_sec_update(sub); - } + bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params.flags), + params.new_key); /* If we have NetKey0 accept initiation only from it */ if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) && @@ -350,20 +356,15 @@ static void secure_beacon_recv(struct net_buf_simple *buf) } BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", - sub->net_idx, iv_index, bt_mesh.iv_index); + sub->net_idx, params.iv_index, bt_mesh.iv_index); if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) && (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) == - BT_MESH_IV_UPDATE(flags))) { + BT_MESH_IV_UPDATE(params.flags))) { bt_mesh_beacon_ivu_initiator(false); } - iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags)); - - if (iv_change) { - /* Update all subnets */ - bt_mesh_net_sec_update(NULL); - } + bt_mesh_net_iv_update(params.iv_index, BT_MESH_IV_UPDATE(params.flags)); update_stats: if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED && @@ -399,6 +400,34 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf) } } +void bt_mesh_beacon_update(struct bt_mesh_subnet *sub) +{ + uint8_t flags = bt_mesh_net_flags(sub); + struct bt_mesh_subnet_keys *keys; + int err; + + keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)]; + + BT_DBG("NetIndex 0x%03x Using %s key", sub->net_idx, + SUBNET_KEY_TX_IDX(sub) ? "new" : "current"); + BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); + + err = bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, + bt_mesh.iv_index, sub->auth); + if (err) { + BT_ERR("Failed updating net beacon for 0x%03x", sub->net_idx); + } +} + +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + if (evt == BT_MESH_KEY_ADDED || evt == BT_MESH_KEY_SWAPPED) { + bt_mesh_beacon_update(sub); + } +} + +BT_MESH_SUBNET_CB_DEFINE(subnet_evt); + void bt_mesh_beacon_init(void) { k_delayed_work_init(&beacon_timer, beacon_send); @@ -415,27 +444,22 @@ void bt_mesh_beacon_ivu_initiator(bool enable) } } +static void subnet_beacon_enable(struct bt_mesh_subnet *sub) +{ + sub->beacons_last = 0U; + sub->beacons_cur = 0U; + + bt_mesh_beacon_update(sub); +} + void bt_mesh_beacon_enable(void) { - int i; - if (!bt_mesh_is_provisioned()) { k_work_submit(&beacon_timer.work); return; } - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - sub->beacons_last = 0U; - sub->beacons_cur = 0U; - - bt_mesh_net_beacon_update(sub); - } + bt_mesh_subnet_foreach(subnet_beacon_enable); k_work_submit(&beacon_timer.work); } diff --git a/subsys/bluetooth/mesh/beacon.h b/subsys/bluetooth/mesh/beacon.h index afa08fdcba7..3f940d7249b 100644 --- a/subsys/bluetooth/mesh/beacon.h +++ b/subsys/bluetooth/mesh/beacon.h @@ -17,3 +17,4 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct net_buf_simple *buf); void bt_mesh_beacon_init(void); +void bt_mesh_beacon_update(struct bt_mesh_subnet *sub); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 7c75a24ea14..11ad85b10ad 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -179,22 +179,6 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, } } -static bool app_key_is_valid(uint16_t app_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != BT_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return true; - } - } - - return false; -} - static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, uint8_t retransmit, bool store) @@ -235,7 +219,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, return STATUS_SUCCESS; } - if (!bt_mesh_app_key_find(app_idx)) { + if (!bt_mesh_app_key_exists(app_idx)) { return STATUS_INVALID_APPKEY; } @@ -283,7 +267,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) BT_DBG("model %p key_idx 0x%03x", model, key_idx); - if (!app_key_is_valid(key_idx)) { + if (!bt_mesh_app_key_exists(key_idx)) { return STATUS_INVALID_APPKEY; } @@ -315,7 +299,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); - if (!app_key_is_valid(key_idx)) { + if (!bt_mesh_app_key_exists(key_idx)) { return STATUS_INVALID_APPKEY; } @@ -339,115 +323,26 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st return STATUS_SUCCESS; } -struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx) +static void send_app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t app_idx, uint16_t net_idx) { - int i; + BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_STATUS, 4); - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); + net_buf_simple_add_u8(&msg, status); + key_idx_pack(&msg, net_idx, app_idx); - if (key->net_idx == BT_MESH_KEY_UNUSED) { - return key; - } + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("Unable to send App Key Status response"); } - - return NULL; -} - -static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val[16], - bool update) -{ - struct bt_mesh_app_keys *keys; - struct bt_mesh_app_key *key; - struct bt_mesh_subnet *sub; - - BT_DBG("net_idx 0x%04x app_idx %04x update %u val %s", - net_idx, app_idx, update, bt_hex(val, 16)); - - sub = bt_mesh_subnet_get(net_idx); - if (!sub) { - return STATUS_INVALID_NETKEY; - } - - key = bt_mesh_app_key_find(app_idx); - if (update) { - if (!key) { - return STATUS_INVALID_APPKEY; - } - - if (key->net_idx != net_idx) { - return STATUS_INVALID_BINDING; - } - - keys = &key->keys[1]; - - /* The AppKey Update message shall generate an error when node - * is in normal operation, Phase 2, or Phase 3 or in Phase 1 - * when the AppKey Update message on a valid AppKeyIndex when - * the AppKey value is different. - */ - if (sub->kr_phase != BT_MESH_KR_PHASE_1) { - return STATUS_CANNOT_UPDATE; - } - - if (key->updated) { - if (memcmp(keys->val, val, 16)) { - return STATUS_CANNOT_UPDATE; - } else { - return STATUS_SUCCESS; - } - } - - key->updated = true; - } else { - if (key) { - if (key->net_idx == net_idx && - !memcmp(key->keys[0].val, val, 16)) { - return STATUS_SUCCESS; - } - - if (key->net_idx == net_idx) { - return STATUS_IDX_ALREADY_STORED; - } else { - return STATUS_INVALID_NETKEY; - } - } - - key = bt_mesh_app_key_alloc(app_idx); - if (!key) { - return STATUS_INSUFF_RESOURCES; - } - - keys = &key->keys[0]; - } - - if (bt_mesh_app_id(val, &keys->id)) { - if (update) { - key->updated = false; - } - - return STATUS_STORAGE_FAIL; - } - - BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, keys->id); - - key->net_idx = net_idx; - key->app_idx = app_idx; - memcpy(keys->val, val, 16); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(key); - } - - return STATUS_SUCCESS; } static void app_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_STATUS, 4); uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -455,24 +350,15 @@ static void app_key_add(struct bt_mesh_model *model, BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); + status = bt_mesh_app_key_add(key_app_idx, key_net_idx, buf->data); - status = app_key_set(key_net_idx, key_app_idx, buf->data, false); - BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); - - key_idx_pack(&msg, key_net_idx, key_app_idx); - - if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { - BT_ERR("Unable to send App Key Status response"); - } + send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } static void app_key_update(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_STATUS, 4); uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -480,93 +366,45 @@ static void app_key_update(struct bt_mesh_model *model, BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); - - status = app_key_set(key_net_idx, key_app_idx, buf->data, true); + status = bt_mesh_app_key_update(key_app_idx, key_net_idx, buf->data); BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); - key_idx_pack(&msg, key_net_idx, key_app_idx); + send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); +} - if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { - BT_ERR("Unable to send App Key Status response"); +static void mod_app_key_del(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, bool vnd, bool primary, + void *user_data) +{ + uint16_t *app_idx = user_data; + + mod_unbind(mod, *app_idx, true); +} + +static void app_key_evt(uint16_t app_idx, uint16_t net_idx, + enum bt_mesh_key_evt evt) +{ + if (evt == BT_MESH_KEY_DELETED) { + bt_mesh_model_foreach(&mod_app_key_del, &app_idx); } } -struct unbind_data { - uint16_t app_idx; - bool store; -}; - -static void _mod_unbind(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - struct unbind_data *data = user_data; - - mod_unbind(mod, data->app_idx, data->store); -} - -void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store) -{ - struct unbind_data data = { .app_idx = key->app_idx, .store = store }; - - BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); - - bt_mesh_model_foreach(_mod_unbind, &data); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_app_key(key); - } - - key->net_idx = BT_MESH_KEY_UNUSED; - (void)memset(key->keys, 0, sizeof(key->keys)); -} +BT_MESH_APP_KEY_CB_DEFINE(app_key_evt); static void app_key_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_STATUS, 4); uint16_t key_net_idx, key_app_idx; - struct bt_mesh_app_key *key; uint8_t status; key_idx_unpack(buf, &key_net_idx, &key_app_idx); BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); - if (!bt_mesh_subnet_get(key_net_idx)) { - status = STATUS_INVALID_NETKEY; - goto send_status; - } + status = bt_mesh_app_key_del(key_net_idx, key_net_idx); - key = bt_mesh_app_key_find(key_app_idx); - if (!key) { - /* Treat as success since the client might have missed a - * previous response and is resending the request. - */ - status = STATUS_SUCCESS; - goto send_status; - } - - if (key->net_idx != key_net_idx) { - status = STATUS_INVALID_BINDING; - goto send_status; - } - - bt_mesh_app_key_del(key, true); - status = STATUS_SUCCESS; - -send_status: - bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); - - net_buf_simple_add_u8(&msg, status); - - key_idx_pack(&msg, key_net_idx, key_app_idx); - - if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { - BT_ERR("Unable to send App Key Status response"); - } + send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ @@ -578,8 +416,11 @@ static void app_key_get(struct bt_mesh_model *model, { BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_LIST, 3 + IDX_LEN(CONFIG_BT_MESH_APP_KEY_COUNT)); - uint16_t get_idx, i, prev; + uint16_t app_idx[CONFIG_BT_MESH_APP_KEY_COUNT]; + uint16_t get_idx; uint8_t status; + ssize_t count; + int i; get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { @@ -591,7 +432,7 @@ static void app_key_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(&msg, OP_APP_KEY_LIST); - if (!bt_mesh_subnet_get(get_idx)) { + if (!bt_mesh_subnet_exists(get_idx)) { status = STATUS_INVALID_NETKEY; } else { status = STATUS_SUCCESS; @@ -604,25 +445,17 @@ static void app_key_get(struct bt_mesh_model *model, goto send_status; } - prev = BT_MESH_KEY_UNUSED; - for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != get_idx) { - continue; - } - - if (prev == BT_MESH_KEY_UNUSED) { - prev = key->app_idx; - continue; - } - - key_idx_pack(&msg, prev, key->app_idx); - prev = BT_MESH_KEY_UNUSED; + count = bt_mesh_app_keys_get(get_idx, app_idx, ARRAY_SIZE(app_idx), 0); + if (count < 0 || count > ARRAY_SIZE(app_idx)) { + count = ARRAY_SIZE(app_idx); } - if (prev != BT_MESH_KEY_UNUSED) { - net_buf_simple_add_le16(&msg, prev); + for (i = 0; i < count - 1; i += 2) { + key_idx_pack(&msg, app_idx[i], app_idx[i + 1]); + } + + if (i < count) { + net_buf_simple_add_le16(&msg, app_idx[i]); } send_status: @@ -2122,9 +1955,8 @@ static void net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_subnet *sub; + uint8_t status; uint16_t idx; - int err; idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2134,72 +1966,17 @@ static void net_key_add(struct bt_mesh_model *model, BT_DBG("idx 0x%04x", idx); - sub = bt_mesh_subnet_get(idx); - if (!sub) { - int i; + status = bt_mesh_subnet_add(idx, buf->data); - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) { - sub = &bt_mesh.sub[i]; - break; - } - } - - if (!sub) { - send_net_key_status(model, ctx, idx, - STATUS_INSUFF_RESOURCES); - return; - } - } - - /* Check for already existing subnet */ - if (sub->net_idx == idx) { - uint8_t status; - - if (memcmp(buf->data, sub->keys[0].net, 16)) { - status = STATUS_IDX_ALREADY_STORED; - } else { - status = STATUS_SUCCESS; - } - - send_net_key_status(model, ctx, idx, status); - return; - } - - err = bt_mesh_net_keys_create(&sub->keys[0], buf->data); - if (err) { - send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); - return; - } - - sub->net_idx = idx; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); - bt_mesh_store_subnet(sub); - } - - /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; - bt_mesh_proxy_beacon_send(sub); - bt_mesh_adv_update(); - } else { - sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; - } - - send_net_key_status(model, ctx, idx, STATUS_SUCCESS); + send_net_key_status(model, ctx, idx, status); } static void net_key_update(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_subnet *sub; + uint8_t status; uint16_t idx; - int err; idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2207,59 +1984,9 @@ static void net_key_update(struct bt_mesh_model *model, return; } - BT_DBG("idx 0x%04x", idx); + status = bt_mesh_subnet_update(idx, buf->data); - sub = bt_mesh_subnet_get(idx); - if (!sub) { - send_net_key_status(model, ctx, idx, STATUS_INVALID_NETKEY); - return; - } - - /* The node shall successfully process a NetKey Update message on a - * valid NetKeyIndex when the NetKey value is different and the Key - * Refresh procedure has not been started, or when the NetKey value is - * the same in Phase 1. The NetKey Update message shall generate an - * error when the node is in Phase 2, or Phase 3. - */ - switch (sub->kr_phase) { - case BT_MESH_KR_NORMAL: - if (!memcmp(buf->data, sub->keys[0].net, 16)) { - return; - } - break; - case BT_MESH_KR_PHASE_1: - if (!memcmp(buf->data, sub->keys[1].net, 16)) { - send_net_key_status(model, ctx, idx, STATUS_SUCCESS); - return; - } - __fallthrough; - case BT_MESH_KR_PHASE_2: - case BT_MESH_KR_PHASE_3: - send_net_key_status(model, ctx, idx, STATUS_CANNOT_UPDATE); - return; - } - - err = bt_mesh_net_keys_create(&sub->keys[1], buf->data); - if (!err && (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BT_MESH_FRIEND))) { - err = friend_cred_update(sub); - } - - if (err) { - send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); - return; - } - - sub->kr_phase = BT_MESH_KR_PHASE_1; - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); - bt_mesh_store_subnet(sub); - } - - bt_mesh_net_beacon_update(sub); - - send_net_key_status(model, ctx, idx, STATUS_SUCCESS); + send_net_key_status(model, ctx, idx, status); } static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) @@ -2278,9 +2005,7 @@ static void net_key_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_subnet *sub; uint16_t del_idx; - uint8_t status; del_idx = net_buf_simple_pull_le16(buf); if (del_idx > 0xfff) { @@ -2290,28 +2015,18 @@ static void net_key_del(struct bt_mesh_model *model, BT_DBG("idx 0x%04x", del_idx); - sub = bt_mesh_subnet_get(del_idx); - if (!sub) { - /* This could be a retry of a previous attempt that had its - * response lost, so pretend that it was a success. - */ - status = STATUS_SUCCESS; - goto send_status; - } - /* The key that the message was encrypted with cannot be removed. * The NetKey List must contain a minimum of one NetKey. */ if (ctx->net_idx == del_idx) { - status = STATUS_CANNOT_REMOVE; - goto send_status; + send_net_key_status(model, ctx, del_idx, + STATUS_CANNOT_REMOVE); + return; } - bt_mesh_subnet_del(sub, true); - status = STATUS_SUCCESS; + bt_mesh_subnet_del(del_idx); -send_status: - send_net_key_status(model, ctx, del_idx, status); + send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); } static void net_key_get(struct bt_mesh_model *model, @@ -2320,29 +2035,23 @@ static void net_key_get(struct bt_mesh_model *model, { BT_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_LIST, IDX_LEN(CONFIG_BT_MESH_SUBNET_COUNT)); - uint16_t prev, i; + uint16_t net_idx[CONFIG_BT_MESH_SUBNET_COUNT]; + ssize_t count; + int i; bt_mesh_model_msg_init(&msg, OP_NET_KEY_LIST); - prev = BT_MESH_KEY_UNUSED; - for (i = 0U; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (prev == BT_MESH_KEY_UNUSED) { - prev = sub->net_idx; - continue; - } - - key_idx_pack(&msg, prev, sub->net_idx); - prev = BT_MESH_KEY_UNUSED; + count = bt_mesh_subnets_get(net_idx, ARRAY_SIZE(net_idx), 0); + if (count < 0 || count > ARRAY_SIZE(net_idx)) { + count = ARRAY_SIZE(net_idx); } - if (prev != BT_MESH_KEY_UNUSED) { - net_buf_simple_add_le16(&msg, prev); + for (i = 0; i < count - 1; i += 2) { + key_idx_pack(&msg, net_idx[i], net_idx[i + 1]); + } + + if (i < count) { + net_buf_simple_add_le16(&msg, net_idx[i]); } if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -2350,13 +2059,29 @@ static void net_key_get(struct bt_mesh_model *model, } } +static void send_node_id_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t net_idx, uint8_t node_id) +{ + BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_IDENTITY_STATUS, 4); + + bt_mesh_model_msg_init(&msg, OP_NODE_IDENTITY_STATUS); + net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_le16(&msg, net_idx); + net_buf_simple_add_u8(&msg, node_id); + + if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { + BT_ERR("Unable to send Node Identity Status"); + } +} + static void node_identity_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_IDENTITY_STATUS, 4); - struct bt_mesh_subnet *sub; - uint8_t node_id; + enum bt_mesh_feat_state node_id; + uint8_t status; uint16_t idx; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", @@ -2369,32 +2094,16 @@ static void node_identity_get(struct bt_mesh_model *model, return; } - bt_mesh_model_msg_init(&msg, OP_NODE_IDENTITY_STATUS); + status = bt_mesh_subnet_node_id_get(idx, &node_id); - sub = bt_mesh_subnet_get(idx); - if (!sub) { - net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); - node_id = 0x00; - } else { - net_buf_simple_add_u8(&msg, STATUS_SUCCESS); - node_id = sub->node_id; - } - - net_buf_simple_add_le16(&msg, idx); - net_buf_simple_add_u8(&msg, node_id); - - if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { - BT_ERR("Unable to send Node Identity Status"); - } + send_node_id_status(model, ctx, status, idx, node_id); } static void node_identity_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_IDENTITY_STATUS, 4); - struct bt_mesh_subnet *sub; - uint8_t node_id; + uint8_t node_id, status; uint16_t idx; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", @@ -2413,32 +2122,21 @@ static void node_identity_set(struct bt_mesh_model *model, return; } - bt_mesh_model_msg_init(&msg, OP_NODE_IDENTITY_STATUS); - - sub = bt_mesh_subnet_get(idx); - if (!sub) { - net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); - net_buf_simple_add_le16(&msg, idx); - net_buf_simple_add_u8(&msg, node_id); - } else { - net_buf_simple_add_u8(&msg, STATUS_SUCCESS); - net_buf_simple_add_le16(&msg, idx); - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - if (node_id) { - bt_mesh_proxy_identity_start(sub); - } else { - bt_mesh_proxy_identity_stop(sub); - } - bt_mesh_adv_update(); - } - - net_buf_simple_add_u8(&msg, sub->node_id); + status = bt_mesh_subnet_node_id_set(idx, node_id); + if (status == STATUS_INVALID_NETKEY) { + send_node_id_status(model, ctx, status, idx, + BT_MESH_NODE_IDENTITY_STOPPED); + return; } - if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { - BT_ERR("Unable to send Node Identity Status"); + if (status == STATUS_FEAT_NOT_SUPP) { + /* Should return success, even if feature isn't supported: */ + send_node_id_status(model, ctx, STATUS_SUCCESS, idx, + BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); + return; } + + send_node_id_status(model, ctx, status, idx, node_id); } static void create_mod_app_status(struct net_buf_simple *msg, @@ -2727,7 +2425,7 @@ static void friend_set(struct bt_mesh_model *model, } if (cfg->frnd == BT_MESH_FRIEND_DISABLED) { - bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY); + bt_mesh_friends_clear(); } } @@ -2802,7 +2500,7 @@ static void send_krp_status(struct bt_mesh_model *model, static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_subnet *sub; + uint8_t kr_phase, status; uint16_t idx; idx = net_buf_simple_pull_le16(buf); @@ -2813,20 +2511,15 @@ static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, BT_DBG("idx 0x%04x", idx); - sub = bt_mesh_subnet_get(idx); - if (!sub) { - send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); - } else { - send_krp_status(model, ctx, idx, sub->kr_phase, - STATUS_SUCCESS); - } + status = bt_mesh_subnet_kr_phase_get(idx, &kr_phase); + + send_krp_status(model, ctx, idx, kr_phase, status); } static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - struct bt_mesh_subnet *sub; - uint8_t phase; + uint8_t phase, status; uint16_t idx; idx = net_buf_simple_pull_le16(buf); @@ -2837,48 +2530,13 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return; } - BT_DBG("idx 0x%04x transition 0x%02x", idx, phase); - - sub = bt_mesh_subnet_get(idx); - if (!sub) { - send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); + status = bt_mesh_subnet_kr_phase_set(idx, &phase); + if (status == STATUS_CANNOT_UPDATE) { + BT_ERR("Invalid kr phase transition 0x%02x", phase); return; } - BT_DBG("%u -> %u", sub->kr_phase, phase); - - if (phase < BT_MESH_KR_PHASE_2 || phase > BT_MESH_KR_PHASE_3 || - (sub->kr_phase == BT_MESH_KR_NORMAL && - phase == BT_MESH_KR_PHASE_2)) { - BT_WARN("Prohibited transition %u -> %u", sub->kr_phase, phase); - return; - } - - if (sub->kr_phase == BT_MESH_KR_PHASE_1 && - phase == BT_MESH_KR_PHASE_2) { - sub->kr_phase = BT_MESH_KR_PHASE_2; - sub->kr_flag = 1; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing krp phase persistently"); - bt_mesh_store_subnet(sub); - } - - bt_mesh_net_beacon_update(sub); - } else if ((sub->kr_phase == BT_MESH_KR_PHASE_1 || - sub->kr_phase == BT_MESH_KR_PHASE_2) && - phase == BT_MESH_KR_PHASE_3) { - bt_mesh_net_revoke_keys(sub); - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - friend_cred_refresh(ctx->net_idx); - } - - sub->kr_phase = BT_MESH_KR_NORMAL; - sub->kr_flag = 0; - bt_mesh_net_beacon_update(sub); - } - - send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS); + send_krp_status(model, ctx, idx, phase, status); } static uint8_t hb_log(uint16_t val) @@ -3382,7 +3040,6 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, void bt_mesh_cfg_reset(void) { struct bt_mesh_cfg_srv *cfg = conf; - int i; BT_DBG(""); @@ -3392,17 +3049,6 @@ void bt_mesh_cfg_reset(void) cfg->hb_sub.dst = BT_MESH_ADDR_UNASSIGNED; cfg->hb_sub.expiry = 0; - /* Delete all net keys, which also takes care of all app keys which - * are associated with each net key. - */ - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx != BT_MESH_KEY_UNUSED) { - bt_mesh_subnet_del(sub, true); - } - } - bt_mesh_model_foreach(mod_reset, NULL); (void)memset(labels, 0, sizeof(labels)); @@ -3535,40 +3181,3 @@ struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) { return conf; } - -void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store) -{ - int i; - - BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); - - if (conf->hb_pub.net_idx == sub->net_idx) { - hb_pub_disable(conf); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_hb_pub(); - } - } - - /* Delete any app keys bound to this NetKey index */ - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx == sub->net_idx) { - bt_mesh_app_key_del(key, store); - } - } - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - bt_mesh_friend_clear_net_idx(sub->net_idx); - } - - bt_mesh_net_loopback_clear(sub->net_idx); - - if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_subnet(sub); - } - - (void)memset(sub, 0, sizeof(*sub)); - sub->net_idx = BT_MESH_KEY_UNUSED; -} diff --git a/subsys/bluetooth/mesh/crypto.c b/subsys/bluetooth/mesh/crypto.c index cf7ceb98762..2bbed8e8ebe 100644 --- a/subsys/bluetooth/mesh/crypto.c +++ b/subsys/bluetooth/mesh/crypto.c @@ -333,67 +333,69 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, &buf->data[7], mic_len); } -static void create_app_nonce(uint8_t nonce[13], bool dev_key, uint8_t aszmic, - uint16_t src, uint16_t dst, uint32_t seq_num, - uint32_t iv_index) +static void create_app_nonce(uint8_t nonce[13], + const struct bt_mesh_app_crypto_ctx *ctx) { - if (dev_key) { + if (ctx->dev_key) { nonce[0] = 0x02; } else { nonce[0] = 0x01; } - sys_put_be32((seq_num | ((uint32_t)aszmic << 31)), &nonce[1]); + sys_put_be32((ctx->seq_num | ((uint32_t)ctx->aszmic << 31)), &nonce[1]); - sys_put_be16(src, &nonce[5]); - sys_put_be16(dst, &nonce[7]); + sys_put_be16(ctx->src, &nonce[5]); + sys_put_be16(ctx->dst, &nonce[7]); - sys_put_be32(iv_index, &nonce[9]); + sys_put_be32(ctx->iv_index, &nonce[9]); } -int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct net_buf_simple *buf, const uint8_t *ad, - uint16_t src, uint16_t dst, uint32_t seq_num, uint32_t iv_index) +int bt_mesh_app_encrypt(const uint8_t key[16], + const struct bt_mesh_app_crypto_ctx *ctx, + struct net_buf_simple *buf) { uint8_t nonce[13]; int err; BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst); - BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index); + BT_DBG("dev_key %u src 0x%04x dst 0x%04x", ctx->dev_key, ctx->src, + ctx->dst); + BT_DBG("seq_num 0x%08x iv_index 0x%08x", ctx->seq_num, ctx->iv_index); BT_DBG("Clear: %s", bt_hex(buf->data, buf->len)); - create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); + create_app_nonce(nonce, ctx); BT_DBG("Nonce %s", bt_hex(nonce, 13)); - err = bt_ccm_encrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, - buf->data, APP_MIC_LEN(aszmic)); + err = bt_ccm_encrypt(key, nonce, buf->data, buf->len, ctx->ad, + ctx->ad ? 16 : 0, buf->data, + APP_MIC_LEN(ctx->aszmic)); if (!err) { - net_buf_simple_add(buf, APP_MIC_LEN(aszmic)); + net_buf_simple_add(buf, APP_MIC_LEN(ctx->aszmic)); BT_DBG("Encr: %s", bt_hex(buf->data, buf->len)); } return err; } -int bt_mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct net_buf_simple *buf, struct net_buf_simple *out, - const uint8_t *ad, uint16_t src, uint16_t dst, uint32_t seq_num, - uint32_t iv_index) +int bt_mesh_app_decrypt(const uint8_t key[16], + const struct bt_mesh_app_crypto_ctx *ctx, + struct net_buf_simple *buf, struct net_buf_simple *out) { uint8_t nonce[13]; int err; - BT_DBG("EncData (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("EncData (len %u) %s", buf->len, + bt_hex(buf->data, buf->len)); - create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); + create_app_nonce(nonce, ctx); BT_DBG("AppKey %s", bt_hex(key, 16)); BT_DBG("Nonce %s", bt_hex(nonce, 13)); - err = bt_ccm_decrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, - out->data, APP_MIC_LEN(aszmic)); + err = bt_ccm_decrypt(key, nonce, buf->data, buf->len, ctx->ad, + ctx->ad ? 16 : 0, out->data, + APP_MIC_LEN(ctx->aszmic)); if (!err) { net_buf_simple_add(out, buf->len); } diff --git a/subsys/bluetooth/mesh/crypto.h b/subsys/bluetooth/mesh/crypto.h index f2c28cf4ed8..118b03d584d 100644 --- a/subsys/bluetooth/mesh/crypto.h +++ b/subsys/bluetooth/mesh/crypto.h @@ -127,14 +127,24 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, uint32_t iv_index, bool proxy); -int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct net_buf_simple *buf, const uint8_t *ad, - uint16_t src, uint16_t dst, uint32_t seq_num, uint32_t iv_index); -int bt_mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct net_buf_simple *buf, struct net_buf_simple *out, - const uint8_t *ad, uint16_t src, uint16_t dst, uint32_t seq_num, - uint32_t iv_index); +struct bt_mesh_app_crypto_ctx { + bool dev_key; + uint8_t aszmic; + uint16_t src; + uint16_t dst; + uint32_t seq_num; + uint32_t iv_index; + const uint8_t *ad; +}; + +int bt_mesh_app_encrypt(const uint8_t key[16], + const struct bt_mesh_app_crypto_ctx *ctx, + struct net_buf_simple *buf); + +int bt_mesh_app_decrypt(const uint8_t key[16], + const struct bt_mesh_app_crypto_ctx *ctx, + struct net_buf_simple *buf, struct net_buf_simple *out); uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len); diff --git a/subsys/bluetooth/mesh/foundation.h b/subsys/bluetooth/mesh/foundation.h index 8afadd24d4e..f0589dec636 100644 --- a/subsys/bluetooth/mesh/foundation.h +++ b/subsys/bluetooth/mesh/foundation.h @@ -145,11 +145,6 @@ uint8_t bt_mesh_beacon_get(void); uint8_t bt_mesh_gatt_proxy_get(void); uint8_t bt_mesh_default_ttl_get(void); -void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store); - -struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx); -void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store); - #include static inline void key_idx_pack(struct net_buf_simple *buf, diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index e229ecb477a..be3b0d86115 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -22,6 +22,7 @@ #include "adv.h" #include "mesh.h" #include "net.h" +#include "app_keys.h" #include "transport.h" #include "access.h" #include "foundation.h" @@ -85,7 +86,7 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (valid && !frnd->valid) { + if (valid && !frnd->subnet) { continue; } @@ -93,7 +94,8 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, continue; } - if (net_idx != BT_MESH_KEY_ANY && frnd->net_idx != net_idx) { + if (net_idx != BT_MESH_KEY_ANY && + (!frnd->subnet || frnd->subnet->net_idx != net_idx)) { continue; } @@ -105,6 +107,14 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, return NULL; } +static int friend_cred_create(struct bt_mesh_friend *frnd, uint8_t idx) +{ + return bt_mesh_friend_cred_create(&frnd->cred[idx], frnd->lpn, + bt_mesh_primary_addr(), + frnd->lpn_counter, frnd->counter, + frnd->subnet->keys[idx].net); +} + static void purge_buffers(sys_slist_t *list) { while (!sys_slist_is_empty(list)) { @@ -141,7 +151,7 @@ static void friend_clear(struct bt_mesh_friend *frnd) k_delayed_work_cancel(&frnd->timer); - friend_cred_del(frnd->net_idx, frnd->lpn); + memset(frnd->cred, 0, sizeof(frnd->cred)); if (frnd->last) { /* Cancel the sending if necessary */ @@ -162,7 +172,7 @@ static void friend_clear(struct bt_mesh_friend *frnd) seg->seg_count = 0U; } - frnd->valid = 0U; + frnd->subnet = NULL; frnd->established = 0U; frnd->pending_buf = 0U; frnd->fsn = 0U; @@ -171,22 +181,20 @@ static void friend_clear(struct bt_mesh_friend *frnd) (void)memset(frnd->sub_list, 0, sizeof(frnd->sub_list)); } -void bt_mesh_friend_clear_net_idx(uint16_t net_idx) +void bt_mesh_friends_clear(void) { int i; - BT_DBG("net_idx 0x%04x", net_idx); + BT_DBG(""); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (frnd->net_idx == BT_MESH_KEY_UNUSED) { + if (!frnd->subnet) { continue; } - if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) { - friend_clear(frnd); - } + friend_clear(frnd); } } @@ -201,11 +209,12 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (frnd->net_idx == BT_MESH_KEY_UNUSED) { + if (!frnd->subnet) { continue; } - if (net_idx == BT_MESH_KEY_ANY || frnd->net_idx == net_idx) { + if (net_idx == BT_MESH_KEY_ANY || + frnd->subnet->net_idx == net_idx) { enqueue_update(frnd, 0x00); } } @@ -323,12 +332,10 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, } struct unseg_app_sdu_meta { - struct bt_mesh_net_rx net; + struct bt_mesh_app_crypto_ctx crypto; const uint8_t *key; struct bt_mesh_subnet *subnet; - bool is_dev_key; uint8_t aid; - uint8_t *ad; }; static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, @@ -336,24 +343,30 @@ 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; + struct bt_mesh_net_rx net; int err; - meta->subnet = bt_mesh_subnet_get(frnd->net_idx); - meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx); - bt_mesh_net_header_parse(&buf->b, &meta->net); - err = bt_mesh_app_key_get(meta->subnet, app_idx, meta->net.ctx.recv_dst, - &meta->key, &meta->aid); + meta->subnet = frnd->subnet; + bt_mesh_net_header_parse(&buf->b, &net); + err = bt_mesh_keys_resolve(&net.ctx, &net.sub, &meta->key, &meta->aid); if (err) { return err; } - if (BT_MESH_ADDR_IS_VIRTUAL(meta->net.ctx.recv_dst)) { - meta->ad = bt_mesh_label_uuid_get(meta->net.ctx.recv_dst); - if (!meta->ad) { + meta->crypto.src = net.ctx.addr; + meta->crypto.dst = net.ctx.recv_dst; + meta->crypto.iv_index = BT_MESH_NET_IVI_TX; + meta->crypto.dev_key = BT_MESH_IS_DEV_KEY(app_idx); + meta->crypto.seq_num = net.seq; + meta->crypto.aszmic = 0; + + if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) { + meta->crypto.ad = bt_mesh_label_uuid_get(meta->crypto.dst); + if (!meta->crypto.ad) { return -ENOENT; } } else { - meta->ad = NULL; + meta->crypto.ad = NULL; } return 0; @@ -369,10 +382,7 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; - return bt_mesh_app_decrypt(meta->key, meta->is_dev_key, 0, &sdu, &sdu, - meta->ad, meta->net.ctx.addr, - meta->net.ctx.recv_dst, meta->net.seq, - BT_MESH_NET_IVI_TX); + return bt_mesh_app_decrypt(meta->key, &meta->crypto, &sdu, &sdu); } static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, @@ -385,10 +395,7 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; - return bt_mesh_app_encrypt(meta->key, meta->is_dev_key, 0, &sdu, - meta->ad, meta->net.ctx.addr, - meta->net.ctx.recv_dst, bt_mesh.seq, - BT_MESH_NET_IVI_TX); + return bt_mesh_app_encrypt(meta->key, &meta->crypto, &sdu); } static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, @@ -409,7 +416,7 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, /* No need to reencrypt the message if the sequence number is * unchanged. */ - if (meta.net.seq == bt_mesh.seq) { + if (meta.crypto.seq_num == bt_mesh.seq) { return 0; } @@ -430,22 +437,16 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, bool master_cred) { - struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx); - const uint8_t *enc, *priv; + const struct bt_mesh_net_cred *cred; uint32_t iv_index; uint16_t src; - uint8_t nid; int err; if (master_cred) { - enc = sub->keys[sub->kr_flag].enc; - priv = sub->keys[sub->kr_flag].privacy; - nid = sub->keys[sub->kr_flag].nid; + cred = &frnd->subnet->keys[SUBNET_KEY_TX_IDX(frnd->subnet)] + .msg; } else { - if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) { - BT_ERR("friend_cred_get failed"); - return -ENOENT; - } + cred = &frnd->cred[SUBNET_KEY_TX_IDX(frnd->subnet)]; } src = sys_get_be16(&buf->data[5]); @@ -470,14 +471,14 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi)); } - buf->data[0] = (nid | (iv_index & 1) << 7); + buf->data[0] = (cred->nid | (iv_index & 1) << 7); - if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false)) { + if (bt_mesh_net_encrypt(cred->enc, &buf->b, iv_index, false)) { BT_ERR("Encrypting failed"); return -EINVAL; } - if (bt_mesh_net_obfuscate(buf->data, iv_index, priv)) { + if (bt_mesh_net_obfuscate(buf->data, iv_index, cred->privacy)) { BT_ERR("Obfuscating failed"); return -EINVAL; } @@ -512,16 +513,15 @@ static struct net_buf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) { struct bt_mesh_ctl_friend_update *upd; NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*upd)); - struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx); - __ASSERT_NO_MSG(sub != NULL); + __ASSERT_NO_MSG(frnd->subnet); BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); net_buf_simple_reserve(&sdu, 1); upd = net_buf_simple_add(&sdu, sizeof(*upd)); - upd->flags = bt_mesh_net_flags(sub); + upd->flags = bt_mesh_net_flags(frnd->subnet); upd->iv_index = sys_cpu_to_be32(bt_mesh.iv_index); upd->md = md; @@ -742,13 +742,13 @@ static const struct bt_mesh_send_cb clear_sent_cb = { static void send_friend_clear(struct bt_mesh_friend *frnd) { struct bt_mesh_msg_ctx ctx = { - .net_idx = frnd->net_idx, + .net_idx = frnd->subnet->net_idx, .app_idx = BT_MESH_KEY_UNUSED, .addr = frnd->clear.frnd, .send_ttl = BT_MESH_TTL_MAX, }; struct bt_mesh_net_tx tx = { - .sub = bt_mesh_subnet_get(frnd->net_idx), + .sub = frnd->subnet, .ctx = &ctx, .src = bt_mesh_primary_addr(), .xmit = bt_mesh_net_transmit_get(), @@ -903,7 +903,7 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) struct bt_mesh_ctl_friend_req *msg = (void *)buf->data; struct bt_mesh_friend *frnd = NULL; uint32_t poll_to; - int i; + int i, err; if (rx->net_if == BT_MESH_NET_IF_LOCAL) { BT_DBG("Ignoring Friend request from local interface"); @@ -957,9 +957,8 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { - if (!bt_mesh.frnd[i].valid) { + if (!bt_mesh.frnd[i].subnet) { frnd = &bt_mesh.frnd[i]; - frnd->valid = 1U; break; } } @@ -972,12 +971,19 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) init_friend: frnd->lpn = rx->ctx.addr; frnd->num_elem = msg->num_elem; - frnd->net_idx = rx->sub->net_idx; + frnd->subnet = rx->sub; frnd->recv_delay = msg->recv_delay; frnd->poll_to = poll_to * 100U; frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter); frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr); + err = friend_cred_create(frnd, SUBNET_KEY_TX_IDX(frnd->subnet)); + if (err) { + BT_ERR("Failed to create friend credentials"); + friend_clear(frnd); + return -EIO; + } + BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums", frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, frnd->poll_to); @@ -990,9 +996,6 @@ init_friend: K_MSEC(offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria))); - friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, - frnd->counter); - enqueue_offer(frnd, rx->ctx.recv_rssi); return 0; @@ -1207,6 +1210,53 @@ send_last: bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); } +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + int i, err; + + if (evt == BT_MESH_KEY_ADDED) { + return; + } + + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (frnd->subnet != sub) { + continue; + } + + switch (evt) { + case BT_MESH_KEY_DELETED: + BT_DBG("Cleared network for 0x%04x", frnd->lpn); + friend_clear(frnd); + break; + case BT_MESH_KEY_UPDATED: + BT_DBG("Generating new keys for 0x%04x", frnd->lpn); + err = friend_cred_create(frnd, 1); + if (err) { + BT_ERR("Failed updating friend cred for 0x%04x", + frnd->lpn); + friend_clear(frnd); + break; + } + + enqueue_update(frnd, 0); + break; + case BT_MESH_KEY_REVOKED: + BT_DBG("Revoking old keys for 0x%04x", frnd->lpn); + memcpy(&frnd->cred[0], &frnd->cred[1], + sizeof(frnd->cred[0])); + memset(&frnd->cred[1], 0, sizeof(frnd->cred[1])); + enqueue_update(frnd, 0); + break; + default: + break; + } + } +} + +BT_MESH_SUBNET_CB_DEFINE(subnet_evt); + int bt_mesh_friend_init(void) { int i; @@ -1215,8 +1265,6 @@ int bt_mesh_friend_init(void) struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; int j; - frnd->net_idx = BT_MESH_KEY_UNUSED; - sys_slist_init(&frnd->queue); k_delayed_work_init(&frnd->timer, friend_timeout); @@ -1394,7 +1442,7 @@ static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, return false; } - if (net_idx != frnd->net_idx) { + if (net_idx != frnd->subnet->net_idx) { return false; } diff --git a/subsys/bluetooth/mesh/friend.h b/subsys/bluetooth/mesh/friend.h index 6ea397d54b9..8736f36974b 100644 --- a/subsys/bluetooth/mesh/friend.h +++ b/subsys/bluetooth/mesh/friend.h @@ -34,7 +34,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, void bt_mesh_friend_sec_update(uint16_t net_idx); -void bt_mesh_friend_clear_net_idx(uint16_t net_idx); +void bt_mesh_friends_clear(void); int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 6e9d20cf01a..98bf3e0b7b5 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -175,20 +175,20 @@ static const struct bt_mesh_send_cb clear_sent_cb = { static int send_friend_clear(void) { struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, + .net_idx = bt_mesh.lpn.sub->net_idx, .app_idx = BT_MESH_KEY_UNUSED, .addr = bt_mesh.lpn.frnd, .send_ttl = 0, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], + .sub = bt_mesh.lpn.sub, .ctx = &ctx, .src = bt_mesh_primary_addr(), .xmit = bt_mesh_net_transmit_get(), }; struct bt_mesh_ctl_friend_clear req = { .lpn_addr = sys_cpu_to_be16(tx.src), - .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter), + .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.lpn_counter), }; BT_DBG(""); @@ -215,8 +215,6 @@ static void clear_friendship(bool force, bool disable) k_delayed_work_cancel(&lpn->timer); - friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd); - if (lpn->clear_success) { lpn->old_friend = BT_MESH_ADDR_UNASSIGNED; } else { @@ -236,6 +234,7 @@ static void clear_friendship(bool force, bool disable) lpn->sent_req = 0U; lpn->established = 0U; lpn->clear_success = 0U; + lpn->sub = NULL; group_zero(lpn->added); group_zero(lpn->pending); @@ -289,13 +288,13 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, + .net_idx = lpn->sub->net_idx, .app_idx = BT_MESH_KEY_UNUSED, .addr = BT_MESH_ADDR_FRIENDS, .send_ttl = 0, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], + .sub = bt_mesh.lpn.sub, .ctx = &ctx, .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, @@ -306,7 +305,7 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) .poll_to = LPN_POLL_TO, .prev_addr = sys_cpu_to_be16(lpn->old_friend), .num_elem = comp->elem_count, - .lpn_counter = sys_cpu_to_be16(lpn->counter), + .lpn_counter = sys_cpu_to_be16(lpn->lpn_counter), }; BT_DBG(""); @@ -355,13 +354,13 @@ static const struct bt_mesh_send_cb req_sent_cb = { static int send_friend_poll(void) { struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, + .net_idx = bt_mesh.lpn.sub->net_idx, .app_idx = BT_MESH_KEY_UNUSED, .addr = bt_mesh.lpn.frnd, .send_ttl = 0, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], + .sub = bt_mesh.lpn.sub, .ctx = &ctx, .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, @@ -482,13 +481,21 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) send_friend_poll(); } +static int friend_cred_create(struct bt_mesh_net_cred *cred, + const uint8_t key[16]) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + + return bt_mesh_friend_cred_create(cred, bt_mesh_primary_addr(), + lpn->frnd, lpn->lpn_counter, + lpn->frnd_counter, key); +} + int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { struct bt_mesh_ctl_friend_offer *msg = (void *)buf->data; struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - struct bt_mesh_subnet *sub = rx->sub; - struct friend_cred *cred; uint16_t frnd_counter; int err; @@ -513,16 +520,26 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi, frnd_counter); + lpn->frnd_counter = frnd_counter; lpn->frnd = rx->ctx.addr; + lpn->sub = rx->sub; - cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter); - if (!cred) { - lpn->frnd = BT_MESH_ADDR_UNASSIGNED; - return -ENOMEM; + /* Create friend credentials for each of the valid keys in the + * friendship subnet: + */ + for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) { + if (!lpn->sub->keys[i].valid) { + continue; + } + + err = friend_cred_create(&lpn->cred[i], lpn->sub->keys[i].net); + if (err) { + lpn->frnd = BT_MESH_ADDR_UNASSIGNED; + return err; + } } /* TODO: Add offer acceptance criteria check */ - k_delayed_work_cancel(&lpn->timer); lpn->recv_win = msg->recv_win; @@ -530,14 +547,14 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, err = send_friend_poll(); if (err) { - friend_cred_clear(cred); + lpn->sub = NULL; lpn->frnd = BT_MESH_ADDR_UNASSIGNED; lpn->recv_win = 0U; lpn->queue_size = 0U; return err; } - lpn->counter++; + lpn->lpn_counter++; return 0; } @@ -564,7 +581,7 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter); - if (addr != bt_mesh_primary_addr() || counter != lpn->counter) { + if (addr != bt_mesh_primary_addr() || counter != lpn->lpn_counter) { BT_WARN("Invalid parameters in Friend Clear Confirm"); return 0; } @@ -637,13 +654,13 @@ static bool sub_update(uint8_t op) struct bt_mesh_lpn *lpn = &bt_mesh.lpn; int added_count = group_popcount(lpn->added); struct bt_mesh_msg_ctx ctx = { - .net_idx = bt_mesh.sub[0].net_idx, + .net_idx = lpn->sub->net_idx, .app_idx = BT_MESH_KEY_UNUSED, .addr = lpn->frnd, .send_ttl = 0, }; struct bt_mesh_net_tx tx = { - .sub = &bt_mesh.sub[0], + .sub = lpn->sub, .ctx = &ctx, .src = bt_mesh_primary_addr(), .xmit = POLL_XMIT, @@ -764,7 +781,7 @@ static void lpn_timeout(struct k_work *work) if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { bt_mesh_scan_disable(); } - lpn->counter++; + lpn->lpn_counter++; lpn_set_state(BT_MESH_LPN_ENABLED); lpn->sent_req = 0U; k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); @@ -985,11 +1002,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags, iv_index, msg->md); - if (bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags), - rx->new_key)) { - bt_mesh_net_beacon_update(sub); - } - + bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags), rx->new_key); bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags)); if (lpn->groups_changed) { @@ -1029,6 +1042,26 @@ void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established)) lpn_cb = cb; } +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + switch (evt) { + case BT_MESH_KEY_DELETED: + if (sub == bt_mesh.lpn.sub) { + BT_DBG("NetKey deleted"); + clear_friendship(true, false); + } + break; + case BT_MESH_KEY_UPDATED: + BT_DBG("NetKey updated"); + friend_cred_create(&bt_mesh.lpn.cred[1], sub->keys[1].net); + break; + default: + break; + } +} + +BT_MESH_SUBNET_CB_DEFINE(subnet_evt); + int bt_mesh_lpn_init(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index dc4633f1f37..499e3360014 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 "app_keys.h" #include "rpl.h" #include "beacon.h" #include "lpn.h" @@ -129,13 +130,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_lpn_group_add(BT_MESH_ADDR_ALL_NODES); } - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing network information persistently"); - bt_mesh_store_net(); - bt_mesh_store_subnet(&bt_mesh.sub[0]); - bt_mesh_store_iv(false); - } - bt_mesh_start(); return 0; @@ -178,6 +172,8 @@ void bt_mesh_reset(void) bt_mesh_rx_reset(); bt_mesh_tx_reset(); + bt_mesh_app_keys_reset(); + bt_mesh_net_keys_reset(); bt_mesh_net_loopback_clear(BT_MESH_KEY_ANY); @@ -192,7 +188,7 @@ void bt_mesh_reset(void) } if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY); + bt_mesh_friends_clear(); } if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { diff --git a/subsys/bluetooth/mesh/mesh.h b/subsys/bluetooth/mesh/mesh.h index 78fc4572db5..8285cbeb2dc 100644 --- a/subsys/bluetooth/mesh/mesh.h +++ b/subsys/bluetooth/mesh/mesh.h @@ -7,13 +7,39 @@ */ #define BT_MESH_KEY_PRIMARY 0x0000 -#define BT_MESH_KEY_ANY 0xffff #define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) #define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00) #define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000) #define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb) +enum bt_mesh_key_evt { + BT_MESH_KEY_ADDED, /* New key added */ + BT_MESH_KEY_DELETED, /* Existing key deleted */ + BT_MESH_KEY_UPDATED, /* KR phase 1, second key added */ + BT_MESH_KEY_SWAPPED, /* KR phase 2, now sending on second key */ + BT_MESH_KEY_REVOKED, /* KR phase 3, old key removed */ +}; + +/** Appkey callback. Instantiate with @ref BT_MESH_APP_KEY_CB */ +struct bt_mesh_app_key_cb { + void (*evt_handler)(uint16_t app_idx, uint16_t net_idx, + enum bt_mesh_key_evt evt); +}; + +/** @def BT_MESH_APP_KEY_CB + * + * @brief Register an AppKey event callback. + * + * @param _handler Handler function, see @ref bt_mesh_app_key_cb::evt_handler. + */ +#define BT_MESH_APP_KEY_CB_DEFINE(_handler) \ + static const Z_STRUCT_SECTION_ITERABLE(bt_mesh_app_key_cb, \ + _CONCAT(bt_mesh_app_key_cb_, \ + _handler)) = { \ + .evt_handler = (_handler), \ + } + struct bt_mesh_net; int bt_mesh_start(void); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 7bcbe7b8b15..0e706d10836 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -61,17 +61,6 @@ #define SRC(pdu) (sys_get_be16(&(pdu)[5])) #define DST(pdu) (sys_get_be16(&(pdu)[7])) -/* Determine how many friendship credentials we need */ -#if defined(CONFIG_BT_MESH_FRIEND) -#define FRIEND_CRED_COUNT CONFIG_BT_MESH_FRIEND_LPN_COUNT -#elif defined(CONFIG_BT_MESH_LOW_POWER) -#define FRIEND_CRED_COUNT CONFIG_BT_MESH_SUBNET_COUNT -#else -#define FRIEND_CRED_COUNT 0 -#endif - -static struct friend_cred friend_cred[FRIEND_CRED_COUNT]; - static struct { uint32_t src : 15, /* MSb of source is always 0 */ seq : 17; @@ -81,16 +70,6 @@ static uint16_t msg_cache_next; /* Singleton network context (the implementation only supports one) */ struct bt_mesh_net bt_mesh = { .local_queue = SYS_SLIST_STATIC_INIT(&bt_mesh.local_queue), - .sub = { - [0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, - .app_keys = { - [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, }; NET_BUF_POOL_DEFINE(loopback_buf_pool, CONFIG_BT_MESH_LOOPBACK_BUFS, @@ -141,330 +120,29 @@ static void msg_cache_add(struct bt_mesh_net_rx *rx) msg_cache_next %= ARRAY_SIZE(msg_cache); } -struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) -{ - int i; - - if (net_idx == BT_MESH_KEY_ANY) { - return &bt_mesh.sub[0]; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx == net_idx) { - return &bt_mesh.sub[i]; - } - } - - return NULL; -} - -int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, - const uint8_t key[16]) -{ - uint8_t p[] = { 0 }; - uint8_t nid; - int err; - - err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->enc, keys->privacy); - if (err) { - BT_ERR("Unable to generate NID, EncKey & PrivacyKey"); - return err; - } - - memcpy(keys->net, key, 16); - - keys->nid = nid; - - BT_DBG("NID 0x%02x EncKey %s", keys->nid, bt_hex(keys->enc, 16)); - BT_DBG("PrivacyKey %s", bt_hex(keys->privacy, 16)); - - err = bt_mesh_k3(key, keys->net_id); - if (err) { - BT_ERR("Unable to generate Net ID"); - return err; - } - - BT_DBG("NetID %s", bt_hex(keys->net_id, 8)); - -#if defined(CONFIG_BT_MESH_GATT_PROXY) - err = bt_mesh_identity_key(key, keys->identity); - if (err) { - BT_ERR("Unable to generate IdentityKey"); - return err; - } - - BT_DBG("IdentityKey %s", bt_hex(keys->identity, 16)); -#endif /* GATT_PROXY */ - - err = bt_mesh_beacon_key(key, keys->beacon); - if (err) { - BT_ERR("Unable to generate beacon key"); - return err; - } - - BT_DBG("BeaconKey %s", bt_hex(keys->beacon, 16)); - - return 0; -} - -int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key[16]) -{ - uint16_t lpn_addr, frnd_addr; - int err; - uint8_t p[9]; - -#if defined(CONFIG_BT_MESH_LOW_POWER) - if (cred->addr == bt_mesh.lpn.frnd) { - lpn_addr = bt_mesh_primary_addr(); - frnd_addr = cred->addr; - } else { - lpn_addr = cred->addr; - frnd_addr = bt_mesh_primary_addr(); - } -#else - lpn_addr = cred->addr; - frnd_addr = bt_mesh_primary_addr(); -#endif - - BT_DBG("LPNAddress 0x%04x FriendAddress 0x%04x", lpn_addr, frnd_addr); - BT_DBG("LPNCounter 0x%04x FriendCounter 0x%04x", cred->lpn_counter, - cred->frnd_counter); - - p[0] = 0x01; - sys_put_be16(lpn_addr, p + 1); - sys_put_be16(frnd_addr, p + 3); - sys_put_be16(cred->lpn_counter, p + 5); - sys_put_be16(cred->frnd_counter, p + 7); - - err = bt_mesh_k2(net_key, p, sizeof(p), &cred->cred[idx].nid, - cred->cred[idx].enc, cred->cred[idx].privacy); - if (err) { - BT_ERR("Unable to generate NID, EncKey & PrivacyKey"); - return err; - } - - BT_DBG("Friend NID 0x%02x EncKey %s", cred->cred[idx].nid, - bt_hex(cred->cred[idx].enc, 16)); - BT_DBG("Friend PrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); - - return 0; -} - -void friend_cred_refresh(uint16_t net_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { - struct friend_cred *cred = &friend_cred[i]; - - if (cred->addr != BT_MESH_ADDR_UNASSIGNED && - cred->net_idx == net_idx) { - memcpy(&cred->cred[0], &cred->cred[1], - sizeof(cred->cred[0])); - } - } -} - -int friend_cred_update(struct bt_mesh_subnet *sub) -{ - int err, i; - - BT_DBG("net_idx 0x%04x", sub->net_idx); - - for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { - struct friend_cred *cred = &friend_cred[i]; - - if (cred->addr == BT_MESH_ADDR_UNASSIGNED || - cred->net_idx != sub->net_idx) { - continue; - } - - err = friend_cred_set(cred, 1, sub->keys[1].net); - if (err) { - return err; - } - } - - return 0; -} - -struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr, - uint16_t lpn_counter, uint16_t frnd_counter) -{ - struct friend_cred *cred; - int i, err; - - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); - - for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) { - if ((friend_cred[i].addr == BT_MESH_ADDR_UNASSIGNED) || - (friend_cred[i].addr == addr && - friend_cred[i].net_idx == sub->net_idx)) { - cred = &friend_cred[i]; - break; - } - } - - if (!cred) { - BT_WARN("No free friend credential slots"); - return NULL; - } - - cred->net_idx = sub->net_idx; - cred->addr = addr; - cred->lpn_counter = lpn_counter; - cred->frnd_counter = frnd_counter; - - err = friend_cred_set(cred, 0, sub->keys[0].net); - if (err) { - friend_cred_clear(cred); - return NULL; - } - - if (sub->kr_flag) { - err = friend_cred_set(cred, 1, sub->keys[1].net); - if (err) { - friend_cred_clear(cred); - return NULL; - } - } - - return cred; -} - -void friend_cred_clear(struct friend_cred *cred) -{ - cred->net_idx = BT_MESH_KEY_UNUSED; - cred->addr = BT_MESH_ADDR_UNASSIGNED; - cred->lpn_counter = 0U; - cred->frnd_counter = 0U; - (void)memset(cred->cred, 0, sizeof(cred->cred)); -} - -int friend_cred_del(uint16_t net_idx, uint16_t addr) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { - struct friend_cred *cred = &friend_cred[i]; - - if (cred->addr == addr && cred->net_idx == net_idx) { - friend_cred_clear(cred); - return 0; - } - } - - return -ENOENT; -} - -int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, - const uint8_t **enc, const uint8_t **priv) -{ - int i; - - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); - - for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { - struct friend_cred *cred = &friend_cred[i]; - - if (cred->net_idx != sub->net_idx) { - continue; - } - - if (addr != BT_MESH_ADDR_UNASSIGNED && cred->addr != addr) { - continue; - } - - if (nid) { - *nid = cred->cred[sub->kr_flag].nid; - } - - if (enc) { - *enc = cred->cred[sub->kr_flag].enc; - } - - if (priv) { - *priv = cred->cred[sub->kr_flag].privacy; - } - - return 0; - } - - return -ENOENT; -} - -uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) -{ - uint8_t flags = 0x00; - - if (sub && sub->kr_flag) { - flags |= BT_MESH_NET_FLAG_KR; - } - - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { - flags |= BT_MESH_NET_FLAG_IVU; - } - - return flags; -} - -int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub) -{ - uint8_t flags = bt_mesh_net_flags(sub); - struct bt_mesh_subnet_keys *keys; - - if (sub->kr_flag) { - BT_DBG("NetIndex %u Using new key", sub->net_idx); - keys = &sub->keys[1]; - } else { - BT_DBG("NetIndex %u Using current key", sub->net_idx); - keys = &sub->keys[0]; - } - - BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); - - return bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, - bt_mesh.iv_index, sub->auth); -} - int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index) { - struct bt_mesh_subnet *sub; int err; BT_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); BT_DBG("NetKey %s", bt_hex(key, 16)); + if (BT_MESH_KEY_REFRESH(flags)) { + err = bt_mesh_subnet_set(idx, BT_MESH_KR_PHASE_2, NULL, key); + } else { + err = bt_mesh_subnet_set(idx, BT_MESH_KR_NORMAL, key, NULL); + } + + if (err) { + BT_ERR("Failed creating subnet"); + return err; + } + (void)memset(msg_cache, 0, sizeof(msg_cache)); msg_cache_next = 0U; - sub = &bt_mesh.sub[0]; - - sub->kr_flag = BT_MESH_KEY_REFRESH(flags); - if (sub->kr_flag) { - err = bt_mesh_net_keys_create(&sub->keys[1], key); - if (err) { - return -EIO; - } - - sub->kr_phase = BT_MESH_KR_PHASE_2; - } else { - err = bt_mesh_net_keys_create(&sub->keys[0], key); - if (err) { - return -EIO; - } - } - - sub->net_idx = idx; - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; - } else { - sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; - } - bt_mesh.iv_index = iv_index; atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, BT_MESH_IV_UPDATE(flags)); @@ -475,91 +153,16 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], */ bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; - /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + BT_DBG("Storing network information persistently"); + bt_mesh_store_net(); + bt_mesh_store_subnet(idx); + bt_mesh_store_iv(false); + } return 0; } -void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) -{ - int i; - - BT_DBG("idx 0x%04x", sub->net_idx); - - memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing Updated NetKey persistently"); - bt_mesh_store_subnet(sub); - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != sub->net_idx || !key->updated) { - continue; - } - - memcpy(&key->keys[0], &key->keys[1], sizeof(key->keys[0])); - key->updated = false; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing Updated AppKey persistently"); - bt_mesh_store_app_key(key); - } - } -} - -bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) -{ - if (new_kr != sub->kr_flag && sub->kr_phase == BT_MESH_KR_NORMAL) { - BT_WARN("KR change in normal operation. Are we blacklisted?"); - return false; - } - - sub->kr_flag = new_kr; - - if (sub->kr_flag) { - if (sub->kr_phase == BT_MESH_KR_PHASE_1) { - BT_DBG("Phase 1 -> Phase 2"); - sub->kr_phase = BT_MESH_KR_PHASE_2; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - BT_DBG("Storing krp phase persistently"); - bt_mesh_store_subnet(sub); - } - - return true; - } - } else { - switch (sub->kr_phase) { - case BT_MESH_KR_PHASE_1: - if (!new_key) { - /* Ignore */ - break; - } - /* Upon receiving a Secure Network beacon with the KR flag set - * to 0 using the new NetKey in Phase 1, the node shall - * immediately transition to Phase 3, which effectively skips - * Phase 2. - * - * Intentional fall-through. - */ - __fallthrough; - case BT_MESH_KR_PHASE_2: - BT_DBG("KR Phase 0x%02x -> Normal", sub->kr_phase); - bt_mesh_net_revoke_keys(sub); - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - friend_cred_refresh(sub->net_idx); - } - - sub->kr_phase = BT_MESH_KR_NORMAL; - return true; - } - } - - return false; -} - #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST) void bt_mesh_iv_update_test(bool enable) { @@ -581,29 +184,12 @@ bool bt_mesh_iv_update(void) bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); } - bt_mesh_net_sec_update(NULL); - return atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); } #endif /* CONFIG_BT_MESH_IV_UPDATE_TEST */ -/* Used for sending immediate beacons to Friend queues and GATT clients */ -void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) -{ - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - bt_mesh_friend_sec_update(sub ? sub->net_idx : BT_MESH_KEY_ANY); - } - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { - bt_mesh_proxy_beacon_send(sub); - } -} - bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) { - int i; - if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { /* We're currently in IV Update mode */ @@ -685,12 +271,18 @@ do_update: k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx != BT_MESH_KEY_UNUSED) { - bt_mesh_net_beacon_update(&bt_mesh.sub[i]); - } + /* Notify other modules */ + if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { + bt_mesh_friend_sec_update(BT_MESH_KEY_ANY); } + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && + bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { + bt_mesh_proxy_beacon_send(NULL); + } + + bt_mesh_subnet_foreach(bt_mesh_beacon_update); + if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { bt_mesh_cdb_iv_update(iv_index, iv_update); } @@ -715,7 +307,6 @@ uint32_t bt_mesh_next_seq(void) bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY)) { bt_mesh_beacon_ivu_initiator(true); bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true); - bt_mesh_net_sec_update(NULL); } return seq; @@ -744,7 +335,7 @@ static void bt_mesh_net_local(struct k_work *work) .old_iv = (IVI(buf->data) != (bt_mesh.iv_index & 0x01)), .ctl = CTL(buf->data), .seq = SEQ(buf->data), - .new_key = sub->kr_flag, + .new_key = SUBNET_KEY_TX_IDX(sub), .local_match = 1U, .friend_match = 0U, }; @@ -757,26 +348,16 @@ static void bt_mesh_net_local(struct k_work *work) } } -static void net_tx_cred_get(struct bt_mesh_net_tx *tx, uint8_t *nid, - const uint8_t **enc, const uint8_t **priv) +static const struct bt_mesh_net_cred *net_tx_cred_get(struct bt_mesh_net_tx *tx) { - if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || !tx->friend_cred) { - tx->friend_cred = 0U; - *nid = tx->sub->keys[tx->sub->kr_flag].nid; - *enc = tx->sub->keys[tx->sub->kr_flag].enc; - *priv = tx->sub->keys[tx->sub->kr_flag].privacy; - return; +#if defined(CONFIG_BT_MESH_LOW_POWER) + if (tx->friend_cred && bt_mesh_lpn_established()) { + return &bt_mesh.lpn.cred[SUBNET_KEY_TX_IDX(tx->sub)]; } +#endif - if (friend_cred_get(tx->sub, BT_MESH_ADDR_UNASSIGNED, nid, enc, priv)) { - BT_WARN("Falling back to master credentials"); - - tx->friend_cred = 0U; - - *nid = tx->sub->keys[tx->sub->kr_flag].nid; - *enc = tx->sub->keys[tx->sub->kr_flag].enc; - *priv = tx->sub->keys[tx->sub->kr_flag].privacy; - } + tx->friend_cred = 0U; + return &tx->sub->keys[SUBNET_KEY_TX_IDX(tx->sub)].msg; } static int net_header_encode(struct bt_mesh_net_tx *tx, uint8_t nid, @@ -810,26 +391,33 @@ static int net_header_encode(struct bt_mesh_net_tx *tx, uint8_t nid, return 0; } +static int net_encrypt(struct net_buf_simple *buf, + const struct bt_mesh_net_cred *cred, uint32_t iv_index, + bool proxy) +{ + int err; + + err = bt_mesh_net_encrypt(cred->enc, buf, iv_index, proxy); + if (err) { + return err; + } + + return bt_mesh_net_obfuscate(buf->data, iv_index, cred->privacy); +} + int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, bool proxy) { - const uint8_t *enc, *priv; - uint8_t nid; + const struct bt_mesh_net_cred *cred; int err; - net_tx_cred_get(tx, &nid, &enc, &priv); - - err = net_header_encode(tx, nid, buf); + cred = net_tx_cred_get(tx); + err = net_header_encode(tx, cred->nid, buf); if (err) { return err; } - err = bt_mesh_net_encrypt(enc, buf, BT_MESH_NET_IVI_TX, proxy); - if (err) { - return err; - } - - return bt_mesh_net_obfuscate(buf->data, BT_MESH_NET_IVI_TX, priv); + return net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, proxy); } static int loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, @@ -859,8 +447,7 @@ static int loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { - const uint8_t *enc, *priv; - uint8_t nid; + const struct bt_mesh_net_cred *cred; int err; BT_DBG("src 0x%04x dst 0x%04x len %u headroom %zu tailroom %zu", @@ -873,8 +460,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, tx->ctx->send_ttl = bt_mesh_default_ttl_get(); } - net_tx_cred_get(tx, &nid, &enc, &priv); - err = net_header_encode(tx, nid, &buf->b); + cred = net_tx_cred_get(tx); + err = net_header_encode(tx, cred->nid, &buf->b); if (err) { goto done; } @@ -905,12 +492,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, goto done; } - err = bt_mesh_net_encrypt(enc, &buf->b, BT_MESH_NET_IVI_TX, false); - if (err) { - goto done; - } - - err = bt_mesh_net_obfuscate(buf->data, BT_MESH_NET_IVI_TX, priv); + err = net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_TX, false); if (err) { goto done; } @@ -956,186 +538,49 @@ void bt_mesh_net_loopback_clear(uint16_t net_idx) bt_mesh.local_queue = new_list; } -static bool auth_match(struct bt_mesh_subnet_keys *keys, - const uint8_t net_id[8], uint8_t flags, - uint32_t iv_index, const uint8_t auth[8]) +static bool net_decrypt(struct bt_mesh_net_rx *rx, struct net_buf_simple *in, + struct net_buf_simple *out, + const struct bt_mesh_net_cred *cred) { - uint8_t net_auth[8]; + bool proxy = (rx->net_if == BT_MESH_NET_IF_PROXY_CFG); - if (memcmp(net_id, keys->net_id, 8)) { + if (NID(in->data) != cred->nid) { return false; } - bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, iv_index, - net_auth); + BT_DBG("NID 0x%02x", NID(in->data)); + BT_DBG("IVI %u net->iv_index 0x%08x", IVI(in->data), bt_mesh.iv_index); - if (memcmp(auth, net_auth, 8)) { - BT_WARN("Authentication Value %s", bt_hex(auth, 8)); - BT_WARN(" != %s", bt_hex(net_auth, 8)); + rx->old_iv = (IVI(in->data) != (bt_mesh.iv_index & 0x01)); + + net_buf_simple_reset(out); + net_buf_simple_add_mem(out, in->data, in->len); + + if (bt_mesh_net_obfuscate(out->data, BT_MESH_NET_IVI_RX(rx), + cred->privacy)) { return false; } - return true; -} - -struct bt_mesh_subnet *bt_mesh_subnet_find(const uint8_t net_id[8], uint8_t flags, - uint32_t iv_index, const uint8_t auth[8], - bool *new_key) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (auth_match(&sub->keys[0], net_id, flags, iv_index, auth)) { - *new_key = false; - return sub; - } - - if (sub->kr_phase == BT_MESH_KR_NORMAL) { - continue; - } - - if (auth_match(&sub->keys[1], net_id, flags, iv_index, auth)) { - *new_key = true; - return sub; - } - } - - return NULL; -} - -static int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, - const uint8_t *priv, const uint8_t *data, - size_t data_len, struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf) -{ - BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); - BT_DBG("IVI %u net->iv_index 0x%08x", IVI(data), bt_mesh.iv_index); - - rx->old_iv = (IVI(data) != (bt_mesh.iv_index & 0x01)); - - net_buf_simple_reset(buf); - memcpy(net_buf_simple_add(buf, data_len), data, data_len); - - if (bt_mesh_net_obfuscate(buf->data, BT_MESH_NET_IVI_RX(rx), priv)) { - return -ENOENT; - } - - rx->ctx.addr = SRC(buf->data); + rx->ctx.addr = SRC(out->data); if (!BT_MESH_ADDR_IS_UNICAST(rx->ctx.addr)) { BT_DBG("Ignoring non-unicast src addr 0x%04x", rx->ctx.addr); - return -EINVAL; + return false; } if (bt_mesh_elem_find(rx->ctx.addr)) { BT_DBG("Dropping locally originated packet"); - return -EBADMSG; + return false; } - if (rx->net_if == BT_MESH_NET_IF_ADV && msg_cache_match(buf)) { + if (rx->net_if == BT_MESH_NET_IF_ADV && msg_cache_match(out)) { BT_DBG("Duplicate found in Network Message Cache"); - return -EALREADY; + return false; } BT_DBG("src 0x%04x", rx->ctx.addr); - if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && - rx->net_if == BT_MESH_NET_IF_PROXY_CFG) { - return bt_mesh_net_decrypt(enc, buf, BT_MESH_NET_IVI_RX(rx), - true); - } - - return bt_mesh_net_decrypt(enc, buf, BT_MESH_NET_IVI_RX(rx), false); -} - -static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, - size_t data_len, struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf) -{ - int i; - - BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx); - - for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { - struct friend_cred *cred = &friend_cred[i]; - - if (cred->net_idx != sub->net_idx) { - continue; - } - - if (NID(data) == cred->cred[0].nid && - !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, - data, data_len, rx, buf)) { - return 0; - } - - if (sub->kr_phase == BT_MESH_KR_NORMAL) { - continue; - } - - if (NID(data) == cred->cred[1].nid && - !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, - data, data_len, rx, buf)) { - rx->new_key = 1U; - return 0; - } - } - - return -ENOENT; -} - -static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, - struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf) -{ - struct bt_mesh_subnet *sub; - int i; - - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - sub = &bt_mesh.sub[i]; - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if ((IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) || - IS_ENABLED(CONFIG_BT_MESH_FRIEND)) && - !friend_decrypt(sub, data, data_len, rx, buf)) { - rx->friend_cred = 1U; - rx->ctx.net_idx = sub->net_idx; - rx->sub = sub; - return true; - } - - if (NID(data) == sub->keys[0].nid && - !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, - data, data_len, rx, buf)) { - rx->ctx.net_idx = sub->net_idx; - rx->sub = sub; - return true; - } - - if (sub->kr_phase == BT_MESH_KR_NORMAL) { - continue; - } - - if (NID(data) == sub->keys[1].nid && - !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, - data, data_len, rx, buf)) { - rx->new_key = 1U; - rx->ctx.net_idx = sub->net_idx; - rx->sub = sub; - return true; - } - } - - return false; + return bt_mesh_net_decrypt(cred->enc, out, BT_MESH_NET_IVI_RX(rx), + proxy) == 0; } /* Relaying from advertising to the advertising bearer should only happen @@ -1158,9 +603,9 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) static void bt_mesh_net_relay(struct net_buf_simple *sbuf, struct bt_mesh_net_rx *rx) { - const uint8_t *enc, *priv; + const struct bt_mesh_net_cred *cred; struct net_buf *buf; - uint8_t nid, transmit; + uint8_t transmit; if (rx->ctx.recv_ttl <= 1U) { return; @@ -1197,32 +642,25 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, net_buf_add_mem(buf, sbuf->data, sbuf->len); - enc = rx->sub->keys[rx->sub->kr_flag].enc; - priv = rx->sub->keys[rx->sub->kr_flag].privacy; - nid = rx->sub->keys[rx->sub->kr_flag].nid; + cred = &rx->sub->keys[SUBNET_KEY_TX_IDX(rx->sub)].msg; BT_DBG("Relaying packet. TTL is now %u", TTL(buf->data)); /* Update NID if RX or RX was with friend credentials */ if (rx->friend_cred) { buf->data[0] &= 0x80; /* Clear everything except IVI */ - buf->data[0] |= nid; + buf->data[0] |= cred->nid; } /* We re-encrypt and obfuscate using the received IVI rather than * the normal TX IVI (which may be different) since the transport * layer nonce includes the IVI. */ - if (bt_mesh_net_encrypt(enc, &buf->b, BT_MESH_NET_IVI_RX(rx), false)) { + if (net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_RX(rx), false)) { BT_ERR("Re-encrypting failed"); goto done; } - if (bt_mesh_net_obfuscate(buf->data, BT_MESH_NET_IVI_RX(rx), priv)) { - BT_ERR("Re-obfuscating failed"); - goto done; - } - /* Sending to the GATT bearer should only happen if GATT Proxy * is enabled. */ @@ -1253,24 +691,24 @@ void bt_mesh_net_header_parse(struct net_buf_simple *buf, rx->ctx.recv_dst = DST(buf->data); } -int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) +int bt_mesh_net_decode(struct net_buf_simple *in, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct net_buf_simple *out) { - if (data->len < BT_MESH_NET_MIN_PDU_LEN) { - BT_WARN("Dropping too short mesh packet (len %u)", data->len); - BT_WARN("%s", bt_hex(data->data, data->len)); + if (in->len < BT_MESH_NET_MIN_PDU_LEN) { + BT_WARN("Dropping too short mesh packet (len %u)", in->len); + BT_WARN("%s", bt_hex(in->data, in->len)); return -EINVAL; } - if (net_if == BT_MESH_NET_IF_ADV && check_dup(data)) { + if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) { return -EINVAL; } - BT_DBG("%u bytes: %s", data->len, bt_hex(data->data, data->len)); + BT_DBG("%u bytes: %s", in->len, bt_hex(in->data, in->len)); rx->net_if = net_if; - if (!net_find_and_decrypt(data->data, data->len, rx, buf)) { + if (!bt_mesh_net_cred_find(rx, in, out, net_decrypt)) { BT_DBG("Unable to find matching net for packet"); return -ENOENT; } @@ -1278,7 +716,7 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, /* Initialize AppIdx to a sane value */ rx->ctx.app_idx = BT_MESH_KEY_UNUSED; - rx->ctx.recv_ttl = TTL(buf->data); + rx->ctx.recv_ttl = TTL(out->data); /* Default to responding with TTL 0 for non-routed messages */ if (rx->ctx.recv_ttl == 0U) { @@ -1287,11 +725,11 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT; } - rx->ctl = CTL(buf->data); - rx->seq = SEQ(buf->data); - rx->ctx.recv_dst = DST(buf->data); + rx->ctl = CTL(out->data); + rx->seq = SEQ(out->data); + rx->ctx.recv_dst = DST(out->data); - BT_DBG("Decryption successful. Payload len %u", buf->len); + BT_DBG("Decryption successful. Payload len %u", out->len); if (net_if != BT_MESH_NET_IF_PROXY_CFG && rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) { @@ -1301,7 +739,7 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_ttl); - BT_DBG("PDU: %s", bt_hex(buf->data, buf->len)); + BT_DBG("PDU: %s", bt_hex(out->data, out->len)); msg_cache_add(rx); @@ -1417,10 +855,10 @@ void bt_mesh_net_start(void) } if (IS_ENABLED(CONFIG_BT_MESH_PROV)) { - uint16_t net_idx = bt_mesh.sub[0].net_idx; + struct bt_mesh_subnet *sub = bt_mesh_subnet_next(NULL); uint16_t addr = bt_mesh_primary_addr(); - bt_mesh_prov_complete(net_idx, addr); + bt_mesh_prov_complete(sub->net_idx, addr); } } diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index 3f3c7324ed5..3f41409eb67 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -6,13 +6,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define BT_MESH_NET_FLAG_KR BIT(0) -#define BT_MESH_NET_FLAG_IVU BIT(1) - -#define BT_MESH_KR_NORMAL 0x00 -#define BT_MESH_KR_PHASE_1 0x01 -#define BT_MESH_KR_PHASE_2 0x02 -#define BT_MESH_KR_PHASE_3 0x03 +#include "subnet.h" #define BT_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01) #define BT_MESH_KEY_REFRESH(flags) (flags & 0x01) @@ -23,15 +17,7 @@ CONFIG_BT_MESH_IVU_DIVIDER) #define BT_MESH_IVU_TIMEOUT K_HOURS(BT_MESH_IVU_HOURS) -struct bt_mesh_app_key { - uint16_t net_idx; - uint16_t app_idx; - bool updated; - struct bt_mesh_app_keys { - uint8_t id; - uint8_t val[16]; - } keys[2]; -}; +struct bt_mesh_net_cred; struct bt_mesh_node { uint16_t addr; @@ -40,40 +26,6 @@ struct bt_mesh_node { uint8_t num_elem; }; -struct bt_mesh_subnet { - uint32_t beacon_sent; /* Timestamp of last sent beacon */ - uint8_t beacons_last; /* Number of beacons during last - * observation window - */ - uint8_t beacons_cur; /* Number of beaconds observed during - * currently ongoing window. - */ - - uint8_t beacon_cache[21]; /* Cached last authenticated beacon */ - - uint16_t net_idx; /* NetKeyIndex */ - - bool kr_flag; /* Key Refresh Flag */ - uint8_t kr_phase; /* Key Refresh Phase */ - - uint8_t node_id; /* Node Identity State */ - uint32_t node_id_start; /* Node Identity started timestamp */ - - uint8_t auth[8]; /* Beacon Authentication Value */ - - struct bt_mesh_subnet_keys { - uint8_t net[16]; /* NetKey */ - uint8_t nid; /* NID */ - uint8_t enc[16]; /* EncKey */ - uint8_t net_id[8]; /* Network ID */ -#if defined(CONFIG_BT_MESH_GATT_PROXY) - uint8_t identity[16]; /* IdentityKey */ -#endif - uint8_t privacy[16]; /* PrivacyKey */ - uint8_t beacon[16]; /* BeaconKey */ - } keys[2]; -}; - #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 @@ -89,14 +41,15 @@ struct bt_mesh_friend { send_last:1, pending_req:1, pending_buf:1, - valid:1, established:1; int32_t poll_to; uint8_t num_elem; uint16_t lpn_counter; uint16_t counter; - uint16_t net_idx; + struct bt_mesh_subnet *subnet; + + struct bt_mesh_net_cred cred[2]; uint16_t sub_list[FRIEND_SUB_LIST_SIZE]; @@ -173,8 +126,11 @@ struct bt_mesh_lpn { /* Friend Queue Size */ uint8_t queue_size; + /* FriendCounter */ + uint16_t frnd_counter; + /* LPNCounter */ - uint16_t counter; + uint16_t lpn_counter; /* Previous Friend of this LPN */ uint16_t old_friend; @@ -188,6 +144,10 @@ struct bt_mesh_lpn { /* Subscribed groups */ uint16_t groups[LPN_GROUPS]; + struct bt_mesh_subnet *sub; + + struct bt_mesh_net_cred cred[2]; + /* Bit fields for tracking which groups the Friend knows about */ ATOMIC_DEFINE(added, LPN_GROUPS); ATOMIC_DEFINE(pending, LPN_GROUPS); @@ -244,10 +204,6 @@ struct bt_mesh_net { struct k_delayed_work ivu_timer; uint8_t dev_key[16]; - - struct bt_mesh_app_key app_keys[CONFIG_BT_MESH_APP_KEY_COUNT]; - - struct bt_mesh_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT]; }; /* Network interface */ @@ -293,38 +249,19 @@ extern struct bt_mesh_net bt_mesh; #define BT_MESH_NET_HDR_LEN 9 -int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, - const uint8_t key[16]); - int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index); -uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub); - -bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key); - -void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub); - -int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub); - bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); -void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub); - -struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx); - -struct bt_mesh_subnet *bt_mesh_subnet_find(const uint8_t net_id[8], uint8_t flags, - uint32_t iv_index, const uint8_t auth[8], - bool *new_key); - int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, bool proxy); int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data); -int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); +int bt_mesh_net_decode(struct net_buf_simple *in, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct net_buf_simple *out); void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, enum bt_mesh_net_if net_if); @@ -339,31 +276,6 @@ void bt_mesh_net_init(void); void bt_mesh_net_header_parse(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); -/* Friendship Credential Management */ -struct friend_cred { - uint16_t net_idx; - uint16_t addr; - - uint16_t lpn_counter; - uint16_t frnd_counter; - - struct { - uint8_t nid; /* NID */ - uint8_t enc[16]; /* EncKey */ - uint8_t privacy[16]; /* PrivacyKey */ - } cred[2]; -}; - -int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, - const uint8_t **enc, const uint8_t **priv); -int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key[16]); -void friend_cred_refresh(uint16_t net_idx); -int friend_cred_update(struct bt_mesh_subnet *sub); -struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr, - uint16_t lpn_counter, uint16_t frnd_counter); -void friend_cred_clear(struct friend_cred *cred); -int friend_cred_del(uint16_t net_idx, uint16_t addr); - static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb, void *cb_data) { diff --git a/subsys/bluetooth/mesh/proxy.c b/subsys/bluetooth/mesh/proxy.c index 68c6fb5230c..925d9c37013 100644 --- a/subsys/bluetooth/mesh/proxy.c +++ b/subsys/bluetooth/mesh/proxy.c @@ -144,7 +144,7 @@ static void proxy_sar_timeout(struct k_work *work) #if defined(CONFIG_BT_MESH_GATT_PROXY) /* Next subnet in queue to be advertised */ -static int next_idx; +static struct bt_mesh_subnet *beacon_sub; static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type, struct net_buf_simple *msg); @@ -341,20 +341,20 @@ static int beacon_send(struct bt_conn *conn, struct bt_mesh_subnet *sub) return proxy_segment_and_send(conn, BT_MESH_PROXY_BEACON, &buf); } +static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data) +{ + struct bt_mesh_proxy_client *client = cb_data; + + return beacon_send(client->conn, sub); +} + static void proxy_send_beacons(struct k_work *work) { struct bt_mesh_proxy_client *client; - int i; client = CONTAINER_OF(work, struct bt_mesh_proxy_client, send_beacons); - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx != BT_MESH_KEY_UNUSED) { - beacon_send(client->conn, sub); - } - } + (void)bt_mesh_subnet_find(send_beacon_cb, client); } void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) @@ -363,12 +363,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) if (!sub) { /* NULL means we send on all subnets */ - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx != BT_MESH_KEY_UNUSED) { - bt_mesh_proxy_beacon_send(&bt_mesh.sub[i]); - } - } - + bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send); return; } @@ -379,13 +374,18 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) } } -void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) +static void node_id_start(struct bt_mesh_subnet *sub) { sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING; sub->node_id_start = k_uptime_get_32(); +} + +void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) +{ + node_id_start(sub); /* Prioritize the recently enabled subnet */ - next_idx = sub - bt_mesh.sub; + beacon_sub = sub; } void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) @@ -396,30 +396,13 @@ void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) int bt_mesh_proxy_identity_enable(void) { - int i, count = 0; - BT_DBG(""); if (!bt_mesh_is_provisioned()) { return -EAGAIN; } - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) { - continue; - } - - bt_mesh_proxy_identity_start(sub); - count++; - } - - if (count) { + if (bt_mesh_subnet_foreach(node_id_start)) { bt_mesh_adv_update(); } @@ -1094,7 +1077,8 @@ static int node_id_adv(struct bt_mesh_subnet *sub) memcpy(tmp + 6, proxy_svc_data + 11, 8); sys_put_be16(bt_mesh_primary_addr(), tmp + 14); - err = bt_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp); + err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp, + tmp); if (err) { return err; } @@ -1122,9 +1106,9 @@ static int net_id_adv(struct bt_mesh_subnet *sub) proxy_svc_data[2] = ID_TYPE_NET; BT_DBG("Advertising with NetId %s", - bt_hex(sub->keys[sub->kr_flag].net_id, 8)); + bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8)); - memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8); + memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8); err = bt_le_adv_start(&slow_adv_param, net_id_ad, ARRAY_SIZE(net_id_ad), NULL, 0); @@ -1150,32 +1134,46 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub) static struct bt_mesh_subnet *next_sub(void) { - int i; + struct bt_mesh_subnet *sub = NULL; - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub; - - sub = &bt_mesh.sub[(i + next_idx) % ARRAY_SIZE(bt_mesh.sub)]; - if (advertise_subnet(sub)) { - next_idx = (next_idx + 1) % ARRAY_SIZE(bt_mesh.sub); - return sub; + if (!beacon_sub) { + beacon_sub = bt_mesh_subnet_next(NULL); + if (!beacon_sub) { + /* No valid subnets */ + return NULL; } } + sub = beacon_sub; + do { + if (advertise_subnet(sub)) { + beacon_sub = sub; + return sub; + } + + sub = bt_mesh_subnet_next(sub); + } while (sub != beacon_sub); + + /* No subnets to advertise on */ return NULL; } +static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) +{ + int *count = cb_data; + + if (advertise_subnet(sub)) { + (*count)++; + } + + return 0; +} + static int sub_count(void) { - int i, count = 0; + int count = 0; - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (advertise_subnet(sub)) { - count++; - } - } + (void)bt_mesh_subnet_find(sub_count_cb, &count); return count; } @@ -1192,6 +1190,7 @@ static k_timeout_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) return K_FOREVER; } + sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); if (!sub) { BT_WARN("No subnets to advertise on"); return K_FOREVER; @@ -1235,6 +1234,8 @@ static k_timeout_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) BT_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); + beacon_sub = bt_mesh_subnet_next(beacon_sub); + return SYS_TIMEOUT_MS(remaining); } #endif /* GATT_PROXY */ @@ -1347,6 +1348,21 @@ void bt_mesh_proxy_adv_stop(void) } } +#if defined(CONFIG_BT_MESH_GATT_PROXY) +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + if (evt == BT_MESH_KEY_DELETED) { + if (sub == beacon_sub) { + beacon_sub = NULL; + } + } else { + bt_mesh_proxy_beacon_send(sub); + } +} + +BT_MESH_SUBNET_CB_DEFINE(subnet_evt); +#endif + static struct bt_conn_cb conn_callbacks = { .connected = proxy_connected, .disconnected = proxy_disconnected, diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 92a1f03f989..d01a9fa28c3 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -25,6 +25,8 @@ #include "common/log.h" #include "mesh.h" +#include "subnet.h" +#include "app_keys.h" #include "net.h" #include "crypto.h" #include "rpl.h" @@ -334,9 +336,8 @@ static int rpl_set(const char *name, size_t len_rd, static int net_key_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_subnet *sub; struct net_key_val key; - int i, err; + int err; uint16_t net_idx; if (!name) { @@ -345,64 +346,22 @@ static int net_key_set(const char *name, size_t len_rd, } net_idx = strtol(name, NULL, 16); - sub = bt_mesh_subnet_get(net_idx); - - if (len_rd == 0) { - BT_DBG("val (null)"); - if (!sub) { - BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); - return -ENOENT; - } - - BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); - bt_mesh_subnet_del(sub, false); - return 0; - } - err = mesh_x_set(read_cb, cb_arg, &key, sizeof(key)); if (err) { BT_ERR("Failed to set \'net-key\'"); return err; } - if (sub) { - BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net, &key.val[0], 16); - memcpy(sub->keys[1].net, &key.val[1], 16); - - return 0; - } - - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) { - sub = &bt_mesh.sub[i]; - break; - } - } - - if (!sub) { - BT_ERR("No space to allocate a new subnet"); - return -ENOMEM; - } - - sub->net_idx = net_idx; - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net, &key.val[0], 16); - memcpy(sub->keys[1].net, &key.val[1], 16); - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - return 0; + return bt_mesh_subnet_set( + net_idx, key.kr_phase, key.val[0], + (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); } static int app_key_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { - struct bt_mesh_app_key *app; struct app_key_val key; uint16_t app_idx; int err; @@ -414,43 +373,22 @@ static int app_key_set(const char *name, size_t len_rd, app_idx = strtol(name, NULL, 16); - if (len_rd == 0) { - BT_DBG("val (null)"); - BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); - - app = bt_mesh_app_key_find(app_idx); - if (app) { - bt_mesh_app_key_del(app, false); - } - + if (!len_rd) { return 0; } - err = mesh_x_set(read_cb, cb_arg, &key, sizeof(key)); + len_rd = read_cb(cb_arg, &key, sizeof(key)); + if (len_rd != sizeof(key)) { + return -EINVAL; + } + + err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], + key.updated ? key.val[1] : NULL); if (err) { BT_ERR("Failed to set \'app-key\'"); return err; } - app = bt_mesh_app_key_find(app_idx); - if (!app) { - app = bt_mesh_app_key_alloc(app_idx); - } - - if (!app) { - BT_ERR("No space for a new app key"); - return -ENOMEM; - } - - app->net_idx = key.net_idx; - app->app_idx = app_idx; - app->updated = key.updated; - memcpy(app->keys[0].val, key.val[0], 16); - memcpy(app->keys[1].val, key.val[1], 16); - - bt_mesh_app_id(app->keys[0].val, &app->keys[0].id); - bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); return 0; @@ -1042,37 +980,6 @@ static int mesh_set(const char *name, size_t len_rd, return -ENOENT; } -static int subnet_init(struct bt_mesh_subnet *sub) -{ - int err; - - err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net); - if (err) { - BT_ERR("Unable to generate keys for subnet"); - return -EIO; - } - - if (sub->kr_phase != BT_MESH_KR_NORMAL) { - err = bt_mesh_net_keys_create(&sub->keys[1], sub->keys[1].net); - if (err) { - BT_ERR("Unable to generate keys for subnet"); - (void)memset(&sub->keys[0], 0, sizeof(sub->keys[0])); - return -EIO; - } - } - - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; - } else { - sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; - } - - /* Make sure we have valid beacon data to be sent */ - bt_mesh_net_beacon_update(sub); - - return 0; -} - static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { @@ -1101,11 +1008,8 @@ static int mesh_commit(void) { struct bt_mesh_hb_pub *hb_pub; struct bt_mesh_cfg_srv *cfg; - int i; - BT_DBG("sub[0].net_idx 0x%03x", bt_mesh.sub[0].net_idx); - - if (bt_mesh.sub[0].net_idx == BT_MESH_KEY_UNUSED) { + if (!bt_mesh_subnet_next(NULL)) { /* Nothing to do since we're not yet provisioned */ return 0; } @@ -1114,20 +1018,6 @@ static int mesh_commit(void) bt_mesh_proxy_prov_disable(true); } - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - int err; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - err = subnet_init(sub); - if (err) { - BT_ERR("Failed to init subnet 0x%03x", sub->net_idx); - } - } - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); } @@ -1452,22 +1342,28 @@ static void clear_net_key(uint16_t net_idx) } } -static void store_net_key(struct bt_mesh_subnet *sub) +static void store_subnet(uint16_t net_idx) { + const struct bt_mesh_subnet *sub; struct net_key_val key; char path[20]; int err; - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net, 16)); + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + BT_WARN("NetKeyIndex 0x%03x not found", net_idx); + return; + } + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", net_idx); memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); - key.kr_flag = sub->kr_flag; + key.kr_flag = 0U; /* Deprecated */ key.kr_phase = sub->kr_phase; - snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", sub->net_idx); - err = settings_save_one(path, &key, sizeof(key)); if (err) { BT_ERR("Failed to store NetKey value"); @@ -1476,19 +1372,27 @@ static void store_net_key(struct bt_mesh_subnet *sub) } } -static void store_app_key(struct bt_mesh_app_key *app) +static void store_app(uint16_t app_idx) { + const struct bt_mesh_app_key *app; struct app_key_val key; char path[20]; int err; - key.net_idx = app->net_idx; - key.updated = app->updated; + snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app_idx); + + app = bt_mesh_app_key_get(app_idx); + if (!app) { + BT_WARN("ApKeyIndex 0x%03x not found", app_idx); + return; + } + + key.net_idx = app->net_idx, + key.updated = app->updated, + memcpy(key.val[0], app->keys[0].val, 16); memcpy(key.val[1], app->keys[1].val, 16); - snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app->app_idx); - err = settings_save_one(path, &key, sizeof(key)); if (err) { BT_ERR("Failed to store AppKey %s value", log_strdup(path)); @@ -1516,26 +1420,9 @@ static void store_pending_keys(void) } } else { if (update->app_key) { - struct bt_mesh_app_key *key; - - key = bt_mesh_app_key_find(update->key_idx); - if (key) { - store_app_key(key); - } else { - BT_WARN("AppKeyIndex 0x%03x not found", - update->key_idx); - } - + store_app(update->key_idx); } else { - struct bt_mesh_subnet *sub; - - sub = bt_mesh_subnet_get(update->key_idx); - if (sub) { - store_net_key(sub); - } else { - BT_WARN("NetKeyIndex 0x%03x not found", - update->key_idx); - } + store_subnet(update->key_idx); } } @@ -2066,13 +1953,13 @@ static struct key_update *key_update_find(bool app_key, uint16_t key_idx, return match; } -void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) +void bt_mesh_store_subnet(uint16_t net_idx) { struct key_update *update, *free_slot; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("NetKeyIndex 0x%03x", net_idx); - update = key_update_find(false, sub->net_idx, &free_slot); + update = key_update_find(false, net_idx, &free_slot); if (update) { update->clear = 0U; schedule_store(BT_MESH_KEYS_PENDING); @@ -2080,25 +1967,25 @@ void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) } if (!free_slot) { - store_net_key(sub); + store_subnet(net_idx); return; } free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; + free_slot->key_idx = net_idx; free_slot->app_key = 0U; free_slot->clear = 0U; schedule_store(BT_MESH_KEYS_PENDING); } -void bt_mesh_store_app_key(struct bt_mesh_app_key *key) +void bt_mesh_store_app_key(uint16_t app_idx) { struct key_update *update, *free_slot; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("AppKeyIndex 0x%03x", app_idx); - update = key_update_find(true, key->app_idx, &free_slot); + update = key_update_find(true, app_idx, &free_slot); if (update) { update->clear = 0U; schedule_store(BT_MESH_KEYS_PENDING); @@ -2106,12 +1993,12 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) } if (!free_slot) { - store_app_key(key); + store_app(app_idx); return; } free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; + free_slot->key_idx = app_idx; free_slot->app_key = 1U; free_slot->clear = 0U; @@ -2135,13 +2022,13 @@ void bt_mesh_clear_net(void) schedule_store(BT_MESH_CFG_PENDING); } -void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) +void bt_mesh_clear_subnet(uint16_t net_idx) { struct key_update *update, *free_slot; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("NetKeyIndex 0x%03x", net_idx); - update = key_update_find(false, sub->net_idx, &free_slot); + update = key_update_find(false, net_idx, &free_slot); if (update) { update->clear = 1U; schedule_store(BT_MESH_KEYS_PENDING); @@ -2149,25 +2036,25 @@ void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) } if (!free_slot) { - clear_net_key(sub->net_idx); + clear_net_key(net_idx); return; } free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; + free_slot->key_idx = net_idx; free_slot->app_key = 0U; free_slot->clear = 1U; schedule_store(BT_MESH_KEYS_PENDING); } -void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) +void bt_mesh_clear_app_key(uint16_t app_idx) { struct key_update *update, *free_slot; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("AppKeyIndex 0x%03x", app_idx); - update = key_update_find(true, key->app_idx, &free_slot); + update = key_update_find(true, app_idx, &free_slot); if (update) { update->clear = 1U; schedule_store(BT_MESH_KEYS_PENDING); @@ -2175,12 +2062,12 @@ void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) } if (!free_slot) { - clear_app_key(key->app_idx); + clear_app_key(app_idx); return; } free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; + free_slot->key_idx = app_idx; free_slot->app_key = 1U; free_slot->clear = 1U; diff --git a/subsys/bluetooth/mesh/settings.h b/subsys/bluetooth/mesh/settings.h index 2718cb5e3a2..9060a14a726 100644 --- a/subsys/bluetooth/mesh/settings.h +++ b/subsys/bluetooth/mesh/settings.h @@ -8,8 +8,8 @@ void bt_mesh_store_net(void); void bt_mesh_store_iv(bool only_duration); void bt_mesh_store_seq(void); void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); -void bt_mesh_store_subnet(struct bt_mesh_subnet *sub); -void bt_mesh_store_app_key(struct bt_mesh_app_key *key); +void bt_mesh_store_subnet(uint16_t net_idx); +void bt_mesh_store_app_key(uint16_t app_idx); void bt_mesh_store_hb_pub(void); void bt_mesh_store_cfg(void); void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); @@ -22,8 +22,8 @@ void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub); void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app); void bt_mesh_clear_net(void); -void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); -void bt_mesh_clear_app_key(struct bt_mesh_app_key *key); +void bt_mesh_clear_subnet(uint16_t net_idx); +void bt_mesh_clear_app_key(uint16_t app_idx); void bt_mesh_clear_rpl(void); void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node); void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub); diff --git a/subsys/bluetooth/mesh/shell.c b/subsys/bluetooth/mesh/shell.c index 8361a338b87..b61ba6a106f 100644 --- a/subsys/bluetooth/mesh/shell.c +++ b/subsys/bluetooth/mesh/shell.c @@ -703,8 +703,6 @@ static int cmd_net_send(const struct shell *shell, size_t argc, char *argv[]) struct bt_mesh_net_tx tx = { .ctx = &ctx, .src = net.local, - .xmit = bt_mesh_net_transmit_get(), - .sub = bt_mesh_subnet_get(net.net_idx), }; size_t len; int err; @@ -713,12 +711,6 @@ static int cmd_net_send(const struct shell *shell, size_t argc, char *argv[]) return -EINVAL; } - if (!tx.sub) { - shell_print(shell, "No matching subnet for NetKey Index 0x%04x", - net.net_idx); - return 0; - } - len = hex2bin(argv[1], strlen(argv[1]), msg.data, net_buf_simple_tailroom(&msg) - 4); net_buf_simple_add(&msg, len); diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c new file mode 100644 index 00000000000..f83b0ebad4d --- /dev/null +++ b/subsys/bluetooth/mesh/subnet.c @@ -0,0 +1,660 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * 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_KEYS) +#define LOG_MODULE_NAME bt_mesh_net_keys +#include "common/log.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh.h" +#include "net.h" +#include "lpn.h" +#include "friend.h" +#include "proxy.h" +#include "transport.h" +#include "access.h" +#include "foundation.h" +#include "beacon.h" +#include "rpl.h" +#include "settings.h" +#include "prov.h" + +static struct bt_mesh_subnet subnets[CONFIG_BT_MESH_SUBNET_COUNT] = { + [0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = { + .net_idx = BT_MESH_KEY_UNUSED, + }, +}; + +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + Z_STRUCT_SECTION_FOREACH(bt_mesh_subnet_cb, cb) { + cb->evt_handler(sub, evt); + } +} + +uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) +{ + uint8_t flags = 0x00; + + if (sub && (sub->kr_phase == BT_MESH_KR_PHASE_2)) { + flags |= BT_MESH_NET_FLAG_KR; + } + + if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) { + flags |= BT_MESH_NET_FLAG_IVU; + } + + return flags; +} + +static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) +{ + BT_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase); + + switch (new_phase) { + /* Added second set of keys */ + case BT_MESH_KR_PHASE_1: + sub->kr_phase = new_phase; + subnet_evt(sub, BT_MESH_KEY_UPDATED); + break; + /* Now using new keys for TX */ + case BT_MESH_KR_PHASE_2: + sub->kr_phase = new_phase; + subnet_evt(sub, BT_MESH_KEY_SWAPPED); + break; + /* Revoking keys */ + case BT_MESH_KR_PHASE_3: + case BT_MESH_KR_NORMAL: + sub->kr_phase = BT_MESH_KR_NORMAL; + memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); + sub->keys[1].valid = 0U; + subnet_evt(sub, BT_MESH_KEY_REVOKED); + break; + } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + BT_DBG("Storing Updated NetKey persistently"); + bt_mesh_store_subnet(sub->net_idx); + } +} + +void bt_mesh_kr_update(struct bt_mesh_subnet *sub, bool kr_flag, bool new_key) +{ + if (!new_key) { + return; + } + + if (sub->kr_phase == BT_MESH_KR_PHASE_1) { + /* Bluetooth Mesh Profile Specification Section 3.10.4.1: + * Can skip phase 2 if we get KR=0 on new key. + */ + key_refresh(sub, (kr_flag ? BT_MESH_KR_PHASE_2 : + BT_MESH_KR_PHASE_3)); + } else if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !kr_flag) { + key_refresh(sub, BT_MESH_KR_PHASE_3); + } +} + +static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) +{ + struct bt_mesh_subnet *sub = NULL; + + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + /* Check for already existing subnet */ + if (subnets[i].net_idx == net_idx) { + return &subnets[i]; + } + + if (!sub && subnets[i].net_idx == BT_MESH_KEY_UNUSED) { + sub = &subnets[i]; + } + } + + return sub; +} + +static void subnet_del(struct bt_mesh_subnet *sub) +{ + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_clear_subnet(sub->net_idx); + } + + bt_mesh_net_loopback_clear(sub->net_idx); + + subnet_evt(sub, BT_MESH_KEY_DELETED); + (void)memset(sub, 0, sizeof(*sub)); + sub->net_idx = BT_MESH_KEY_UNUSED; +} + +static int msg_cred_create(struct bt_mesh_net_cred *cred, const uint8_t *p, + size_t p_len, const uint8_t key[16]) +{ + return bt_mesh_k2(key, p, p_len, &cred->nid, cred->enc, cred->privacy); +} + +static int net_keys_create(struct bt_mesh_subnet_keys *keys, + const uint8_t key[16]) +{ + uint8_t p = 0; + int err; + + err = msg_cred_create(&keys->msg, &p, 1, key); + if (err) { + BT_ERR("Unable to generate NID, EncKey & PrivacyKey"); + return err; + } + + memcpy(keys->net, key, 16); + + BT_DBG("NID 0x%02x EncKey %s", keys->msg.nid, + bt_hex(keys->msg.enc, 16)); + BT_DBG("PrivacyKey %s", bt_hex(keys->msg.privacy, 16)); + + err = bt_mesh_k3(key, keys->net_id); + if (err) { + BT_ERR("Unable to generate Net ID"); + return err; + } + + BT_DBG("NetID %s", bt_hex(keys->net_id, 8)); + +#if defined(CONFIG_BT_MESH_GATT_PROXY) + err = bt_mesh_identity_key(key, keys->identity); + if (err) { + BT_ERR("Unable to generate IdentityKey"); + return err; + } + + BT_DBG("IdentityKey %s", bt_hex(keys->identity, 16)); +#endif /* GATT_PROXY */ + + err = bt_mesh_beacon_key(key, keys->beacon); + if (err) { + BT_ERR("Unable to generate beacon key"); + return err; + } + + BT_DBG("BeaconKey %s", bt_hex(keys->beacon, 16)); + + keys->valid = 1U; + + return 0; +} + +uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]) +{ + struct bt_mesh_subnet *sub = NULL; + int err; + + BT_DBG("0x%03x", net_idx); + + sub = subnet_alloc(net_idx); + if (!sub) { + return STATUS_INSUFF_RESOURCES; + } + + if (sub->net_idx == net_idx) { + if (memcmp(key, sub->keys[0].net, 16)) { + return STATUS_IDX_ALREADY_STORED; + } + + return STATUS_SUCCESS; + } + + err = net_keys_create(&sub->keys[0], key); + if (err) { + return STATUS_UNSPECIFIED; + } + + sub->net_idx = net_idx; + sub->kr_phase = BT_MESH_KR_NORMAL; + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; + } else { + sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; + } + + subnet_evt(sub, BT_MESH_KEY_ADDED); + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + BT_DBG("Storing NetKey persistently"); + bt_mesh_store_subnet(sub->net_idx); + } + + return STATUS_SUCCESS; +} + +bool bt_mesh_subnet_exists(uint16_t net_idx) +{ + return !!bt_mesh_subnet_get(net_idx); +} + +uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]) +{ + struct bt_mesh_subnet *sub; + int err; + + BT_DBG("0x%03x", net_idx); + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + return STATUS_INVALID_NETKEY; + } + + /* The node shall successfully process a NetKey Update message on a + * valid NetKeyIndex when the NetKey value is different and the Key + * Refresh procedure has not been started, or when the NetKey value is + * the same in Phase 1. The NetKey Update message shall generate an + * error when the node is in Phase 2, or Phase 3. + */ + switch (sub->kr_phase) { + case BT_MESH_KR_NORMAL: + if (!memcmp(key, sub->keys[0].net, 16)) { + return STATUS_IDX_ALREADY_STORED; + } + break; + case BT_MESH_KR_PHASE_1: + if (!memcmp(key, sub->keys[1].net, 16)) { + return STATUS_SUCCESS; + } + __fallthrough; + case BT_MESH_KR_PHASE_2: + case BT_MESH_KR_PHASE_3: + return STATUS_CANNOT_UPDATE; + } + + err = net_keys_create(&sub->keys[1], key); + if (err) { + return STATUS_CANNOT_UPDATE; + } + + key_refresh(sub, BT_MESH_KR_PHASE_1); + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_subnet_del(uint16_t net_idx) +{ + struct bt_mesh_subnet *sub; + + BT_DBG("0x%03x", net_idx); + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + /* This could be a retry of a previous attempt that had its + * response lost, so pretend that it was a success. + */ + return STATUS_INVALID_NETKEY; + } + + subnet_del(sub); + + return STATUS_SUCCESS; +} + +int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, uint16_t lpn_addr, + uint16_t frnd_addr, uint16_t lpn_counter, + uint16_t frnd_counter, const uint8_t key[16]) +{ + uint8_t p[9]; + + p[0] = 0x01; + sys_put_be16(lpn_addr, p + 1); + sys_put_be16(frnd_addr, p + 3); + sys_put_be16(lpn_counter, p + 5); + sys_put_be16(frnd_counter, p + 7); + + return msg_cred_create(cred, p, sizeof(p), key); +} + +uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase) +{ + /* Table in Bluetooth Mesh Profile Specification Section 4.2.14: */ + const uint8_t valid_transitions[] = { + 0x00, /* Normal phase: KR is started by key update */ + BIT(BT_MESH_KR_PHASE_2) | BIT(BT_MESH_KR_PHASE_3), /* Phase 1 */ + BIT(BT_MESH_KR_PHASE_3), /* Phase 2 */ + /* Subnet is never in Phase 3 */ + }; + struct bt_mesh_subnet *sub; + + BT_DBG("0x%03x", net_idx); + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + *phase = 0x00; + return STATUS_INVALID_NETKEY; + } + + if (*phase == sub->kr_phase) { + return STATUS_SUCCESS; + } + + if (sub->kr_phase < ARRAY_SIZE(valid_transitions) && + valid_transitions[sub->kr_phase] & BIT(*phase)) { + key_refresh(sub, *phase); + + *phase = sub->kr_phase; + + return STATUS_SUCCESS; + } + + BT_WARN("Invalid KR transition: 0x%02x -> 0x%02x", sub->kr_phase, + *phase); + + *phase = sub->kr_phase; + + return STATUS_CANNOT_UPDATE; +} + +uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase) +{ + struct bt_mesh_subnet *sub; + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + *phase = BT_MESH_KR_NORMAL; + return STATUS_INVALID_NETKEY; + } + + *phase = sub->kr_phase; + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx, + enum bt_mesh_feat_state node_id) +{ + struct bt_mesh_subnet *sub; + + if (node_id == BT_MESH_FEATURE_NOT_SUPPORTED) { + return STATUS_CANNOT_SET; + } + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + return STATUS_INVALID_NETKEY; + } + + if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + return STATUS_FEAT_NOT_SUPP; + } + + if (node_id) { + bt_mesh_proxy_identity_start(sub); + } else { + bt_mesh_proxy_identity_stop(sub); + } + + bt_mesh_adv_update(); + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx, + enum bt_mesh_feat_state *node_id) +{ + struct bt_mesh_subnet *sub; + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + *node_id = 0x00; + return STATUS_INVALID_NETKEY; + } + + *node_id = sub->node_id; + + return STATUS_SUCCESS; +} + +ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip) +{ + size_t count = 0; + + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + struct bt_mesh_subnet *sub = &subnets[i]; + + if (sub->net_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (skip) { + skip--; + continue; + } + + if (count >= max) { + return -ENOMEM; + } + + net_idxs[count++] = sub->net_idx; + } + + return count; +} + +struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) +{ + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + struct bt_mesh_subnet *sub = &subnets[i]; + + if (sub->net_idx == net_idx) { + return sub; + } + } + + return NULL; +} + +int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, + const uint8_t old_key[16], const uint8_t new_key[16]) +{ + const uint8_t *keys[] = { old_key, new_key }; + struct bt_mesh_subnet *sub; + + sub = subnet_alloc(net_idx); + if (!sub) { + return -ENOMEM; + } + + if (sub->net_idx == net_idx) { + return -EALREADY; + } + + for (int i = 0; i < ARRAY_SIZE(keys); i++) { + if (!keys[i]) { + continue; + } + + if (net_keys_create(&sub->keys[i], keys[i])) { + return -EIO; + } + } + + sub->net_idx = net_idx; + sub->kr_phase = kr_phase; + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; + } else { + sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; + } + + /* Make sure we have valid beacon data to be sent */ + bt_mesh_beacon_update(sub); + + return 0; +} + +struct bt_mesh_subnet *bt_mesh_subnet_find(int (*cb)(struct bt_mesh_subnet *sub, + void *cb_data), + void *cb_data) +{ + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + if (subnets[i].net_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (!cb || cb(&subnets[i], cb_data)) { + return &subnets[i]; + } + } + + return NULL; +} + +size_t bt_mesh_subnet_foreach(void (*cb)(struct bt_mesh_subnet *sub)) +{ + size_t count = 0; + + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + if (subnets[i].net_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + cb(&subnets[i]); + count++; + } + + return count; +} + +struct bt_mesh_subnet *bt_mesh_subnet_next(struct bt_mesh_subnet *sub) +{ + if (sub) { + sub++; + } else { + sub = &subnets[0]; + } + + for (int i = 0; i < ARRAY_SIZE(subnets); i++, sub++) { + /* Roll over once we reach the end */ + if (sub == &subnets[ARRAY_SIZE(subnets)]) { + sub = &subnets[0]; + } + + if (sub->net_idx != BT_MESH_KEY_UNUSED) { + return sub; + } + } + + return NULL; +} + +void bt_mesh_net_keys_reset(void) +{ + int i; + + /* Delete all net keys, which also takes care of all app keys which + * are associated with each net key. + */ + for (i = 0; i < ARRAY_SIZE(subnets); i++) { + struct bt_mesh_subnet *sub = &subnets[i]; + + if (sub->net_idx != BT_MESH_KEY_UNUSED) { + subnet_del(sub); + } + } +} + +bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct net_buf_simple *in, + struct net_buf_simple *out, + bool (*cb)(struct bt_mesh_net_rx *rx, + struct net_buf_simple *in, + struct net_buf_simple *out, + const struct bt_mesh_net_cred *cred)) +{ + int i, j; + + BT_DBG(""); + + rx->friend_cred = 1U; +#if defined(CONFIG_BT_MESH_LOW_POWER) + if (bt_mesh_lpn_established()) { + rx->sub = bt_mesh.lpn.sub; + + for (j = 0; j < ARRAY_SIZE(bt_mesh.lpn.cred); j++) { + if (!rx->sub->keys[j].valid) { + continue; + } + + if (cb(rx, in, out, &bt_mesh.lpn.cred[j])) { + rx->new_key = (j > 0); + return true; + } + } + + /* LPN Should only receive on the friendship credentials when in + * a friendship. + */ + return false; + } +#endif + +#if defined(CONFIG_BT_MESH_FRIEND) + /** Each friendship has unique friendship credentials */ + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { + struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + + if (!frnd->established) { + continue; + } + + if (!frnd->subnet) { + continue; + } + + rx->sub = frnd->subnet; + + for (j = 0; j < ARRAY_SIZE(frnd->cred); j++) { + if (!rx->sub->keys[j].valid) { + continue; + } + + if (cb(rx, in, out, &frnd->cred[j])) { + rx->new_key = (j > 0); + return true; + } + } + } +#endif + + for (i = 0; i < ARRAY_SIZE(subnets); i++) { + rx->sub = &subnets[i]; + if (rx->sub->net_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + for (j = 0; j < ARRAY_SIZE(rx->sub->keys); j++) { + if (!rx->sub->keys[j].valid) { + continue; + } + + if (cb(rx, in, out, &rx->sub->keys[j].msg)) { + rx->new_key = (j > 0); + return true; + } + } + } + + return false; +} diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h new file mode 100644 index 00000000000..647d39d28d6 --- /dev/null +++ b/subsys/bluetooth/mesh/subnet.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_SUBNET_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_SUBNET_H_ + +#include +#include +#include +#include + +#define BT_MESH_NET_FLAG_KR BIT(0) +#define BT_MESH_NET_FLAG_IVU BIT(1) + +#define BT_MESH_KR_NORMAL 0x00 +#define BT_MESH_KR_PHASE_1 0x01 +#define BT_MESH_KR_PHASE_2 0x02 +#define BT_MESH_KR_PHASE_3 0x03 + +/** Which of the two subnet.keys should be used for sending. */ +#define SUBNET_KEY_TX_IDX(sub) ((sub)->kr_phase == BT_MESH_KR_PHASE_2) + +struct bt_mesh_net_rx; +enum bt_mesh_key_evt; + +/** Network message encryption credentials */ +struct bt_mesh_net_cred { + uint8_t nid; /* NID */ + uint8_t enc[16]; /* EncKey */ + uint8_t privacy[16]; /* PrivacyKey */ +}; + +/** Subnet instance. */ +struct bt_mesh_subnet { + uint32_t beacon_sent; /* Timestamp of last sent beacon */ + uint8_t beacons_last; /* Number of beacons during last + * observation window + */ + uint8_t beacons_cur; /* Number of beaconds observed during + * currently ongoing window. + */ + + uint8_t beacon_cache[21]; /* Cached last authenticated beacon */ + + uint16_t net_idx; /* NetKeyIndex */ + + uint8_t kr_phase; /* Key Refresh Phase */ + + uint8_t node_id; /* Node Identity State */ + uint32_t node_id_start; /* Node Identity started timestamp */ + + uint8_t auth[8]; /* Beacon Authentication Value */ + + struct bt_mesh_subnet_keys { + bool valid; + uint8_t net[16]; /* NetKey */ + struct bt_mesh_net_cred msg; + uint8_t net_id[8]; /* Network ID */ + #if defined(CONFIG_BT_MESH_GATT_PROXY) + uint8_t identity[16]; /* IdentityKey */ + #endif + uint8_t beacon[16]; /* BeaconKey */ + } keys[2]; +}; + +/** Subnet callback structure. Instantiate with @ref BT_MESH_SUBNET_CB */ +struct bt_mesh_subnet_cb { + void (*evt_handler)(struct bt_mesh_subnet *subnet, + enum bt_mesh_key_evt evt); +}; + +/** @def BT_MESH_SUBNET_CB + * + * @brief Register a subnet event callback. + * + * @param _handler Handler function, see @ref bt_mesh_subnet_cb::evt_handler. + */ +#define BT_MESH_SUBNET_CB_DEFINE(_handler) \ + static const Z_STRUCT_SECTION_ITERABLE( \ + bt_mesh_subnet_cb, _CONCAT(bt_mesh_subnet_cb_, _handler)) = { \ + .evt_handler = (_handler), \ + } + +/** @brief Reset all Network keys. */ +void bt_mesh_net_keys_reset(void); + +/** @brief Call cb on every valid Subnet until it returns a non-zero value. + * + * @param cb Callback to call, or NULL to return first valid subnet. + * @param cb_data Callback data to pass to callback. + * + * @return Subnet that returned non-zero value. + */ +struct bt_mesh_subnet *bt_mesh_subnet_find(int (*cb)(struct bt_mesh_subnet *sub, + void *cb_data), + void *cb_data); + +/** @brief Iterate through all valid Subnets. + * + * @param cb Callback to call on every Subnet. + * + * @returns The number of valid subnets. + */ +size_t bt_mesh_subnet_foreach(void (*cb)(struct bt_mesh_subnet *sub)); + +/** @brief Get the next valid Subnet. + * + * If there's only one valid Subnet, this will be returned on every call. + * + * @param sub Previous Subnet, or NULL to get the first valid. + * + * @returns Gets the next valid Subnet after @c sub, or NULL if there are no + * valid Subnets. + */ +struct bt_mesh_subnet *bt_mesh_subnet_next(struct bt_mesh_subnet *sub); + +/** @brief Get a pointer to the Subnet with the given index. + * + * @param net_idx Network index to look for. + * + * @returns Subnet with index @c net_idx, or NULL if no such Subnet is known. + */ +struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx); + +/** @brief Initialize a new Subnet. + * + * @param net_idx Network index of the Subnet. + * @param kr_phase Key refresh phase the Subnet should be in. + * @param key The current network key for the Subnet. + * @param new_key New network key, if available. + * + * @returns 0 on success, or (negative) error code on failure. + */ +int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, + const uint8_t key[16], const uint8_t new_key[16]); + +/** @brief Create Friendship credentials. + * + * @param cred Credential object to create. + * @param lpn_addr Address of the LPN node in the friendship. + * @param frnd_addr Address of the Friend node in the friendship. + * @param lpn_counter The LPN's counter parameter. + * @param frnd_counter The Friend node's counter parameter. + * @param key Network key to create the Friendship credentials for. + * + * @returns 0 on success, or (negative) error code on failure. + */ +int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, + uint16_t lpn_addr, uint16_t frnd_addr, + uint16_t lpn_counter, uint16_t frnd_counter, + const uint8_t key[16]); + +/** @brief Iterate through all valid network credentials to decrypt a message. + * + * @param rx Network RX parameters, passed to the callback. + * @param in Input message buffer, passed to the callback. + * @param out Output message buffer, passed to the callback. + * @param cb Callback to call for each known network credential. Iteration + * stops when this callback returns @c true. + * + * @returns Whether any of the credentials got a @c true return from the + * callback. + */ +bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct net_buf_simple *in, + struct net_buf_simple *out, + bool (*cb)(struct bt_mesh_net_rx *rx, + struct net_buf_simple *in, + struct net_buf_simple *out, + const struct bt_mesh_net_cred *cred)); + +/** @brief Get the network flags of the given Subnet. + * + * @param sub Subnet to get the network flags of. + * + * @returns A bitmap of @ref BT_MESH_NET_FLAG_KR and @ref BT_MESH_NET_FLAG_IVU. + */ +uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub); + +/** @brief Process a Key Refresh event from a beacon. + * + * @param sub Subnet the Key Refresh was received on. + * @param kr_flag Key Refresh flag. + * @param new_key Whether the Key Refresh event was received on the new key + * set. + */ +void bt_mesh_kr_update(struct bt_mesh_subnet *sub, bool kr_flag, bool new_key); + +/** @brief Check whether the Subnet has the refreshed keys. + * + * @param sub Subnet. + * + * @returns Whether the Subnet's second key is valid. + */ +static inline bool +bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub) +{ + return sub->kr_phase != BT_MESH_KR_NORMAL; +} + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_SUBNET_H_ */ diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 36596100cea..35f37bc2917 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -28,6 +28,7 @@ #include "adv.h" #include "mesh.h" #include "net.h" +#include "app_keys.h" #include "lpn.h" #include "rpl.h" #include "friend.h" @@ -268,9 +269,7 @@ static void seg_tx_reset(struct seg_tx *tx) /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ - if (bt_mesh_net_iv_update(bt_mesh.iv_index, false)) { - bt_mesh_net_sec_update(NULL); - } + bt_mesh_net_iv_update(bt_mesh.iv_index, false); } } @@ -596,27 +595,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, return 0; } -struct bt_mesh_app_key *bt_mesh_app_key_find(uint16_t app_idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - if (key->net_idx != BT_MESH_KEY_UNUSED && - key->app_idx == app_idx) { - return key; - } - } - - return NULL; -} - int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { + struct bt_mesh_app_crypto_ctx crypto = { + .dev_key = BT_MESH_IS_DEV_KEY(tx->ctx->app_idx), + .aszmic = tx->aszmic, + .src = tx->src, + .dst = tx->ctx->addr, + .seq_num = bt_mesh.seq, + .iv_index = BT_MESH_NET_IVI_TX, + }; const uint8_t *key; - uint8_t *ad; uint8_t aid; int err; @@ -643,12 +633,12 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->ctx->app_idx, tx->ctx->addr); BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); - err = bt_mesh_app_key_get(tx->sub, tx->ctx->app_idx, - tx->ctx->addr, &key, &aid); + err = bt_mesh_keys_resolve(tx->ctx, &tx->sub, &key, &aid); if (err) { return err; } + tx->xmit = bt_mesh_net_transmit_get(); tx->aid = aid; if (!tx->ctx->send_rel || net_buf_simple_tailroom(msg) < 8) { @@ -658,14 +648,10 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, } if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - ad = bt_mesh_label_uuid_get(tx->ctx->addr); - } else { - ad = NULL; + crypto.ad = bt_mesh_label_uuid_get(tx->ctx->addr); } - err = bt_mesh_app_encrypt(key, BT_MESH_IS_DEV_KEY(tx->ctx->app_idx), - tx->aszmic, msg, ad, tx->src, tx->ctx->addr, - bt_mesh.seq, BT_MESH_NET_IVI_TX); + err = bt_mesh_app_encrypt(key, &crypto, msg); if (err) { return err; } @@ -698,93 +684,46 @@ static void seg_rx_assemble(struct seg_rx *rx, struct net_buf_simple *buf, } } -static int remote_devkey_decrypt(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t *ad, - uint8_t aszmic, struct net_buf_simple *buf, - struct net_buf_simple *sdu) +struct decrypt_ctx { + struct bt_mesh_app_crypto_ctx crypto; + struct net_buf_simple *buf; + struct net_buf_simple *sdu; + struct seg_rx *seg; +}; + +static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const uint8_t key[16], + void *cb_data) { - struct bt_mesh_cdb_node *node; - int err; + const struct decrypt_ctx *ctx = cb_data; - if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) { - return -ENOENT; + if (ctx->seg) { + seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); } - /* We will try our local devkey separately. */ - if (bt_mesh_elem_find(rx->ctx.addr)) { - return -ENOENT; - } + net_buf_simple_reset(ctx->sdu); - /* - * There is no way of knowing if we should use our - * local DevKey or the remote DevKey to decrypt the - * message so we must try both. - */ - node = bt_mesh_cdb_node_get(rx->ctx.addr); - if (node == NULL) { - BT_ERR("No node found for addr 0x%04x", rx->ctx.addr); - return -EINVAL; - } - - err = bt_mesh_app_decrypt(node->dev_key, true, aszmic, buf, sdu, ad, - rx->ctx.addr, rx->ctx.recv_dst, seq, - BT_MESH_NET_IVI_RX(rx)); - if (err) { - BT_DBG("Unable to decrypt with node DevKey"); - return -EINVAL; - } - - return 0; + return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); } -static int app_key_decrypt(struct bt_mesh_net_rx *rx, - struct bt_mesh_app_key *key, uint32_t seq, uint8_t *ad, - uint8_t hdr, uint8_t aszmic, struct net_buf_simple *buf, - struct net_buf_simple *sdu) +static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, + struct net_buf_simple *buf, struct net_buf_simple *sdu, + struct seg_rx *seg) { - struct bt_mesh_app_keys *keys; - int err; + struct decrypt_ctx ctx = { + .crypto = { + .dev_key = !AKF(&hdr), + .aszmic = aszmic, + .src = rx->ctx.addr, + .dst = rx->ctx.recv_dst, + .seq_num = rx->seq, + .iv_index = BT_MESH_NET_IVI_RX(rx), + }, + .buf = buf, + .sdu = sdu, + .seg = seg, + }; - /* Check that this AppKey matches received net_idx */ - if (key->net_idx != rx->sub->net_idx) { - return -EINVAL; - } - - if (rx->new_key && key->updated) { - keys = &key->keys[1]; - } else { - keys = &key->keys[0]; - } - - /* Check that the AppKey ID matches */ - if (AID(&hdr) != keys->id) { - return -EINVAL; - } - - err = bt_mesh_app_decrypt(keys->val, false, aszmic, buf, sdu, ad, - rx->ctx.addr, rx->ctx.recv_dst, seq, - BT_MESH_NET_IVI_RX(rx)); - if (err) { - BT_WARN("Unable to decrypt with AppKey 0x%03x", key->app_idx); - } - - return err; -} - -static int sdu_recv_unseg(struct bt_mesh_net_rx *rx, uint8_t hdr, - struct net_buf_simple *buf) -{ - NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_SDU_UNSEG_MAX); - uint8_t *ad; - uint16_t i; - int err; - - BT_DBG("AKF %u AID 0x%02x", AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); - - if (buf->len < 1 + APP_MIC_LEN(0)) { - BT_ERR("Too short SDU + MIC"); - return -EINVAL; - } + BT_DBG("AKF %u AID 0x%02x", !ctx.crypto.dev_key, AID(&hdr)); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !rx->local_match) { BT_DBG("Ignoring PDU for LPN 0x%04x of this Friend", @@ -793,157 +732,19 @@ static int sdu_recv_unseg(struct bt_mesh_net_rx *rx, uint8_t hdr, } if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ad = bt_mesh_label_uuid_get(rx->ctx.recv_dst); - } else { - ad = NULL; + ctx.crypto.ad = bt_mesh_label_uuid_get(rx->ctx.recv_dst); } - /* Adjust the length to not contain the MIC at the end */ - buf->len -= APP_MIC_LEN(0); - - if (!AKF(&hdr)) { - /* Attempt remote dev key first, as that is only available for - * provisioner devices, which normally don't interact with nodes - * that know their local dev key. - */ - net_buf_simple_reset(&sdu); - err = remote_devkey_decrypt(rx, rx->seq, ad, 0, buf, &sdu); - if (!err) { - rx->ctx.app_idx = BT_MESH_KEY_DEV_REMOTE; - bt_mesh_model_recv(rx, &sdu); - return 0; - } - - net_buf_simple_reset(&sdu); - err = bt_mesh_app_decrypt(bt_mesh.dev_key, true, 0, buf, &sdu, - ad, rx->ctx.addr, rx->ctx.recv_dst, - rx->seq, BT_MESH_NET_IVI_RX(rx)); - if (err) { - BT_ERR("Unable to decrypt with local DevKey"); - return err; - } - - rx->ctx.app_idx = BT_MESH_KEY_DEV_LOCAL; - bt_mesh_model_recv(rx, &sdu); + 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) { + BT_DBG("No matching AppKey"); return 0; } - for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + BT_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx); - net_buf_simple_reset(&sdu); - err = app_key_decrypt(rx, &bt_mesh.app_keys[i], rx->seq, ad, - hdr, 0, buf, &sdu); - - if (err) { - continue; - } - - rx->ctx.app_idx = key->app_idx; - - bt_mesh_model_recv(rx, &sdu); - return 0; - } - - if (rx->local_match) { - BT_WARN("No matching AppKey"); - } - - return 0; -} - -static int sdu_recv_seg(struct seg_rx *seg, uint8_t hdr, uint8_t aszmic, - struct bt_mesh_net_rx *rx) -{ - NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_RX_SDU_MAX); - struct net_buf_simple sdu; - uint32_t seq = (seg->seq_auth & 0xffffff); - uint8_t *ad; - uint16_t i; - int err; - - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); - - if (seg->len < 1 + APP_MIC_LEN(aszmic)) { - BT_ERR("Too short SDU + MIC"); - return -EINVAL; - } - - if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && !rx->local_match) { - BT_DBG("Ignoring PDU for LPN 0x%04x of this Friend", - rx->ctx.recv_dst); - return 0; - } - - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ad = bt_mesh_label_uuid_get(rx->ctx.recv_dst); - } else { - ad = NULL; - } - - /* Decrypting in place to avoid creating two assembly buffers. - * We'll reassemble the buffer from the segments before each decryption - * attempt. - */ - if (!AKF(&hdr)) { - /* Attempt remote dev key first, as that is only available for - * provisioner devices, which normally don't interact with nodes - * that know their local dev key. - */ - seg_rx_assemble(seg, &buf, aszmic); - net_buf_simple_init_with_data(&sdu, buf.data, - seg->len - APP_MIC_LEN(aszmic)); - sdu.len = 0; - - err = remote_devkey_decrypt(rx, seq, ad, aszmic, &buf, &sdu); - if (!err) { - rx->ctx.app_idx = BT_MESH_KEY_DEV_REMOTE; - bt_mesh_model_recv(rx, &sdu); - return 0; - } - - seg_rx_assemble(seg, &buf, aszmic); - net_buf_simple_init_with_data(&sdu, buf.data, - seg->len - APP_MIC_LEN(aszmic)); - sdu.len = 0; - - err = bt_mesh_app_decrypt(bt_mesh.dev_key, true, aszmic, &buf, - &sdu, ad, rx->ctx.addr, - rx->ctx.recv_dst, seq, - BT_MESH_NET_IVI_RX(rx)); - if (err) { - BT_ERR("Unable to decrypt with local DevKey"); - return err; - } - - rx->ctx.app_idx = BT_MESH_KEY_DEV_LOCAL; - bt_mesh_model_recv(rx, &sdu); - return 0; - } - - for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - seg_rx_assemble(seg, &buf, aszmic); - net_buf_simple_init_with_data(&sdu, buf.data, - seg->len - APP_MIC_LEN(aszmic)); - sdu.len = 0; - - err = app_key_decrypt(rx, &bt_mesh.app_keys[i], seq, ad, hdr, - aszmic, &buf, &sdu); - if (err) { - continue; - } - - rx->ctx.app_idx = key->app_idx; - - bt_mesh_model_recv(rx, &sdu); - return 0; - } - - if (rx->local_match) { - BT_WARN("No matching AppKey"); - } + bt_mesh_model_recv(rx, sdu); return 0; } @@ -1150,6 +951,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, uint64_t *seq_auth) { + NET_BUF_SIMPLE_DEFINE_STATIC(sdu, BT_MESH_SDU_UNSEG_MAX); uint8_t hdr; BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); @@ -1169,14 +971,17 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, if (rx->ctl) { return ctl_recv(rx, hdr, buf, seq_auth); - } else { - /* SDUs must match a local element or an LPN of this Friend. */ - if (!rx->local_match && !rx->friend_match) { - return 0; - } - - return sdu_recv_unseg(rx, hdr, buf); } + + if (buf->len < 1 + APP_MIC_LEN(0)) { + BT_ERR("Too short SDU + MIC"); + return -EINVAL; + } + + /* Adjust the length to not contain the MIC at the end */ + buf->len -= APP_MIC_LEN(0); + + return sdu_recv(rx, hdr, 0, buf, &sdu, NULL); } static inline int32_t ack_timeout(struct seg_rx *rx) @@ -1643,12 +1448,29 @@ found_rx: send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); + /* Decrypt with seqAuth */ + net_rx->seq = (rx->seq_auth & 0xffffff); + if (net_rx->ctl) { NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_RX_CTL_MAX); seg_rx_assemble(rx, &sdu, 0U); err = ctl_recv(net_rx, *hdr, &sdu, seq_auth); + } else if (rx->len < 1 + APP_MIC_LEN(ASZMIC(hdr))) { + BT_ERR("Too short SDU + MIC"); + err = -EINVAL; } else { - err = sdu_recv_seg(rx, *hdr, ASZMIC(hdr), net_rx); + NET_BUF_SIMPLE_DEFINE_STATIC(seg_buf, BT_MESH_RX_SDU_MAX); + struct net_buf_simple sdu; + + /* Decrypting in place to avoid creating two assembly buffers. + * We'll reassemble the buffer from the segments before each + * decryption attempt. + */ + net_buf_simple_init(&seg_buf, 0); + net_buf_simple_init_with_data( + &sdu, seg_buf.data, rx->len - APP_MIC_LEN(ASZMIC(hdr))); + + err = sdu_recv(net_rx, *hdr, ASZMIC(hdr), &seg_buf, &sdu, rx); } seg_rx_reset(rx, false); @@ -1834,49 +1656,3 @@ int bt_mesh_heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data) return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), cb, cb_data); } - -int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - uint16_t addr, const uint8_t **key, uint8_t *aid) -{ - struct bt_mesh_app_key *app_key; - - if (app_idx == BT_MESH_KEY_DEV_LOCAL || - (app_idx == BT_MESH_KEY_DEV_REMOTE && - bt_mesh_elem_find(addr) != NULL)) { - *aid = 0; - *key = bt_mesh.dev_key; - return 0; - } else if (app_idx == BT_MESH_KEY_DEV_REMOTE) { - if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) { - return -EINVAL; - } - - struct bt_mesh_cdb_node *node = bt_mesh_cdb_node_get(addr); - if (!node) { - return -EINVAL; - } - - *key = node->dev_key; - *aid = 0; - return 0; - } - - if (!subnet) { - return -EINVAL; - } - - app_key = bt_mesh_app_key_find(app_idx); - if (!app_key) { - return -ENOENT; - } - - if (subnet->kr_phase == BT_MESH_KR_PHASE_2 && app_key->updated) { - *key = app_key->keys[1].val; - *aid = app_key->keys[1].id; - } else { - *key = app_key->keys[0].val; - *aid = app_key->keys[0].id; - } - - return 0; -} diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index e7d83e711d8..ae2742462a6 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -81,8 +81,6 @@ struct bt_mesh_ctl_friend_sub_confirm { void bt_mesh_set_hb_sub_dst(uint16_t addr); -struct bt_mesh_app_key *bt_mesh_app_key_find(uint16_t app_idx); - bool bt_mesh_tx_in_progress(void); void bt_mesh_rx_reset(void); @@ -92,6 +90,16 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, size_t data_len, const struct bt_mesh_send_cb *cb, void *cb_data); +/** @brief Send an access payload message. + * + * @param tx Network TX parameters. Only @c ctx, @c src and @c friend_cred + * have to be filled. + * @param msg Access payload to send. + * @param cb Message callback. + * @param cb_data Message callback data. + * + * @return 0 on success, or (negative) error code otherwise. + */ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data); @@ -100,6 +108,3 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); void bt_mesh_trans_init(void); 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, - uint16_t addr, const uint8_t **key, uint8_t *aid);