Skip to content

Commit f297b41

Browse files
jhedbergknutel-nordic
authored andcommitted
[nrf fromtree] tests: Bluetooth: host_long_adv_recv: Add malformed periodic report test
Enable periodic advertising sync in the test configuration and add a test which establishes a sync with the fake controller and sends periodic advertising reports whose length field claims more data than the event carries. The reports must be dropped without invoking the receive callback, and the sync must remain usable afterwards. Assisted-by: Claude:claude-fable-5 Signed-off-by: Johan Hedberg <johan.hedberg@silabs.com> (cherry picked from commit 3da48bd)
1 parent dcc403c commit f297b41

2 files changed

Lines changed: 164 additions & 4 deletions

File tree

tests/bluetooth/host_long_adv_recv/prj.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ CONFIG_BT_HCI=n
88
CONFIG_BT_HCI_RAW=n
99
CONFIG_BT_OBSERVER=y
1010
CONFIG_BT_EXT_ADV=y
11+
CONFIG_BT_PER_ADV_SYNC=y
1112

1213
CONFIG_LOG=y
1314
CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=n
1415
CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=n
1516
CONFIG_BT_LOG_LEVEL_DBG=y
1617

1718
CONFIG_BT_EXT_SCAN_BUF_SIZE=91
19+
CONFIG_BT_PER_ADV_SYNC_BUF_SIZE=91

tests/bluetooth/host_long_adv_recv/src/main.c

Lines changed: 162 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,19 @@ static void generic_success(struct net_buf *buf, struct net_buf **evt, uint8_t l
156156
ccst->status = BT_HCI_ERR_SUCCESS;
157157
}
158158

159+
/* Generic command status with success status. */
160+
static void generic_status(struct net_buf *buf, struct net_buf **evt, uint8_t len, uint16_t opcode)
161+
{
162+
struct bt_hci_evt_cmd_status *cs;
163+
164+
*evt = bt_buf_get_evt(BT_HCI_EVT_CMD_STATUS, false, K_FOREVER);
165+
evt_create(*evt, BT_HCI_EVT_CMD_STATUS, sizeof(*cs));
166+
cs = net_buf_add(*evt, sizeof(*cs));
167+
cs->status = BT_HCI_ERR_SUCCESS;
168+
cs->ncmd = 1U;
169+
cs->opcode = sys_cpu_to_le16(opcode);
170+
}
171+
159172
/* Bogus handler for BT_HCI_OP_READ_LOCAL_FEATURES. */
160173
static void read_local_features(struct net_buf *buf, struct net_buf **evt, uint8_t len,
161174
uint16_t opcode)
@@ -221,6 +234,7 @@ static const struct cmd_handler cmds[] = {
221234
generic_success },
222235
{ BT_HCI_OP_LE_SET_EXT_SCAN_PARAM, sizeof(struct bt_hci_evt_cc_status), generic_success },
223236
{ BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE, sizeof(struct bt_hci_evt_cc_status), generic_success },
237+
{ BT_HCI_OP_LE_PER_ADV_CREATE_SYNC, 0, generic_status },
224238
{ BT_HCI_OP_RESET, sizeof(struct bt_hci_evt_cc_status), generic_success },
225239
};
226240

@@ -360,6 +374,83 @@ static void scan_timeout_cb(void)
360374
zassert_unreachable("Timeout should not happen");
361375
}
362376

