Bluetooth: controller: fix CIS REQ event generation and rejection

Check LE event mask state as well as host controlled feature mask state
and reject CIS request accordingly.
Release pre-allocated ISO resources on rejection of request

Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
Erik Brockhoff 2022-10-05 14:18:25 +02:00 committed by Fabio Baltieri
commit 6b324122e7
5 changed files with 45 additions and 9 deletions

View file

@ -4097,14 +4097,6 @@ static void le_cis_request(struct pdu_data *pdu_data,
struct node_rx_conn_iso_req *req; struct node_rx_conn_iso_req *req;
void *node; void *node;
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
!(le_event_mask & BT_EVT_MASK_LE_CIS_REQ)) {
return;
}
sep = meta_evt(buf, BT_HCI_EVT_LE_CIS_REQ, sizeof(*sep));
sep->acl_handle = sys_cpu_to_le16(node_rx->hdr.handle);
/* Check for pdu field being aligned before accessing CIS established /* Check for pdu field being aligned before accessing CIS established
* event. * event.
*/ */
@ -4112,6 +4104,15 @@ static void le_cis_request(struct pdu_data *pdu_data,
LL_ASSERT(IS_PTR_ALIGNED(node, struct node_rx_conn_iso_estab)); LL_ASSERT(IS_PTR_ALIGNED(node, struct node_rx_conn_iso_estab));
req = node; req = node;
if (!(ll_feat_get() & BIT64(BT_LE_FEAT_BIT_ISO_CHANNELS)) ||
!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
!(le_event_mask & BT_EVT_MASK_LE_CIS_REQ)) {
ll_cis_reject(req->cis_handle, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE);
return;
}
sep = meta_evt(buf, BT_HCI_EVT_LE_CIS_REQ, sizeof(*sep));
sep->acl_handle = sys_cpu_to_le16(node_rx->hdr.handle);
sep->cis_handle = sys_cpu_to_le16(req->cis_handle); sep->cis_handle = sys_cpu_to_le16(req->cis_handle);
sep->cig_id = req->cig_id; sep->cig_id = req->cig_id;
sep->cis_id = req->cis_id; sep->cis_id = req->cis_id;

View file

@ -463,6 +463,8 @@ static void rp_cc_state_wait_reply(struct ll_conn *conn, struct proc_ctx *ctx, u
ctx->data.cis_create.error = BT_HCI_ERR_CONN_ACCEPT_TIMEOUT; ctx->data.cis_create.error = BT_HCI_ERR_CONN_ACCEPT_TIMEOUT;
/* If timeout is hit, fall through and reject */ /* If timeout is hit, fall through and reject */
case RP_CC_EVT_CIS_REQ_REJECT: case RP_CC_EVT_CIS_REQ_REJECT:
/* CIS Request is rejected, so clean up CIG/CIS acquisitions */
ull_peripheral_iso_release(ctx->data.cis_create.cis_handle);
/* Continue procedure in next prepare run */ /* Continue procedure in next prepare run */
ctx->state = RP_CC_STATE_WAIT_TX_REJECT_IND; ctx->state = RP_CC_STATE_WAIT_TX_REJECT_IND;
break; break;

View file

@ -123,7 +123,7 @@ uint8_t ll_cis_reject(uint16_t handle, uint8_t reason)
struct ll_conn *acl_conn = ll_cis_get_acl_awaiting_reply(handle, &status); struct ll_conn *acl_conn = ll_cis_get_acl_awaiting_reply(handle, &status);
if (acl_conn) { if (acl_conn) {
/* Accept request */ /* Reject request */
ull_cp_cc_reject(acl_conn, reason); ull_cp_cc_reject(acl_conn, reason);
} }
#endif #endif
@ -141,6 +141,28 @@ int ull_peripheral_iso_reset(void)
return 0; return 0;
} }
/* Use this function to release CIS/CIG resources on an aborted CIS setup
* ie if CIS setup is 'cancelled' after call to ull_peripheral_iso_acquire()
* because of a rejection of the CIS request
*/
void ull_peripheral_iso_release(uint16_t cis_handle)
{
struct ll_conn_iso_stream *cis;
struct ll_conn_iso_group *cig;
cis = ll_conn_iso_stream_get(cis_handle);
LL_ASSERT(cis);
cig = cis->group;
ll_conn_iso_stream_release(cis);
cig->lll.num_cis--;
if (!cig->lll.num_cis) {
ll_conn_iso_group_release(cig);
}
}
uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl, uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
struct pdu_data_llctrl_cis_req *req, struct pdu_data_llctrl_cis_req *req,
uint16_t *cis_handle) uint16_t *cis_handle)
@ -202,6 +224,12 @@ uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
/* Acquire new CIS */ /* Acquire new CIS */
cis = ll_conn_iso_stream_acquire(); cis = ll_conn_iso_stream_acquire();
if (cis == NULL) { if (cis == NULL) {
if (!cig->lll.num_cis) {
/* No CIS's in CIG, so this was just allocated
* so release as we can't use it
*/
ll_conn_iso_group_release(cig);
}
/* No space for new CIS */ /* No space for new CIS */
return BT_HCI_ERR_INSUFFICIENT_RESOURCES; return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
} }

View file

@ -8,6 +8,7 @@
int ull_peripheral_iso_init(void); int ull_peripheral_iso_init(void);
int ull_peripheral_iso_reset(void); int ull_peripheral_iso_reset(void);
void ull_peripheral_iso_release(uint16_t cis_handle);
uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl, uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
struct pdu_data_llctrl_cis_req *req, struct pdu_data_llctrl_cis_req *req,
uint16_t *cis_handle); uint16_t *cis_handle);

View file

@ -39,6 +39,10 @@
#include "ull_conn_iso_internal.h" #include "ull_conn_iso_internal.h"
#include "lll_peripheral_iso.h" #include "lll_peripheral_iso.h"
void ull_peripheral_iso_release(uint16_t cis_handle)
{
}
uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl, uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
struct pdu_data_llctrl_cis_req *req, struct pdu_data_llctrl_cis_req *req,
uint16_t *cis_handle) uint16_t *cis_handle)