diff --git a/nimble/host/mesh/include/mesh/access.h b/nimble/host/mesh/include/mesh/access.h index fcd796be0..48ab62b48 100644 --- a/nimble/host/mesh/include/mesh/access.h +++ b/nimble/host/mesh/include/mesh/access.h @@ -28,6 +28,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 @@ -392,7 +393,7 @@ struct bt_mesh_model_pub { /** @brief Publication buffer, containing the publication message. * * The application is expected to initialize this with - * a valid net_buf_simple pointer, with the help of e.g. + * a valid os_mbuf pointer, with the help of e.g. * the NET_BUF_SIMPLE() macro. The publication buffer must * contain a valid publication message before calling the * bt_mesh_model_publish() API or after the publication's diff --git a/nimble/host/mesh/include/mesh/cfg.h b/nimble/host/mesh/include/mesh/cfg.h new file mode 100644 index 000000000..0cef42ada --- /dev/null +++ b/nimble/host/mesh/include/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 _BT_MESH_CFG_H_ +#define _BT_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 /* _BT_MESH_CFG_H_ */ \ No newline at end of file diff --git a/nimble/host/mesh/include/mesh/glue.h b/nimble/host/mesh/include/mesh/glue.h index 651bdea53..c7d104a89 100644 --- a/nimble/host/mesh/include/mesh/glue.h +++ b/nimble/host/mesh/include/mesh/glue.h @@ -234,10 +234,9 @@ static inline void net_buf_simple_init(struct os_mbuf *buf, } #define net_buf_simple_init_with_data(buf, data, size) \ - buf = NET_BUF_SIMPLE(size); \ os_mbuf_copyinto(buf, 0, data, size); -static inline void net_buf_simple_reset(struct os_mbuf *om) +static inline void os_mbuf_reset(struct os_mbuf *om) { om->om_len = 0; om->om_data = om->om_databuf; @@ -262,7 +261,7 @@ void net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val); void net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val); void net_buf_simple_push_be24(struct os_mbuf *om, uint32_t val); void net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val); -void *net_buf_simple_pull(struct os_mbuf *om, uint8_t len); +void *net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len); void *net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len); void *net_buf_simple_add(struct os_mbuf *om, uint8_t len); bool k_fifo_is_empty(struct ble_npl_eventq *q); @@ -278,7 +277,7 @@ void net_buf_reserve(struct os_mbuf *om, size_t reserve); #define net_buf_clone(a, b) os_mbuf_dup(a) #define net_buf_add_be32(a, b) net_buf_simple_add_be32(a, b) #define net_buf_add_be16(a, b) net_buf_simple_add_be16(a, b) -#define net_buf_pull(a, b) net_buf_simple_pull(a, b) +#define net_buf_pull(a, b) net_buf_simple_pull_mem(a, b) #define net_buf_pull_mem(a, b) net_buf_simple_pull_mem(a, b) #define net_buf_pull_u8(a) net_buf_simple_pull_u8(a) #define net_buf_pull_be16(a) net_buf_simple_pull_be16(a) @@ -346,14 +345,14 @@ void k_work_add_arg(struct ble_npl_callout *w, void *arg); void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg); uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w); -static inline void net_buf_simple_save(struct os_mbuf *buf, +static inline void os_mbuf_save(struct os_mbuf *buf, struct net_buf_simple_state *state) { state->offset = net_buf_simple_headroom(buf); state->len = buf->om_len; } -static inline void net_buf_simple_restore(struct os_mbuf *buf, +static inline void os_mbuf_restore(struct os_mbuf *buf, struct net_buf_simple_state *state) { buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + state->offset; diff --git a/nimble/host/mesh/include/mesh/health_srv.h b/nimble/host/mesh/include/mesh/health_srv.h index 5d1c0de01..ad79e368d 100644 --- a/nimble/host/mesh/include/mesh/health_srv.h +++ b/nimble/host/mesh/include/mesh/health_srv.h @@ -52,7 +52,7 @@ struct bt_mesh_health_srv_cb { * * @param max_faults Maximum number of faults the element can have. * - * @return a New net_buf_simple of the needed size. + * @return a New os_mbuf of the needed size. */ #define BT_MESH_HEALTH_FAULT_MSG(max_faults) \ NET_BUF_SIMPLE(1 + 3 + (max_faults)) diff --git a/nimble/host/mesh/include/mesh/mesh.h b/nimble/host/mesh/include/mesh/mesh.h index c67bf912d..77b37d7fa 100644 --- a/nimble/host/mesh/include/mesh/mesh.h +++ b/nimble/host/mesh/include/mesh/mesh.h @@ -23,5 +23,6 @@ #include "health_cli.h" #include "proxy.h" #include "cdb.h" +#include "cfg.h" #endif /* __BT_MESH_H */ diff --git a/nimble/host/mesh/src/access.c b/nimble/host/mesh/src/access.c index e87151de9..952ab0183 100644 --- a/nimble/host/mesh/src/access.c +++ b/nimble/host/mesh/src/access.c @@ -156,30 +156,18 @@ static int publish_retransmit(struct bt_mesh_model *mod) { struct os_mbuf *sdu = NET_BUF_SIMPLE(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, }; int err; - key = bt_mesh_app_key_find(pub->key); - if (!key) { - err = -EADDRNOTAVAIL; - goto done; - } - - tx.sub = bt_mesh_subnet_get(key->net_idx); - - ctx.net_idx = key->net_idx; - ctx.app_idx = key->app_idx; - net_buf_simple_init(sdu, 0); net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); @@ -187,7 +175,6 @@ static int publish_retransmit(struct bt_mesh_model *mod) err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); -done: os_mbuf_free_chain(sdu); return err; } @@ -630,9 +617,9 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) * store the parsing state in case multiple models * receive the message. */ - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); op->func(model, &rx->ctx, buf); - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); } } @@ -698,24 +685,9 @@ int bt_mesh_model_send(struct bt_mesh_model *model, struct os_mbuf *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); @@ -725,13 +697,15 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) { struct os_mbuf *sdu = NET_BUF_SIMPLE(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; @@ -747,12 +721,6 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) goto done; } - key = bt_mesh_app_key_find(pub->key); - if (!key) { - err = -EADDRNOTAVAIL; - goto done; - } - if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) { BT_ERR("Message does not fit maximum SDU size"); err = -EMSGSIZE; @@ -767,14 +735,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) net_buf_simple_init(sdu, 0); net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_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/nimble/host/mesh/src/adv.c b/nimble/host/mesh/src/adv.c index 5cb0aa6a7..314383809 100644 --- a/nimble/host/mesh/src/adv.c +++ b/nimble/host/mesh/src/adv.c @@ -281,7 +281,7 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, return; } - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); type = net_buf_simple_pull_u8(buf); @@ -301,8 +301,8 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, break; } - net_buf_simple_restore(buf, &state); - net_buf_simple_pull(buf, len); + os_mbuf_restore(buf, &state); + net_buf_simple_pull_mem(buf, len); } } @@ -360,7 +360,7 @@ ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_EXT_DISC: ext_desc = &event->ext_disc; buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0); - if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) { + if (!buf || os_mbuf_append(buf, ext_desc->om_data, ext_desc->length_data)) { BT_ERR("Could not append data"); goto done; } diff --git a/nimble/host/mesh/src/app_keys.c b/nimble/host/mesh/src/app_keys.c new file mode 100644 index 000000000..ccdaad3f7 --- /dev/null +++ b/nimble/host/mesh/src/app_keys.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "mesh/mesh.h" +#include "mesh_priv.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" +#include "subnet.h" + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_KEYS) +#define LOG_MODULE_NAME bt_mesh_app_keys +#include "log/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) +{ + int i; + + for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { + bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); + } +} + +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; +} + +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); + } + } +} + +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]) +{ + bt_mesh_subnet_cb_list[0] = subnet_evt; + 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; +} + + +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); + } + } +} \ No newline at end of file diff --git a/nimble/host/mesh/src/app_keys.h b/nimble/host/mesh/src/app_keys.h new file mode 100644 index 000000000..d007b785f --- /dev/null +++ b/nimble/host/mesh/src/app_keys.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BT_MESH_APP_KEYS_H_ +#define _BT_MESH_APP_KEYS_H_ + +#include "mesh/mesh.h" +#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); + +struct bt_mesh_app_key *app_get(uint16_t app_idx); + +extern void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, + enum bt_mesh_key_evt evt); + +#endif /* _BT_MESH_APP_KEYS_H_ */ \ No newline at end of file diff --git a/nimble/host/mesh/src/beacon.c b/nimble/host/mesh/src/beacon.c index 2db03cf93..f83ed55ac 100644 --- a/nimble/host/mesh/src/beacon.c +++ b/nimble/host/mesh/src/beacon.c @@ -36,23 +36,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) @@ -77,11 +63,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); @@ -103,44 +85,34 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, #define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \ K_SECONDS(5)) -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 os_mbuf *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 os_mbuf *buf; - uint32_t time_diff; - - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - continue; - } - - time_diff = now - sub->beacon_sent; - if (time_diff < K_SECONDS(600) && - 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); - - 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); + + bt_mesh_adv_send(buf, &send_cb, sub); + net_buf_unref(buf); + return 0; } @@ -232,10 +204,15 @@ static void unprovisioned_beacon_recv(struct os_mbuf *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 @@ -246,16 +223,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 = 0; - } + bt_mesh_subnet_foreach(sub_update_beacon_observation); } static void beacon_send(struct ble_npl_event *work) @@ -271,7 +239,7 @@ static void beacon_send(struct ble_npl_event *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 || @@ -290,20 +258,62 @@ static void beacon_send(struct ble_npl_event *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 os_mbuf *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->om_len < 21) { BT_ERR("Too short secure beacon (len %u)", buf->om_len); return; } - sub = cache_check(buf->om_data); + sub = bt_mesh_subnet_find(cache_check, buf->om_data); if (sub) { /* We've seen this beacon before - just update the stats */ goto update_stats; @@ -312,33 +322,29 @@ static void secure_beacon_recv(struct os_mbuf *buf) /* So we can add to the cache if auth matches */ data = buf->om_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->om_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->om_data; BT_DBG("flags 0x%02x id %s iv_index 0x%08x", - flags, bt_hex(net_id, 8), (unsigned) 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) && @@ -348,20 +354,15 @@ static void secure_beacon_recv(struct os_mbuf *buf) } BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", - sub->net_idx, (unsigned) iv_index, (unsigned) 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 && @@ -397,8 +398,36 @@ void bt_mesh_beacon_recv(struct os_mbuf *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); + } +} + void bt_mesh_beacon_init(void) { + bt_mesh_subnet_cb_list[1] = subnet_evt; + k_delayed_work_init(&beacon_timer, beacon_send); } @@ -413,27 +442,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 = 0; - sub->beacons_cur = 0; - - bt_mesh_net_beacon_update(sub); - } + bt_mesh_subnet_foreach(subnet_beacon_enable); k_work_submit(&beacon_timer.work); } diff --git a/nimble/host/mesh/src/beacon.h b/nimble/host/mesh/src/beacon.h index ac4bfed8a..a6aa8cbb2 100644 --- a/nimble/host/mesh/src/beacon.h +++ b/nimble/host/mesh/src/beacon.h @@ -22,5 +22,6 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct os_mbuf *buf); void bt_mesh_beacon_init(void); +void bt_mesh_beacon_update(struct bt_mesh_subnet *sub); #endif diff --git a/nimble/host/mesh/src/cfg_srv.c b/nimble/host/mesh/src/cfg_srv.c index f9ae62f7c..3b52f865f 100644 --- a/nimble/host/mesh/src/cfg_srv.c +++ b/nimble/host/mesh/src/cfg_srv.c @@ -17,6 +17,7 @@ #include "mesh_priv.h" #include "adv.h" +#include "app_keys.h" #include "net.h" #include "rpl.h" #include "lpn.h" @@ -40,6 +41,9 @@ static struct label labels[CONFIG_BT_MESH_LABEL_COUNT]; static uint8_t va_del(uint8_t *label_uuid, uint16_t *addr); #endif +void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, + enum bt_mesh_key_evt evt); + static int comp_add_elem(struct os_mbuf *buf, struct bt_mesh_elem *elem, bool primary) { @@ -174,22 +178,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) @@ -230,7 +218,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; } @@ -277,7 +265,7 @@ 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; } @@ -309,7 +297,7 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) 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; } @@ -333,115 +321,27 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) 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; + struct os_mbuf *msg = NET_BUF_SIMPLE( + BT_MESH_MODEL_BUF_LEN(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 os_mbuf *buf) { - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_STATUS, 4); uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -449,26 +349,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->om_data); - status = app_key_set(key_net_idx, key_app_idx, buf->om_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"); - } - - os_mbuf_free_chain(msg); + 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 os_mbuf *buf) { - struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_STATUS, 4); uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -476,97 +365,42 @@ 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->om_data, true); + status = bt_mesh_app_key_update(key_app_idx, key_net_idx, buf->om_data); 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"); - } - - os_mbuf_free_chain(msg); + send_app_key_status(model, ctx, status, key_app_idx, key_net_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) +static void mod_app_key_del(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, bool vnd, bool primary, + void *user_data) { - struct unbind_data *data = user_data; + uint16_t *app_idx = user_data; - mod_unbind(mod, data->app_idx, data->store); + mod_unbind(mod, *app_idx, true); } -void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store) +static void app_key_evt(uint16_t app_idx, uint16_t net_idx, + enum bt_mesh_key_evt evt) { - 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); + if (evt == BT_MESH_KEY_DELETED) { + bt_mesh_model_foreach(&mod_app_key_del, &app_idx); } - - key->net_idx = BT_MESH_KEY_UNUSED; - memset(key->keys, 0, sizeof(key->keys)); } static void app_key_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - struct os_mbuf *msg = BT_MESH_MODEL_BUF(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"); - } - - os_mbuf_free_chain(msg); + 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 */ @@ -579,8 +413,11 @@ static void app_key_get(struct bt_mesh_model *model, struct os_mbuf *msg = BT_MESH_MODEL_BUF(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) { @@ -592,7 +429,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; @@ -605,25 +442,17 @@ static void app_key_get(struct bt_mesh_model *model, goto send_status; } - prev = BT_MESH_KEY_UNUSED; - 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 != 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: @@ -1334,8 +1163,8 @@ static void mod_pub_va_set(struct bt_mesh_model *model, return; } - net_buf_simple_pull(buf, 16); - mod_id = net_buf_simple_pull(buf, 4); + net_buf_simple_pull_mem(buf, 16); + mod_id = net_buf_simple_pull_mem(buf, 4); BT_DBG("elem_addr 0x%04x", elem_addr); @@ -2044,7 +1873,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, return; } - net_buf_simple_pull(buf, 16); + net_buf_simple_pull_mem(buf, 16); mod_id = buf->om_data; @@ -2085,7 +1914,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model, return; } - net_buf_simple_pull(buf, 16); + net_buf_simple_pull_mem(buf, 16); mod_id = buf->om_data; @@ -2124,7 +1953,7 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, return; } - net_buf_simple_pull(buf, 18); + net_buf_simple_pull_mem(buf, 18); mod_id = buf->om_data; @@ -2170,9 +1999,8 @@ static void net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - struct bt_mesh_subnet *sub; + uint8_t status; uint16_t idx; - int err; idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2182,72 +2010,16 @@ 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; - - 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->om_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->om_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 ((MYNEWT_VAL(BLE_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); + status = bt_mesh_subnet_add(idx, buf->om_data); + 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 os_mbuf *buf) { - struct bt_mesh_subnet *sub; + uint8_t status; uint16_t idx; - int err; idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2255,59 +2027,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->om_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->om_data, sub->keys[0].net, 16)) { - return; - } - break; - case BT_MESH_KR_PHASE_1: - if (!memcmp(buf->om_data, sub->keys[1].net, 16)) { - send_net_key_status(model, ctx, idx, STATUS_SUCCESS); - return; - } - /* fall through */ - 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->om_data); - if (!err && ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) || - (MYNEWT_VAL(BLE_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) @@ -2326,9 +2048,7 @@ static void net_key_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *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) { @@ -2338,28 +2058,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, @@ -2369,29 +2079,23 @@ static void net_key_get(struct bt_mesh_model *model, struct os_mbuf *msg = BT_MESH_MODEL_BUF(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 = 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 (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)) { @@ -2401,13 +2105,29 @@ static void net_key_get(struct bt_mesh_model *model, os_mbuf_free_chain(msg); } +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) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(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 os_mbuf *buf) { - struct os_mbuf *msg = BT_MESH_MODEL_BUF(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", @@ -2417,38 +2137,19 @@ static void node_identity_get(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - goto done; + 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"); - } - -done: - os_mbuf_free_chain(msg); + 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 os_mbuf *buf) { - struct os_mbuf *msg = BT_MESH_MODEL_BUF(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", @@ -2458,45 +2159,30 @@ static void node_identity_set(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_WARN("Invalid NetKeyIndex 0x%04x", idx); - goto done; + return; } node_id = net_buf_simple_pull_u8(buf); if (node_id != 0x00 && node_id != 0x01) { BT_WARN("Invalid Node ID value 0x%02x", node_id); - goto done; + 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 (MYNEWT_VAL(BLE_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; } -done: - os_mbuf_free_chain(msg); - + send_node_id_status(model, ctx, status, idx, node_id); } static void create_mod_app_status(struct os_mbuf *msg, @@ -2797,7 +2483,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(); } } @@ -2878,7 +2564,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 os_mbuf *buf) { - struct bt_mesh_subnet *sub; + uint8_t kr_phase, status; uint16_t idx; idx = net_buf_simple_pull_le16(buf); @@ -2889,20 +2575,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 os_mbuf *buf) { - struct bt_mesh_subnet *sub; - uint8_t phase; + uint8_t phase, status; uint16_t idx; idx = net_buf_simple_pull_le16(buf); @@ -2913,47 +2594,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 ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) || - (MYNEWT_VAL(BLE_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) @@ -3388,6 +3035,8 @@ static int cfg_srv_init(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + bt_mesh_app_key_cb_list[0] = app_key_evt; + BT_DBG(""); if (!bt_mesh_model_in_primary(model)) { @@ -3466,7 +3115,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(""); @@ -3476,17 +3124,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); memset(labels, 0, sizeof(labels)); @@ -3619,40 +3256,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); - } - - memset(sub, 0, sizeof(*sub)); - sub->net_idx = BT_MESH_KEY_UNUSED; -} diff --git a/nimble/host/mesh/src/crypto.c b/nimble/host/mesh/src/crypto.c index c9bf41ecc..3111a6efa 100644 --- a/nimble/host/mesh/src/crypto.c +++ b/nimble/host/mesh/src/crypto.c @@ -325,114 +325,70 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct os_mbuf *buf, NULL, 0, &buf->om_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]); } -static int mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *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 os_mbuf *buf) { + int err; uint8_t nonce[13]; 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", (unsigned) seq_num, - (unsigned) 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->om_data, buf->om_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)); - return bt_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ad, - ad ? 16 : 0, buf->om_data, - APP_MIC_LEN(aszmic)); -} + err = bt_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad, + ctx->ad ? 16 : 0, buf->om_data, + APP_MIC_LEN(ctx->aszmic)); -int bt_mesh_app_encrypt_in_place(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *buf, const uint8_t *ad, uint16_t src, - uint16_t dst, uint32_t seq_num, uint32_t iv_index) -{ - int err; - - err = mesh_app_encrypt(key, dev_key, aszmic, buf, ad, src, dst, - seq_num, iv_index); if (!err) { + net_buf_simple_add(buf, APP_MIC_LEN(ctx->aszmic)); BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len)); } return err; } -int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *buf, const uint8_t *ad, - uint16_t src, uint16_t dst, uint32_t seq_num, uint32_t iv_index) -{ - int err; - - err = mesh_app_encrypt(key, dev_key, aszmic, buf, ad, src, dst, - seq_num, iv_index); - - if (!err) { - net_buf_simple_add(buf, APP_MIC_LEN(aszmic)); - BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len)); - } - - return err; -} - -static int mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *buf, struct os_mbuf *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 os_mbuf *buf, struct os_mbuf *out) { uint8_t nonce[13]; + int err; BT_DBG("EncData (len %u) %s", buf->om_len, bt_hex(buf->om_data, buf->om_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)); - return bt_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ad, - ad ? 16 : 0, out->om_data, - APP_MIC_LEN(aszmic)); -} - -int bt_mesh_app_decrypt_in_place(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *buf, const uint8_t *ad, uint16_t src, - uint16_t dst, uint32_t seq_num, uint32_t iv_index) -{ - return mesh_app_decrypt(key, dev_key, aszmic, buf, buf, - ad, src, dst, seq_num, iv_index); -} - -int bt_mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, - struct os_mbuf *buf, struct os_mbuf *out, - const uint8_t *ad, uint16_t src, uint16_t dst, uint32_t seq_num, - uint32_t iv_index) -{ - int err; - - err = mesh_app_decrypt(key, dev_key, aszmic, buf, out, - ad, src, dst, seq_num, iv_index); + err = bt_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad, + ctx->ad ? 16 : 0, out->om_data, + APP_MIC_LEN(ctx->aszmic)); if (!err) { net_buf_simple_add(out, buf->om_len); } diff --git a/nimble/host/mesh/src/crypto.h b/nimble/host/mesh/src/crypto.h index 35fabe509..4b2961d1d 100644 --- a/nimble/host/mesh/src/crypto.h +++ b/nimble/host/mesh/src/crypto.h @@ -135,18 +135,27 @@ int bt_mesh_app_encrypt_in_place(const uint8_t key[16], bool dev_key, uint8_t as struct os_mbuf*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], bool dev_key, uint8_t aszmic, - struct os_mbuf*buf, const uint8_t *ad, - uint16_t src, uint16_t dst, uint32_t seq_num, uint32_t iv_index); - int bt_mesh_app_decrypt_in_place(const uint8_t key[16], bool dev_key, uint8_t aszmic, struct os_mbuf *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 os_mbuf*buf, struct os_mbuf*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 os_mbuf *buf); + +int bt_mesh_app_decrypt(const uint8_t key[16], + const struct bt_mesh_app_crypto_ctx *ctx, + struct os_mbuf *buf, struct os_mbuf *out); uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len); diff --git a/nimble/host/mesh/src/foundation.h b/nimble/host/mesh/src/foundation.h index 2679bdfc7..985894b2c 100644 --- a/nimble/host/mesh/src/foundation.h +++ b/nimble/host/mesh/src/foundation.h @@ -148,11 +148,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); - static inline void key_idx_pack(struct os_mbuf *buf, uint16_t idx1, uint16_t idx2) { @@ -165,7 +160,7 @@ static inline void key_idx_unpack(struct os_mbuf *buf, { *idx1 = sys_get_le16(&buf->om_data[0]) & 0xfff; *idx2 = sys_get_le16(&buf->om_data[1]) >> 4; - net_buf_simple_pull(buf, 3); + net_buf_simple_pull_mem(buf, 3); } #endif diff --git a/nimble/host/mesh/src/friend.c b/nimble/host/mesh/src/friend.c index 4915e389d..ed6e69dd9 100644 --- a/nimble/host/mesh/src/friend.c +++ b/nimble/host/mesh/src/friend.c @@ -21,10 +21,12 @@ #include "crypto.h" #include "adv.h" #include "net.h" +#include "app_keys.h" #include "transport.h" #include "access.h" #include "foundation.h" #include "friend.h" +#include "subnet.h" /* We reserve one extra buffer for each friendship, since we need to be able * to resend the last sent PDU, which sits separately outside of the queue. @@ -89,7 +91,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; } @@ -97,7 +99,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; } @@ -109,6 +112,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(struct net_buf_slist_t *list) { struct os_mbuf *buf; @@ -142,7 +153,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 */ @@ -163,7 +174,7 @@ static void friend_clear(struct bt_mesh_friend *frnd) seg->seg_count = 0U; } - frnd->valid = 0; + frnd->subnet = NULL; frnd->established = 0; frnd->pending_buf = 0; frnd->fsn = 0; @@ -172,22 +183,20 @@ static void friend_clear(struct bt_mesh_friend *frnd) 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); } } @@ -202,11 +211,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); } } @@ -324,12 +334,10 @@ static struct os_mbuf *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, @@ -337,25 +345,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 = (app_idx == BT_MESH_KEY_DEV); - meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx); - bt_mesh_net_header_parse(buf, &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, &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; @@ -370,16 +383,14 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, BT_DBG(""); - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); net_buf_simple_pull_mem(buf, 10); buf->om_len -= 4; - err = bt_mesh_app_decrypt_in_place(meta->key, meta->is_dev_key, - 0, buf, meta->ad, meta->net.ctx.addr, - meta->net.ctx.recv_dst, meta->net.seq, - BT_MESH_NET_IVI_TX); + err = bt_mesh_app_decrypt(meta->key, &meta->crypto, buf, buf); - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); + net_buf_unref(buf); return err; } @@ -392,16 +403,13 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, BT_DBG(""); - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); net_buf_simple_pull_mem(buf, 10); buf->om_len -= 4; - err = bt_mesh_app_encrypt_in_place(meta->key, meta->is_dev_key, 0, buf, - meta->ad, meta->net.ctx.addr, - meta->net.ctx.recv_dst, bt_mesh.seq, - BT_MESH_NET_IVI_TX); + err = bt_mesh_app_encrypt(meta->key, &meta->crypto, buf); - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); return err; } @@ -425,7 +433,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; } @@ -446,22 +454,16 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *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->om_data[5]); @@ -486,14 +488,14 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi)); } - buf->om_data[0] = (nid | (iv_index & 1) << 7); + buf->om_data[0] = (cred->nid | (iv_index & 1) << 7); - if (bt_mesh_net_encrypt(enc, buf, iv_index, false)) { + if (bt_mesh_net_encrypt(cred->enc, buf, iv_index, false)) { BT_ERR("Encrypting failed"); return -EINVAL; } - if (bt_mesh_net_obfuscate(buf->om_data, iv_index, priv)) { + if (bt_mesh_net_obfuscate(buf->om_data, iv_index, cred->privacy)) { BT_ERR("Obfuscating failed"); return -EINVAL; } @@ -528,17 +530,16 @@ static struct os_mbuf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) { struct bt_mesh_ctl_friend_update *upd; struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd)); - struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx); struct os_mbuf *buf; - __ASSERT_NO_MSG(sub != NULL); + __ASSERT_NO_MSG(frnd->subnet); BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); net_buf_simple_init(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; @@ -765,13 +766,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(), @@ -932,7 +933,7 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) struct bt_mesh_ctl_friend_req *msg = (void *)buf->om_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_WARN("Ignoring Friend request from local interface"); @@ -986,9 +987,8 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *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 = 1; break; } } @@ -1001,12 +1001,19 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *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 * 100; 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, (unsigned) frnd->poll_to); @@ -1020,9 +1027,6 @@ init_friend: 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; @@ -1039,12 +1043,12 @@ static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_ze return false; } - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); net_buf_skip(buf, 5); /* skip IVI, NID, CTL, TTL, SEQ */ buf_src = net_buf_pull_be16(buf); net_buf_skip(buf, 3); /* skip DST, OP/AID */ buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK); - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); return ((src == buf_src) && (seq_zero == buf_seq_zero)); } @@ -1157,7 +1161,7 @@ static void update_overwrite(struct os_mbuf *buf, uint8_t md) return; } - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); net_buf_skip(buf, 1); /* skip IVI, NID */ @@ -1177,7 +1181,7 @@ static void update_overwrite(struct os_mbuf *buf, uint8_t md) upd->md = md; end: - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); } static void friend_timeout(struct ble_npl_event *work) @@ -1236,8 +1240,54 @@ 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; + } + } +} + int bt_mesh_friend_init(void) { + bt_mesh_subnet_cb_list[3] = subnet_evt; int rc; int i; @@ -1255,8 +1305,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; - net_buf_slist_init(&frnd->queue); k_delayed_work_init(&frnd->timer, friend_timeout); @@ -1281,7 +1329,7 @@ static bool is_segack(struct os_mbuf *buf, uint64_t *seqauth, uint16_t src) return false; } - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); net_buf_skip(buf, 1); /* skip IVI, NID */ @@ -1304,7 +1352,7 @@ static bool is_segack(struct os_mbuf *buf, uint64_t *seqauth, uint16_t src) found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == (*seqauth & TRANS_SEQ_ZERO_MASK); end: - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); return found; } @@ -1435,7 +1483,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/nimble/host/mesh/src/friend.h b/nimble/host/mesh/src/friend.h index 48acc2278..ee783f33a 100644 --- a/nimble/host/mesh/src/friend.h +++ b/nimble/host/mesh/src/friend.h @@ -39,7 +39,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 os_mbuf *buf); int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); diff --git a/nimble/host/mesh/src/glue.c b/nimble/host/mesh/src/glue.c index 6d046eb59..e1c2ae3f4 100644 --- a/nimble/host/mesh/src/glue.c +++ b/nimble/host/mesh/src/glue.c @@ -336,7 +336,7 @@ net_buf_simple_pull_mem(struct os_mbuf *om, uint8_t len) { void *data = om->om_data; - net_buf_simple_pull(om, len); + net_buf_simple_pull_mem(om, len); return data; } diff --git a/nimble/host/mesh/src/lpn.c b/nimble/host/mesh/src/lpn.c index 783e03127..df0c6c238 100644 --- a/nimble/host/mesh/src/lpn.c +++ b/nimble/host/mesh/src/lpn.c @@ -171,20 +171,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(""); @@ -211,8 +211,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 { @@ -232,6 +230,7 @@ static void clear_friendship(bool force, bool disable) lpn->sent_req = 0; lpn->established = 0; lpn->clear_success = 0; + lpn->sub = NULL; group_zero(lpn->added); group_zero(lpn->pending); @@ -285,13 +284,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, @@ -302,7 +301,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(""); @@ -351,13 +350,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, @@ -478,13 +477,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 os_mbuf *buf) { struct bt_mesh_ctl_friend_offer *msg = (void *)buf->om_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; @@ -511,14 +518,21 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, lpn->frnd = rx->ctx.addr; - 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; @@ -526,14 +540,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 = 0; lpn->queue_size = 0; return err; } - lpn->counter++; + lpn->lpn_counter++; return 0; } @@ -560,7 +574,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; } @@ -633,13 +647,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, @@ -760,7 +774,7 @@ static void lpn_timeout(struct ble_npl_event *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); @@ -981,11 +995,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, (unsigned) 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) { @@ -1025,10 +1035,30 @@ 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; + } +} + int bt_mesh_lpn_init(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + bt_mesh_subnet_cb_list[2] = subnet_evt; + BT_DBG(""); k_delayed_work_init(&lpn->timer, lpn_timeout); diff --git a/nimble/host/mesh/src/mesh.c b/nimble/host/mesh/src/mesh.c index da688840e..0d68c25f1 100644 --- a/nimble/host/mesh/src/mesh.c +++ b/nimble/host/mesh/src/mesh.c @@ -19,6 +19,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, memcpy(bt_mesh.dev_key, dev_key, 16); - 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 ((MYNEWT_VAL(BLE_MESH_FRIEND))) { - bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY); + bt_mesh_friends_clear(); } if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) { diff --git a/nimble/host/mesh/src/mesh_priv.h b/nimble/host/mesh/src/mesh_priv.h index 03e61c877..11efcac44 100644 --- a/nimble/host/mesh/src/mesh_priv.h +++ b/nimble/host/mesh/src/mesh_priv.h @@ -8,7 +8,8 @@ #ifndef __MESH_PRIV_H #define __MESH_PRIV_H -#include +#include +#include #define BT_MESH_KEY_PRIMARY 0x0000 #define BT_MESH_KEY_ANY 0xffff @@ -17,6 +18,21 @@ #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); +}; + struct bt_mesh_net; int bt_mesh_start(void); diff --git a/nimble/host/mesh/src/net.c b/nimble/host/mesh/src/net.c index 7e7cc939e..c10fb614c 100644 --- a/nimble/host/mesh/src/net.c +++ b/nimble/host/mesh/src/net.c @@ -56,17 +56,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 (MYNEWT_VAL(BLE_MESH_FRIEND)) -#define FRIEND_CRED_COUNT MYNEWT_VAL(BLE_MESH_FRIEND_LPN_COUNT) -#elif (MYNEWT_VAL(BLE_MESH_LOW_POWER)) -#define FRIEND_CRED_COUNT MYNEWT_VAL(BLE_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; @@ -76,16 +65,6 @@ static uint16_t msg_cache_next; /* Singleton network context (the implementation only supports one) */ struct bt_mesh_net bt_mesh = { .local_queue = STAILQ_HEAD_INITIALIZER(bt_mesh.local_queue), - .sub = { - [0 ... (MYNEWT_VAL(BLE_MESH_SUBNET_COUNT) - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, - .app_keys = { - [0 ... (MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT) - 1)] = { - .net_idx = BT_MESH_KEY_UNUSED, - } - }, }; static struct os_mempool loopback_buf_pool_mem; @@ -137,331 +116,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 (MYNEWT_VAL(BLE_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 (MYNEWT_VAL(BLE_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 = 0; - cred->frnd_counter = 0; - 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, (unsigned) 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, - (unsigned) iv_index); + 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 ((MYNEWT_VAL(BLE_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)); @@ -472,89 +149,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. - */ - case BT_MESH_KR_PHASE_2: - BT_DBG("KR Phase 0x%02x -> Normal", sub->kr_phase); - bt_mesh_net_revoke_keys(sub); - if ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) || - (MYNEWT_VAL(BLE_MESH_FRIEND))) { - friend_cred_refresh(sub->net_idx); - } - sub->kr_phase = BT_MESH_KR_NORMAL; - return true; - } - } - - return false; -} - #if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST) void bt_mesh_iv_update_test(bool enable) { @@ -576,29 +180,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 */ @@ -682,12 +269,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 (MYNEWT_VAL(BLE_MESH_CDB)) { bt_mesh_cdb_iv_update(iv_index, iv_update); } @@ -712,7 +305,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; @@ -741,7 +333,7 @@ static void bt_mesh_net_local(struct ble_npl_event *work) .old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01)), .ctl = CTL(buf->om_data), .seq = SEQ(buf->om_data), - .new_key = sub->kr_flag, + .new_key = SUBNET_KEY_TX_IDX(sub), .local_match = 1U, .friend_match = 0U, }; @@ -754,26 +346,16 @@ static void bt_mesh_net_local(struct ble_npl_event *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(BLE_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, @@ -808,26 +390,33 @@ static int net_header_encode(struct bt_mesh_net_tx *tx, uint8_t nid, return 0; } +static int net_encrypt(struct os_mbuf *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->om_data, iv_index, cred->privacy); +} + int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *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->om_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, @@ -857,8 +446,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 os_mbuf *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", @@ -871,8 +459,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *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); + cred = net_tx_cred_get(tx); + err = net_header_encode(tx, cred->nid, buf); if (err) { goto done; } @@ -904,12 +492,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, goto done; } - err = bt_mesh_net_encrypt(enc, buf, BT_MESH_NET_IVI_TX, false); - if (err) { - goto done; - } - - err = bt_mesh_net_obfuscate(buf->om_data, BT_MESH_NET_IVI_TX, priv); + err = net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, false); if (err) { goto done; } @@ -956,187 +539,47 @@ 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 os_mbuf *in, + struct os_mbuf *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->om_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->om_data)); + BT_DBG("IVI %u net->iv_index 0x%08x", IVI(in->om_data), bt_mesh.iv_index); - if (memcmp(auth, net_auth, 8)) { - BT_WARN("Authentication Value %s != %s", - bt_hex(auth, 8), bt_hex(net_auth, 8)); + rx->old_iv = (IVI(in->om_data) != (bt_mesh.iv_index & 0x01)); + os_mbuf_reset(out); + net_buf_simple_add_mem(out, in->om_data, in->om_len); + + if (bt_mesh_net_obfuscate(out->om_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 os_mbuf *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), - (unsigned) bt_mesh.iv_index); - - rx->old_iv = (IVI(data) != (bt_mesh.iv_index & 0x01)); - - net_buf_simple_init(buf, 0); - memcpy(net_buf_simple_add(buf, data_len), data, data_len); - - if (bt_mesh_net_obfuscate(buf->om_data, BT_MESH_NET_IVI_RX(rx), priv)) { - return -ENOENT; - } - - rx->ctx.addr = SRC(buf->om_data); + rx->ctx.addr = SRC(out->om_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 ((MYNEWT_VAL(BLE_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 os_mbuf *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 = 1; - 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 os_mbuf *buf) -{ - struct bt_mesh_subnet *sub; - unsigned 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 = 1; - 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 @@ -1159,9 +602,9 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) static void bt_mesh_net_relay(struct os_mbuf *sbuf, struct bt_mesh_net_rx *rx) { - const uint8_t *enc, *priv; + const struct bt_mesh_net_cred *cred; struct os_mbuf *buf; - uint8_t nid, transmit; + uint8_t transmit; if (rx->ctx.recv_ttl <= 1U) { return; @@ -1198,32 +641,25 @@ static void bt_mesh_net_relay(struct os_mbuf *sbuf, net_buf_add_mem(buf, sbuf->om_data, sbuf->om_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->om_data)); /* Update NID if RX or RX was with friend credentials */ if (rx->friend_cred) { buf->om_data[0] &= 0x80; /* Clear everything except IVI */ - buf->om_data[0] |= nid; + buf->om_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, BT_MESH_NET_IVI_RX(rx), false)) { + if (net_encrypt(buf, cred, BT_MESH_NET_IVI_RX(rx), false)) { BT_ERR("Re-encrypting failed"); goto done; } - if (bt_mesh_net_obfuscate(buf->om_data, BT_MESH_NET_IVI_RX(rx), priv)) { - BT_ERR("Re-obfuscating failed"); - goto done; - } - BT_DBG("encoded %u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); @@ -1257,26 +693,26 @@ void bt_mesh_net_header_parse(struct os_mbuf *buf, rx->ctx.recv_dst = DST(buf->om_data); } -int bt_mesh_net_decode(struct os_mbuf *data, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct os_mbuf *buf) +int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct os_mbuf *out) { - if (data->om_len < BT_MESH_NET_MIN_PDU_LEN) { - BT_WARN("Dropping too short mesh packet (len %u)", data->om_len); - BT_WARN("%s", bt_hex(data->om_data, data->om_len)); + if (in->om_len < BT_MESH_NET_MIN_PDU_LEN) { + BT_WARN("Dropping too short mesh packet (len %u)", in->om_len); + BT_WARN("%s", bt_hex(in->om_data, in->om_len)); return -EINVAL; } - if (net_if == BT_MESH_NET_IF_ADV && check_dup(data)) { - BT_DBG("duplicate packet; dropping %u bytes: %s", data->om_len, - bt_hex(data->om_data, data->om_len)); + if (net_if == BT_MESH_NET_IF_ADV && check_dup(in)) { + BT_DBG("duplicate packet; dropping %u bytes: %s", in->om_len, + bt_hex(in->om_data, in->om_len)); return -EINVAL; } - BT_DBG("%u bytes: %s", data->om_len, bt_hex(data->om_data, data->om_len)); + BT_DBG("%u bytes: %s", in->om_len, bt_hex(in->om_data, in->om_len)); rx->net_if = net_if; - if (!net_find_and_decrypt(data->om_data, data->om_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; } @@ -1284,7 +720,7 @@ int bt_mesh_net_decode(struct os_mbuf *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->om_data); + rx->ctx.recv_ttl = TTL(out->om_data); /* Default to responding with TTL 0 for non-routed messages */ if (rx->ctx.recv_ttl == 0) { @@ -1293,12 +729,12 @@ int bt_mesh_net_decode(struct os_mbuf *data, enum bt_mesh_net_if net_if, rx->ctx.send_ttl = BT_MESH_TTL_DEFAULT; } - rx->ctl = CTL(buf->om_data); - rx->seq = SEQ(buf->om_data); - rx->ctx.recv_dst = DST(buf->om_data); + rx->ctl = CTL(out->om_data); + rx->seq = SEQ(out->om_data); + rx->ctx.recv_dst = DST(out->om_data); - BT_DBG("Decryption successful. Payload len %u: %s", buf->om_len, - bt_hex(buf->om_data, buf->om_len)); + BT_DBG("Decryption successful. Payload len %u: %s", out->om_len, + bt_hex(out->om_data, out->om_len)); if (net_if != BT_MESH_NET_IF_PROXY_CFG && rx->ctx.recv_dst == BT_MESH_ADDR_UNASSIGNED) { @@ -1308,7 +744,7 @@ int bt_mesh_net_decode(struct os_mbuf *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->om_data, buf->om_len)); + BT_DBG("PDU: %s", bt_hex(out->om_data, out->om_len)); msg_cache_add(rx); @@ -1334,7 +770,7 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, } /* Save the state so the buffer can later be relayed */ - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || bt_mesh_elem_find(rx.ctx.recv_dst)); @@ -1369,7 +805,7 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, */ if (!BT_MESH_ADDR_IS_UNICAST(rx.ctx.recv_dst) || (!rx.local_match && !rx.friend_match)) { - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); bt_mesh_net_relay(buf, &rx); } @@ -1428,10 +864,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/nimble/host/mesh/src/net.h b/nimble/host/mesh/src/net.h index 1f73e59d3..b3f245769 100644 --- a/nimble/host/mesh/src/net.h +++ b/nimble/host/mesh/src/net.h @@ -9,13 +9,7 @@ #ifndef __NET_H__ #define __NET_H__ -#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) @@ -31,15 +25,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; @@ -48,40 +34,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 (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - uint8_t identity[16]; /* IdentityKey */ -#endif - uint8_t privacy[16]; /* PrivacyKey */ - uint8_t beacon[16]; /* BeaconKey */ - } keys[2]; -}; - #if MYNEWT_VAL(BLE_MESH_FRIEND) #define FRIEND_SEG_RX MYNEWT_VAL(BLE_MESH_FRIEND_SEG_RX) #define FRIEND_SUB_LIST_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_SUB_LIST_SIZE) @@ -97,14 +49,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]; @@ -181,8 +134,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; @@ -196,6 +152,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); @@ -252,10 +212,6 @@ struct bt_mesh_net { struct k_delayed_work ivu_timer; uint8_t dev_key[16]; - - struct bt_mesh_app_key app_keys[MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)]; - - struct bt_mesh_subnet sub[MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)]; }; /* Network interface */ @@ -306,39 +262,20 @@ static inline void *net_buf_user_data(const struct os_mbuf *buf) return (void *)buf->om_data; } -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 os_mbuf *buf, bool proxy); +int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if, + struct bt_mesh_net_rx *rx, struct os_mbuf *out); + int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, const struct bt_mesh_send_cb *cb, void *cb_data); -int bt_mesh_net_decode(struct os_mbuf *data, enum bt_mesh_net_if net_if, - struct bt_mesh_net_rx *rx, struct os_mbuf *buf); - void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, enum bt_mesh_net_if net_if); @@ -352,30 +289,6 @@ void bt_mesh_net_init(void); void bt_mesh_net_header_parse(struct os_mbuf *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/nimble/host/mesh/src/pb_adv.c b/nimble/host/mesh/src/pb_adv.c index 05142939e..26c656504 100644 --- a/nimble/host/mesh/src/pb_adv.c +++ b/nimble/host/mesh/src/pb_adv.c @@ -205,7 +205,7 @@ static void reset_adv_link(void) } link.tx.pending_ack = XACT_ID_NVAL; link.rx.buf = &rx_buf; - net_buf_simple_reset(link.rx.buf); + os_mbuf_reset(link.rx.buf); } static void close_link(enum prov_bearer_link_status reason) @@ -340,7 +340,7 @@ static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf) link.rx.id = rx->xact_id; - net_buf_simple_reset(link.rx.buf); + os_mbuf_reset(link.rx.buf); link.rx.seg = SEG_NVAL; link.rx.last_seg = SEG_NVAL; @@ -427,7 +427,7 @@ static void gen_prov_start(struct prov_rx *rx, struct os_mbuf *buf) return; } - net_buf_simple_reset(link.rx.buf); + os_mbuf_reset(link.rx.buf); link.rx.buf->om_len = net_buf_simple_pull_be16(buf); link.rx.id = rx->xact_id; link.rx.fcs = net_buf_simple_pull_u8(buf); @@ -673,7 +673,7 @@ static int prov_send_adv(struct os_mbuf *msg, seg_len = MIN(msg->om_len, START_PAYLOAD_MAX); BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->om_data, seg_len)); net_buf_add_mem(start, msg->om_data, seg_len); - net_buf_simple_pull(msg, seg_len); + net_buf_simple_pull_mem(msg, seg_len); buf = start; for (seg_id = 1U; msg->om_len > 0; seg_id++) { @@ -700,7 +700,7 @@ static int prov_send_adv(struct os_mbuf *msg, net_buf_add_u8(buf, link.tx.id); net_buf_add_u8(buf, GPC_CONT(seg_id)); net_buf_add_mem(buf, msg->om_data, seg_len); - net_buf_simple_pull(msg, seg_len); + net_buf_simple_pull_mem(msg, seg_len); } send_reliable(); @@ -740,7 +740,7 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) link.id = rx->link_id; atomic_set_bit(link.flags, LINK_ACTIVE); - net_buf_simple_reset(link.rx.buf); + os_mbuf_reset(link.rx.buf); bearer_ctl_send(LINK_ACK, NULL, 0, false); @@ -820,7 +820,7 @@ static int prov_link_open(const uint8_t uuid[16], int32_t timeout, link.cb = cb; link.cb_data = cb_data; - net_buf_simple_reset(link.rx.buf); + os_mbuf_reset(link.rx.buf); bearer_ctl_send(LINK_OPEN, uuid, 16, true); diff --git a/nimble/host/mesh/src/proxy.c b/nimble/host/mesh/src/proxy.c index 64c9d5b20..f99aa917b 100644 --- a/nimble/host/mesh/src/proxy.c +++ b/nimble/host/mesh/src/proxy.c @@ -202,7 +202,7 @@ static struct bt_mesh_proxy_client *find_client(uint16_t conn_handle) #if (MYNEWT_VAL(BLE_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(uint16_t conn_handle, uint8_t type, struct os_mbuf *msg); @@ -341,7 +341,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) } /* Remove network headers */ - net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); @@ -396,21 +396,20 @@ static int beacon_send(uint16_t conn_handle, struct bt_mesh_subnet *sub) return rc; } +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_handle, sub); +} + static void proxy_send_beacons(struct ble_npl_event *work) { struct bt_mesh_proxy_client *client; - int i; - client = ble_npl_event_get_arg(work); - 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_handle, sub); - } - } + (void)bt_mesh_subnet_find(send_beacon_cb, client); } static void proxy_sar_timeout(struct ble_npl_event *work) @@ -436,12 +435,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; } @@ -452,13 +446,17 @@ 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) @@ -469,30 +467,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(); } @@ -1045,7 +1026,7 @@ static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull(msg, mtu); + net_buf_simple_pull_mem(msg, mtu); while (msg->om_len) { if (msg->om_len + 1 < mtu) { @@ -1056,7 +1037,7 @@ static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull(msg, mtu); + net_buf_simple_pull_mem(msg, mtu); } return 0; @@ -1139,7 +1120,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; } @@ -1167,9 +1149,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); @@ -1195,33 +1177,47 @@ 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(void) +static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) { - int i, count = 0; + int *count = cb_data; - for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { - struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; - - if (advertise_subnet(sub)) { - count++; - } + if (advertise_subnet(sub)) { + (*count)++; } + return 0; +} + +static int sub_count(void) +{ + int count = 0; + + (void)bt_mesh_subnet_find(sub_count_cb, &count); return count; } @@ -1237,6 +1233,7 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) return remaining; } + sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); if (!sub) { BT_WARN("No subnets to advertise on"); return remaining; @@ -1281,6 +1278,8 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) BT_DBG("Advertising %d ms for net_idx 0x%04x", (int) remaining, sub->net_idx); + beacon_sub = bt_mesh_subnet_next(beacon_sub); + return remaining; } #endif /* GATT_PROXY */ @@ -1393,6 +1392,19 @@ 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); + } +} +#endif + static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg) { #if MYNEWT_VAL(BLE_EXT_ADV) @@ -1509,6 +1521,10 @@ int bt_mesh_proxy_init(void) { int i; +#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) + bt_mesh_subnet_cb_list[4] = subnet_evt; +#endif + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { #if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) k_work_init(&clients[i].send_beacons, proxy_send_beacons); diff --git a/nimble/host/mesh/src/settings.c b/nimble/host/mesh/src/settings.c index febe5e649..6f26f27ec 100644 --- a/nimble/host/mesh/src/settings.c +++ b/nimble/host/mesh/src/settings.c @@ -12,6 +12,8 @@ #include "mesh_priv.h" #include "mesh/mesh.h" #include "mesh/glue.h" +#include "subnet.h" +#include "app_keys.h" #include "net.h" #include "rpl.h" #include "crypto.h" @@ -356,26 +358,13 @@ static int rpl_set(int argc, char **argv, char *val) static int net_key_set(int argc, char **argv, char *val) { - struct bt_mesh_subnet *sub; struct net_key_val key; - int len, i, err; + int len, err; uint16_t net_idx; BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); net_idx = strtol(argv[0], NULL, 16); - sub = bt_mesh_subnet_get(net_idx); - - if (!val) { - 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; - } len = sizeof(key); err = settings_bytes_from_str(val, &key, &len); @@ -389,93 +378,41 @@ static int net_key_set(int argc, char **argv, char *val) return -EINVAL; } - 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(int argc, char **argv, char *val) { - struct bt_mesh_app_key *app; struct app_key_val key; uint16_t app_idx; - int len, err; + int len_rd, err; BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); app_idx = strtol(argv[0], NULL, 16); + len_rd = strtol(argv[1], NULL, 16); - if (!val) { - 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; } - len = sizeof(key); - err = settings_bytes_from_str(val, &key, &len); + err = settings_bytes_from_str(val, &key, &len_rd); if (err) { BT_ERR("Failed to decode value %s (err %d)", val, err); return err; } - if (len != sizeof(key)) { - BT_ERR("Unexpected value length (%d != %zu)", len, 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; @@ -1069,37 +1006,6 @@ static int mesh_set(int argc, char **argv, char *val) 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"); - 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) { @@ -1128,11 +1034,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; } @@ -1141,20 +1044,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); } @@ -1532,31 +1421,36 @@ 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) { - char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; + const struct bt_mesh_subnet *sub; struct net_key_val key; + char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; char path[20]; char *str; 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; str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); if (!str) { - BT_ERR("Unable to encode NetKey as value"); + BT_ERR("Unable to encode AppKey as value"); return; } - snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", sub->net_idx); - - BT_DBG("Saving NetKey %s as value %s", path, str); err = settings_save_one(path, str); if (err) { BT_ERR("Failed to store NetKey"); @@ -1565,16 +1459,26 @@ 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; char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; struct app_key_val key; char path[20]; char *str; 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); @@ -1613,28 +1517,7 @@ static void store_pending_keys(void) clear_net_key(update->key_idx); } } 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); - } - - } 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); } update->valid = 0; @@ -2223,13 +2106,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 = 0; schedule_store(BT_MESH_KEYS_PENDING); @@ -2237,25 +2120,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 = 1; - free_slot->key_idx = sub->net_idx; + free_slot->key_idx = net_idx; free_slot->app_key = 0; free_slot->clear = 0; 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 = 0; schedule_store(BT_MESH_KEYS_PENDING); @@ -2263,12 +2146,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 = 1; - free_slot->key_idx = key->app_idx; + free_slot->key_idx = app_idx; free_slot->app_key = 1; free_slot->clear = 0; @@ -2292,13 +2175,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 = 1; schedule_store(BT_MESH_KEYS_PENDING); @@ -2306,25 +2189,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 = 1; - free_slot->key_idx = sub->net_idx; + free_slot->key_idx = net_idx; free_slot->app_key = 0; free_slot->clear = 1; 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 = 1; schedule_store(BT_MESH_KEYS_PENDING); @@ -2332,12 +2215,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 = 1; - free_slot->key_idx = key->app_idx; + free_slot->key_idx = app_idx; free_slot->app_key = 1; free_slot->clear = 1; diff --git a/nimble/host/mesh/src/settings.h b/nimble/host/mesh/src/settings.h index 2718cb5e3..9060a14a7 100644 --- a/nimble/host/mesh/src/settings.h +++ b/nimble/host/mesh/src/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/nimble/host/mesh/src/shell.c b/nimble/host/mesh/src/shell.c index d2f4ccbf2..e84541858 100644 --- a/nimble/host/mesh/src/shell.c +++ b/nimble/host/mesh/src/shell.c @@ -833,8 +833,6 @@ static int cmd_net_send(int 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 = 0; @@ -844,12 +842,6 @@ static int cmd_net_send(int argc, char *argv[]) goto done; } - if (!tx.sub) { - printk("No matching subnet for NetKey Index 0x%04x\n", - net.net_idx); - goto done; - } - net_buf_simple_init(msg, 0); len = hex2bin(argv[1], msg->om_data, net_buf_simple_tailroom(msg) - 4); net_buf_simple_add(msg, len); diff --git a/nimble/host/mesh/src/subnet.c b/nimble/host/mesh/src/subnet.c new file mode 100644 index 000000000..626cb3c50 --- /dev/null +++ b/nimble/host/mesh/src/subnet.c @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" +#define MESH_LOG_MODULE BLE_MESH_NET_KEYS_LOG + +#include "log/log.h" + +#include "crypto.h" +#include "adv.h" +#include "mesh/mesh.h" +#include "net.h" +#include "mesh_priv.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" + +#ifdef CONFIG_BT_MESH_GATT_PROXY +void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub, + enum bt_mesh_key_evt evt); +#else +void (*bt_mesh_subnet_cb_list[4]) (struct bt_mesh_subnet *sub, + enum bt_mesh_key_evt evt); +#endif + +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) +{ + int i; + for (i = 0; i < (sizeof(bt_mesh_subnet_cb_list)/sizeof(void *)); i++) { + bt_mesh_subnet_cb_list[i] (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 os_mbuf *in, + struct os_mbuf *out, + bool (*cb)(struct bt_mesh_net_rx *rx, + struct os_mbuf *in, + struct os_mbuf *out, + const struct bt_mesh_net_cred *cred)) +{ + int i, j; + + BT_DBG(""); + + rx->friend_cred = 1U; +#if MYNEWT_VAL(BLE_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 MYNEWT_VAL(BLE_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/nimble/host/mesh/src/subnet.h b/nimble/host/mesh/src/subnet.h new file mode 100644 index 000000000..da0a1dfc5 --- /dev/null +++ b/nimble/host/mesh/src/subnet.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BLUETOOTH_MESH_SUBNET_H_ +#define _BLUETOOTH_MESH_SUBNET_H_ + +#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]; +}; + +#ifdef CONFIG_BT_MESH_GATT_PROXY +extern void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub, + enum bt_mesh_key_evt evt); +#else +extern void (*bt_mesh_subnet_cb_list[4]) (struct bt_mesh_subnet *sub, + enum bt_mesh_key_evt evt); +#endif + +/** 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); +}; + +/** @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 os_mbuf *in, + struct os_mbuf *out, + bool (*cb)(struct bt_mesh_net_rx *rx, + struct os_mbuf *in, + struct os_mbuf *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 /* _BLUETOOTH_MESH_SUBNET_H_ */ \ No newline at end of file diff --git a/nimble/host/mesh/src/testing.c b/nimble/host/mesh/src/testing.c index c9e3e09b9..2bef38e23 100644 --- a/nimble/host/mesh/src/testing.c +++ b/nimble/host/mesh/src/testing.c @@ -13,6 +13,7 @@ #include "mesh/access.h" #include "net.h" +#include "app_keys.h" #include "rpl.h" #include "testing.h" #include "access.h" @@ -115,38 +116,37 @@ int bt_test_mesh_rpl_clear(void) void bt_test_print_credentials(void) { int i; - uint8_t nid; - const uint8_t *enc; - const uint8_t *priv; - struct bt_mesh_subnet *sub; - struct bt_mesh_app_key *app_key; + struct bt_mesh_cdb_subnet *sub; + struct bt_mesh_cdb_app_key *app_key; + struct bt_mesh_subnet *subnet; console_printf("IV Index: %08lx\n", (long) bt_mesh.iv_index); console_printf("Dev key: %s\n", bt_hex(bt_mesh.dev_key, 16)); - for (i = 0; i < MYNEWT_VAL(BLE_MESH_SUBNET_COUNT); ++i) + for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { - if (bt_mesh.app_keys[i].net_idx == BT_MESH_KEY_UNUSED) { + app_key = &bt_mesh_cdb.app_keys[i]; + if (app_key->net_idx == BT_MESH_KEY_UNUSED) { continue; } - sub = &bt_mesh.sub[i]; + sub = bt_mesh_cdb_subnet_get(i); console_printf("Subnet: %d\n", i); console_printf("\tNetKeyIdx: %04x\n", sub->net_idx); console_printf("\tNetKey: %s\n", - bt_hex(sub->keys[sub->kr_flag].net, 16)); + bt_hex(sub->keys[sub->kr_flag].net_key, 16)); } - for (i = 0; i < MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT); ++i) + for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { - if (bt_mesh.app_keys[i].net_idx == BT_MESH_KEY_UNUSED) { + if (app_key->net_idx == BT_MESH_KEY_UNUSED) { continue; } - sub = &bt_mesh.sub[i]; - app_key = &bt_mesh.app_keys[i]; + sub = bt_mesh_cdb_subnet_get(i); + app_key = &bt_mesh_cdb.app_keys[i]; console_printf("AppKey: %d\n", i); console_printf("\tNetKeyIdx: %04x\n", @@ -154,28 +154,26 @@ void bt_test_print_credentials(void) console_printf("\tAppKeyIdx: %04x\n", app_key->app_idx); console_printf("\tAppKey: %s\n", - bt_hex(app_key->keys[sub->kr_flag].val, 16)); + bt_hex(app_key->keys[sub->kr_flag].app_key, 16)); } - for (i = 0; i < MYNEWT_VAL(BLE_MESH_SUBNET_COUNT); ++i) + for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) { - if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) { + sub = bt_mesh_cdb_subnet_get(i); + if (sub[i].net_idx == BT_MESH_KEY_UNUSED) { continue; } - if (friend_cred_get(&bt_mesh.sub[i], BT_MESH_ADDR_UNASSIGNED, - &nid, &enc, &priv)) { - return; - } + subnet = bt_mesh_subnet_get(app_key->net_idx); console_printf("Friend cred: %d\n", i); console_printf("\tNetKeyIdx: %04x\n", - bt_mesh.sub[i].net_idx); - console_printf("\tNID: %02x\n", nid); + sub[i].net_idx); + console_printf("\tNID: %02x\n", subnet->keys->msg.nid); console_printf("\tEncKey: %s\n", - bt_hex(enc, 16)); + bt_hex(subnet->keys->msg.enc, 16)); console_printf("\tPrivKey: %s\n", - bt_hex(priv, 16)); + bt_hex(subnet->keys->msg.privacy, 16)); } } diff --git a/nimble/host/mesh/src/transport.c b/nimble/host/mesh/src/transport.c index 33a1557b7..b9f32760d 100644 --- a/nimble/host/mesh/src/transport.c +++ b/nimble/host/mesh/src/transport.c @@ -19,6 +19,7 @@ #include "crypto.h" #include "adv.h" #include "net.h" +#include "app_keys.h" #include "rpl.h" #include "lpn.h" #include "friend.h" @@ -265,9 +266,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); } } @@ -442,7 +441,6 @@ static void seg_retransmit(struct ble_npl_event *work) static int send_seg(struct bt_mesh_net_tx *net_tx, struct os_mbuf *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, uint8_t *ctl_op) -{ { bool blocked = false; struct seg_tx *tx; @@ -582,8 +580,6 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct os_mbuf *sdu, seg_tx_send_unacked(tx); - } - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && bt_mesh_lpn_established()) { bt_mesh_lpn_poll(); @@ -592,27 +588,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct os_mbuf *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 os_mbuf *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; @@ -640,12 +627,12 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg, tx->ctx->app_idx, tx->ctx->addr); BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_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) { @@ -655,14 +642,10 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *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; } @@ -681,7 +664,7 @@ static void seg_rx_assemble(struct seg_rx *rx, struct os_mbuf *buf, { int i; - net_buf_simple_reset(buf); + os_mbuf_reset(buf); for (i = 0; i <= rx->seg_n; i++) { net_buf_simple_add_mem(buf, rx->seg[i], @@ -695,178 +678,47 @@ static void seg_rx_assemble(struct seg_rx *rx, struct os_mbuf *buf, } } -static int remote_devkey_decrypt(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t *ad, - uint8_t aszmic, struct os_mbuf *buf, - struct os_mbuf *sdu) -{ - struct bt_mesh_cdb_node *node; - int err; - - if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) { - return -ENOENT; - } - - /* We will try our local devkey separately. */ - if (bt_mesh_elem_find(rx->ctx.addr)) { - return -ENOENT; - } - - /* - * 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; -} - -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 os_mbuf *buf, - struct os_mbuf *sdu) -{ - struct bt_mesh_app_keys *keys; - int err; - - /* 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 os_mbuf *buf) -{ - struct os_mbuf *sdu = - NET_BUF_SIMPLE(BT_MESH_SDU_UNSEG_MAX); - uint8_t *ad; - uint16_t i; - int err = 0; - - BT_DBG("AKF %u AID 0x%02x", AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_len < 1 + APP_MIC_LEN(0)) { - 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; - } - - /* Adjust the length to not contain the MIC at the end */ - buf->om_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); - return 0; - } - - for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; - - 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) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); +struct decrypt_ctx { + struct bt_mesh_app_crypto_ctx crypto; + struct os_mbuf *buf; struct os_mbuf *sdu; - uint32_t seq = (seg->seq_auth & 0xffffff); - uint8_t *ad; - uint16_t i; - int err; + struct seg_rx *seg; +}; - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); +static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const uint8_t key[16], + void *cb_data) +{ + const struct decrypt_ctx *ctx = cb_data; - if (seg->len < 1 + APP_MIC_LEN(aszmic)) { - BT_ERR("Too short SDU + MIC"); - return -EINVAL; + if (ctx->seg) { + seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); } + os_mbuf_reset(ctx->sdu); + + return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); +} + +static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, + struct os_mbuf *buf, struct os_mbuf *sdu, + struct seg_rx *seg) +{ + 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, + }; + + 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", rx->ctx.recv_dst); @@ -874,76 +726,19 @@ static int sdu_recv_seg(struct seg_rx *seg, uint8_t hdr, uint8_t aszmic, } 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); } - /* 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->om_data, - seg->len - APP_MIC_LEN(aszmic)); - sdu->om_len = 0; - - /* Check that the AppKey ID matches */ - 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->om_data, - seg->len - APP_MIC_LEN(aszmic)); - sdu->om_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); + 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); - seg_rx_assemble(seg, buf, aszmic); - net_buf_simple_init_with_data(sdu, buf->om_data, - seg->len - APP_MIC_LEN(aszmic)); - sdu->om_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); os_mbuf_free_chain(sdu); return 0; @@ -1152,6 +947,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, static int trans_unseg(struct os_mbuf *buf, struct bt_mesh_net_rx *rx, uint64_t *seq_auth) { + struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_SDU_UNSEG_MAX); uint8_t hdr; BT_DBG("AFK %u AID 0x%02x", AKF(buf->om_data), AID(buf->om_data)); @@ -1171,14 +967,17 @@ static int trans_unseg(struct os_mbuf *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->om_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->om_len -= APP_MIC_LEN(0); + + return sdu_recv(rx, hdr, 0, buf, sdu, NULL); } static inline int32_t ack_timeout(struct seg_rx *rx) @@ -1209,7 +1008,7 @@ static inline int32_t ack_timeout(struct seg_rx *rx) 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) { - struct os_mbuf *buf; + struct os_mbuf *buf = NET_BUF_SIMPLE(data_len); net_buf_simple_init_with_data(buf, data, data_len); @@ -1461,7 +1260,7 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); - net_buf_simple_pull(buf, 1); + net_buf_simple_pull_mem(buf, 1); seq_zero = net_buf_simple_pull_be16(buf); seg_o = (seq_zero & 0x03) << 3; @@ -1646,12 +1445,31 @@ 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) { struct os_mbuf *sdu = NET_BUF_SIMPLE(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); + struct os_mbuf *seg_buf = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); + struct os_mbuf *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); + + sdu = NET_BUF_SIMPLE(rx->len - APP_MIC_LEN(ASZMIC(hdr))); + net_buf_simple_init_with_data( + sdu, seg_buf->om_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); @@ -1679,7 +1497,7 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx) rx->friend_match); /* Remove network headers */ - net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); BT_DBG("Payload %s", bt_hex(buf->om_data, buf->om_len)); @@ -1702,7 +1520,7 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx) /* Save the app-level state so the buffer can later be placed in * the Friend Queue. */ - net_buf_simple_save(buf, &state); + os_mbuf_save(buf, &state); if (SEG(buf->om_data)) { /* Segmented messages must match a local element or an @@ -1735,7 +1553,7 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx) bt_mesh_lpn_msg_received(rx); } - net_buf_simple_restore(buf, &state); + os_mbuf_restore(buf, &state); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->friend_match && !err) { if (seq_auth == TRANS_SEQ_AUTH_NVAL) { @@ -1843,49 +1661,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/nimble/host/mesh/src/transport.h b/nimble/host/mesh/src/transport.h index 76af1542b..11ad70188 100644 --- a/nimble/host/mesh/src/transport.h +++ b/nimble/host/mesh/src/transport.h @@ -84,8 +84,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); @@ -102,6 +100,3 @@ int bt_mesh_trans_recv(struct os_mbuf *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); diff --git a/nimble/host/mesh/syscfg.yml b/nimble/host/mesh/syscfg.yml index d3b2cf077..446aee16e 100644 --- a/nimble/host/mesh/syscfg.yml +++ b/nimble/host/mesh/syscfg.yml @@ -688,6 +688,15 @@ syscfg.defs: Minimum level for the BLE Mesh Replay protection list log. value: 1 + BLE_MESH_NET_KEYS_LOG_MOD: + description: > + Numeric module ID to use for BLE Mesh Replay protection list messages. + value: 23 + BLE_MESH_NET_KEYS_LOG_LVL: + description: > + Minimum level for the BLE Mesh Replay protection list log. + value: 1 + syscfg.logs: BLE_MESH_LOG: module: MYNEWT_VAL(BLE_MESH_LOG_MOD) @@ -745,6 +754,10 @@ syscfg.logs: module: MYNEWT_VAL(BLE_MESH_TRANS_LOG_MOD) level: MYNEWT_VAL(BLE_MESH_TRANS_LOG_LVL) + BLE_MESH_NET_KEYS_LOG: + module: MYNEWT_VAL(BLE_MESH_NET_KEYS_LOG_MOD) + level: MYNEWT_VAL(BLE_MESH_NET_KEYS_LOG_LVL) + syscfg.vals.BLE_MESH_SHELL: BLE_MESH_CFG_CLI: 1 BLE_MESH_HEALTH_CLI: 1 diff --git a/porting/examples/linux_blemesh/include/logcfg/logcfg.h b/porting/examples/linux_blemesh/include/logcfg/logcfg.h index 686ffcb70..6eff5efc2 100644 --- a/porting/examples/linux_blemesh/include/logcfg/logcfg.h +++ b/porting/examples/linux_blemesh/include/logcfg/logcfg.h @@ -113,6 +113,13 @@ #define BLE_MESH_RPL_LOG_CRITICAL(...) MODLOG_CRITICAL(22, __VA_ARGS__) #define BLE_MESH_RPL_LOG_DISABLED(...) MODLOG_DISABLED(22, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_INFO(...) MODLOG_INFO(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_WARN(...) MODLOG_WARN(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_ERROR(...) MODLOG_ERROR(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_CRITICAL(...) MODLOG_CRITICAL(23, __VA_ARGS__) +#define BLE_MESH_NET_KEYS_LOG_DISABLED(...) MODLOG_DISABLED(23, __VA_ARGS__) + #define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) #define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) #define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__)