377+
#define SYNC_HANDLE 0x0001
378+
379+
/* Send a periodic advertising sync established event for the pending sync. */
380+
static void send_per_adv_sync_established(const bt_addr_le_t *addr, uint8_t sid)
381+
{
382+
struct bt_hci_evt_le_meta_event *meta_evt;
383+
struct bt_hci_evt_le_per_adv_sync_established *evt;
384+
struct net_buf *buf;
385+
386+
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
387+
evt_create(buf, BT_HCI_EVT_LE_META_EVENT, sizeof(*meta_evt) + sizeof(*evt));
388+
meta_evt = net_buf_add(buf, sizeof(*meta_evt));
389+
le_meta_evt_create(meta_evt, BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED);
390+
evt = net_buf_add(buf, sizeof(*evt));
391+
evt->status = BT_HCI_ERR_SUCCESS;
392+
evt->handle = sys_cpu_to_le16(SYNC_HANDLE);
393+
evt->sid = sid;
394+
bt_addr_le_copy(&evt->adv_addr, addr);
395+
evt->phy = BT_HCI_LE_PHY_1M;
396+
evt->interval = sys_cpu_to_le16(0x0100);
397+
evt->clock_accuracy = 0;
398+
399+
bt_recv_job_submit(buf);
400+
}
401+
402+
/* Send a periodic advertising report carrying data_len bytes of data, whose length
403+
* field claims claimed_len bytes.
404+
*/
405+
static void send_per_adv_report(uint8_t data_status, const uint8_t *data, uint8_t data_len,
406+
uint8_t claimed_len)
407+
{
408+
struct bt_hci_evt_le_meta_event *meta_evt;
409+
struct bt_hci_evt_le_per_advertising_report *evt;
410+
struct net_buf *buf;
411+
412+
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
413+
evt_create(buf, BT_HCI_EVT_LE_META_EVENT, sizeof(*meta_evt) + sizeof(*evt) + data_len);
414+
meta_evt = net_buf_add(buf, sizeof(*meta_evt));
415+
le_meta_evt_create(meta_evt, BT_HCI_EVT_LE_PER_ADVERTISING_REPORT);
416+
evt = net_buf_add(buf, sizeof(*evt));
417+
evt->handle = sys_cpu_to_le16(SYNC_HANDLE);
418+
evt->tx_power = 0;
419+
evt->rssi = 0;
420+
evt->cte_type = BT_HCI_LE_NO_CTE;
421+
evt->data_status = data_status;
422+
evt->length = claimed_len;
423+
net_buf_add_mem(buf, data, data_len);
424+
425+
bt_recv_job_submit(buf);
426+
}
427+
428+
static K_SEM_DEFINE(per_adv_synced_sem, 0, 1);
429+
430+
static void per_adv_sync_synced_cb(struct bt_le_per_adv_sync *sync,
431+
struct bt_le_per_adv_sync_synced_info *info)
432+
{
433+
k_sem_give(&per_adv_synced_sem);
434+
}
435+
436+
static void per_adv_sync_term_cb(struct bt_le_per_adv_sync *sync,
437+
const struct bt_le_per_adv_sync_term_info *info)
438+
{
439+
zassert_unreachable("Sync should not be terminated");
440+
}
441+
442+
static void per_adv_sync_recv_cb(struct bt_le_per_adv_sync *sync,
443+
const struct bt_le_per_adv_sync_recv_info *info,
444+
struct net_buf_simple *buf)
445+
{
446+
const struct test_adv_report expected = get_expected_report();
447+
448+
LOG_DBG("Received periodic adv report with length %u", buf->len);
449+
450+
zassert_equal(buf->len, expected.length, "Lengths should be equal");
451+
zassert_mem_equal(buf->data, expected.data, buf->len, "Data should be equal");
452+
}
453+
363454
static void generate_sequence(uint8_t *dest, uint16_t len, uint8_t range_start, uint8_t range_end)
364455
{
365456
uint16_t written = 0;
@@ -374,15 +465,19 @@ static void generate_sequence(uint8_t *dest, uint16_t len, uint8_t range_start,
374465
}
375466
}
376467

377-
ZTEST_SUITE(long_adv_rx_tests, NULL, NULL, NULL, NULL, NULL);
468+
static void *suite_setup(void)
469+
{
470+
zassert_true((bt_enable(NULL) == 0), "bt_enable failed");
471+
472+
return NULL;
473+
}
474+
475+
ZTEST_SUITE(long_adv_rx_tests, NULL, suite_setup, NULL, NULL, NULL);
378476

