From 6e8e8f782f201075d6c3094acf5c20501104e2ad Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 4 May 2026 10:28:09 +0200 Subject: [PATCH] nimble/ll: Fix BIGInfo report parsing This fixes the missing BIGInfo size check as well as the PHY value passed to the HCI BIGInfo report, which was not corresponding to the one in the LL event. Additionally, this fix addresses the framing field. In accordance with the Core Specification, unsupported PHY reports are now discarded. --- nimble/controller/src/ble_ll_sync.c | 72 ++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c index f1a709fb9e..56f4e87324 100644 --- a/nimble/controller/src/ble_ll_sync.c +++ b/nimble/controller/src/ble_ll_sync.c @@ -673,11 +673,36 @@ ble_ll_sync_send_truncated_per_adv_rpt(struct ble_ll_sync_sm *sm, uint8_t *evbuf } #if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static uint8_t +ble_ll_sync_biginfo_phy_get(const uint8_t *biginfo) +{ + uint8_t phy; + + phy = (biginfo[27] >> 5) & 0x07; + + switch (phy) { + case 0: + return BLE_PHY_1M; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + case 1: + return BLE_PHY_2M; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + case 2: + return BLE_PHY_CODED; +#endif + default: + return 0x00; + } +} + static void ble_ll_sync_parse_biginfo_to_ev(struct ble_hci_ev_le_subev_biginfo_adv_report *ev, const uint8_t *biginfo, uint8_t biginfo_len) { uint32_t fields_buf; + uint8_t framing_mode; + uint8_t framed; fields_buf = get_le32(&biginfo[0]); ev->iso_interval = (fields_buf >> 15) & 0x0FFF; @@ -693,14 +718,20 @@ ble_ll_sync_parse_biginfo_to_ev(struct ble_hci_ev_le_subev_biginfo_adv_report *e ev->max_pdu = (fields_buf >> 24) & 0xFF; fields_buf = get_le32(&biginfo[17]); - ev->sdu_interval[0] = fields_buf & 0xFF; - ev->sdu_interval[1] = (fields_buf >> 8) & 0xFF; - ev->sdu_interval[2] = (fields_buf >> 16) & 0x0F; + put_le24(ev->sdu_interval, fields_buf & 0x0FFFFF); ev->max_sdu = (fields_buf >> 20) & 0x0FFF; - ev->phy = (biginfo[27] >> 5) & 0x07; + ev->phy = ble_ll_sync_biginfo_phy_get(biginfo); - ev->framing = (biginfo[32] >> 7) & 0x01; + framed = (biginfo[32] >> 7) & 0x01; + framing_mode = (biginfo[12] >> 7) & 0x01; + if (framed && framing_mode) { + ev->framing = BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED; + } else if (framed) { + ev->framing = BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE; + } else { + ev->framing = BLE_HCI_ISO_FRAMING_UNFRAMED; + } if (biginfo_len == BLE_LL_SYNC_BIGINFO_LEN_ENC) { ev->encryption = 1; @@ -712,25 +743,42 @@ ble_ll_sync_parse_biginfo_to_ev(struct ble_hci_ev_le_subev_biginfo_adv_report *e static void ble_ll_sync_send_biginfo_adv_rpt(struct ble_ll_sync_sm *sm, const uint8_t *biginfo, uint8_t biginfo_len) { - struct ble_hci_ev_le_subev_biginfo_adv_report *ev; + struct ble_hci_ev_le_subev_biginfo_adv_report ev; struct ble_hci_ev *hci_ev; if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT)) { return; } + /* The BIGInfo length is 33 octets for an unencrypted BIG and 57 octets for an encrypted BIG. */ + if (biginfo_len != BLE_LL_SYNC_BIGINFO_LEN && + biginfo_len != BLE_LL_SYNC_BIGINFO_LEN_ENC) { + return; + } + + memset(&ev, 0, sizeof(ev)); + ble_ll_sync_parse_biginfo_to_ev(&ev, biginfo, biginfo_len); + + if (!ev.phy) { + /* Core 6.0 | Vol 6, Part B, 4.4.5.2 + * If the PHY field of the BIGInfo specifies a PHY that the Link Layer does not support or is + * reserved for future use, the Link Layer shall ignore the BIGInfo, shall not report the + * BIGInfo to the Host, and shall not enter the Synchronization state for the BIG specified + * in the BIGinfo. + */ + return; + } + hci_ev = ble_transport_alloc_evt(1); if (!hci_ev) { return; } hci_ev->opcode = BLE_HCI_EVCODE_LE_META; - hci_ev->length = sizeof(*ev); - ev = (void *) hci_ev->data; - - ev->subev_code = BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT; - ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); - ble_ll_sync_parse_biginfo_to_ev(ev, biginfo, biginfo_len); + hci_ev->length = sizeof(ev); + ev.subev_code = BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT; + ev.sync_handle = htole16(ble_ll_sync_get_handle(sm)); + memcpy(hci_ev->data, &ev, sizeof(ev)); ble_ll_hci_event_send(hci_ev); }