Repository: zephyrproject-rtos/zephyr
Pull request #89881: bluetooth: mesh: fix advertiser pool memory leakage after device is suspended
Author: login: alxelax
Labels: name: area: Bluetooth
name: area: Bluetooth Mesh
name: platform: nRF BSIM
description: Nordic Semiconductors, nRF BabbleSim
Created: 2025-05-13T10:56:13Z | Merged: 2025-05-20T13:25:06Z

If the device is suspended, then the advertiser is stopped and deleted. The high level logic that is responsible for adv memory unreferencing is not called.
PR adds advertisement buffer unreferencing if advertiser in SUSPENDING state as well as bsim test that checks there is no memory leakage anymore.


Diff:
diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c
index 7641ba33224a8..b056f74a5876b 100644
--- a/subsys/bluetooth/mesh/adv_ext.c
+++ b/subsys/bluetooth/mesh/adv_ext.c
@@ -434,6 +434,13 @@ void bt_mesh_adv_friend_ready(void)
 	}
 }
 
+static void adv_sent(struct bt_mesh_ext_adv *ext_adv)
+{
+	atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
+
+	bt_mesh_wq_submit(&ext_adv->work);
+}
+
 int bt_mesh_adv_terminate(struct bt_mesh_adv *adv)
 {
 	int err;
@@ -458,9 +465,7 @@ int bt_mesh_adv_terminate(struct bt_mesh_adv *adv)
 		/* Do not call `cb:end`, since this user action */
 		adv->ctx.cb = NULL;
 
-		atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
-
-		bt_mesh_wq_submit(&ext_adv->work);
+		adv_sent(ext_adv);
 
 		return 0;
 	}
@@ -502,8 +507,7 @@ static struct bt_mesh_ext_adv *adv_instance_find(struct bt_le_ext_adv *instance)
 	return NULL;
 }
 
-static void adv_sent(struct bt_le_ext_adv *instance,
-		     struct bt_le_ext_adv_sent_info *info)
+static void ext_adv_set_sent(struct bt_le_ext_adv *instance, struct bt_le_ext_adv_sent_info *info)
 {
 	struct bt_mesh_ext_adv *ext_adv = adv_instance_find(instance);
 
@@ -517,9 +521,7 @@ static void adv_sent(struct bt_le_ext_adv *instance,
 		return;
 	}
 
-	atomic_set_bit(ext_adv->flags, ADV_FLAG_SENT);
-
-	bt_mesh_wq_submit(&ext_adv->work);
+	adv_sent(ext_adv);
 }
 
 int bt_mesh_adv_enable(void)
@@ -527,7 +529,7 @@ int bt_mesh_adv_enable(void)
 	int err;
 
 	static const struct bt_le_ext_adv_cb adv_cb = {
-		.sent = adv_sent,
+		.sent = ext_adv_set_sent,
 	};
 
 	if (advs[0].instance) {
@@ -536,8 +538,7 @@ int bt_mesh_adv_enable(void)
 	}
 
 	for (int i = 0; i < ARRAY_SIZE(advs); i++) {
-		err = bt_le_ext_adv_create(&advs[i].adv_param, &adv_cb,
-					   &advs[i].instance);
+		err = bt_le_ext_adv_create(&advs[i].adv_param, &adv_cb, &advs[i].instance);
 		if (err) {
 			return err;
 		}
@@ -565,11 +566,6 @@ int bt_mesh_adv_disable(void)
 			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);
@@ -579,6 +575,11 @@ int bt_mesh_adv_disable(void)
 		advs[i].instance = NULL;
 
 		atomic_clear_bit(advs[i].flags, ADV_FLAG_SUSPENDING);
+
+		/* `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]);
 	}
 
 	return 0;
diff --git a/tests/bsim/bluetooth/mesh/src/test_advertiser.c b/tests/bsim/bluetooth/mesh/src/test_advertiser.c
index 97b3c9c8aebbc..f7489f9e8315c 100644
--- a/tests/bsim/bluetooth/mesh/src/test_advertiser.c
+++ b/tests/bsim/bluetooth/mesh/src/test_advertiser.c
@@ -19,6 +19,12 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
 
 #define WAIT_TIME 60 /*seconds*/
 
