Bluetooth: Mesh: Call friendship callbacks at the end

If a user does some heavy operations in friendship callbacks
unintentionally, this may break friendship communication as timers will
be scheduled or messages will be queued only after code execution comes
back from these callbacks. To avoid this issue, call callbacks only after
required operations are done.

Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
Pavel Vasilyev 2022-12-06 09:55:30 +01:00 committed by Carles Cufí
commit 5b4b5c0d34
2 changed files with 48 additions and 37 deletions

View file

@ -730,6 +730,23 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf)
friend_recv_delay(frnd);
if (msg->fsn == frnd->fsn && frnd->last) {
LOG_DBG("Re-sending last PDU");
frnd->send_last = 1U;
} else {
if (frnd->last) {
net_buf_unref(frnd->last);
frnd->last = NULL;
}
frnd->fsn = msg->fsn;
if (sys_slist_is_empty(&frnd->queue)) {
enqueue_update(frnd, 0);
LOG_DBG("Enqueued Friend Update to empty queue");
}
}
STRUCT_SECTION_FOREACH(bt_mesh_friend_cb, cb) {
if (cb->polled) {
cb->polled(frnd->subnet->net_idx, frnd->lpn);
@ -748,23 +765,6 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf)
}
}
if (msg->fsn == frnd->fsn && frnd->last) {
LOG_DBG("Re-sending last PDU");
frnd->send_last = 1U;
} else {
if (frnd->last) {
net_buf_unref(frnd->last);
frnd->last = NULL;
}
frnd->fsn = msg->fsn;
if (sys_slist_is_empty(&frnd->queue)) {
enqueue_update(frnd, 0);
LOG_DBG("Enqueued Friend Update to empty queue");
}
}
return 0;
}

View file

@ -217,6 +217,9 @@ static int send_friend_clear(void)
static void clear_friendship(bool force, bool disable)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
bool established = lpn->established;
uint16_t frnd = lpn->frnd;
uint16_t net_idx = lpn->sub->net_idx;
LOG_DBG("force %u disable %u", force, disable);
@ -244,14 +247,6 @@ static void clear_friendship(bool force, bool disable)
lpn->old_friend = lpn->frnd;
}
if (lpn->established) {
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->terminated) {
cb->terminated(lpn->sub->net_idx, lpn->frnd);
}
}
}
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->fsn = 0U;
lpn->req_attempts = 0U;
@ -284,6 +279,14 @@ static void clear_friendship(bool force, bool disable)
k_work_reschedule(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
}
if (established) {
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->terminated) {
cb->terminated(net_idx, frnd);
}
}
}
}
static void friend_req_sent(uint16_t duration, int err, void *user_data)
@ -358,6 +361,7 @@ static int send_friend_req(struct bt_mesh_lpn *lpn)
static void req_sent(uint16_t duration, int err, void *user_data)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
bool retry;
if (lpn->state == BT_MESH_LPN_DISABLED) {
return;
@ -375,11 +379,7 @@ static void req_sent(uint16_t duration, int err, void *user_data)
return;
}
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->polled) {
cb->polled(lpn->sub->net_idx, lpn->frnd, !!(lpn->req_attempts));
}
}
retry = (lpn->req_attempts > 0);
lpn->req_attempts++;
lpn->adv_duration = duration;
@ -397,6 +397,12 @@ static void req_sent(uint16_t duration, int err, void *user_data)
K_MSEC(LPN_RECV_DELAY + duration +
lpn->recv_win));
}
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->polled) {
cb->polled(lpn->sub->net_idx, lpn->frnd, retry);
}
}
}
static const struct bt_mesh_send_cb req_sent_cb = {
@ -984,6 +990,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub;
uint32_t iv_index;
bool established = false;
if (buf->len < sizeof(*msg)) {
LOG_WRN("Too short Friend Update");
@ -1023,16 +1030,11 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->established) {
cb->established(lpn->sub->net_idx, lpn->frnd,
lpn->queue_size, lpn->recv_win);
}
}
/* Set initial poll timeout */
lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn),
POLL_TIMEOUT_INIT);
established = true;
}
friend_response_received(lpn);
@ -1058,6 +1060,15 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
send_friend_poll();
}
if (established) {
STRUCT_SECTION_FOREACH(bt_mesh_lpn_cb, cb) {
if (cb->established) {
cb->established(lpn->sub->net_idx, lpn->frnd,
lpn->queue_size, lpn->recv_win);
}
}
}
return 0;
}