nimble/ll: Fix extended advertising reports HCI events

Since single extended advertising PDU can fit more data than single HCI
event, it is possible that received data do not fit into single event
and we dropped entire PDU in this case.

To handle this properly we need to fragment received data into multiple
HCI events. New code will fragment data automatically depending on max
event size configured and adjust data status flags accordingly.

Also, data status flag was set incorrectly and this is also fixed now.

X-Original-Commit: a1000b8d60912e89d186719904b85e9e49585407
This commit is contained in:
Andrzej Kaczmarek
2018-02-07 11:05:18 +01:00
parent 5810f86a1a
commit 2823507047
3 changed files with 79 additions and 54 deletions
@@ -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);
+74 -50
View File
@@ -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
/**
+4 -3
View File
@@ -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)