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>
This commit is contained in:
parent
070bd0e295
commit
c3df8fcd92
@ -53,6 +53,10 @@
|
||||
#include <soc.h>
|
||||
#include "hal/debug.h"
|
||||
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
|
||||
#define SUB_INTERVAL_MIN 400
|
||||
|
||||
static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||
{
|
||||
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,
|
||||
return BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Validate that the LL_CIS_REQ parameters are valid according to the rules in
|
||||
* Core Specification v5.4, Vol. 6, Part B, Section 2.4.2.29
|
||||
*/
|
||||
static uint8_t rp_cc_validate_req(struct ll_conn *conn, struct proc_ctx *ctx,
|
||||
struct pdu_data *pdu)
|
||||
{
|
||||
uint32_t cis_offset_max;
|
||||
uint32_t cis_offset_min;
|
||||
uint32_t c_sdu_interval;
|
||||
uint32_t p_sdu_interval;
|
||||
uint32_t sub_interval;
|
||||
uint16_t iso_interval;
|
||||
uint16_t c_max_pdu;
|
||||
uint16_t p_max_pdu;
|
||||
uint8_t result;
|
||||
|
||||
result = rp_cc_check_phy(conn, ctx, pdu);
|
||||
if (result != BT_HCI_ERR_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Note: SDU intervals are 20 bits; Mask away RFU bits */
|
||||
c_sdu_interval = sys_get_le24(pdu->llctrl.cis_req.c_sdu_interval) & 0x0FFFFF;
|
||||
p_sdu_interval = sys_get_le24(pdu->llctrl.cis_req.p_sdu_interval) & 0x0FFFFF;
|
||||
if (c_sdu_interval < BT_HCI_ISO_SDU_INTERVAL_MIN ||
|
||||
p_sdu_interval < BT_HCI_ISO_SDU_INTERVAL_MIN) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
c_max_pdu = sys_le16_to_cpu(pdu->llctrl.cis_req.c_max_pdu);
|
||||
p_max_pdu = sys_le16_to_cpu(pdu->llctrl.cis_req.p_max_pdu);
|
||||
if (c_max_pdu > BT_ISO_PDU_MAX || p_max_pdu > BT_ISO_PDU_MAX) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
if (!IN_RANGE(pdu->llctrl.cis_req.nse, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
iso_interval = sys_le16_to_cpu(pdu->llctrl.cis_req.iso_interval);
|
||||
sub_interval = sys_get_le24(pdu->llctrl.cis_req.sub_interval);
|
||||
if (pdu->llctrl.cis_req.nse == 1) {
|
||||
if (sub_interval > 0) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
} else if (!IN_RANGE(sub_interval, SUB_INTERVAL_MIN,
|
||||
iso_interval * CONN_INT_UNIT_US - 1)) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
if ((pdu->llctrl.cis_req.c_bn == 0 && c_max_pdu > 0) ||
|
||||
(pdu->llctrl.cis_req.p_bn == 0 && p_max_pdu > 0)) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
if (pdu->llctrl.cis_req.c_ft == 0 || pdu->llctrl.cis_req.p_ft == 0) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
if (!IN_RANGE(iso_interval, BT_HCI_ISO_INTERVAL_MIN, BT_HCI_ISO_INTERVAL_MAX)) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
cis_offset_min = sys_get_le24(pdu->llctrl.cis_req.cis_offset_min);
|
||||
if (cis_offset_min < PDU_CIS_OFFSET_MIN_US) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
cis_offset_max = sys_get_le24(pdu->llctrl.cis_req.cis_offset_max);
|
||||
if (!IN_RANGE(cis_offset_max, cis_offset_min, conn->lll.interval * CONN_INT_UNIT_US - 1)) {
|
||||
return BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
}
|
||||
|
||||
return BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||
void *param)
|
||||
{
|
||||
@ -331,8 +411,8 @@ static void rp_cc_state_wait_rx_cis_req(struct ll_conn *conn, struct proc_ctx *c
|
||||
/* Handle CIS request */
|
||||
llcp_pdu_decode_cis_req(ctx, pdu);
|
||||
|
||||
/* Check PHY */
|
||||
ctx->data.cis_create.error = rp_cc_check_phy(conn, ctx, pdu);
|
||||
/* Check validity of request */
|
||||
ctx->data.cis_create.error = rp_cc_validate_req(conn, ctx, pdu);
|
||||
|
||||
if (ctx->data.cis_create.error == BT_HCI_ERR_SUCCESS) {
|
||||
ctx->data.cis_create.error =
|
||||
|
||||
@ -47,6 +47,10 @@ DEFINE_FFF_GLOBALS;
|
||||
#include "helper_pdu.h"
|
||||
#include "helper_util.h"
|
||||
|
||||
#include <zephyr/bluetooth/iso.h>
|
||||
|
||||
#define SUB_INTERVAL_MIN 400
|
||||
|
||||
static struct ll_conn conn;
|
||||
|
||||
static struct ll_conn_iso_group cig_mock = { 0 };
|
||||
@ -84,11 +88,11 @@ static struct pdu_data_llctrl_cis_req remote_cis_req = {
|
||||
.p_ft = 1,
|
||||
.iso_interval = 6,
|
||||
.conn_event_count = 12,
|
||||
.c_sdu_interval = { 0, 0, 0},
|
||||
.p_sdu_interval = { 0, 0, 0},
|
||||
.sub_interval = { 0, 0, 0},
|
||||
.cis_offset_min = { 0, 0, 0},
|
||||
.cis_offset_max = { 0, 0, 0}
|
||||
.c_sdu_interval = { 0, 0x02, 0}, /* 512 us */
|
||||
.p_sdu_interval = { 0, 0x02, 0}, /* 512 us */
|
||||
.sub_interval = { 0x90, 0x01, 0x00}, /* 400 us */
|
||||
.cis_offset_min = { 0, 0x02, 0}, /* 512 us */
|
||||
.cis_offset_max = { 0, 0x02, 0} /* 512 us */
|
||||
};
|
||||
|
||||
static struct pdu_data_llctrl_cis_ind remote_cis_ind = {
|
||||
@ -169,8 +173,8 @@ ZTEST(cis_create, test_cc_create_periph_rem_host_accept)
|
||||
.cis_id = 0x02
|
||||
};
|
||||
struct pdu_data_llctrl_cis_rsp local_cis_rsp = {
|
||||
.cis_offset_max = { 0, 0, 0},
|
||||
.cis_offset_min = { 0, 0, 0},
|
||||
.cis_offset_max = { 0, 0x02, 0},
|
||||
.cis_offset_min = { 0, 0x02, 0},
|
||||
.conn_event_count = 12
|
||||
};
|
||||
struct node_rx_conn_iso_estab cis_estab = {
|
||||
@ -525,6 +529,196 @@ ZTEST(cis_create, test_cc_create_periph_rem_invalid_phy)
|
||||
"Free CTX buffers %d", llcp_ctx_buffers_free());
|
||||
}
|
||||
|
||||
static void rx_remote_cis_req_invalid_param(struct pdu_data_llctrl_cis_req *req)
|
||||
{
|
||||
struct node_tx *tx;
|
||||
struct pdu_data_llctrl_reject_ext_ind local_reject = {
|
||||
.error_code = BT_HCI_ERR_INVALID_LL_PARAM,
|
||||
.reject_opcode = PDU_DATA_LLCTRL_TYPE_CIS_REQ
|
||||
};
|
||||
|
||||
test_setup(&conn);
|
||||
|
||||
/* Role */
|
||||
test_set_role(&conn, BT_HCI_ROLE_PERIPHERAL);
|
||||
|
||||
/* Connect */
|
||||
ull_cp_state_set(&conn, ULL_CP_CONNECTED);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Rx */
|
||||
lt_tx(LL_CIS_REQ, &conn, req);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
/* Prepare */
|
||||
event_prepare(&conn);
|
||||
|
||||
/* Tx Queue should have one LL Control PDU */
|
||||
lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &local_reject);
|
||||
lt_rx_q_is_empty(&conn);
|
||||
|
||||
/* Done */
|
||||
event_done(&conn);
|
||||
|
||||
zassert_equal(llcp_ctx_buffers_free(), test_ctx_buffers_cnt(),
|
||||
"Free CTX buffers %d", llcp_ctx_buffers_free());
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated CIS Create procedure.
|
||||
* Central requests CIS w. invalid param, peripheral Host rejects.
|
||||
*
|
||||
* +-----+ +-------+ +-----+
|
||||
* | UT | | LL_S | | LT |
|
||||
* +-----+ +-------+ +-----+
|
||||
* | | |
|
||||
* | | LL_CIS_REQ (invalid param) |
|
||||
* | |<------------------------------|
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* | | LL_REJECT_EXT_IND |
|
||||
* | |------------------------------>|
|
||||
* | | |
|
||||
*/
|
||||
ZTEST(cis_create, test_cc_create_periph_rem_invalid_param)
|
||||
{
|
||||
struct pdu_data_llctrl_cis_req remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with c_sdu_interval < 255 */
|
||||
sys_put_le24(BT_HCI_ISO_SDU_INTERVAL_MIN-1, remote_cis_req_invalid_param.c_sdu_interval);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with p_sdu_interval < 255 */
|
||||
sys_put_le24(BT_HCI_ISO_SDU_INTERVAL_MIN-1, remote_cis_req_invalid_param.p_sdu_interval);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with c_max_pdu > 251 */
|
||||
remote_cis_req_invalid_param.c_max_pdu = sys_cpu_to_le16(BT_ISO_PDU_MAX + 1);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with p_max_pdu > 251 */
|
||||
remote_cis_req_invalid_param.p_max_pdu = sys_cpu_to_le16(BT_ISO_PDU_MAX + 1);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with nse == 0 */
|
||||
remote_cis_req_invalid_param.nse = 0;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with nse > 31 */
|
||||
remote_cis_req_invalid_param.nse = BT_ISO_NSE_MAX + 1;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with sub_interval > 0 && nse == 1 */
|
||||
remote_cis_req_invalid_param.nse = 1;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with sub_interval < 400 && nse > 1 */
|
||||
sys_put_le24(SUB_INTERVAL_MIN - 1, remote_cis_req_invalid_param.sub_interval);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with sub_interval >= iso_interval */
|
||||
sys_put_le24(sys_le16_to_cpu(remote_cis_req_invalid_param.iso_interval) * CONN_INT_UNIT_US,
|
||||
remote_cis_req_invalid_param.sub_interval);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
|
||||
/* Rx with c_bn == 0 && c_max_pdu > 0 */
|
||||
remote_cis_req_invalid_param.c_bn = 0;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with p_bn == 0 && p_max_pdu > 0 */
|
||||
remote_cis_req_invalid_param.p_bn = 0;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with c_ft == 0 */
|
||||
remote_cis_req_invalid_param.c_ft = 0;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with p_ft == 0 */
|
||||
remote_cis_req_invalid_param.p_ft = 0;
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with iso_interval < 4 */
|
||||
remote_cis_req_invalid_param.iso_interval = sys_cpu_to_le16(BT_HCI_ISO_INTERVAL_MIN - 1);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with iso_interval > 3200 */
|
||||
remote_cis_req_invalid_param.iso_interval = sys_cpu_to_le16(BT_HCI_ISO_INTERVAL_MAX + 1);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with cis_offset_min < 500 */
|
||||
sys_put_le24(PDU_CIS_OFFSET_MIN_US - 1, remote_cis_req_invalid_param.cis_offset_min);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with cis_offset_max < cis_offset_min */
|
||||
sys_put_le24(0x01FF, remote_cis_req_invalid_param.cis_offset_max);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
|
||||
/* Restore to valid params */
|
||||
remote_cis_req_invalid_param = remote_cis_req;
|
||||
|
||||
/* Rx with cis_offset_max >= conn_interval */
|
||||
sys_put_le24(conn.lll.interval * CONN_INT_UNIT_US,
|
||||
remote_cis_req_invalid_param.cis_offset_max);
|
||||
rx_remote_cis_req_invalid_param(&remote_cis_req_invalid_param);
|
||||
}
|
||||
|
||||
/*
|
||||
* Central-initiated CIS Create procedure.
|
||||
* Host requests CIS, LL replies with 'remote feature unsupported'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user