From d8d8d82f0e99de63f344311bdd38441b88a20dd2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 24 Aug 2021 16:46:46 +0200 Subject: [PATCH] Bluetooth: ISO: Add ISO limits as #defines and use them Add #define's for ISO HCI limits and use them to validate input parameters. Signed-off-by: Emil Gydesen --- include/bluetooth/iso.h | 124 ++++++++++++++++++++++++------ subsys/bluetooth/host/iso.c | 145 ++++++++++++++++++++++++++++++++++-- 2 files changed, 241 insertions(+), 28 deletions(-) diff --git a/include/bluetooth/iso.h b/include/bluetooth/iso.h index 9efd170878f..ed2e13909eb 100644 --- a/include/bluetooth/iso.h +++ b/include/bluetooth/iso.h @@ -35,7 +35,44 @@ extern "C" { BT_HCI_ISO_DATA_HDR_SIZE) /** Value to set the ISO data path over HCi. */ -#define BT_ISO_DATA_PATH_HCI 0x00 +#define BT_ISO_DATA_PATH_HCI 0x00 + +/** Minimum interval value in microseconds */ +#define BT_ISO_INTERVAL_MIN 0x0000FF +/** Maximum interval value in microseconds */ +#define BT_ISO_INTERVAL_MAX 0x0FFFFF +/** Minimum latency value in milliseconds */ +#define BT_ISO_LATENCY_MIN 0x0005 +/** Maximum latency value in milliseconds */ +#define BT_ISO_LATENCY_MAX 0x0FA0 +/** Packets will be sent sequentially between the channels in the group */ +#define BT_ISO_PACKING_SEQUENTIAL 0x00 +/** Packets will be sent interleaved between the channels in the group */ +#define BT_ISO_PACKING_INTERLEAVED 0x01 +/** Packets may be framed or unframed */ +#define BT_ISO_FRAMING_UNFRAMED 0x00 +/** Packets are always framed */ +#define BT_ISO_FRAMING_FRAMED 0x01 +/** Maximum number of isochronous channels in a single group */ +#define BT_ISO_MAX_GROUP_ISO_COUNT 0x1F +/** Maximum SDU size */ +#define BT_ISO_MAX_SDU 0x0FFF +/** Minimum BIG sync timeout value (N * 10 ms) */ +#define BT_ISO_SYNC_TIMEOUT_MIN 0x000A +/** Maximum BIG sync timeout value (N * 10 ms) */ +#define BT_ISO_SYNC_TIMEOUT_MAX 0x4000 +/** Controller controlled maximum subevent count value */ +#define BT_ISO_SYNC_MSE_ANY 0x00 +/** Minimum BIG sync maximum subevent count value */ +#define BT_ISO_SYNC_MSE_MIN 0x01 +/** Maximum BIG sync maximum subevent count value */ +#define BT_ISO_SYNC_MSE_MAX 0x1F +/** Maximum connected ISO retransmission value */ +#define BT_ISO_CONNECTED_RTN_MAX 0xFF +/** Maximum broadcast ISO retransmission value */ +#define BT_ISO_BROADCAST_RTN_MAX 0x1E +/** Broadcast code size */ +#define BT_ISO_BROADCAST_CODE_SIZE 16 struct bt_iso_chan; @@ -70,13 +107,13 @@ struct bt_iso_chan { /** @brief ISO Channel IO QoS structure. */ struct bt_iso_chan_io_qos { - /** Channel SDU. Value range 0x0000 - 0x0FFF. */ + /** Channel SDU. Maximum value is BT_ISO_MAX_SDU */ uint16_t sdu; /** Channel PHY - See BT_GAP_LE_PHY for values. * Setting BT_GAP_LE_PHY_NONE is invalid. */ uint8_t phy; - /** Channel Retransmission Number. Value range 0x00 - 0x0F. */ + /** Channel Retransmission Number. */ uint8_t rtn; /** @brief Channel data path reference * @@ -156,19 +193,29 @@ struct bt_iso_recv_info { struct bt_iso_cig; struct bt_iso_cig_create_param { - /** Array of pointers to CIS channels + /** @brief Array of pointers to CIS channels * * This array shall remain valid for the duration of the CIG. */ struct bt_iso_chan **cis_channels; - /** Number channels in @p cis_channels */ + /** @brief Number channels in @p cis_channels + * + * Maximum number of channels in a single group is + * BT_ISO_MAX_GROUP_ISO_COUNT + */ uint8_t num_cis; - /** Channel interval in us. Value range 0x0000FF - 0xFFFFFF. */ + /** @brief Channel interval in us. + * + * Value range BT_ISO_INTERVAL_MIN - BT_ISO_INTERVAL_MAX. + */ uint32_t interval; - /** Channel Latency in ms. Value range 0x0005 - 0x0FA0. */ + /** @brief Channel Latency in ms. + * + * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. + */ uint16_t latency; /** @brief Channel peripherals sleep clock accuracy Only for CIS @@ -180,10 +227,17 @@ struct bt_iso_cig_create_param { */ uint8_t sca; - /** Channel packing mode. 0 for unpacked, 1 for packed. */ + /** @brief Channel packing mode. + * + * BT_ISO_PACKING_SEQUENTIAL or BT_ISO_PACKING_INTERLEAVED + */ uint8_t packing; - /** Channel framing mode. 0 for unframed, 1 for framed. */ + /** @brief Channel framing mode. + * + * BT_ISO_FRAMING_UNFRAMED for unframed and + * BT_ISO_FRAMING_FRAMED for framed. + */ uint8_t framing; }; @@ -205,37 +259,58 @@ struct bt_iso_big_create_param { */ struct bt_iso_chan **bis_channels; - /** Number channels in @p bis_channels */ + /** @brief Number channels in @p bis_channels + * + * Maximum number of channels in a single group is + * BT_ISO_MAX_GROUP_ISO_COUNT + */ uint8_t num_bis; - /** Channel interval in us. Value range 0x0000FF - 0xFFFFFF. */ + /** @brief Channel interval in us. + * + * Value range BT_ISO_INTERVAL_MIN - BT_ISO_INTERVAL_MAX. + */ uint32_t interval; - /** Channel Latency in ms. Value range 0x0005 - 0x0FA0. */ + /** @brief Channel Latency in ms. + * + * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. + */ uint16_t latency; - /** Channel packing mode. 0 for unpacked, 1 for packed. */ + /** @brief Channel packing mode. + * + * BT_ISO_PACKING_SEQUENTIAL or BT_ISO_PACKING_INTERLEAVED + */ uint8_t packing; - /** Channel framing mode. 0 for unframed, 1 for framed. */ + /** @brief Channel framing mode. + * + * BT_ISO_FRAMING_UNFRAMED for unframed and + * BT_ISO_FRAMING_FRAMED for framed. + */ uint8_t framing; /** Whether or not to encrypt the streams. */ - bool encryption; + bool encryption; /** @brief Broadcast code * * The code used to derive the session key that is used to encrypt and * decrypt BIS payloads. */ - uint8_t bcode[16]; + uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; }; struct bt_iso_big_sync_param { /** Array of pointers to BIS channels */ struct bt_iso_chan **bis_channels; - /** Number channels in @p bis_channels */ + /** @brief Number channels in @p bis_channels + * + * Maximum number of channels in a single group is + * BT_ISO_MAX_GROUP_ISO_COUNT + */ uint8_t num_bis; /** Bitfield of the BISes to sync to */ @@ -243,12 +318,19 @@ struct bt_iso_big_sync_param { /** @brief Maximum subevents * - * The MSE (Maximum Subevents) parameter is the maximum number of subevents that a - * Controller should use to receive data payloads in each interval for a BIS + * The MSE (Maximum Subevents) parameter is the maximum number of + * subevents that a Controller should use to receive data payloads + * in each interval for a BIS. + * + * Value range is BT_ISO_SYNC_MSE_MIN to BT_ISO_SYNC_MSE_MAX, or + * BT_ISO_SYNC_MSE_ANY to let the controller choose. */ uint32_t mse; - /** Synchronization timeout for the BIG (N * 10 MS) */ + /** @brief Synchronization timeout for the BIG (N * 10 MS) + * + * Value range is BT_ISO_SYNC_TIMEOUT_MIN to BT_ISO_SYNC_TIMEOUT_MAX. + */ uint16_t sync_timeout; /** Whether or not the streams of the BIG are encrypted */ @@ -259,7 +341,7 @@ struct bt_iso_big_sync_param { * The code used to derive the session key that is used to encrypt and * decrypt BIS payloads. */ - uint8_t bcode[16]; + uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; }; struct bt_iso_biginfo { diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index e4b238bb18c..66af8234826 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -664,7 +664,50 @@ struct bt_conn_iso *bt_conn_iso(struct bt_conn *conn) return &conn->iso; } +static bool valid_chan_io_qos(const struct bt_iso_chan_io_qos *io_qos, + bool is_tx) +{ + const size_t max_mtu = (is_tx ? CONFIG_BT_ISO_TX_MTU : CONFIG_BT_ISO_RX_MTU) - + BT_ISO_CHAN_SEND_RESERVE; + const size_t max_sdu = MIN(max_mtu, BT_ISO_MAX_SDU); + + if (io_qos->sdu > max_sdu) { + BT_DBG("sdu (%u) shall be smaller than %u", + io_qos->sdu, max_sdu); + return false; + } + + if (io_qos->phy > BT_GAP_LE_PHY_CODED) { + BT_DBG("Invalid phy %u", io_qos->phy); + return false; + } + + return true; +} + #if defined(CONFIG_BT_ISO_UNICAST) +static bool valid_chan_qos(const struct bt_iso_chan_qos *qos) +{ + if (qos->rx != NULL) { + if (!valid_chan_io_qos(qos->rx, false)) { + BT_DBG("Invalid rx qos"); + return false; + } + } else if (qos->tx == NULL) { + BT_DBG("Both rx and tx qos are NULL"); + return false; + } + + if (qos->tx != NULL) { + if (!valid_chan_io_qos(qos->tx, true)) { + BT_DBG("Invalid tx qos"); + return false; + } + } + + return true; +} + void bt_iso_cleanup(struct bt_conn *conn) { struct bt_conn_iso *iso = bt_conn_iso(conn); @@ -953,11 +996,16 @@ static int cig_init_cis(struct bt_iso_cig *cig) for (int i = 0; i < cig->num_cis; i++) { struct bt_iso_chan *cis = cig->cis[i]; - if (cis == NULL) { + CHECKIF(cis == NULL) { BT_DBG("CIS was NULL"); return -EINVAL; } + CHECKIF(valid_chan_qos(cis->qos)) { + BT_DBG("Invalid QOS"); + return -EINVAL; + } + if (cis->conn) { BT_DBG("CIS conn was already allocated"); return -EALREADY; @@ -1023,6 +1071,44 @@ int bt_iso_cig_create(const struct bt_iso_cig_create_param *param, return -EINVAL; } + for (int i = 0; i < param->num_cis; i++) { + CHECKIF(param->cis_channels[i] == NULL) { + BT_DBG("NULL channel in cis_channels[%d]", i); + return -EINVAL; + } + } + + CHECKIF(param->framing != BT_ISO_FRAMING_UNFRAMED && + param->framing != BT_ISO_FRAMING_FRAMED) { + BT_DBG("Invalid framing parameter: %u", param->framing); + return -EINVAL; + } + + CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL && + param->packing != BT_ISO_PACKING_INTERLEAVED) { + BT_DBG("Invalid framing parameter: %u", param->framing); + return -EINVAL; + } + + CHECKIF(param->num_cis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_cis > CONFIG_BT_ISO_MAX_CHAN) { + BT_DBG("num_cis (%u) shall be lower than: %u", param->num_cis, + MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); + return -EINVAL; + } + + CHECKIF(param->interval < BT_ISO_INTERVAL_MIN || + param->interval > BT_ISO_INTERVAL_MAX) { + BT_DBG("Invalid interval: %u", param->interval); + return -EINVAL; + } + + CHECKIF(param->latency < BT_ISO_LATENCY_MIN || + param->latency > BT_ISO_LATENCY_MAX) { + BT_DBG("Invalid latency: %u", param->latency); + return -EINVAL; + } + cig = get_free_cig(); if (!cig) { @@ -1352,11 +1438,24 @@ static int big_init_bis(struct bt_iso_big *big, bool broadcaster) return -EALREADY; } - if (!bis->qos || (!bis->qos->tx && broadcaster)) { - BT_DBG("BIS QOS was invalid"); + CHECKIF(bis->qos == NULL) { + BT_DBG("BIS QOS is NULL"); return -EINVAL; } + if (broadcaster) { + CHECKIF(bis->qos->tx == NULL || + valid_chan_io_qos(bis->qos->tx, true)) { + BT_DBG("Invalid BIS QOS"); + return -EINVAL; + } + } else { + CHECKIF(bis->qos->rx == NULL) { + BT_DBG("Invalid BIS QOS"); + return -EINVAL; + } + } + bis->conn = iso_new(); if (!bis->conn) { @@ -1446,12 +1545,43 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param } for (int i = 0; i < param->num_bis; i++) { - if (param->bis_channels[i] == NULL) { + CHECKIF(param->bis_channels[i] == NULL) { BT_DBG("NULL channel in bis_channels[%d]", i); return -EINVAL; } } + CHECKIF(param->framing != BT_ISO_FRAMING_UNFRAMED && + param->framing != BT_ISO_FRAMING_FRAMED) { + BT_DBG("Invalid framing parameter: %u", param->framing); + return -EINVAL; + } + + CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL && + param->packing != BT_ISO_PACKING_INTERLEAVED) { + BT_DBG("Invalid framing parameter: %u", param->framing); + return -EINVAL; + } + + CHECKIF(param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { + BT_DBG("num_bis (%u) shall be lower than: %u", param->num_bis, + MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); + return -EINVAL; + } + + CHECKIF(param->interval < BT_ISO_INTERVAL_MIN || + param->interval > BT_ISO_INTERVAL_MAX) { + BT_DBG("Invalid interval: %u", param->interval); + return -EINVAL; + } + + CHECKIF(param->latency < BT_ISO_LATENCY_MIN || + param->latency > BT_ISO_LATENCY_MAX) { + BT_DBG("Invalid latency: %u", param->latency); + return -EINVAL; + } + big = get_free_big(); if (!big) { @@ -1722,7 +1852,7 @@ static int hci_le_big_create_sync(const struct bt_le_per_adv_sync *sync, struct req->sync_timeout = sys_cpu_to_le16(param->sync_timeout); req->num_bis = big->num_bis; /* Transform from bitfield to array */ - for (int i = 0; i < 0x1F; i++) { + for (int i = 0; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { if (param->bis_bitfield & BIT(i)) { if (bit_idx == big->num_bis) { BT_DBG("BIG cannot contain %u BISes", bit_idx + 1); @@ -1755,12 +1885,13 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para return -EINVAL; } - CHECKIF(param->mse > 0x1F) { + CHECKIF(param->mse > BT_ISO_SYNC_MSE_MAX) { BT_DBG("Invalid MSE 0x%02x", param->mse); return -EINVAL; } - CHECKIF(param->sync_timeout < 0x000A || param->sync_timeout > 0x4000) { + CHECKIF(param->sync_timeout < BT_ISO_SYNC_TIMEOUT_MIN || + param->sync_timeout > BT_ISO_SYNC_TIMEOUT_MAX) { BT_DBG("Invalid sync timeout 0x%04x", param->sync_timeout); return -EINVAL; }