From 8bfccba598dc4f175cde202b4204ef73f9bf2eaf Mon Sep 17 00:00:00 2001 From: lly Date: Tue, 12 May 2020 20:18:45 +0800 Subject: [PATCH] ble_mesh: Check if subnet exists before updating beacon_sent - Before updating the "beacon_sent" of a subnet, we need to check if the subnet still exists, especially for a Provisioner. - Fix a bug which will cause Provisioner failed to send Secure Network Beacon if no device is provisioned --- components/bt/esp_ble_mesh/mesh_core/beacon.c | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/components/bt/esp_ble_mesh/mesh_core/beacon.c b/components/bt/esp_ble_mesh/mesh_core/beacon.c index 2f53aa49f..e7462d80a 100644 --- a/components/bt/esp_ble_mesh/mesh_core/beacon.c +++ b/components/bt/esp_ble_mesh/mesh_core/beacon.c @@ -40,6 +40,9 @@ /* 1 transmission, 20ms interval */ #define PROV_XMIT BLE_MESH_TRANSMIT(0, 20) +#define SNB_NET_IDX_SET(_val) ((void *)((u32_t)(_val))) +#define SNB_NET_IDX_GET(_ptr) ((u32_t)(_ptr)) + static struct k_delayed_work beacon_timer; static struct bt_mesh_subnet *cache_check(u8_t data[21]) @@ -71,11 +74,30 @@ static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub) static void beacon_complete(int err, void *user_data) { - struct bt_mesh_subnet *sub = user_data; + struct bt_mesh_subnet *sub = NULL; + u16_t net_idx = BLE_MESH_KEY_UNUSED; BT_DBG("err %d", err); - sub->beacon_sent = k_uptime_get_32(); + net_idx = (u16_t)SNB_NET_IDX_GET(user_data); + + /* For node, directly updating the "beacon_sent" timestamp is fine, + * since the subnet is pre-allocated. + * For Provisioner, before updating the "beacon_sent" timestamp, we + * need to make sure that the subnet still exists, because there is + * a chance that the subnet is removed just before the completion of + * sending the Secure Network Beacon. + */ + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + sub = bt_mesh_subnet_get(net_idx); + } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && + bt_mesh_is_provisioner_en()) { + sub = bt_mesh_provisioner_subnet_get(net_idx); + } + + if (sub) { + sub->beacon_sent = k_uptime_get_32(); + } } void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, @@ -161,7 +183,17 @@ static int secure_beacon_send(void) bt_mesh_beacon_create(sub, &buf->b); - bt_mesh_adv_send(buf, &send_cb, sub); + /* Care should be taken here. Previously the user_data is the + * pointer of a subnet. When the device is a Provisioner, its + * subnet is created dynamically. If the corresponding subnet + * is removed right after the Secure Network Beacon is sent, + * update its "beacon_sent" timestamp in beacon_complete() will + * cause exception. + * Here we use the "net_idx" of the subnet instead. And in the + * beacon_complete(), we will try to get the subnet before + * updating its "beacon_sent" timestamp. + */ + bt_mesh_adv_send(buf, &send_cb, SNB_NET_IDX_SET(sub->net_idx)); net_buf_unref(buf); } @@ -264,16 +296,9 @@ static void update_beacon_observation(void) static bool ready_to_send(void) { - if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + if (bt_mesh_is_provisioned() || bt_mesh_is_provisioner_en()) { return true; } - - if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { - if (bt_mesh_provisioner_get_node_count()) { - return true; - } - } - return false; }