Bluetooth: controller: Fixes for BIGinfo endianness issues
The BIGinfo PDU bitsets were not accessed in a portable maner for endianness independence, and need to be handled as bit-manipulations. Add utility functions to access PDU bitset variables independent of endianness. Use macros to abstract the offsets and widths. Conversion of BIG_Handle to LE in HCI layer incorrectly use sys_cpu_to_le16, which fail because target type is 8-bit. Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
parent
2262b294dd
commit
a30795e1f6
6 changed files with 177 additions and 81 deletions
|
@ -7772,19 +7772,23 @@ no_ext_hdr:
|
|||
|
||||
sep->sync_handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||
|
||||
/* NOTE: both sep and bi struct store little-endian values,
|
||||
* explicit endian-ness conversion not required.
|
||||
/* NOTE: both sep and bi struct store little-endian values.
|
||||
* Multi-byte variables extracted using
|
||||
* PDU_BIG_INFO_ISO_*_GET macros, which return
|
||||
* value in host-endianness, require conversion.
|
||||
*/
|
||||
sep->num_bis = bi->num_bis;
|
||||
sep->nse = bi->nse;
|
||||
sep->iso_interval = bi->iso_interval;
|
||||
sep->bn = bi->bn;
|
||||
sep->pto = bi->pto;
|
||||
sep->irc = bi->irc;
|
||||
sep->max_pdu = bi->max_pdu;
|
||||
sys_put_le24(sys_le24_to_cpu(bi->sdu_interval),
|
||||
sep->num_bis = PDU_BIG_INFO_NUM_BIS_GET(bi);
|
||||
sep->nse = PDU_BIG_INFO_NSE_GET(bi);
|
||||
sep->iso_interval =
|
||||
sys_cpu_to_le16(PDU_BIG_INFO_ISO_INTERVAL_GET(bi));
|
||||
sep->bn = PDU_BIG_INFO_BN_GET(bi);
|
||||
sep->pto = PDU_BIG_INFO_PTO_GET(bi);
|
||||
sep->irc = PDU_BIG_INFO_IRC_GET(bi);
|
||||
|
||||
sep->max_pdu = sys_cpu_to_le16(bi->max_pdu);
|
||||
sys_put_le24(PDU_BIG_INFO_SDU_INTERVAL_GET(bi),
|
||||
sep->sdu_interval);
|
||||
sep->max_sdu = bi->max_sdu;
|
||||
sep->max_sdu = sys_cpu_to_le16(PDU_BIG_INFO_MAX_SDU_GET(bi));
|
||||
sep->phy = HCI_AUX_PHY_TO_HCI_PHY(bi->chm_phy[4] >> 5);
|
||||
sep->framing = (bi->payload_count_framing[4] >> 7) & 0x01;
|
||||
if (bi_size == (PDU_BIG_INFO_ENCRYPTED_SIZE + 1)) {
|
||||
|
@ -7833,7 +7837,7 @@ static void le_big_sync_established(struct pdu_data *pdu,
|
|||
evt_size = sizeof(*sep) + (lll->num_bis * sizeof(uint16_t));
|
||||
|
||||
sep = meta_evt(buf, BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED, evt_size);
|
||||
sep->big_handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||
sep->big_handle = (uint8_t)node_rx->hdr.handle;
|
||||
|
||||
/* Check for pdu field being aligned before accessing ISO sync
|
||||
* established event.
|
||||
|
@ -7879,7 +7883,7 @@ static void le_big_sync_lost(struct pdu_data *pdu,
|
|||
}
|
||||
|
||||
sep = meta_evt(buf, BT_HCI_EVT_LE_BIG_SYNC_LOST, sizeof(*sep));
|
||||
sep->big_handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||
sep->big_handle = (uint8_t)node_rx->hdr.handle;
|
||||
sep->reason = *((uint8_t *)pdu);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
|
||||
|
@ -7927,7 +7931,7 @@ static void le_big_complete(struct pdu_data *pdu_data,
|
|||
sep = meta_evt(buf, BT_HCI_EVT_LE_BIG_COMPLETE, evt_size);
|
||||
|
||||
sep->status = BT_HCI_ERR_SUCCESS;
|
||||
sep->big_handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||
sep->big_handle = (uint8_t)node_rx->hdr.handle;
|
||||
|
||||
if (sep->status) {
|
||||
return;
|
||||
|
@ -7966,7 +7970,7 @@ static void le_big_terminate(struct pdu_data *pdu,
|
|||
}
|
||||
|
||||
sep = meta_evt(buf, BT_HCI_EVT_LE_BIG_TERMINATE, sizeof(*sep));
|
||||
sep->big_handle = sys_cpu_to_le16(node_rx->hdr.handle);
|
||||
sep->big_handle = (uint8_t)node_rx->hdr.handle;
|
||||
sep->reason = *((uint8_t *)pdu);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO */
|
||||
|
|
|
@ -1128,49 +1128,35 @@ struct pdu_bis {
|
|||
} __packed;
|
||||
|
||||
struct pdu_big_info {
|
||||
#ifdef CONFIG_LITTLE_ENDIAN
|
||||
uint32_t offs:14;
|
||||
uint32_t offs_units:1;
|
||||
uint32_t iso_interval:12;
|
||||
uint32_t num_bis:5;
|
||||
/* offs:14 [0].0 - [1].5
|
||||
* offs_units:1 [1].6
|
||||
* iso_interval:12 [1].7 - [3].2
|
||||
* num_bis:5 [3].3 - [3].7
|
||||
*/
|
||||
uint8_t bi_packed_0_3[4];
|
||||
|
||||
uint32_t nse:5;
|
||||
uint32_t bn:3;
|
||||
uint32_t sub_interval:20;
|
||||
uint32_t pto:4;
|
||||
/* nse:5 [0].0 - [0].4
|
||||
* bn:3 [0].5 - [0].7
|
||||
* sub_interval:20 [1].0 - [3].3
|
||||
* pto:4 [3].4 - [3].7
|
||||
*/
|
||||
uint8_t bi_packed_4_7[4];
|
||||
|
||||
uint32_t spacing:20;
|
||||
uint32_t irc:4;
|
||||
uint32_t max_pdu:8;
|
||||
/* spacing:20 [0].0 - [2].3
|
||||
* irc:4 [2].4 - [2].7
|
||||
*/
|
||||
uint8_t bi_packed_8_11[3];
|
||||
|
||||
uint8_t max_pdu;
|
||||
|
||||
uint8_t rfu;
|
||||
|
||||
uint32_t seed_access_addr;
|
||||
|
||||
uint32_t sdu_interval:20;
|
||||
uint32_t max_sdu:12;
|
||||
#else
|
||||
uint32_t num_bis:5;
|
||||
uint32_t iso_interval:12;
|
||||
uint32_t offs_units:1;
|
||||
uint32_t offs:14;
|
||||
|
||||
uint32_t pto:4;
|
||||
uint32_t sub_interval:20;
|
||||
uint32_t bn:3;
|
||||
uint32_t nse:5;
|
||||
|
||||
uint32_t max_pdu:8;
|
||||
uint32_t irc:4;
|
||||
uint32_t spacing:20;
|
||||
|
||||
uint8_t rfu;
|
||||
|
||||
uint32_t seed_access_addr;
|
||||
|
||||
uint32_t max_sdu:12;
|
||||
uint32_t sdu_interval:20;
|
||||
#endif /* CONFIG_LITTLE_ENDIAN */
|
||||
/* sdu_interval:20 [0].0 - [2].3
|
||||
* max_sdu:12; [2].4 - [3].7
|
||||
*/
|
||||
uint8_t sdu_packed[4];
|
||||
|
||||
uint16_t base_crc_init;
|
||||
|
||||
|
@ -1185,6 +1171,56 @@ struct pdu_big_info {
|
|||
#define PDU_BIG_BN_MAX 0x07
|
||||
#define PDU_BIG_PAYLOAD_COUNT_MAX 28
|
||||
|
||||
#define PDU_BIG_INFO_OFFS_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_0_3[0], 0, 14)
|
||||
#define PDU_BIG_INFO_OFFS_UNITS_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_0_3[1], 6, 1)
|
||||
#define PDU_BIG_INFO_ISO_INTERVAL_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_0_3[1], 7, 12)
|
||||
#define PDU_BIG_INFO_NUM_BIS_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_0_3[3], 3, 5)
|
||||
#define PDU_BIG_INFO_NSE_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_4_7[0], 0, 5)
|
||||
#define PDU_BIG_INFO_BN_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_4_7[0], 5, 3)
|
||||
#define PDU_BIG_INFO_SUB_INTERVAL_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_4_7[1], 0, 20)
|
||||
#define PDU_BIG_INFO_PTO_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_4_7[3], 4, 4)
|
||||
#define PDU_BIG_INFO_SPACING_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_8_11[0], 0, 20)
|
||||
#define PDU_BIG_INFO_IRC_GET(bi) \
|
||||
util_get_bits(&(bi)->bi_packed_8_11[2], 4, 4)
|
||||
#define PDU_BIG_INFO_SDU_INTERVAL_GET(bi) \
|
||||
util_get_bits(&(bi)->sdu_packed[0], 0, 20)
|
||||
#define PDU_BIG_INFO_MAX_SDU_GET(bi) \
|
||||
util_get_bits(&(bi)->sdu_packed[2], 4, 12)
|
||||
|
||||
#define PDU_BIG_INFO_OFFS_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_0_3[0], 0, 14, val)
|
||||
#define PDU_BIG_INFO_OFFS_UNITS_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_0_3[1], 6, 1, val)
|
||||
#define PDU_BIG_INFO_ISO_INTERVAL_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_0_3[1], 7, 12, val)
|
||||
#define PDU_BIG_INFO_NUM_BIS_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_0_3[3], 3, 5, val)
|
||||
#define PDU_BIG_INFO_NSE_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_4_7[0], 0, 5, val)
|
||||
#define PDU_BIG_INFO_BN_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_4_7[0], 5, 3, val)
|
||||
#define PDU_BIG_INFO_SUB_INTERVAL_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_4_7[1], 0, 20, val)
|
||||
#define PDU_BIG_INFO_PTO_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_4_7[3], 4, 4, val)
|
||||
#define PDU_BIG_INFO_SPACING_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_8_11[0], 0, 20, val)
|
||||
#define PDU_BIG_INFO_IRC_SET(bi, val) \
|
||||
util_set_bits(&(bi)->bi_packed_8_11[2], 4, 4, val)
|
||||
#define PDU_BIG_INFO_SDU_INTERVAL_SET(bi, val) \
|
||||
util_set_bits(&(bi)->sdu_packed[0], 0, 20, val)
|
||||
#define PDU_BIG_INFO_MAX_SDU_SET(bi, val) \
|
||||
util_set_bits(&(bi)->sdu_packed[2], 4, 12, val)
|
||||
|
||||
struct pdu_dtm {
|
||||
#ifdef CONFIG_LITTLE_ENDIAN
|
||||
uint8_t type:4;
|
||||
|
|
|
@ -481,20 +481,21 @@ ll_big_create_rtn_retry:
|
|||
* advertising event.
|
||||
*/
|
||||
|
||||
big_info->iso_interval =
|
||||
sys_cpu_to_le16(iso_interval_us / PERIODIC_INT_UNIT_US);
|
||||
big_info->num_bis = lll_adv_iso->num_bis;
|
||||
big_info->nse = lll_adv_iso->nse;
|
||||
big_info->bn = lll_adv_iso->bn;
|
||||
big_info->sub_interval = sys_cpu_to_le24(lll_adv_iso->sub_interval);
|
||||
big_info->pto = lll_adv_iso->pto;
|
||||
big_info->spacing = sys_cpu_to_le24(lll_adv_iso->bis_spacing);
|
||||
big_info->irc = lll_adv_iso->irc;
|
||||
PDU_BIG_INFO_ISO_INTERVAL_SET(big_info, iso_interval_us / PERIODIC_INT_UNIT_US);
|
||||
PDU_BIG_INFO_NUM_BIS_SET(big_info, lll_adv_iso->num_bis);
|
||||
PDU_BIG_INFO_NSE_SET(big_info, lll_adv_iso->nse);
|
||||
PDU_BIG_INFO_BN_SET(big_info, lll_adv_iso->bn);
|
||||
PDU_BIG_INFO_SUB_INTERVAL_SET(big_info, lll_adv_iso->sub_interval);
|
||||
PDU_BIG_INFO_PTO_SET(big_info, lll_adv_iso->pto);
|
||||
PDU_BIG_INFO_SPACING_SET(big_info, lll_adv_iso->bis_spacing);
|
||||
PDU_BIG_INFO_IRC_SET(big_info, lll_adv_iso->irc);
|
||||
|
||||
big_info->max_pdu = lll_adv_iso->max_pdu;
|
||||
|
||||
(void)memcpy(&big_info->seed_access_addr, lll_adv_iso->seed_access_addr,
|
||||
sizeof(big_info->seed_access_addr));
|
||||
big_info->sdu_interval = sys_cpu_to_le24(sdu_interval);
|
||||
big_info->max_sdu = max_sdu;
|
||||
PDU_BIG_INFO_SDU_INTERVAL_SET(big_info, sdu_interval);
|
||||
PDU_BIG_INFO_MAX_SDU_SET(big_info, max_sdu);
|
||||
(void)memcpy(&big_info->base_crc_init, lll_adv_iso->base_crc_init,
|
||||
sizeof(big_info->base_crc_init));
|
||||
pdu_big_info_chan_map_phy_set(big_info->chm_phy,
|
||||
|
@ -1377,12 +1378,12 @@ static inline void big_info_offset_fill(struct pdu_big_info *bi,
|
|||
offs = HAL_TICKER_TICKS_TO_US(ticks_offset) - start_us;
|
||||
offs = offs / OFFS_UNIT_30_US;
|
||||
if (!!(offs >> OFFS_UNIT_BITS)) {
|
||||
bi->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US /
|
||||
PDU_BIG_INFO_OFFS_SET(bi, offs / (OFFS_UNIT_300_US /
|
||||
OFFS_UNIT_30_US));
|
||||
bi->offs_units = 1U;
|
||||
PDU_BIG_INFO_OFFS_UNITS_SET(bi, 1U);
|
||||
} else {
|
||||
bi->offs = sys_cpu_to_le16(offs);
|
||||
bi->offs_units = 0U;
|
||||
PDU_BIG_INFO_OFFS_SET(bi, offs);
|
||||
PDU_BIG_INFO_OFFS_UNITS_SET(bi, 0U);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -424,20 +424,20 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso,
|
|||
|
||||
lll->phy = BIT(bi->chm_phy[4] >> 5);
|
||||
|
||||
lll->num_bis = bi->num_bis;
|
||||
lll->bn = bi->bn;
|
||||
lll->nse = bi->nse;
|
||||
lll->sub_interval = sys_le24_to_cpu(bi->sub_interval);
|
||||
lll->num_bis = PDU_BIG_INFO_NUM_BIS_GET(bi);
|
||||
lll->bn = PDU_BIG_INFO_BN_GET(bi);
|
||||
lll->nse = PDU_BIG_INFO_NSE_GET(bi);
|
||||
lll->sub_interval = PDU_BIG_INFO_SUB_INTERVAL_GET(bi);
|
||||
lll->max_pdu = bi->max_pdu;
|
||||
lll->pto = bi->pto;
|
||||
lll->pto = PDU_BIG_INFO_PTO_GET(bi);
|
||||
if (lll->pto) {
|
||||
lll->ptc = lll->bn;
|
||||
} else {
|
||||
lll->ptc = 0U;
|
||||
}
|
||||
lll->bis_spacing = sys_le24_to_cpu(bi->spacing);
|
||||
lll->irc = bi->irc;
|
||||
lll->sdu_interval = sys_le24_to_cpu(bi->sdu_interval);
|
||||
lll->bis_spacing = PDU_BIG_INFO_SPACING_GET(bi);
|
||||
lll->irc = PDU_BIG_INFO_IRC_GET(bi);
|
||||
lll->sdu_interval = PDU_BIG_INFO_SDU_INTERVAL_GET(bi);
|
||||
|
||||
/* Pick the 39-bit payload count, 1 MSb is framing bit */
|
||||
lll->payload_count = (uint64_t)bi->payload_count_framing[0];
|
||||
|
@ -479,7 +479,7 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso,
|
|||
}
|
||||
}
|
||||
|
||||
lll->iso_interval = sys_le16_to_cpu(bi->iso_interval);
|
||||
lll->iso_interval = PDU_BIG_INFO_ISO_INTERVAL_GET(bi);
|
||||
interval_us = lll->iso_interval * PERIODIC_INT_UNIT_US;
|
||||
|
||||
sync_iso->timeout_reload =
|
||||
|
@ -492,7 +492,7 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso,
|
|||
lll_clock_ppm_get(sca)) *
|
||||
interval_us), USEC_PER_SEC);
|
||||
lll->window_widening_max_us = (interval_us >> 1) - EVENT_IFS_US;
|
||||
if (bi->offs_units) {
|
||||
if (PDU_BIG_INFO_OFFS_UNITS_GET(bi)) {
|
||||
lll->window_size_event_us = OFFS_UNIT_300_US;
|
||||
} else {
|
||||
lll->window_size_event_us = OFFS_UNIT_30_US;
|
||||
|
@ -505,7 +505,7 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso,
|
|||
|
||||
/* Calculate the BIG Offset in microseconds */
|
||||
sync_iso_offset_us = ftr->radio_end_us;
|
||||
sync_iso_offset_us += (uint32_t)sys_le16_to_cpu(bi->offs) *
|
||||
sync_iso_offset_us += PDU_BIG_INFO_OFFS_GET(bi) *
|
||||
lll->window_size_event_us;
|
||||
/* Skip to first selected BIS subevent */
|
||||
/* FIXME: add support for interleaved packing */
|
||||
|
@ -631,7 +631,6 @@ void ull_sync_iso_estab_done(struct node_rx_event_done *done)
|
|||
{
|
||||
struct ll_sync_iso_set *sync_iso;
|
||||
struct node_rx_sync_iso *se;
|
||||
struct lll_sync_iso *lll;
|
||||
struct node_rx_pdu *rx;
|
||||
|
||||
/* switch to normal prepare */
|
||||
|
@ -639,7 +638,6 @@ void ull_sync_iso_estab_done(struct node_rx_event_done *done)
|
|||
|
||||
/* Get reference to ULL context */
|
||||
sync_iso = CONTAINER_OF(done->param, struct ll_sync_iso_set, ull);
|
||||
lll = &sync_iso->lll;
|
||||
|
||||
/* Prepare BIG Sync Established */
|
||||
rx = (void *)sync_iso->sync->iso.node_rx_estab;
|
||||
|
|
|
@ -312,3 +312,57 @@ void util_bis_aa_le32(uint8_t bis, uint8_t *saa, uint8_t *dst)
|
|||
dst[2] ^= dwh[0];
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_SYNC_ISO*/
|
||||
|
||||
/** @brief Get a bit aligned value from a byte array
|
||||
* Converts bitsets to any size variable (<= 32 bit), which is returned
|
||||
* as a uint32_t value.
|
||||
*
|
||||
* @param data Pointer to bytes containing the requested value
|
||||
* @param bit_offs Bit offset into data[0] for value LSB
|
||||
* @param num_bits Number of bits to extract and convert to value
|
||||
*/
|
||||
uint32_t util_get_bits(uint8_t *data, uint8_t bit_offs, uint8_t num_bits)
|
||||
{
|
||||
uint32_t value;
|
||||
uint8_t shift, byteIdx, bits;
|
||||
|
||||
value = 0;
|
||||
shift = 0;
|
||||
byteIdx = 0;
|
||||
|
||||
while (num_bits) {
|
||||
bits = MIN(num_bits, 8 - bit_offs);
|
||||
value |= ((data[byteIdx] >> bit_offs) & BIT_MASK(bits)) << shift;
|
||||
shift += bits;
|
||||
num_bits -= bits;
|
||||
bit_offs = 0;
|
||||
byteIdx++;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/** @brief Set a bit aligned value in a byte array
|
||||
* Converts a value up to 32 bits to a bitset in a byte array.
|
||||
*
|
||||
* @param data Pointer to bytes in which to place the value
|
||||
* @param bit_offs Bit offset into data[0] for value LSB
|
||||
* @param num_bits Number of bits to set in data
|
||||
*/
|
||||
void util_set_bits(uint8_t *data, uint8_t bit_offs, uint8_t num_bits,
|
||||
uint32_t value)
|
||||
{
|
||||
uint8_t byteIdx, bits;
|
||||
|
||||
byteIdx = 0;
|
||||
|
||||
while (num_bits) {
|
||||
bits = MIN(num_bits, 8 - bit_offs);
|
||||
data[byteIdx] = (data[byteIdx] & ~(BIT_MASK(bits) << bit_offs)) |
|
||||
((value & BIT_MASK(bits)) << bit_offs);
|
||||
value >>= bits;
|
||||
num_bits -= bits;
|
||||
bit_offs = 0;
|
||||
byteIdx++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,3 +17,6 @@ uint8_t util_ones_count_get(const uint8_t *octets, uint8_t octets_len);
|
|||
int util_aa_le32(uint8_t *dst);
|
||||
int util_saa_le32(uint8_t *dst, uint8_t handle);
|
||||
void util_bis_aa_le32(uint8_t bis, uint8_t *saa, uint8_t *dst);
|
||||
uint32_t util_get_bits(uint8_t *data, uint8_t bit_offs, uint8_t num_bits);
|
||||
void util_set_bits(uint8_t *data, uint8_t bit_offs, uint8_t num_bits,
|
||||
uint32_t value);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue