2020-11-13 16:21:32 +01:00
|
|
|
/*
|
2021-11-03 17:05:10 +08:00
|
|
|
* Copyright (c) 2021 Xiaomi Corporation
|
2020-11-13 16:21:32 +01:00
|
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
|
|
* Copyright (c) 2017 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
includes: prefer <zephyr/kernel.h> over <zephyr/zephyr.h>
As of today <zephyr/zephyr.h> is 100% equivalent to <zephyr/kernel.h>.
This patch proposes to then include <zephyr/kernel.h> instead of
<zephyr/zephyr.h> since it is more clear that you are including the
Kernel APIs and (probably) nothing else. <zephyr/zephyr.h> sounds like a
catch-all header that may be confusing. Most applications need to
include a bunch of other things to compile, e.g. driver headers or
subsystem headers like BT, logging, etc.
The idea of a catch-all header in Zephyr is probably not feasible
anyway. Reason is that Zephyr is not a library, like it could be for
example `libpython`. Zephyr provides many utilities nowadays: a kernel,
drivers, subsystems, etc and things will likely grow. A catch-all header
would be massive, difficult to keep up-to-date. It is also likely that
an application will only build a small subset. Note that subsystem-level
headers may use a catch-all approach to make things easier, though.
NOTE: This patch is **NOT** removing the header, just removing its usage
in-tree. I'd advocate for its deprecation (add a #warning on it), but I
understand many people will have concerns.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-08-25 09:58:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/debug/stack.h>
|
2023-05-15 15:50:28 +02:00
|
|
|
#include <zephyr/sys/iterable_sections.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/net/buf.h>
|
|
|
|
#include <zephyr/bluetooth/bluetooth.h>
|
2022-11-02 14:31:13 +01:00
|
|
|
#include <zephyr/bluetooth/hci.h>
|
2022-05-06 11:12:04 +02:00
|
|
|
#include <zephyr/bluetooth/mesh.h>
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2022-10-25 08:48:54 +02:00
|
|
|
#include "common/bt_str.h"
|
2020-11-13 16:21:32 +01:00
|
|
|
|
|
|
|
#include "host/hci_core.h"
|
|
|
|
|
|
|
|
#include "net.h"
|
|
|
|
#include "proxy.h"
|
2022-10-19 09:42:02 +02:00
|
|
|
#include "solicitation.h"
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
#define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(bt_mesh_adv_ext);
|
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
/* Convert from ms to 0.625ms units */
|
|
|
|
#define ADV_INT_FAST_MS 20
|
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
#ifndef CONFIG_BT_MESH_RELAY_ADV_SETS
|
|
|
|
#define CONFIG_BT_MESH_RELAY_ADV_SETS 0
|
2022-03-01 16:40:27 +01:00
|
|
|
#endif
|
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
enum {
|
|
|
|
/** Controller is currently advertising */
|
|
|
|
ADV_FLAG_ACTIVE,
|
2022-03-23 14:54:01 +08:00
|
|
|
/** Advertising sending completed */
|
|
|
|
ADV_FLAG_SENT,
|
2020-11-13 16:21:32 +01:00
|
|
|
/** Currently performing proxy advertising */
|
|
|
|
ADV_FLAG_PROXY,
|
Bluetooth: Mesh: Fix unable sent mesh message
In PR (#58723) has introduce another bug, that,
the flag ADV_FLAG_PROXY set before actually enabled.
When ctx:: BT RX call schedule_send will atomic_test_and_clear
ADV_FLAG_PROXY, but at this time, the proxy advertising will
not at advertising state, maybe in update params or set adverting
data phase,
so that, call bt_le_ext_adv_stop will nothing, and then call
k_work_reschedule --> send_pending_adv(at this time, the proxy
advertising actually enabled, but the upper layer clear proxy flags),
cause latest advertising unable start, because unable in advertising
state to update params(-EINVAL).
Fixes: #58721
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
2023-06-06 10:09:16 +08:00
|
|
|
/** The proxy has been start, but maybe pending. */
|
|
|
|
ADV_FLAG_PROXY_START,
|
2022-02-28 10:32:52 +08:00
|
|
|
/** The send-call has been pending. */
|
|
|
|
ADV_FLAG_SCHEDULE_PENDING,
|
2020-11-13 16:21:32 +01:00
|
|
|
/** Custom adv params have been set, we need to update the parameters on
|
|
|
|
* the next send.
|
|
|
|
*/
|
|
|
|
ADV_FLAG_UPDATE_PARAMS,
|
|
|
|
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
/** The advertiser is suspending. */
|
|
|
|
ADV_FLAG_SUSPENDING,
|
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
/* Number of adv flags. */
|
|
|
|
ADV_FLAGS_NUM
|
|
|
|
};
|
|
|
|
|
2021-11-23 14:18:01 +08:00
|
|
|
struct bt_mesh_ext_adv {
|
2023-09-08 13:56:10 +08:00
|
|
|
const enum bt_mesh_adv_tag_bit tags;
|
2020-11-13 16:21:32 +01:00
|
|
|
ATOMIC_DEFINE(flags, ADV_FLAGS_NUM);
|
|
|
|
struct bt_le_ext_adv *instance;
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_adv *adv;
|
2023-12-15 10:33:41 +01:00
|
|
|
uint32_t timestamp;
|
|
|
|
struct k_work work;
|
2021-11-03 17:05:10 +08:00
|
|
|
struct bt_le_adv_param adv_param;
|
|
|
|
};
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2021-11-03 17:05:10 +08:00
|
|
|
static void send_pending_adv(struct k_work *work);
|
2023-12-05 10:01:19 +08:00
|
|
|
static bool schedule_send(struct bt_mesh_ext_adv *ext_adv);
|
2021-11-23 14:18:01 +08:00
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
static struct bt_mesh_ext_adv advs[] = {
|
|
|
|
[0] = {
|
|
|
|
.tags = (
|
2023-01-11 10:35:46 +01:00
|
|
|
#if !defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)
|
2023-09-08 13:56:10 +08:00
|
|
|
BT_MESH_ADV_TAG_BIT_FRIEND |
|
2023-01-11 10:35:46 +01:00
|
|
|
#endif
|
2021-11-23 11:23:06 +08:00
|
|
|
#if !defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE)
|
2023-09-08 13:56:10 +08:00
|
|
|
BT_MESH_ADV_TAG_BIT_PROXY |
|
2021-11-23 11:23:06 +08:00
|
|
|
#endif /* !CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */
|
2022-11-10 12:23:07 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET)
|
2023-09-08 13:56:10 +08:00
|
|
|
BT_MESH_ADV_TAG_BIT_RELAY |
|
2022-11-10 12:23:07 +08:00
|
|
|
#endif /* CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET */
|
2023-09-08 13:56:10 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_PB_ADV)
|
|
|
|
BT_MESH_ADV_TAG_BIT_PROV |
|
|
|
|
#endif /* CONFIG_BT_MESH_PB_ADV */
|
|
|
|
BT_MESH_ADV_TAG_BIT_LOCAL
|
|
|
|
),
|
2023-12-15 10:33:41 +01:00
|
|
|
.work = Z_WORK_INITIALIZER(send_pending_adv),
|
2023-09-08 13:56:10 +08:00
|
|
|
},
|
|
|
|
#if CONFIG_BT_MESH_RELAY_ADV_SETS
|
|
|
|
[1 ... CONFIG_BT_MESH_RELAY_ADV_SETS] = {
|
2023-09-06 16:47:20 +08:00
|
|
|
.tags = (
|
|
|
|
#if defined(CONFIG_BT_MESH_RELAY)
|
2023-09-08 13:56:10 +08:00
|
|
|
BT_MESH_ADV_TAG_BIT_RELAY |
|
2023-09-06 16:47:20 +08:00
|
|
|
#endif /* CONFIG_BT_MESH_RELAY */
|
2023-09-08 13:56:10 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS)
|
|
|
|
BT_MESH_ADV_TAG_BIT_PROV |
|
|
|
|
#endif /* CONFIG_BT_MESH_PB_ADV_USE_RELAY_SETS */
|
2023-09-06 16:47:20 +08:00
|
|
|
0),
|
2023-12-15 10:33:41 +01:00
|
|
|
.work = Z_WORK_INITIALIZER(send_pending_adv),
|
2023-09-08 13:56:10 +08:00
|
|
|
},
|
|
|
|
#endif /* CONFIG_BT_MESH_RELAY_ADV_SETS */
|
2023-01-11 10:35:46 +01:00
|
|
|
#if defined(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)
|
2023-09-08 13:56:10 +08:00
|
|
|
{
|
|
|
|
.tags = BT_MESH_ADV_TAG_BIT_FRIEND,
|
2023-12-15 10:33:41 +01:00
|
|
|
.work = Z_WORK_INITIALIZER(send_pending_adv),
|
2023-09-08 13:56:10 +08:00
|
|
|
},
|
2023-01-11 10:35:46 +01:00
|
|
|
#endif /* CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE */
|
2021-11-03 17:05:10 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE)
|
2023-09-08 13:56:10 +08:00
|
|
|
{
|
|
|
|
.tags = BT_MESH_ADV_TAG_BIT_PROXY,
|
2023-12-15 10:33:41 +01:00
|
|
|
.work = Z_WORK_INITIALIZER(send_pending_adv),
|
2023-09-08 13:56:10 +08:00
|
|
|
},
|
2021-11-03 17:05:10 +08:00
|
|
|
#endif /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */
|
2023-09-08 13:56:10 +08:00
|
|
|
};
|
2021-11-03 17:05:10 +08:00
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
BUILD_ASSERT(ARRAY_SIZE(advs) <= CONFIG_BT_EXT_ADV_MAX_ADV_SET,
|
2021-11-03 17:05:10 +08:00
|
|
|
"Insufficient adv instances");
|
|
|
|
|
2021-11-23 14:27:31 +08:00
|
|
|
static inline struct bt_mesh_ext_adv *relay_adv_get(void)
|
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
if (!!(CONFIG_BT_MESH_RELAY_ADV_SETS)) {
|
|
|
|
return &advs[1];
|
|
|
|
} else {
|
|
|
|
return &advs[0];
|
|
|
|
}
|
2021-11-23 14:27:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct bt_mesh_ext_adv *gatt_adv_get(void)
|
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE)) {
|
|
|
|
return &advs[ARRAY_SIZE(advs) - 1];
|
|
|
|
} else {
|
|
|
|
return &advs[0];
|
|
|
|
}
|
2021-11-23 14:27:31 +08:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
static int adv_start(struct bt_mesh_ext_adv *ext_adv,
|
2021-11-03 17:05:10 +08:00
|
|
|
const struct bt_le_adv_param *param,
|
2020-11-13 16:21:32 +01:00
|
|
|
struct bt_le_ext_adv_start_param *start,
|
|
|
|
const struct bt_data *ad, size_t ad_len,
|
|
|
|
const struct bt_data *sd, size_t sd_len)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (!ext_adv->instance) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Mesh advertiser not enabled");
|
2020-11-13 16:21:32 +01:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_and_set_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Advertiser is busy");
|
2020-11-13 16:21:32 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS)) {
|
|
|
|
err = bt_le_ext_adv_update_param(ext_adv->instance, param);
|
2020-11-13 16:21:32 +01:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed updating adv params: %d", err);
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
2020-11-13 16:21:32 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit_to(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS,
|
|
|
|
param != &ext_adv->adv_param);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
err = bt_le_ext_adv_set_data(ext_adv->instance, ad, ad_len, sd, sd_len);
|
2020-11-13 16:21:32 +01:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Failed setting adv data: %d", err);
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
2020-11-13 16:21:32 +01:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-12-15 10:33:41 +01:00
|
|
|
ext_adv->timestamp = k_uptime_get_32();
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
err = bt_le_ext_adv_start(ext_adv->instance, start);
|
2020-11-13 16:21:32 +01:00
|
|
|
if (err) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_ERR("Advertising failed: err %d", err);
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
static int bt_data_send(struct bt_mesh_ext_adv *ext_adv, uint8_t num_events, uint16_t adv_interval,
|
2022-10-19 09:42:02 +02:00
|
|
|
const struct bt_data *ad, size_t ad_len)
|
2020-11-13 16:21:32 +01:00
|
|
|
{
|
|
|
|
struct bt_le_ext_adv_start_param start = {
|
2022-10-19 09:42:02 +02:00
|
|
|
.num_events = num_events,
|
2020-11-13 16:21:32 +01:00
|
|
|
};
|
2022-10-19 09:42:02 +02:00
|
|
|
|
|
|
|
adv_interval = MAX(ADV_INT_FAST_MS, adv_interval);
|
|
|
|
|
|
|
|
/* Only update advertising parameters if they're different */
|
2023-12-05 10:01:19 +08:00
|
|
|
if (ext_adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) {
|
|
|
|
ext_adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval);
|
|
|
|
ext_adv->adv_param.interval_max = ext_adv->adv_param.interval_min;
|
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS);
|
2022-10-19 09:42:02 +02:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
return adv_start(ext_adv, &ext_adv->adv_param, &start, ad, ad_len, NULL, 0);
|
2022-10-19 09:42:02 +02:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
static int adv_send(struct bt_mesh_ext_adv *ext_adv, struct bt_mesh_adv *adv)
|
2022-10-19 09:42:02 +02:00
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
uint8_t num_events = BT_MESH_TRANSMIT_COUNT(adv->ctx.xmit) + 1;
|
2020-11-13 16:21:32 +01:00
|
|
|
uint16_t duration, adv_int;
|
|
|
|
struct bt_data ad;
|
|
|
|
int err;
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
adv_int = BT_MESH_TRANSMIT_INT(adv->ctx.xmit);
|
2020-11-13 16:21:32 +01:00
|
|
|
/* Upper boundary estimate: */
|
2022-10-19 09:42:02 +02:00
|
|
|
duration = num_events * (adv_int + 10);
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
LOG_DBG("type %u len %u: %s", adv->ctx.type,
|
|
|
|
adv->b.len, bt_hex(adv->b.data, adv->b.len));
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("count %u interval %ums duration %ums",
|
2022-10-19 09:42:02 +02:00
|
|
|
num_events, adv_int, duration);
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
ad.type = bt_mesh_adv_type[adv->ctx.type];
|
|
|
|
ad.data_len = adv->b.len;
|
|
|
|
ad.data = adv->b.data;
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
err = bt_data_send(ext_adv, num_events, adv_int, &ad, 1);
|
2021-05-26 20:32:18 -07:00
|
|
|
if (!err) {
|
2023-12-05 10:01:19 +08:00
|
|
|
ext_adv->adv = bt_mesh_adv_ref(adv);
|
2021-05-26 20:32:18 -07:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
bt_mesh_adv_send_start(duration, err, &adv->ctx);
|
2020-11-13 16:21:32 +01:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-09-06 16:47:20 +08:00
|
|
|
static const char * const adv_tag_to_str[] = {
|
|
|
|
[BT_MESH_ADV_TAG_LOCAL] = "local adv",
|
|
|
|
[BT_MESH_ADV_TAG_RELAY] = "relay adv",
|
|
|
|
[BT_MESH_ADV_TAG_PROXY] = "proxy adv",
|
|
|
|
[BT_MESH_ADV_TAG_FRIEND] = "friend adv",
|
|
|
|
[BT_MESH_ADV_TAG_PROV] = "prov adv",
|
|
|
|
};
|
2023-01-11 10:35:46 +01:00
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
static void send_pending_adv(struct k_work *work)
|
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv;
|
|
|
|
struct bt_mesh_adv *adv;
|
2020-11-13 16:21:32 +01:00
|
|
|
int err;
|
|
|
|
|
2023-12-15 10:33:41 +01:00
|
|
|
ext_adv = CONTAINER_OF(work, struct bt_mesh_ext_adv, work);
|
2022-03-23 14:54:01 +08:00
|
|
|
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
if (atomic_test_bit(ext_adv->flags, ADV_FLAG_SUSPENDING)) {
|
|
|
|
LOG_DBG("Advertiser is suspending");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SENT)) {
|
2023-12-15 10:33:41 +01:00
|
|
|
LOG_DBG("Advertising stopped after %u ms for %s",
|
|
|
|
k_uptime_get_32() - ext_adv->timestamp,
|
|
|
|
ext_adv->adv ? adv_tag_to_str[ext_adv->adv->ctx.tag]
|
|
|
|
: adv_tag_to_str[BT_MESH_ADV_TAG_PROXY]);
|
2022-03-23 14:54:01 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY);
|
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START);
|
2022-03-23 14:54:01 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (ext_adv->adv) {
|
2024-01-22 14:40:38 +01:00
|
|
|
struct bt_mesh_adv_ctx ctx = ext_adv->adv->ctx;
|
|
|
|
|
|
|
|
ext_adv->adv->ctx.started = 0;
|
2023-12-05 10:01:19 +08:00
|
|
|
bt_mesh_adv_unref(ext_adv->adv);
|
2024-01-22 14:40:38 +01:00
|
|
|
bt_mesh_adv_send_end(0, &ctx);
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
ext_adv->adv = NULL;
|
2022-03-23 14:54:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
while ((adv = bt_mesh_adv_get_by_tag(ext_adv->tags, K_NO_WAIT))) {
|
2020-11-13 16:21:32 +01:00
|
|
|
/* busy == 0 means this was canceled */
|
2023-12-05 10:01:19 +08:00
|
|
|
if (!adv->ctx.busy) {
|
|
|
|
bt_mesh_adv_unref(adv);
|
2020-11-13 16:21:32 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
adv->ctx.busy = 0U;
|
|
|
|
err = adv_send(ext_adv, adv);
|
2021-05-26 20:32:18 -07:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
bt_mesh_adv_unref(adv);
|
2021-05-26 20:32:18 -07:00
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
if (!err) {
|
|
|
|
return; /* Wait for advertising to finish */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
if (ext_adv->instance == NULL) {
|
|
|
|
LOG_DBG("Advertiser is suspended or deleted");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-05 16:15:41 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) &&
|
|
|
|
!bt_mesh_sol_send()) {
|
2021-11-23 11:23:06 +08:00
|
|
|
return;
|
2021-11-18 10:13:03 +08:00
|
|
|
}
|
2022-02-28 10:32:52 +08:00
|
|
|
|
2024-02-05 16:15:41 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER) ||
|
|
|
|
!(ext_adv->tags & BT_MESH_ADV_TAG_BIT_PROXY)) {
|
2022-10-19 09:42:02 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY_START);
|
2023-06-01 14:38:56 +08:00
|
|
|
|
Bluetooth: Mesh: Fix unable sent mesh message
In PR (#58723) has introduce another bug, that,
the flag ADV_FLAG_PROXY set before actually enabled.
When ctx:: BT RX call schedule_send will atomic_test_and_clear
ADV_FLAG_PROXY, but at this time, the proxy advertising will
not at advertising state, maybe in update params or set adverting
data phase,
so that, call bt_le_ext_adv_stop will nothing, and then call
k_work_reschedule --> send_pending_adv(at this time, the proxy
advertising actually enabled, but the upper layer clear proxy flags),
cause latest advertising unable start, because unable in advertising
state to update params(-EINVAL).
Fixes: #58721
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
2023-06-06 10:09:16 +08:00
|
|
|
if (!bt_mesh_adv_gatt_send()) {
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_PROXY);
|
2022-02-28 10:32:52 +08:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING)) {
|
|
|
|
schedule_send(ext_adv);
|
2022-02-28 10:32:52 +08:00
|
|
|
}
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
static bool schedule_send(struct bt_mesh_ext_adv *ext_adv)
|
2020-11-13 16:21:32 +01:00
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY)) {
|
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START);
|
|
|
|
(void)bt_le_ext_adv_stop(ext_adv->instance);
|
Bluetooth: Mesh: Fix unable sent mesh message
In PR (#58723) has introduce another bug, that,
the flag ADV_FLAG_PROXY set before actually enabled.
When ctx:: BT RX call schedule_send will atomic_test_and_clear
ADV_FLAG_PROXY, but at this time, the proxy advertising will
not at advertising state, maybe in update params or set adverting
data phase,
so that, call bt_le_ext_adv_stop will nothing, and then call
k_work_reschedule --> send_pending_adv(at this time, the proxy
advertising actually enabled, but the upper layer clear proxy flags),
cause latest advertising unable start, because unable in advertising
state to update params(-EINVAL).
Fixes: #58721
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
2023-06-06 10:09:16 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
2021-11-03 17:05:10 +08:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) {
|
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING);
|
2022-02-28 10:32:52 +08:00
|
|
|
return false;
|
2024-02-05 15:57:47 +01:00
|
|
|
} else if (k_work_is_pending(&ext_adv->work)) {
|
2021-11-03 17:05:10 +08:00
|
|
|
return false;
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_SCHEDULE_PENDING);
|
2023-12-15 10:33:41 +01:00
|
|
|
k_work_submit(&ext_adv->work);
|
2021-11-03 17:05:10 +08:00
|
|
|
|
|
|
|
return true;
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2021-11-18 09:23:08 +08:00
|
|
|
void bt_mesh_adv_gatt_update(void)
|
2020-11-13 16:21:32 +01:00
|
|
|
{
|
2021-11-23 14:27:31 +08:00
|
|
|
(void)schedule_send(gatt_adv_get());
|
2021-11-03 17:05:10 +08:00
|
|
|
}
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
void bt_mesh_adv_local_ready(void)
|
2021-11-03 17:05:10 +08:00
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
(void)schedule_send(advs);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
void bt_mesh_adv_relay_ready(void)
|
2020-11-13 16:21:32 +01:00
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv = relay_adv_get();
|
2021-11-03 17:05:10 +08:00
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
for (int i = 0; i < CONFIG_BT_MESH_RELAY_ADV_SETS; i++) {
|
2023-12-05 10:01:19 +08:00
|
|
|
if (schedule_send(&ext_adv[i])) {
|
2021-11-03 17:05:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-09-30 14:44:12 +08:00
|
|
|
|
|
|
|
/* Attempt to use the main adv set for the sending of relay messages. */
|
2022-11-10 12:23:07 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_RELAY_USING_MAIN_ADV_SET)) {
|
2023-09-08 13:56:10 +08:00
|
|
|
(void)schedule_send(advs);
|
2022-11-10 12:23:07 +08:00
|
|
|
}
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
void bt_mesh_adv_friend_ready(void)
|
2023-01-11 10:35:46 +01:00
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE)) {
|
|
|
|
schedule_send(&advs[1 + CONFIG_BT_MESH_RELAY_ADV_SETS]);
|
|
|
|
} else {
|
|
|
|
schedule_send(&advs[0]);
|
|
|
|
}
|
2023-01-11 10:35:46 +01:00
|
|
|
}
|
|
|
|
|
2024-01-22 14:49:19 +01:00
|
|
|
int bt_mesh_adv_terminate(struct bt_mesh_adv *adv)
|
2023-09-06 16:47:20 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv = &advs[i];
|
2023-09-08 13:56:10 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (ext_adv->adv != adv) {
|
2023-09-06 16:47:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) {
|
2024-01-22 14:49:19 +01:00
|
|
|
return 0;
|
2023-09-06 16:47:20 +08:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
err = bt_le_ext_adv_stop(ext_adv->instance);
|
2023-09-06 16:47:20 +08:00
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to stop adv %d", err);
|
2024-01-22 14:49:19 +01:00
|
|
|
return err;
|
2023-09-06 16:47:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Do not call `cb:end`, since this user action */
|
2023-12-05 10:01:19 +08:00
|
|
|
adv->ctx.cb = NULL;
|
2023-09-06 16:47:20 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
|
2023-09-06 16:47:20 +08:00
|
|
|
|
2023-12-15 10:33:41 +01:00
|
|
|
k_work_submit(&ext_adv->work);
|
2023-09-06 16:47:20 +08:00
|
|
|
|
2024-01-22 14:49:19 +01:00
|
|
|
return 0;
|
2023-09-06 16:47:20 +08:00
|
|
|
}
|
2024-01-22 14:49:19 +01:00
|
|
|
|
|
|
|
return -EINVAL;
|
2023-09-06 16:47:20 +08:00
|
|
|
}
|
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
void bt_mesh_adv_init(void)
|
|
|
|
{
|
2021-11-23 14:18:01 +08:00
|
|
|
struct bt_le_adv_param adv_param = {
|
|
|
|
.id = BT_ID_DEFAULT,
|
|
|
|
.interval_min = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS),
|
|
|
|
.interval_max = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS),
|
|
|
|
#if defined(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)
|
|
|
|
.options = BT_LE_ADV_OPT_USE_IDENTITY,
|
|
|
|
#endif
|
2023-09-08 13:56:10 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
|
|
|
|
(void)memcpy(&advs[i].adv_param, &adv_param, sizeof(adv_param));
|
2021-11-23 14:18:01 +08:00
|
|
|
}
|
2021-11-03 17:05:10 +08:00
|
|
|
}
|
|
|
|
|
2021-11-23 14:18:01 +08:00
|
|
|
static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance)
|
2021-11-03 17:05:10 +08:00
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
|
|
|
|
if (advs[i].instance == instance) {
|
|
|
|
return &advs[i];
|
2021-11-03 17:05:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void adv_sent(struct bt_le_ext_adv *instance,
|
|
|
|
struct bt_le_ext_adv_sent_info *info)
|
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv = adv_instance_find(instance);
|
2021-11-03 17:05:10 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (!ext_adv) {
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_WRN("Unexpected adv instance");
|
2021-11-03 17:05:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (!atomic_test_bit(ext_adv->flags, ADV_FLAG_ACTIVE)) {
|
2022-03-23 14:54:01 +08:00
|
|
|
return;
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
|
2022-03-23 14:54:01 +08:00
|
|
|
|
2023-12-15 10:33:41 +01:00
|
|
|
k_work_submit(&ext_adv->work);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2021-11-03 17:05:10 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_GATT_SERVER)
|
2020-11-13 16:21:32 +01:00
|
|
|
static void connected(struct bt_le_ext_adv *instance,
|
|
|
|
struct bt_le_ext_adv_connected_info *info)
|
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv = gatt_adv_get();
|
2021-11-03 17:05:10 +08:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
if (atomic_test_and_clear_bit(ext_adv->flags, ADV_FLAG_PROXY_START)) {
|
|
|
|
atomic_clear_bit(ext_adv->flags, ADV_FLAG_ACTIVE);
|
|
|
|
(void)schedule_send(ext_adv);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
}
|
2021-11-03 17:05:10 +08:00
|
|
|
#endif /* CONFIG_BT_MESH_GATT_SERVER */
|
2020-11-13 16:21:32 +01:00
|
|
|
|
|
|
|
int bt_mesh_adv_enable(void)
|
|
|
|
{
|
2021-11-03 17:05:10 +08:00
|
|
|
int err;
|
|
|
|
|
2020-11-13 16:21:32 +01:00
|
|
|
static const struct bt_le_ext_adv_cb adv_cb = {
|
|
|
|
.sent = adv_sent,
|
2021-11-03 17:05:10 +08:00
|
|
|
#if defined(CONFIG_BT_MESH_GATT_SERVER)
|
2020-11-13 16:21:32 +01:00
|
|
|
.connected = connected,
|
2021-11-03 17:05:10 +08:00
|
|
|
#endif /* CONFIG_BT_MESH_GATT_SERVER */
|
2020-11-13 16:21:32 +01:00
|
|
|
};
|
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
if (advs[0].instance) {
|
2020-11-13 16:21:32 +01:00
|
|
|
/* Already initialized */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-08 13:56:10 +08:00
|
|
|
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
|
|
|
|
err = bt_le_ext_adv_create(&advs[i].adv_param, &adv_cb,
|
|
|
|
&advs[i].instance);
|
2021-11-03 17:05:10 +08:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
|
|
|
|
2023-11-23 12:09:17 +01:00
|
|
|
int bt_mesh_adv_disable(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct k_work_sync sync;
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(advs); i++) {
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
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);
|
|
|
|
}
|
2023-11-23 12:09:17 +01:00
|
|
|
|
|
|
|
err = bt_le_ext_adv_stop(advs[i].instance);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to stop adv %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* `adv_sent` is called to finish transmission of an adv buffer that was pushed to
|
|
|
|
* the host before the advertiser was stopped, but did not finish.
|
|
|
|
*/
|
|
|
|
adv_sent(advs[i].instance, NULL);
|
|
|
|
|
|
|
|
err = bt_le_ext_adv_delete(advs[i].instance);
|
|
|
|
if (err) {
|
|
|
|
LOG_ERR("Failed to delete adv %d", err);
|
|
|
|
return err;
|
|
|
|
}
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
|
2023-11-23 12:09:17 +01:00
|
|
|
advs[i].instance = NULL;
|
Bluetooth: Mesh: Allow to suspend mesh from bt_mesh_send_cb callbacks
This commit allows to suspend the mesh stack from `bt_mesh_send_cb`
callbacks by removing the deadlock caused by `k_work_flush` in the
extended advertiser.
In case of the extended advertiser there are 2 cases:
- when the `bt_mesh_adv_disable` is called from any of `bt_mesh_send_cb`
callbacks which are called from the advertiser work item, or
- when it is called from any other context.
When it is called from `bt_mesh_send_cb` callbacks, since these
callbacks are called from the delayable work which is running on the
system workqueue, the advertiser can check the current context and its
work state. If the function is called from the advertiser work, it can
disable the advertising set straight away because all ble host APIs have
already been called in `adv_start` function. Before sending anything
else, the advertiser checks the `instance` value in `adv_start`
function, which is also reset to NULL in `bt_mesh_adv_disable` call, and
aborts all next advertisements. The `ADV_FLAG_SUSPENDING` tells the
advertiser work to abort processing while `bt_mesh_adv_disable` function
didn't finish stopping advertising set. This can happen if the work has
been already scheduled and the schedler ran it while sleeping inside
the `bt_le_ext_adv_stop` or `bt_le_ext_adv_disable` functions.
When `bt_mesh_adv_disable` is called from any other context or from the
system workqueue but not from the advertiser work, then `k_work_flush`
can be called safely as it won't cause any deadlocks.
The `adv_sent` function is inside the `bt_mesh_adv_disable` function to
schedule the advertiser work (`send_pending_adv`) and abort all pending
advertisements that have been already added to the pool.
In case of the legacy advertiser, if the `bt_mesh_adv_disable` is called
form the advertiser thread (this happens when it is called from
`bt_mesh_send_cb.start` or `bt_mesh_send_cb.end` callbacks), then
`k_thread_join` returns `-EDEADLK`. But the `enabled` flag is set to
false and the thread will abort the current advertisement and the
pending advertisements.
Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
2024-02-01 11:38:18 +01:00
|
|
|
|
|
|
|
atomic_clear_bit(advs[i].flags, ADV_FLAG_SUSPENDING);
|
2023-11-23 12:09:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-11-23 14:18:01 +08:00
|
|
|
int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param,
|
|
|
|
int32_t duration,
|
2021-11-18 09:23:08 +08:00
|
|
|
const struct bt_data *ad, size_t ad_len,
|
|
|
|
const struct bt_data *sd, size_t sd_len)
|
2020-11-13 16:21:32 +01:00
|
|
|
{
|
2023-12-05 10:01:19 +08:00
|
|
|
struct bt_mesh_ext_adv *ext_adv = gatt_adv_get();
|
2020-11-13 16:21:32 +01:00
|
|
|
struct bt_le_ext_adv_start_param start = {
|
|
|
|
/* Timeout is set in 10 ms steps, with 0 indicating "forever" */
|
2022-09-21 09:37:08 +02:00
|
|
|
.timeout = (duration == SYS_FOREVER_MS) ? 0 : MAX(1, duration / 10),
|
2020-11-13 16:21:32 +01:00
|
|
|
};
|
|
|
|
|
2022-11-02 14:31:13 +01:00
|
|
|
LOG_DBG("Start advertising %d ms", duration);
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
atomic_set_bit(ext_adv->flags, ADV_FLAG_UPDATE_PARAMS);
|
2020-11-13 16:21:32 +01:00
|
|
|
|
2023-12-05 10:01:19 +08:00
|
|
|
return adv_start(ext_adv, param, &start, ad, ad_len, sd, sd_len);
|
2020-11-13 16:21:32 +01:00
|
|
|
}
|
2022-10-19 09:42:02 +02:00
|
|
|
|
|
|
|
int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval,
|
|
|
|
const struct bt_data *ad, size_t ad_len)
|
|
|
|
{
|
2023-09-08 13:56:10 +08:00
|
|
|
return bt_data_send(advs, num_events, adv_interval, ad, ad_len);
|
2022-10-19 09:42:02 +02:00
|
|
|
}
|