diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 1622ccebbd8..dfcd1d0bd7c 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -607,10 +607,6 @@ void bt_mesh_reset(void); * If at all possible, the Friendship feature should be used instead, to * make the node into a Low Power Node. * - * @note Should not be called from work queue due to undefined behavior. - * This is due to k_work_flush_delayable() being used in disabling of the - * extended advertising. - * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_suspend(void); diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 6595badc9f9..da86f697c2d 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -94,7 +94,6 @@ int bt_mesh_scan_disable(void); int bt_mesh_adv_enable(void); -/* Should not be called from work queue due to undefined behavior */ int bt_mesh_adv_disable(void); void bt_mesh_adv_local_ready(void); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 5e428283bf9..f6367a05258 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -49,6 +49,9 @@ enum { */ ADV_FLAG_UPDATE_PARAMS, + /** The advertiser is suspending. */ + ADV_FLAG_SUSPENDING, + /* Number of adv flags. */ ADV_FLAGS_NUM }; @@ -246,6 +249,11 @@ static void send_pending_adv(struct k_work *work) ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work); + if (atomic_test_bit(ext_adv->flags, ADV_FLAG_SUSPENDING)) { + LOG_DBG("Advertiser is suspending"); + return; + } + if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) { LOG_DBG("Advertising stopped after %u ms for %s", k_uptime_get_32() - ext_adv->timestamp, @@ -284,6 +292,11 @@ static void send_pending_adv(struct k_work *work) } } + if (ext_adv->instance == NULL) { + LOG_DBG("Advertiser is suspended or deleted"); + return; + } + if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !bt_mesh_sol_send()) { return; @@ -488,7 +501,12 @@ int bt_mesh_adv_disable(void) struct k_work_sync sync; for (int i = 0; i < ARRAY_SIZE(advs); i++) { - k_work_flush(&advs[i].work, &sync); + atomic_set_bit(advs[i].flags, ADV_FLAG_SUSPENDING); + + if (k_current_get() != &k_sys_work_q.thread || + (k_work_busy_get(&advs[i].work) & K_WORK_RUNNING) == 0) { + k_work_flush(&advs[i].work, &sync); + } err = bt_le_ext_adv_stop(advs[i].instance); if (err) { @@ -506,7 +524,10 @@ int bt_mesh_adv_disable(void) LOG_ERR("Failed to delete adv %d", err); return err; } + advs[i].instance = NULL; + + atomic_clear_bit(advs[i].flags, ADV_FLAG_SUSPENDING); } return 0; diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index 867c91bbf8e..2e60ff423c1 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -104,7 +104,9 @@ static int bt_data_send(uint8_t num_events, uint16_t adv_int, bt_mesh_adv_send_start(duration, err, ctx); } - k_sleep(K_MSEC(duration)); + if (enabled) { + k_sleep(K_MSEC(duration)); + } err = bt_le_adv_stop(); if (err) { @@ -239,9 +241,13 @@ int bt_mesh_adv_enable(void) int bt_mesh_adv_disable(void) { + int err; + enabled = false; - k_thread_join(&adv_thread_data, K_FOREVER); - LOG_DBG("Advertising disabled"); + + err = k_thread_join(&adv_thread_data, K_FOREVER); + LOG_DBG("Advertising disabled: %d", err); + return 0; }