Skip to content

Commit c3df8fc

Browse files
Tronilkartben
authored andcommitted
Bluetooth: Controller: Add validation of received LL_CIS_REQ
Validate that a received LL_CIS_REQ is valid and reject if it is not Fixes EBQ test failure in LL/CIS/PER/BI-07-C Signed-off-by: Troels Nilsson <trnn@demant.com>
1 parent 070bd0e commit c3df8fc

File tree

2 files changed

+283
-9
lines changed
  • subsys/bluetooth/controller/ll_sw
  • tests/bluetooth/controller/ctrl_cis_create/src

2 files changed

+283
-9
lines changed

subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
#include <soc.h>
5454
#include "hal/debug.h"
5555

56+
#include <zephyr/bluetooth/iso.h>
57+
58+
#define SUB_INTERVAL_MIN 400
59+
5660
static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx)
5761
{
5862
struct node_rx_conn_iso_estab *pdu;
@@ -321,6 +325,82 @@ static uint8_t rp_cc_check_phy(struct ll_conn *conn, struct proc_ctx *ctx,
321325
return BT_HCI_ERR_SUCCESS;
322326
}
323327

328+
/* Validate that the LL_CIS_REQ parameters are valid according to the rules in
329+
* Core Specification v5.4, Vol. 6, Part B, Section 2.4.2.29
330+
*/
331+
static uint8_t rp_cc_validate_req(struct ll_conn *conn, struct proc_ctx *ctx,
332+
struct pdu_data *pdu)
333+
{
334+
uint32_t cis_offset_max;
335+
uint32_t cis_offset_min;
336+
uint32_t c_sdu_interval;
337+
uint32_t p_sdu_interval;
338+
uint32_t sub_interval;
339+
uint16_t iso_interval;
340+
uint16_t c_max_pdu;
341+
uint16_t p_max_pdu;
342+
uint8_t result;
343+
344+
result = rp_cc_check_phy(conn, ctx, pdu);
345+
if (result != BT_HCI_ERR_SUCCESS) {
346+
return result;
347+
}
348+
349+
/* Note: SDU intervals are 20 bits; Mask away RFU bits */
350+
c_sdu_interval = sys_get_le24(pdu->llctrl.cis_req.c_sdu_interval) & 0x0FFFFF;
351+
p_sdu_interval = sys_get_le24(pdu->llctrl.cis_req.p_sdu_interval) & 0x0FFFFF;
352+
if (c_sdu_interval < BT_HCI_ISO_SDU_INTERVAL_MIN ||
353+
p_sdu_interval < BT_HCI_ISO_SDU_INTERVAL_MIN) {
354+
return BT_HCI_ERR_INVALID_LL_PARAM;
355+
}
356+
357+
c_max_pdu = sys_le16_to_cpu(pdu->llctrl.cis_req.c_max_pdu);
358+
p_max_pdu = sys_le16_to_cpu(pdu->llctrl.cis_req.p_max_pdu);
359+
if (c_max_pdu > BT_ISO_PDU_MAX || p_max_pdu > BT_ISO_PDU_MAX) {
360+
return BT_HCI_ERR_INVALID_LL_PARAM;
361+
}
362+
363+
if (!IN_RANGE(pdu->llctrl.cis_req.nse, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) {
364+
return BT_HCI_ERR_INVALID_LL_PARAM;
365+
}
366+
367+
iso_interval = sys_le16_to_cpu(pdu->llctrl.cis_req.iso_interval);
368+
sub_interval = sys_get_le24(pdu->llctrl.cis_req.sub_interval);
369+
if (pdu->llctrl.cis_req.nse == 1) {
370+
if (sub_interval > 0) {
371+
return BT_HCI_ERR_INVALID_LL_PARAM;
372+
}
373+
} else if (!IN_RANGE(sub_interval, SUB_INTERVAL_MIN,
374+
iso_interval * CONN_INT_UNIT_US - 1)) {
375+
return BT_HCI_ERR_INVALID_LL_PARAM;
376+
}
377+
378+
if ((pdu->llctrl.cis_req.c_bn == 0 && c_max_pdu > 0) ||
379+
(pdu->llctrl.cis_req.p_bn == 0 && p_max_pdu > 0)) {
380+
return BT_HCI_ERR_INVALID_LL_PARAM;
381+
}
382+
383+
if (pdu->llctrl.cis_req.c_ft == 0 || pdu->llctrl.cis_req.p_ft == 0) {
384+
return BT_HCI_ERR_INVALID_LL_PARAM;
385+
}
386+
387+
if (!IN_RANGE(iso_interval, BT_HCI_ISO_INTERVAL_MIN, BT_HCI_ISO_INTERVAL_MAX)) {
388+
return BT_HCI_ERR_INVALID_LL_PARAM;
389+
}
390+
391+
cis_offset_min = sys_get_le24(pdu->llctrl.cis_req.cis_offset_min);
392+
if (cis_offset_min < PDU_CIS_OFFSET_MIN_US) {
393+
return BT_HCI_ERR_INVALID_LL_PARAM;
394+
}
395+
396+
cis_offset_max = sys_get_le24(pdu->llctrl.cis_req.cis_offset_max);
397+
if (!IN_RANGE(cis_offset_max, cis_offset_min, conn->lll.interval * CONN_INT_UNIT_US - 1)) {
398+
return BT_HCI_ERR_INVALID_LL_PARAM;
399+
}
400+
401+
return BT_HCI_ERR_SUCCESS;
402+
}
403+
324404
static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
325405
void *param)
326406
{
@@ -331,8 +411,8 @@ static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *c
331411
/* Handle CIS request */
332412
llcp_pdu_decode_cis_req(ctx, pdu);
333413

334-
/* Check PHY */
335-
ctx->data.cis_create.error = rp_cc_check_phy(conn, ctx, pdu);
414+
/* Check validity of request */
415+
ctx->data.cis_create.error = rp_cc_validate_req(conn, ctx, pdu);
336416

337417
if (ctx->data.cis_create.error == BT_HCI_ERR_SUCCESS) {
338418
ctx->data.cis_create.error =

tests/bluetooth/controller/ctrl_cis_create/src/main.c

Lines changed: 201 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ DEFINE_FFF_GLOBALS;
4747
#include "helper_pdu.h"
4848
#include "helper_util.h"
4949

50+
#include <zephyr/bluetooth/iso.h>
51+
52+
#define SUB_INTERVAL_MIN 400
53+
5054
static struct ll_conn conn;
5155

5256
static struct ll_conn_iso_group cig_mock = { 0 };
@@ -84,11 +88,11 @@ static struct pdu_data_llctrl_cis_req remote_cis_req = {
8488
.p_ft = 1,
8589
.iso_interval = 6,
8690
.conn_event_count = 12,
87-
.c_sdu_interval = { 0, 0, 0},
88-
.p_sdu_interval = { 0, 0, 0},
89-
.sub_interval = { 0, 0, 0},
90-
.cis_offset_min = { 0, 0, 0},
91-
.cis_offset_max = { 0, 0, 0}
91+
.c_sdu_interval = { 0, 0x02, 0}, /* 512 us */
92+
.p_sdu_interval = { 0, 0x02, 0}, /* 512 us */
93+
.sub_interval = { 0x90, 0x01, 0x00}, /* 400 us */
94+
.cis_offset_min = { 0, 0x02, 0}, /* 512 us */
95+
.cis_offset_max = { 0, 0x02, 0} /* 512 us */
9296
};
9397

9498
static struct pdu_data_llctrl_cis_ind remote_cis_ind = {
@@ -169,8 +173,8 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept)
169173
.cis_id = 0x02
170174
};
171175
struct pdu_data_llctrl_cis_rsp local_cis_rsp = {
172-
.cis_offset_max = { 0, 0, 0},
173-
.cis_offset_min = { 0, 0, 0},
176+
.cis_offset_max = { 0, 0x02, 0},
177+
.cis_offset_min = { 0, 0x02, 0},
174178
.conn_event_count = 12
175179
};
176180
struct node_rx_conn_iso_estab cis_estab = {
@@ -525,6 +529,196 @@ ZTEST(cis_create, test_cc_create_periph_rem_invalid_phy)
525529
"Free CTX buffers %d", llcp_ctx_buffers_free());
526530
}
527531

532+
static void rx_remote_cis_req_invalid_param(struct pdu_data_llctrl_cis_req *req)
533+
{
534+
struct node_tx *tx;
535+
struct pdu_data_llctrl_reject_ext_ind local_reject = {
536+
.error_code = BT_HCI_ERR_INVALID_LL_PARAM,
537+
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CIS_REQ
538+
};
539+
540+
test_setup(&conn);
541+
542+
/* Role */
543+
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
544+
545+
/* Connect */
546+
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
547+
548+
/* Prepare */
549+
event_prepare(&conn);
550+
551+
/* Rx */
552+
lt_tx(LL_CIS_REQ, &conn, req);
553+
554+
/* Done */
555+
event_done(&conn);
556+
557+
/* Prepare */
558+
event_prepare(&conn);
559+
560+
/* Tx Queue should have one LL Control PDU */
561+
lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &local_reject);
562+
lt_rx_q_is_empty(&conn);
563+
564+
/* Done */
565+
event_done(&conn);
566+
567+
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
568+
"Free CTX buffers %d", llcp_ctx_buffers_free());
569+
}
570+
571+
/*
572+
* Central-initiated CIS Create procedure.
573+
* Central requests CIS w. invalid param, peripheral Host rejects.
574+
*
575+
* +-----+ +-------+ +-----+
576+
* | UT | | LL_S | | LT |
577+
* +-----+ +-------+ +-----+
578+
* | | |
579+
* | | LL_CIS_REQ (invalid param) |
580+
* | |<------------------------------|
581+
* | | |
582+
* | | |
583+
* | | |
584+
* | | |
585+
* | | |
586+
* | | |
587+
* | | LL_REJECT_EXT_IND |
588+
* | |------------------------------>|
589+
* | | |
590+
*/
591+
ZTEST(cis_create, test_cc_create_periph_rem_invalid_param)
592+
{
593+
struct pdu_data_llctrl_cis_req remote_cis_req_invalid_param = remote_cis_req;
594+
595+
/* Rx with c_sdu_interval < 255 */
596+
sys_put_le24(BT_HCI_ISO_SDU_INTERVAL_MIN-1, remote_cis_req_invalid_param.c_sdu_interval);
597+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
598+
599+
/* Restore to valid params */
600+
remote_cis_req_invalid_param = remote_cis_req;
601+
602+
/* Rx with p_sdu_interval < 255 */
603+
sys_put_le24(BT_HCI_ISO_SDU_INTERVAL_MIN-1, remote_cis_req_invalid_param.p_sdu_interval);
604+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
605+
606+
/* Restore to valid params */
607+
remote_cis_req_invalid_param = remote_cis_req;
608+
609+
/* Rx with c_max_pdu > 251 */
610+
remote_cis_req_invalid_param.c_max_pdu = sys_cpu_to_le16(BT_ISO_PDU_MAX + 1);
611+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
612+
613+
/* Restore to valid params */
614+
remote_cis_req_invalid_param = remote_cis_req;
615+
616+
/* Rx with p_max_pdu > 251 */
617+
remote_cis_req_invalid_param.p_max_pdu = sys_cpu_to_le16(BT_ISO_PDU_MAX + 1);
618+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
619+
620+
/* Restore to valid params */
621+
remote_cis_req_invalid_param = remote_cis_req;
622+
623+
/* Rx with nse == 0 */
624+
remote_cis_req_invalid_param.nse = 0;
625+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
626+
627+
/* Restore to valid params */
628+
remote_cis_req_invalid_param = remote_cis_req;
629+
630+
/* Rx with nse > 31 */
631+
remote_cis_req_invalid_param.nse = BT_ISO_NSE_MAX + 1;
632+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
633+
634+
/* Restore to valid params */
635+
remote_cis_req_invalid_param = remote_cis_req;
636+
637+
/* Rx with sub_interval > 0 && nse == 1 */
638+
remote_cis_req_invalid_param.nse = 1;
639+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
640+
641+
/* Restore to valid params */
642+
remote_cis_req_invalid_param = remote_cis_req;
643+
644+
/* Rx with sub_interval < 400 && nse > 1 */
645+
sys_put_le24(SUB_INTERVAL_MIN - 1, remote_cis_req_invalid_param.sub_interval);
646+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
647+
648+
/* Restore to valid params */
649+
remote_cis_req_invalid_param = remote_cis_req;
650+
651+
/* Rx with sub_interval >= iso_interval */
652+
sys_put_le24(sys_le16_to_cpu(remote_cis_req_invalid_param.iso_interval) * CONN_INT_UNIT_US,
653+
remote_cis_req_invalid_param.sub_interval);
654+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
655+
656+
/* Restore to valid params */
657+
remote_cis_req_invalid_param = remote_cis_req;
658+
659+
660+
/* Rx with c_bn == 0 && c_max_pdu > 0 */
661+
remote_cis_req_invalid_param.c_bn = 0;
662+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
663+
664+
/* Restore to valid params */
665+
remote_cis_req_invalid_param = remote_cis_req;
666+
667+
/* Rx with p_bn == 0 && p_max_pdu > 0 */
668+
remote_cis_req_invalid_param.p_bn = 0;
669+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
670+
671+
/* Restore to valid params */
672+
remote_cis_req_invalid_param = remote_cis_req;
673+
674+
/* Rx with c_ft == 0 */
675+
remote_cis_req_invalid_param.c_ft = 0;
676+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
677+
678+
/* Restore to valid params */
679+
remote_cis_req_invalid_param = remote_cis_req;
680+
681+
/* Rx with p_ft == 0 */
682+
remote_cis_req_invalid_param.p_ft = 0;
683+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
684+
685+
/* Restore to valid params */
686+
remote_cis_req_invalid_param = remote_cis_req;
687+
688+
/* Rx with iso_interval < 4 */
689+
remote_cis_req_invalid_param.iso_interval = sys_cpu_to_le16(BT_HCI_ISO_INTERVAL_MIN - 1);
690+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
691+
692+
/* Restore to valid params */
693+
remote_cis_req_invalid_param = remote_cis_req;
694+
695+
/* Rx with iso_interval > 3200 */
696+
remote_cis_req_invalid_param.iso_interval = sys_cpu_to_le16(BT_HCI_ISO_INTERVAL_MAX + 1);
697+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
698+
699+
/* Restore to valid params */
700+
remote_cis_req_invalid_param = remote_cis_req;
701+
702+
/* Rx with cis_offset_min < 500 */
703+
sys_put_le24(PDU_CIS_OFFSET_MIN_US - 1, remote_cis_req_invalid_param.cis_offset_min);
704+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
705+
706+
/* Restore to valid params */
707+
remote_cis_req_invalid_param = remote_cis_req;
708+
709+
/* Rx with cis_offset_max < cis_offset_min */
710+
sys_put_le24(0x01FF, remote_cis_req_invalid_param.cis_offset_max);
711+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
712+
713+
/* Restore to valid params */
714+
remote_cis_req_invalid_param = remote_cis_req;
715+
716+
/* Rx with cis_offset_max >= conn_interval */
717+
sys_put_le24(conn.lll.interval * CONN_INT_UNIT_US,
718+
remote_cis_req_invalid_param.cis_offset_max);
719+
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
720+
}
721+
528722
/*
529723
* Central-initiated CIS Create procedure.
530724
* Host requests CIS, LL replies with 'remote feature unsupported'

0 commit comments

Comments
 (0)