nimble/gap: Add support for handling extended advertising event

X-Original-Commit: 0429b5e67e1a9cdfd832463eac2ebab85870f26a
This commit is contained in:
Łukasz Rymanowski
2017-06-28 22:48:28 +02:00
parent 3a0e8f86ed
commit 460b464f2a
5 changed files with 204 additions and 33 deletions
+31 -3
View File
@@ -112,6 +112,7 @@ struct hci_conn_update;
#define BLE_GAP_EVENT_MTU 15
#define BLE_GAP_EVENT_IDENTITY_RESOLVED 16
#define BLE_GAP_EVENT_PHY_UPDATE_COMPLETE 17
#define BLE_GAP_EVENT_EXT_DISC 18
/*** Reason codes for the subscribe GAP event. */
@@ -217,6 +218,28 @@ struct ble_gap_passkey_params {
uint32_t numcmp;
};
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_desc {
/*** Common fields. */
uint8_t props;
uint8_t data_status;
uint8_t legacy_event_type;
ble_addr_t addr;
int8_t rssi;
uint8_t tx_power;
uint8_t sid;
uint8_t prim_phy;
uint8_t sec_phy;
uint8_t length_data;
uint8_t *data;
/***
* LE direct advertising report fields; direct_addr is BLE_ADDR_ANY if
* direct address fields are not present.
*/
ble_addr_t direct_addr;
};
#endif
struct ble_gap_disc_desc {
/*** Common fields. */
uint8_t event_type;
@@ -230,9 +253,6 @@ struct ble_gap_disc_desc {
* direct address fields are not present.
*/
ble_addr_t direct_addr;
#if MYNEWT_VAL(BLE_EXT_ADV)
uint8_t tx_power;
#endif
};
/**
@@ -293,6 +313,14 @@ struct ble_gap_event {
*/
struct ble_gap_disc_desc disc;
#if MYNEWT_VAL(BLE_EXT_ADV)
/**
* Represents an extended advertising report received during a discovery
* procedure. Valid for the following event types:
* o BLE_GAP_EVENT_EXT_DISC
*/
struct ble_gap_ext_disc_desc ext_disc;
#endif
/**
* Represents an attempt to update a connection's parameters. If the
* attempt was successful, the connection's descriptor reflects the
+60 -28
View File
@@ -665,8 +665,15 @@ ble_gap_master_connect_cancelled(void)
}
}
static int
ble_gap_is_extended_disc(void)
{
return ble_gap_master.disc.extended;
}
static void
ble_gap_disc_report(struct ble_gap_disc_desc *desc)
ble_gap_disc_report(void *desc)
{
struct ble_gap_master_state state;
struct ble_gap_event event;
@@ -675,8 +682,17 @@ ble_gap_disc_report(struct ble_gap_disc_desc *desc)
if (state.cb != NULL) {
memset(&event, 0, sizeof event);
event.type = BLE_GAP_EVENT_DISC;
event.disc = *desc;
if (ble_gap_is_extended_disc()) {
#if MYNEWT_VAL(BLE_EXT_ADV)
event.type = BLE_GAP_EVENT_EXT_DISC;
event.ext_disc = *((struct ble_gap_ext_disc_desc *)desc);
#else
assert(0);
#endif
} else {
event.type = BLE_GAP_EVENT_DISC;
event.disc = *((struct ble_gap_disc_desc *)desc);
}
state.cb(&event, state.cb_arg);
}
@@ -1114,6 +1130,33 @@ ble_gap_accept_slave_conn(uint8_t addr_type, uint8_t *addr)
return rc;
}
static int
ble_gap_rx_adv_report_sanity_check(uint8_t *adv_data, uint8_t adv_data_len)
{
const struct ble_hs_adv_field *flags;
int rc;
STATS_INC(ble_gap_stats, rx_adv_report);
if (ble_gap_master.op != BLE_GAP_OP_M_DISC) {
return -1;
}
/* If a limited discovery procedure is active, discard non-limited
* advertisements.
*/
if (ble_gap_master.disc.limited) {
rc = ble_hs_adv_find_field(BLE_HS_ADV_TYPE_FLAGS, adv_data,
adv_data_len, &flags);
if ((rc == 0) && (flags->length == 2) &&
!(flags->value[0] & BLE_HS_ADV_F_DISC_LTD)) {
return -1;
}
}
return 0;
}
void
ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc)
{
@@ -1121,30 +1164,24 @@ ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc)
return;
#endif
const struct ble_hs_adv_field *flags;
int rc;
STATS_INC(ble_gap_stats, rx_adv_report);
if (ble_gap_master.op != BLE_GAP_OP_M_DISC) {
if (ble_gap_rx_adv_report_sanity_check(desc->data, desc->length_data)) {
return;
}
/* If a limited discovery procedure is active, discard non-limited
* advertisements.
*/
if (ble_gap_master.disc.limited) {
rc = ble_hs_adv_find_field(BLE_HS_ADV_TYPE_FLAGS, desc->data,
desc->length_data, &flags);
if ((rc == 0) && (flags->length == 2) &&
!(flags->value[0] & BLE_HS_ADV_F_DISC_LTD)) {
return;
}
}
ble_gap_disc_report(desc);
}
#if MYNEWT_VAL(BLE_EXT_ADV)
void
ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc)
{
if (ble_gap_rx_adv_report_sanity_check(desc->data, desc->length_data)) {
return;
}
ble_gap_disc_report(desc);
}
#endif
/**
* Processes an incoming connection-complete HCI event.
*/
@@ -2207,12 +2244,6 @@ ble_gap_ext_disc_enable_tx(uint8_t enable, uint8_t filter_duplicates,
}
#endif
static int
ble_gap_is_extended_disc(void)
{
return ble_gap_master.disc.extended;
}
/**
* Cancels the discovery procedure currently in progress. A success return
* code indicates that scanning has been fully aborted; a new discovery or
@@ -2516,6 +2547,7 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms,
ble_gap_master.disc.limited = params.limited;
ble_gap_master.cb = cb;
ble_gap_master.disc.extended = 0;
ble_gap_master.cb_arg = cb_arg;
BLE_HS_LOG(INFO, "GAP procedure initiated: discovery; ");
@@ -2636,7 +2668,7 @@ ble_gap_ext_conn_create_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr,
const struct ble_gap_conn_params *phy_coded_conn_params)
{
uint8_t buf[BLE_HCI_CMD_HDR_LEN + sizeof(struct hci_ext_create_conn)];
struct hci_ext_create_conn hcc = {};
struct hci_ext_create_conn hcc = {0};
int rc;
if (peer_addr == NULL) {
+3
View File
@@ -74,6 +74,9 @@ extern STATS_SECT_DECL(ble_gap_stats) ble_gap_stats;
#define BLE_GAP_CONN_MODE_MAX 3
#define BLE_GAP_DISC_MODE_MAX 3
#if MYNEWT_VAL(BLE_EXT_ADV)
void ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc);
#endif
void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc);
int ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt);
void ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt);
+83 -2
View File
@@ -47,6 +47,7 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_lt_key_req;
static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_parm_req;
static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_dir_adv_rpt;
static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_phy_update_complete;
static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_ext_adv_rpt;
/* Statistics */
struct host_hci_stats
@@ -95,6 +96,7 @@ static const struct ble_hs_hci_evt_le_dispatch_entry
{ BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT, ble_hs_hci_evt_le_dir_adv_rpt },
{ BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE,
ble_hs_hci_evt_le_phy_update_complete },
{ BLE_HCI_LE_SUBEV_EXT_ADV_RPT, ble_hs_hci_evt_le_ext_adv_rpt },
};
#define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \
@@ -357,7 +359,7 @@ ble_hs_hci_evt_le_adv_rpt_first_pass(uint8_t *data, int len)
static int
ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len)
{
struct ble_gap_disc_desc desc;
struct ble_gap_disc_desc desc = {0};
uint8_t num_reports;
int off;
int rc;
@@ -401,7 +403,7 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len)
static int
ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len)
{
struct ble_gap_disc_desc desc;
struct ble_gap_disc_desc desc = {0};
uint8_t num_reports;
int suboff;
int off;
@@ -453,6 +455,85 @@ ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len)
return 0;
}
#if MYNEWT_VAL(BLE_EXT_ADV)
static int
ble_hs_hci_decode_legacy_type(uint16_t evt_type)
{
switch (evt_type) {
case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND:
return BLE_HCI_ADV_TYPE_ADV_IND;
case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND:
return BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD;
case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND:
return BLE_HCI_ADV_TYPE_ADV_SCAN_IND;
case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND:
return BLE_HCI_ADV_TYPE_ADV_NONCONN_IND;
case BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND:
return BLE_HCI_ADV_TYPE_ADV_SCAN_IND;
default:
return -1;
}
}
#endif
static int
ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, uint8_t *data, int len)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_desc desc = {0};
struct hci_ext_adv_report *ext_adv;
struct hci_ext_adv_report_param *params;
int num_reports;
int i;
int legacy_event_type;
if (len < sizeof(*ext_adv)) {
return BLE_HS_EBADDATA;
}
ext_adv = (struct hci_ext_adv_report *) data;
num_reports = ext_adv->num_reports;
if (num_reports < BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN ||
num_reports > BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX) {
return BLE_HS_EBADDATA;
}
if (len < (sizeof(*ext_adv) + ext_adv->num_reports * sizeof(*params))) {
return BLE_HS_ECONTROLLER;
}
params = &ext_adv->params[0];
for (i = 0; i < num_reports; i++) {
desc.props = (params->evt_type) & 0xFF;
if (desc.props & BLE_HCI_ADV_LEGACY_MASK) {
legacy_event_type = ble_hs_hci_decode_legacy_type(params->evt_type);
if (legacy_event_type < 0) {
params += 1;
continue;
}
desc.legacy_event_type = legacy_event_type;
} else {
desc.data_status = params->evt_type >> 8;
}
desc.addr.type = params->addr_type;
memcpy(desc.addr.val, params->addr, 6);
desc.length_data = params->adv_data_len;
desc.data = params->adv_data;
desc.rssi = params->rssi;
desc.tx_power = params->tx_power;
memcpy(desc.direct_addr.val, params->dir_addr, 6);
desc.direct_addr.type = params->dir_addr_type;
desc.sid = params->sid;
desc.prim_phy = params->prim_phy;
desc.sec_phy = params->sec_phy;
ble_gap_rx_ext_adv_report(&desc);
params += 1;
}
#endif
return 0;
}
static int
ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len)
{
+27
View File
@@ -215,6 +215,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)
/* Own address types */
#define BLE_HCI_ADV_OWN_ADDR_PUBLIC (0)
#define BLE_HCI_ADV_OWN_ADDR_RANDOM (1)
@@ -802,6 +806,29 @@ struct hci_ext_create_conn
uint8_t init_phy_mask;
struct hci_ext_conn_params params[3];
};
struct hci_ext_adv_report_param {
uint16_t evt_type;
uint8_t addr_type;
uint8_t addr[6];
uint8_t prim_phy;
uint8_t sec_phy;
uint8_t sid;
uint8_t tx_power;
int8_t rssi;
uint16_t per_adv_itvl;
uint8_t dir_addr_type;
uint8_t dir_addr[6];
uint8_t adv_data_len;
uint8_t adv_data[0];
} __attribute__((packed));
struct hci_ext_adv_report {
/* We support one report per event for now */
uint8_t subevt;
uint8_t num_reports;
struct hci_ext_adv_report_param params[0];
} __attribute__((packed));
#endif
/* LE connection update command (ocf=0x0013). */