+enum suspending_ctx {
+	NOT_SUSPENDED,
+	SUSPENDED_IN_CTX,
+	SUSPENDED_IN_CB
+};
+
 extern const struct bt_mesh_comp comp;
 
 static uint8_t test_prov_uuid[16] = { 0x6c, 0x69, 0x6e, 0x67, 0x61, 0xaa };
@@ -796,7 +802,7 @@ static void adv_resume(void)
 }
 
 struct adv_suspend_ctx {
-	bool suspend;
+	enum suspending_ctx suspend;
 	int instance_idx;
 };
 
@@ -812,7 +818,7 @@ static void adv_send_end(int err, void *cb_data)
 
 	ASSERT_EQUAL(err, 0);
 
-	if (adv_data->suspend) {
+	if (adv_data->suspend != NOT_SUSPENDED) {
 		/* When suspending, the end callback will be called only for the first adv, because
 		 * it was already scheduled.
 		 */
@@ -831,8 +837,8 @@ static void adv_send_start(uint16_t duration, int err, void *cb_data)
 	LOG_DBG("start(): err (%d), suspend (%d), i (%d)", err, adv_data->suspend,
 		adv_data->instance_idx);
 
-	if (adv_data->suspend) {
-		if (adv_data->instance_idx == 0) {
+	if (adv_data->suspend != NOT_SUSPENDED) {
+		if (adv_data->instance_idx == 0 && adv_data->suspend == SUSPENDED_IN_CB) {
 			ASSERT_EQUAL(err, 0);
 			adv_suspend();
 		} else {
@@ -851,7 +857,8 @@ static void adv_send_start(uint16_t duration, int err, void *cb_data)
 	}
 }
 
-static void adv_create_and_send(bool suspend, uint8_t first_byte, struct adv_suspend_ctx *adv_data)
+static void adv_create_and_send(enum suspending_ctx suspend, uint8_t first_byte,
+				struct adv_suspend_ctx *adv_data)
 {
 	struct bt_mesh_adv *advs[CONFIG_BT_MESH_ADV_BUF_COUNT];
 	static const struct bt_mesh_send_cb send_cb = {
@@ -864,7 +871,7 @@ static void adv_create_and_send(bool suspend, uint8_t first_byte, struct adv_sus
 		adv_data[i].instance_idx = i;
 
 		advs[i] = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL,
-					    BT_MESH_TRANSMIT(2, 20), K_NO_WAIT);
+					     BT_MESH_TRANSMIT(2, 20), K_NO_WAIT);
 		ASSERT_FALSE_MSG(!advs[i], "Out of advs\n");
 
 		net_buf_simple_add_u8(&advs[i]->b, first_byte);
@@ -877,29 +884,41 @@ static void adv_create_and_send(bool suspend, uint8_t first_byte, struct adv_sus
 	}
 }
 
-static void test_tx_disable(void)
+static void check_suspending(void)
 {
-	struct adv_suspend_ctx adv_data[CONFIG_BT_MESH_ADV_BUF_COUNT];
 	struct bt_mesh_adv *extra_adv;
 	int err;
 
-	bt_init();
-	adv_init();
-
-	/* Fill up the adv pool and suspend the advertiser in the first start callback call. */
-	adv_create_and_send(true, 0xAA, adv_data);
-
 	err = k_sem_take(&adv_suspended_sem, K_SECONDS(10));
 	ASSERT_OK_MSG(err, "Not all advs were sent");
 
 	extra_adv = bt_mesh_adv_create(BT_MESH_ADV_DATA, BT_MESH_ADV_TAG_LOCAL,
 				       BT_MESH_TRANSMIT(2, 20), K_NO_WAIT);
 	ASSERT_TRUE_MSG(!extra_adv, "Created adv while suspended");
+}
+
+static void test_tx_disable(void)
+{
+	struct adv_suspend_ctx adv_data[CONFIG_BT_MESH_ADV_BUF_COUNT];
+	int err;
+
+	bt_init();
+	adv_init();
+
+	LOG_INF("Fill up the adv pool and suspend the advertiser right after in the same context.");
+	adv_create_and_send(SUSPENDED_IN_CTX, 0xAA, adv_data);
+	adv_suspend();
+	check_suspending();
+	adv_resume();
 
+	LOG_INF("Fill up the adv pool and suspend the advertiser in the first start callback "
+		"call.");
+	adv_create_and_send(SUSPENDED_IN_CB, 0xAA, adv_data);
+	check_suspending();
 	adv_resume();
 
-	/* Fill up the adv pool and suspend the advertiser and let it send all advs. */
-	adv_create_and_send(false, 0xBB, adv_data);
+	LOG_INF("Fill up the adv pool and suspend the advertiser and let it send all advs");
+	adv_create_and_send(NOT_SUSPENDED, 0xBB, adv_data);
 
 	err = k_sem_take(&adv_sent_sem, K_SECONDS(10));
 	ASSERT_OK_MSG(err, "Not all advs were sent");
diff --git a/tests/bsim/bluetooth/mesh/src/test_suspend.c b/tests/bsim/bluetooth/mesh/src/test_suspend.c
index 34a2ac408957a..7864a9e9c1099 100644
--- a/tests/bsim/bluetooth/mesh/src/test_suspend.c
+++ b/tests/bsim/bluetooth/mesh/src/test_suspend.c
@@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
+	}
+
+	PASS();
+}
+
 #define TEST_CASE(role, name, description)                                                         \
 	{                                                                                          \
 		.test_id = "suspend_" #role "_" #name, .test_descr = description,                  \
@@ -479,6 +507,8 @@ static const struct bst_test_instance test_suspend[] = {
 			 "Suspend and resume Mesh with GATT proxy advs"),
 	TEST_CASE(dut, gatt_suspend_disable_resume,
 			 "Suspend and resume Mesh (and disable/enable BT) with GATT proxy advs"),
+	TEST_CASE(dut, suspend_resume_unref,
+			 "Suspend and resume Mesh twice adv more than advertiser pool size times"),
 
 	TEST_CASE(tester, pub, "Scan and verify behavior of periodic publishing adv"),
 	TEST_CASE(tester, gatt, "Scan and verify behavior of GATT proxy adv"),
diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh
index 4829183057220..aed97abe9c46e 100755
--- a/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh
+++ b/tests/bsim/bluetooth/mesh/tests_scripts/advertiser/disable.sh
@@ -17,15 +17,18 @@ source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
 # 1. Tx device creates `CONFIG_BT_MESH_ADV_BUF_COUNT` advertisements, setting the first byte of the
 # PDU to 0xAA and the second byte of the PDU to the advertisement order number
 # 2. Tx devices pushes all created advs to the pool by calling `bt_mesh_adv_send` function
-# 3. When the `bt_mesh_send_cb.start` callback is called for the first adv, the tx device submits
-#    a work item which suspends the advertiser by calling `bt_mesh_adv_disable`.
+# 3. After calling sending function Tx device immediately suspends the advertiser.
 # 4. Tx device checks that for the first adv the `bt_mesh_send_cb.end` callback is called with the
 #    error code `0`.
 # 5. Tx device checks that for the consecutive advs the `bt_mesh_send_cb.start` is called with error
 #    `-ENODEV`.
 # 6. Tx device checks that no more advs can be created using `bt_mesh_adv_create` function.
 # 7. Tx device resumes the advertiser and repeats steps 1 and 2.
-# 8. Tx device expects that all advs are sent.
+# 8. When the `bt_mesh_send_cb.start` callback is called for the first adv, the tx device submits
+#    a work item which suspends the advertiser by calling `bt_mesh_adv_disable`.
+# 9. Tx device repeats steps 4-6.
+# 10. Tx device resumes the advertiser and repeats steps 1 and 2.
+# 11. Tx device expects that all advs are sent.
 #
 # Rx device procedure:
 # 1. Rx devices listens all the time while tx device sends advs and ensure that no new advs were
@@ -35,7 +38,7 @@ RunTest mesh_adv_disable adv_tx_disable adv_rx_disable
 
 # Low latency overlay uses legacy advertiser
 overlay=overlay_low_lat_conf
-RunTest mesh_adv_disable adv_tx_disable adv_rx_disable
+RunTest mesh_adv_disable_low_lat adv_tx_disable adv_rx_disable
 
 overlay=overlay_workq_sys_conf
 RunTest mesh_adv_disable_workq adv_tx_disable adv_rx_disable
diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume_unref.sh b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume_unref.sh
new file mode 100755
index 0000000000000..4a1bd1cc3e3fe
--- /dev/null
+++ b/tests/bsim/bluetooth/mesh/tests_scripts/suspend/suspend_resume_unref.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Copyright 2025 Nordic Semiconductor
+# SPDX-License-Identifier: Apache-2.0
+
+source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh
+
+# Test that initiates a broadcasting of the test model command and immediately suspends device.
+# After a short pause, the device is resumed and attempt of broadcasting is repeated.
+# This is repeated twice more time than allocated advertiser pool size to be sure in that
+# device unreferences allocated advertiser from the pool back if it is suspended.
+#
+# Test procedure:
+# 0. Provisioning and setup.
+# 1. Send test model command twice to check that all allocated advertisers are freed.
+# 2. Suspend Mesh.
+# 3. Resume Mesh.
+# 4. Repeat steps 1-3 twice more than allocated advertiser pool size.
+overlay="overlay_psa_conf"
+RunTest mesh_suspend_resume_unref suspend_dut_suspend_resume_unref
+
+overlay="overlay_low_lat_conf_overlay_psa_conf"
+RunTest mesh_suspend_resume_unref_low_lat suspend_dut_suspend_resume_unref


Reviews:
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T11:03:05Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T12:06:11Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T13:06:14Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T06:11:35Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T12:39:33Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T06:05:03Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T06:06:57Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:50:19Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T10:59:37Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:39:45Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T12:41:55Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T14:12:29Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T19:00:58Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T20:53:58Z
user: login: PavelVPV
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T06:01:08Z
user: login: PavelVPV
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T06:11:43Z
user: login: omkar3141
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T12:54:10Z
user: login: alxelax
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T13:01:35Z
user: login: omkar3141
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T13:02:50Z

Review comments:
diff_hunk: @@ -347,6 +347,10 @@ static void send_pending_adv(struct k_work *work)
 
 	if (atomic_test_bit(ext_adv->flags, ADV_FLAG_SUSPENDING)) {
 		LOG_DBG("Advertiser is suspending");
+
+		if (ext_adv->adv) {
+			bt_mesh_adv_unref(ext_adv->adv);
path: subsys/bluetooth/mesh/adv_ext.c
user: login: PavelVPV
body: I think this will not release all other adv buffers pending after the one that was scheduled. I've prepared a draft when was discussing this issue with @akredalen with the test that checks this behavior:
https://github.com/zephyrproject-rtos/zephyr/compare/main...PavelVPV:experiment_adv_disable_issue?expand=1#diff-96959e58e40e61bba9cc068e83e7157908d569a5282c573ff55d70d1e99755c9R584
created_at: 2025-05-13T11:03:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: I'd rather extend existing `test_tx_disable` as I attempted to do here: https://github.com/zephyrproject-rtos/zephyr/compare/main...PavelVPV:experiment_adv_disable_issue?expand=1#diff-96959e58e40e61bba9cc068e83e7157908d569a5282c573ff55d70d1e99755c9R584

This test doesn't check if `bt_mesh_adv_send_cb` callback is called with an error for each buffer. The `test_tx_disable` test in turns checks that all buffers were released.

By extend I mean:
1. Convert current `test_tx_disable` to a function that takes boolean as an argument
2. If boolean is true, advertiser is suspended in a callback
3. If boolean is false, advertiser is suspended separately (in the test function).
4. Create 2 test functions: one passes `true` to the `test_tx_disable`, the other one passes `false`.
created_at: 2025-05-14T12:06:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: ```
This test doesn't check if bt_mesh_adv_send_cb callback is called with an error for each buffer.
```
This is not a correct statement for legacy advertiser.

The current test checks also that all allocated buffers are released by cycles twice more than slub pool size. If at least 1 buffer leaked, then the cycle cannot reach the end and test will fail.

I will add the test that you described but only for extended advertiser (it has doubtable value to me since it checks internal advertiser state machine that is messy and should be tested by unit tests if do it correctly).

The test that I implemented covers a use case scenario with a bug that the customer reported.
Testing it on advertiser level is not correct since it uses not public API. Testing it on advertiser doesn't guarantee that suspending functionality is changed with going bug back.
created_at: 2025-05-14T13:06:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: > This is not a correct statement for legacy advertiser.

Could you elaborate? The legacy advertiser provides (or should provide) the same behavior: all pending adv buffers should be released when advertiser is suspended with  error code passed to `bt_mesh_send_cb.start` callback. If this is not true, then it should be fixed as well.

> The current test checks also that all allocated buffers are released by cycles twice more than slub pool size. If at least 1 buffer leaked, then the cycle cannot reach the end and test will fail.

Ok.

> The test that I implemented covers a use case scenario with a bug that the customer reported.
Testing it on advertiser level is not correct since it uses not public API. Testing it on advertiser doesn't guarantee that suspending functionality is changed with going bug back.

I agree with this point, but callbacks should be checked. It is part of advertisers (legacy and extended) behavior.

We also didn't cover segmented message transmission.
created_at: 2025-05-15T06:11:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: ```
Could you elaborate?
```
For legacy advertiser, callback is not called with error for every buffer. Legacy advertiser manages case on different manner
created_at: 2025-05-15T12:39:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: Please fix this as well since you are working on this.
created_at: 2025-05-19T06:05:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: Because I believe it should work the same way: https://github.com/zephyrproject-rtos/zephyr/blob/b5934e8dfe5c8dd4c1a9f2221341aa46e3dce72a/subsys/bluetooth/mesh/adv_legacy.c#L201-L205
created_at: 2025-05-19T06:06:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: I did not get what to fix.
created_at: 2025-05-19T10:50:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: You said that this the legacy advertiser behaves differently:

> For legacy advertiser, callback is not called with error for every buffer. Legacy advertiser manages case on different manner

This needs to be fixed because the disabling mechanism was implemented the same way for the legacy advertiser and should work the same way. Upper layers should get the same behavior from both advertisers.
created_at: 2025-05-19T10:59:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: Hm... Legacy advertiser processes this like single thread rather to extended advertiser work callbacks.
Do you suggest me to redesign legacy advertiser? I do not understand.
created_at: 2025-05-19T12:39:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: No, it is not correct. Both works the same way. I don't suggest to redesign. IT is already designed like this. The test should work for the legacy advertiser as well.
created_at: 2025-05-19T12:41:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: > No, it is not correct.

Please point what is exactly not correct and should be fixed.

> Legacy advertiser processes this like single thread:
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/mesh/adv_legacy.c#L232-L236
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/mesh/adv_legacy.c#L150-L206

> rather to extended advertiser work callbacks.
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/mesh/adv_ext.c#L571
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/mesh/adv_ext.c#L522
https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/bluetooth/mesh/adv_ext.c#L334

I do not understand what you try to say. Seems like throwing common phrases here and there "No, it is not correct." etc
I'm not telepath.

created_at: 2025-05-19T14:12:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: > Legacy advertiser processes this like single thread:
rather to extended advertiser work callbacks.

Both works on threads. Both has callbacks. Both calls callbacks from threads they run.

> I do not understand what you try to say. Seems like throwing common phrases here and there "No, it is not correct." etc
I'm not telepath.

I have responded to your comment:

> This is not a correct statement for legacy advertiser.

If you say so, please fix this, if your statement is not correct, please enable the test for the legacy advertiser.
created_at: 2025-05-19T19:00:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: > > Legacy advertiser processes this like single thread:
> > rather to extended advertiser work callbacks.
> 
> Both works on threads. Both has callbacks. Both calls callbacks from threads they run.
> 
> > I do not understand what you try to say. Seems like throwing common phrases here and there "No, it is not correct." etc
> > I'm not telepath.
> 
> I have responded to your comment:
> 
> > This is not a correct statement for legacy advertiser.
> 
> If you say so, please fix this, if your statement is not correct, please enable the test for the legacy advertiser.

You want me to fix anything but do not want to say what is wrong. Until it, you are going to block this PR. Do I correctly understand you?
created_at: 2025-05-19T20:53:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
+		ASSERT_OK_MSG(bt_mesh_resume(), "Failed to resume Mesh.");
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: PavelVPV
body: Initially you gave a misleading impression of that the legacy advertiser doesn't work:
https://github.com/zephyrproject-rtos/zephyr/pull/89881#discussion_r2088899848

![Screenshot from 2025-05-20 08-02-06](https://github.com/user-attachments/assets/72961f4a-a723-4fcd-85e0-536e4df8fa17)

I checked again the PR and see that test runs for legacy advertiser as well. So my statement was correct:

> The legacy advertiser provides (or should provide) the same behavior

And yours was not:

> For legacy advertiser, callback is not called with error for every buffer. Legacy advertiser manages case on different manner

It turns out the relevant test was indeed enabled. This wasn’t clear from your  comments, and we ended up spending quite a bit of time discussing something that could have been clarified upfront.

I suggest you in future clarify better your changes for everyone's benefit.
created_at: 2025-05-20T06:11:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: omkar3141
body: I'm wondering if this test will actually catch the issue. Since sleep is called for 500ms, the `bt_mesh_test_send_data()` will enqueue the PDU, and then PDU will be disposed off by the advertiser. So, this will always pass.

What would be interesting to check, is:
1. what happens when you have `k_sleep(K_MSEC(5))`  OR
2. have model retransmissions set to max (7), and network retransmissions set to max (7), 

Will this still pass in such scenarios?
created_at: 2025-05-20T12:54:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -464,6 +464,34 @@ static void test_tester_gatt(void)
 	PASS();
 }
 
+static void test_dut_suspend_resume_unref(void)
+{
+	const struct bt_mesh_test_cfg tx_cfg = {
+		.addr = 0x0001,
+		.dev_key = {0x01},
+	};
+
+	bt_mesh_test_cfg_set(&tx_cfg, 2 * WAIT_TIME);
+	bt_mesh_test_setup();
+
+	for (uint16_t count = 0; count < 2 * CONFIG_BT_MESH_ADV_BUF_COUNT; count++) {
+		LOG_DBG("Step %d", count);
+
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+		ASSERT_OK_MSG(bt_mesh_test_send_data(BT_MESH_ADDR_ALL_NODES, NULL,
+						     (uint8_t *)&count, sizeof(count), NULL, NULL),
+			      "Cannot send data");
+
+		ASSERT_OK_MSG(bt_mesh_suspend(), "Failed to suspend Mesh.");
+		k_sleep(K_MSEC(500));
path: tests/bsim/bluetooth/mesh/src/test_suspend.c
user: login: alxelax
body: I did tdd. Test was implemented first and it was failed. After my initial implementation, it passed. After Pavel's clarification about it will not clear adv for the sequenced sending, I added it and test was failed again. After applying Pavel's suggestions, it started passing again.
Answer: yes - test actually catches the issue. 
created_at: 2025-05-20T13:01:35Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-15T13:05:20Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=89881) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=89881&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=89881&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=zephyrproject-rtos_zephyr&pullRequest=89881&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=89881&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=89881&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=89881)


author_association: NONE