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); }