diff --git a/nimble/controller/include/controller/ble_ll_scan.h b/nimble/controller/include/controller/ble_ll_scan.h index 95e9727a2..8a4cee537 100644 --- a/nimble/controller/include/controller/ble_ll_scan.h +++ b/nimble/controller/include/controller/ble_ll_scan.h @@ -226,7 +226,7 @@ int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, /* Called to parse extended advertising*/ struct ble_ll_ext_adv; -int ble_ll_scan_parse_ext_adv(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, +int ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, struct ble_ll_ext_adv *parsed_evt); void ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_scan); diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c index c58fe2120..5aa984b9c 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -544,7 +544,7 @@ ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static struct ble_ll_ext_adv * -ble_ll_scan_init_ext_adv(void) +ble_ll_scan_init_ext_adv(struct ble_ll_ext_adv *copy_from) { struct ble_ll_ext_adv *evt; @@ -554,20 +554,24 @@ ble_ll_scan_init_ext_adv(void) return NULL; } - memset(evt, 0, sizeof(*evt)); + if (copy_from) { + memcpy(evt, copy_from, sizeof(*evt)); + } else { + memset(evt, 0, sizeof(*evt)); - evt->event_meta = BLE_HCI_EVCODE_LE_META; - evt->subevt = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; - /* We support only one report per event now */ - evt->num_reports = 1; - /* Init TX Power with "Not available" which is 127 */ - evt->tx_power = 127; - /* Init RSSI with "Not available" which is 127 */ - evt->rssi = 127; - /* Init SID with "Not available" which is 0xFF */ - evt->sid = 0xFF; - /* Init address type with "anonymous" which is 0xFF */ - evt->addr_type = 0xFF; + evt->event_meta = BLE_HCI_EVCODE_LE_META; + evt->subevt = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; + /* We support only one report per event now */ + evt->num_reports = 1; + /* Init TX Power with "Not available" which is 127 */ + evt->tx_power = 127; + /* Init RSSI with "Not available" which is 127 */ + evt->rssi = 127; + /* Init SID with "Not available" which is 0xFF */ + evt->sid = 0xFF; + /* Init address type with "anonymous" which is 0xFF */ + evt->addr_type = 0xFF; + } return evt; } @@ -591,7 +595,7 @@ ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype, return -1; } - evt = ble_ll_scan_init_ext_adv(); + evt = ble_ll_scan_init_ext_adv(NULL); if (!evt) { return 0; } @@ -1704,11 +1708,11 @@ ble_ll_scan_get_aux_data(struct ble_ll_scan_sm *scansm, * * @return int * < 0 Error - * == 0: Success. + * >= 0: Success (number of bytes left in PDU) * */ int -ble_ll_scan_parse_ext_adv(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, +ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, struct ble_ll_ext_adv *out_evt) { uint8_t pdu_len; @@ -1796,22 +1800,6 @@ ble_ll_scan_parse_ext_adv(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, /* Skip ADAC if it is there */ i = ext_hdr_len; - /* Adjust for advertising data */ - os_mbuf_adj(om, i); - - if ((pdu_len - i - 1 > 0)) { - out_evt->adv_data_len = pdu_len - i - 1; - - /* XXX Drop packet if it does not fit into event buffer for now.*/ - if ((sizeof(*out_evt) + out_evt->adv_data_len) + 1 > - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) { - STATS_INC(ble_ll_stats, adv_evt_dropped); - return -1; - } - - os_mbuf_copydata(om, 0, out_evt->adv_data_len, out_evt->adv_data); - } - /* In the event we need information on primary and secondary PHY used during * advertising. */ @@ -1823,20 +1811,15 @@ ble_ll_scan_parse_ext_adv(struct os_mbuf *om, struct ble_mbuf_hdr *ble_hdr, out_evt->sec_phy = aux_data->aux_phy; out_evt->prim_phy = aux_data->aux_primary_phy; - /* Set event type */ - if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) { - out_evt->evt_type |= (BLE_HCI_ADV_INCOMPLETE << 8); - } else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) { - out_evt->evt_type |= (BLE_HCI_ADV_CORRUPTED << 8); - } - if (BLE_MBUF_HDR_SCAN_RSP_RCV(ble_hdr)) { out_evt->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK; } -done: + /* Adjust mbuf to contain advertising data only */ + os_mbuf_adj(om, i); - return 0; +done: + return pdu_len - i - 1; } static int @@ -2271,29 +2254,70 @@ static void ble_ll_hci_send_ext_adv_report(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hdr) { + struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; struct ble_ll_ext_adv *evt; - int rc; + struct ble_ll_ext_adv *next_evt; + int offset; + int datalen; if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { return; } - evt = ble_ll_scan_init_ext_adv(); + evt = ble_ll_scan_init_ext_adv(NULL); if (!evt) { return; } - rc = ble_ll_scan_parse_ext_adv(om, hdr, evt); - if (rc) { - + datalen = ble_ll_scan_parse_ext_hdr(om, hdr, evt); + if (datalen < 0) { ble_hci_trans_buf_free((uint8_t *)evt); return; } - evt->event_len = sizeof(struct ble_ll_ext_adv) + evt->adv_data_len; - evt->rssi = hdr->rxinfo.rssi; + offset = 0; - ble_ll_hci_event_send((uint8_t *)evt); + do { + next_evt = NULL; + + evt->adv_data_len = min(BLE_LL_MAX_EVT_LEN - sizeof(*evt), + datalen - offset); + os_mbuf_copydata(om, offset, evt->adv_data_len, evt->adv_data); + + offset += evt->adv_data_len; + + if (offset < datalen) { + /* + * We need to fragment this PDU as it does not fit in single HCI + * event. Subsequent event will have exactly the same header data. + * If we cannot allocate another HCI event from pool, just mark + * data as truncated. + */ + next_evt = ble_ll_scan_init_ext_adv(evt); + + if (next_evt) { + evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE); + } else { + evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED); + } + } else { + if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_BIT)) { + evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_INCOMPLETE); + } else if (BLE_LL_CHECK_AUX_FLAG(aux_data, BLE_LL_AUX_INCOMPLETE_ERR_BIT)) { + evt->evt_type |= (BLE_HCI_ADV_DATA_STATUS_TRUNCATED); + } + } + + evt->event_len = (sizeof(*evt) - BLE_HCI_EVENT_HDR_LEN) + + evt->adv_data_len; + evt->rssi = hdr->rxinfo.rssi; + + ble_ll_hci_event_send((uint8_t *)evt); + + evt = next_evt; + } while (evt); + + assert(offset <= datalen); } #endif /** diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 482889d7f..52a676e0c 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -241,9 +241,10 @@ extern "C" { #define BLE_HCI_ADV_SCAN_RSP_MASK (0x0008) #define BLE_HCI_ADV_LEGACY_MASK (0x0010) -#define BLE_HCI_ADV_COMPLETED (0x00) -#define BLE_HCI_ADV_INCOMPLETE (0x01) -#define BLE_HCI_ADV_CORRUPTED (0x10) +#define BLE_HCI_ADV_DATA_STATUS_COMPLETE (0x0000) +#define BLE_HCI_ADV_DATA_STATUS_INCOMPLETE (0x0020) +#define BLE_HCI_ADV_DATA_STATUS_TRUNCATED (0x0040) +#define BLE_HCI_ADV_DATA_STATUS_MASK (0x0060) /* Own address types */ #define BLE_HCI_ADV_OWN_ADDR_PUBLIC (0)