379477
ZTEST(long_adv_rx_tests, test_host_long_adv_recv)
380478
{
381479
struct test_adv_report expected_reports[2];
382480

383-
/* Go! Wait until Bluetooth initialization is done */
384-
zassert_true((bt_enable(NULL) == 0), "bt_enable failed");
385-
386481
static struct bt_le_scan_cb scan_callbacks = { .recv = scan_recv_cb,
387482
.timeout = scan_timeout_cb };
388483
bt_le_scan_cb_register(&scan_callbacks);
@@ -510,3 +605,66 @@ ZTEST(long_adv_rx_tests, test_host_long_adv_recv)
510605
send_adv_report(&report_b_2);
511606
zassert_equal(1, get_expected_report_fake.call_count);
512607
}
608+
609+
ZTEST(long_adv_rx_tests, test_host_per_adv_report_bad_len)
610+
{
611+
static struct bt_le_per_adv_sync_cb sync_callbacks = {
612+
.synced = per_adv_sync_synced_cb,
613+
.term = per_adv_sync_term_cb,
614+
.recv = per_adv_sync_recv_cb,
615+
};
616+
struct bt_le_per_adv_sync_param param = {
617+
.sid = 1,
618+
.timeout = BT_GAP_PER_ADV_MIN_TIMEOUT,
619+
};
620+
struct bt_le_per_adv_sync *sync;
621+
struct test_adv_report report = { .length = 20 };
622+
uint8_t fragment[10];
623+
int err;
624+
625+
RESET_FAKE(get_expected_report);
626+
FFF_RESET_HISTORY();
627+
628+
bt_addr_le_create_static(&param.addr);
629+
generate_sequence(fragment, sizeof(fragment), 'A', 'Z');
630+
generate_sequence(report.data, report.length, 'a', 'z');
631+
632+
err = bt_le_per_adv_sync_cb_register(&sync_callbacks);
633+
zassert_equal(err, 0, "bt_le_per_adv_sync_cb_register failed (err %d)", err);
634+
635+
err = bt_le_per_adv_sync_create(&param, &sync);
636+
zassert_equal(err, 0, "bt_le_per_adv_sync_create failed (err %d)", err);
637+
638+
send_per_adv_sync_established(&param.addr, param.sid);
639+
err = k_sem_take(&per_adv_synced_sem, K_SECONDS(1));
640+
zassert_equal(err, 0, "Sync not established (err %d)", err);
641+
642+
/* A partial fragment claiming more data than the event carries. The report is
643+
* discarded up to and including the next complete fragment, and the one after
644+
* that is delivered intact.
645+
*/
646+
SET_RETURN_SEQ(get_expected_report, &report, 1);
647+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL, fragment, sizeof(fragment),
648+
sizeof(fragment));
649+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL, fragment, sizeof(fragment),
650+
4 * sizeof(fragment));
651+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE, report.data, report.length,
652+
report.length);
653+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE, report.data, report.length,
654+
report.length);
655+
zassert_equal(1, get_expected_report_fake.call_count);
656+
RESET_FAKE(get_expected_report);
657+
FFF_RESET_HISTORY();
658+
659+
/* Same with the complete fragment of a reassembled report being the bad one */
660+
SET_RETURN_SEQ(get_expected_report, &report, 1);
661+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL, fragment, sizeof(fragment),
662+
sizeof(fragment));
663+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE, fragment, sizeof(fragment),
664+
4 * sizeof(fragment));
665+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE, report.data, report.length,
666+
report.length);
667+
send_per_adv_report(BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE, report.data, report.length,
668+
report.length);
669+
zassert_equal(1, get_expected_report_fake.call_count);
670+
}

0 commit comments

Comments
 (0)