Bluetooth: controller: LE Directed Advertising Report

Implement the 4.2 event LE Directed Advertising Report, used for
scanners in a privacy-enabled controller to report directed advertising
events whose TargetA cannot be resolved by the local controller.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2017-08-09 08:37:08 +02:00 committed by Johan Hedberg
commit 868aeeb126
4 changed files with 132 additions and 43 deletions

View file

@ -1607,8 +1607,8 @@ struct bt_hci_evt_le_enh_conn_complete {
#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b
struct bt_hci_evt_le_direct_adv_info {
u8_t evt_type;
bt_addr_le_t dir_addr;
bt_addr_le_t addr;
bt_addr_le_t dir_addr;
s8_t rssi;
} __packed;
struct bt_hci_evt_le_direct_adv_report {

View file

@ -1620,27 +1620,9 @@ int hci_acl_handle(struct net_buf *buf)
return 0;
}
static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
struct net_buf *buf)
{
const u8_t c_adv_type[] = { 0x00, 0x01, 0x03, 0xff, 0x04,
0xff, 0x02 };
struct bt_hci_evt_le_advertising_report *sep;
struct pdu_adv *adv = (struct pdu_adv *)pdu_data;
struct bt_hci_evt_le_advertising_info *adv_info;
u8_t data_len;
u8_t info_len;
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
u8_t rl_idx;
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */
u8_t *rssi;
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
!(le_event_mask & BT_EVT_MASK_LE_ADVERTISING_REPORT)) {
return;
}
#if CONFIG_BT_CONTROLLER_DUP_FILTER_LEN > 0
static inline bool dup_found(struct pdu_adv *adv)
{
/* check for duplicate filtering */
if (dup_count >= 0) {
int i;
@ -1653,11 +1635,11 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
if (dup_filter[i].mask & BIT(adv->type)) {
/* duplicate found */
return;
return true;
}
/* report different adv types */
dup_filter[i].mask |= BIT(adv->type);
goto fill_report;
return false;
}
}
@ -1678,8 +1660,51 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
dup_curr = 0;
}
}
fill_report:
#endif
return false;
}
#endif /* CONFIG_BT_CONTROLLER_DUP_FILTER_LEN > 0 */
static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
struct net_buf *buf)
{
const u8_t c_adv_type[] = { 0x00, 0x01, 0x03, 0xff, 0x04,
0xff, 0x02 };
struct bt_hci_evt_le_advertising_report *sep;
struct pdu_adv *adv = (struct pdu_adv *)pdu_data;
struct bt_hci_evt_le_advertising_info *adv_info;
u8_t data_len;
u8_t info_len;
u8_t rssi;
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
u8_t rl_idx, direct;
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */
u8_t *prssi;
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT)) {
return;
}
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
direct = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len + 2];
if ((!direct && !(le_event_mask & BT_EVT_MASK_LE_ADVERTISING_REPORT)) ||
(direct && !(le_event_mask & BT_HCI_EVT_LE_DIRECT_ADV_REPORT))) {
return;
}
#else
if (!(le_event_mask & BT_EVT_MASK_LE_ADVERTISING_REPORT)) {
return;
}
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */
#if CONFIG_BT_CONTROLLER_DUP_FILTER_LEN > 0
if (dup_found(adv)) {
return;
}
#endif /* CONFIG_BT_CONTROLLER_DUP_FILTER_LEN > 0 */
if (adv->type != PDU_ADV_TYPE_DIRECT_IND) {
data_len = (adv->len - BDADDR_SIZE);
@ -1687,8 +1712,51 @@ fill_report:
data_len = 0;
}
rssi = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len];
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
rl_idx = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len + 1];
if (direct) {
struct bt_hci_evt_le_direct_adv_report *drp;
struct bt_hci_evt_le_direct_adv_info *dir_info;
LL_ASSERT(adv->type == PDU_ADV_TYPE_DIRECT_IND);
drp = meta_evt(buf, BT_HCI_EVT_LE_DIRECT_ADV_REPORT,
sizeof(*drp) + sizeof(*dir_info));
drp->num_reports = 1;
dir_info = (void *)(((u8_t *)drp) + sizeof(*drp));
dir_info->evt_type = c_adv_type[PDU_ADV_TYPE_DIRECT_IND];
if (rl_idx < ll_rl_size_get()) {
/* Store identity address */
ll_rl_id_addr_get(rl_idx, &dir_info->addr.type,
&dir_info->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
dir_info->addr.type += 2;
} else {
dir_info->addr.type = adv->tx_addr;
memcpy(&dir_info->addr.a.val[0],
&adv->payload.direct_ind.adv_addr[0],
sizeof(bt_addr_t));
}
dir_info->dir_addr.type = 0x1;
memcpy(&dir_info->dir_addr.a.val[0],
&adv->payload.direct_ind.tgt_addr[0], sizeof(bt_addr_t));
dir_info->rssi = rssi;
return;
}
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */
info_len = sizeof(struct bt_hci_evt_le_advertising_info) + data_len +
sizeof(*rssi);
sizeof(*prssi);
sep = meta_evt(buf, BT_HCI_EVT_LE_ADVERTISING_REPORT,
sizeof(*sep) + info_len);
@ -1698,8 +1766,6 @@ fill_report:
adv_info->evt_type = c_adv_type[adv->type];
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
rl_idx = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len + 1];
if (rl_idx < ll_rl_size_get()) {
/* Store identity address */
ll_rl_id_addr_get(rl_idx, &adv_info->addr.type,
@ -1719,10 +1785,8 @@ fill_report:
adv_info->length = data_len;
memcpy(&adv_info->data[0], &adv->payload.adv_ind.data[0], data_len);
/* RSSI */
rssi = &adv_info->data[0] + data_len;
*rssi = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len];
prssi = &adv_info->data[0] + data_len;
*prssi = rssi;
}
#if defined(CONFIG_BT_CONTROLLER_ADV_EXT)

View file

@ -1104,7 +1104,7 @@ static inline u32_t isr_rx_adv(u8_t devmatch_ok, u8_t devmatch_id,
return 1;
}
static u32_t isr_rx_scan_report(u8_t rssi_ready, u8_t rl_idx)
static u32_t isr_rx_scan_report(u8_t rssi_ready, u8_t rl_idx, bool dir_report)
{
struct radio_pdu_node_rx *radio_pdu_node_rx;
struct pdu_adv *pdu_adv_rx;
@ -1149,6 +1149,9 @@ static u32_t isr_rx_scan_report(u8_t rssi_ready, u8_t rl_idx)
/* save the resolving list index */
((u8_t *)pdu_adv_rx)[offsetof(struct pdu_adv, payload) +
pdu_adv_rx->len + 1] = rl_idx;
/* save the directed adv report flag */
((u8_t *)pdu_adv_rx)[offsetof(struct pdu_adv, payload) +
pdu_adv_rx->len + 2] = dir_report ? 1 : 0;
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */
packet_rx_enqueue();
@ -1193,8 +1196,25 @@ static inline bool isr_scan_init_adva_check(struct pdu_adv *pdu,
&pdu->payload.adv_ind.addr[0], BDADDR_SIZE) == 0));
}
static inline bool isr_scan_tgta_rpa_check(struct pdu_adv *pdu,
bool *dir_report)
{
if (((_radio.scanner.filter_policy & 0x02) != 0) &&
(pdu->rx_addr != 0) &&
((pdu->payload.direct_ind.tgt_addr[5] & 0xc0) == 0x40)) {
if (dir_report) {
*dir_report = true;
}
return true;
}
return false;
}
static inline bool isr_scan_tgta_check(bool init, struct pdu_adv *pdu,
u8_t rl_idx)
u8_t rl_idx, bool *dir_report)
{
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
if (ctrl_rl_addr_resolve(pdu->rx_addr,
@ -1215,9 +1235,7 @@ static inline bool isr_scan_tgta_check(bool init, struct pdu_adv *pdu,
/* allow directed adv packets where TargetA address
* is resolvable private address (scanner only)
*/
(((_radio.scanner.filter_policy & 0x02) != 0) &&
(pdu->rx_addr != 0) &&
((pdu->payload.direct_ind.tgt_addr[5] & 0xc0) == 0x40));
isr_scan_tgta_rpa_check(pdu, dir_report);
}
static inline bool isr_scan_init_check(struct pdu_adv *pdu, u8_t rl_idx)
@ -1227,7 +1245,7 @@ static inline bool isr_scan_init_check(struct pdu_adv *pdu, u8_t rl_idx)
((pdu->type == PDU_ADV_TYPE_ADV_IND) ||
((pdu->type == PDU_ADV_TYPE_DIRECT_IND) &&
(/* allow directed adv packets addressed to this device */
isr_scan_tgta_check(true, pdu, rl_idx)))));
isr_scan_tgta_check(true, pdu, rl_idx, NULL)))));
}
static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
@ -1235,6 +1253,8 @@ static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
u8_t rssi_ready)
{
struct pdu_adv *pdu_adv_rx;
/* Directed Adverising Report */
bool dir_report = false;
pdu_adv_rx = (struct pdu_adv *)
_radio.packet_rx[_radio.packet_rx_last]->pdu_data;
@ -1521,7 +1541,8 @@ static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
/* save the adv packet */
err = isr_rx_scan_report(rssi_ready,
irkmatch_ok ? rl_idx :
FILTER_IDX_NONE);
FILTER_IDX_NONE,
false);
if (err) {
return err;
}
@ -1563,7 +1584,8 @@ static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
else if (((pdu_adv_rx->type == PDU_ADV_TYPE_ADV_IND) ||
((pdu_adv_rx->type == PDU_ADV_TYPE_DIRECT_IND) &&
(/* allow directed adv packets addressed to this device */
isr_scan_tgta_check(false, pdu_adv_rx, rl_idx))) ||
isr_scan_tgta_check(false, pdu_adv_rx, rl_idx,
&dir_report))) ||
(pdu_adv_rx->type == PDU_ADV_TYPE_NONCONN_IND) ||
(pdu_adv_rx->type == PDU_ADV_TYPE_SCAN_IND) ||
#if defined(CONFIG_BT_CONTROLLER_ADV_EXT)
@ -1579,7 +1601,8 @@ static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
/* save the scan response packet */
err = isr_rx_scan_report(rssi_ready,
irkmatch_ok ? rl_idx :
FILTER_IDX_NONE);
FILTER_IDX_NONE,
dir_report);
if (err) {
return err;
}

View file

@ -273,9 +273,11 @@ struct pdu_data_q_tx {
struct radio_pdu_node_tx *node_tx;
};
/* Extra bytes for enqueued rx_node metadata: rssi and resolving index */
/* Extra bytes for enqueued rx_node metadata: rssi (always) and resolving
* index and directed adv report (with privacy enabled).
*/
#if defined(CONFIG_BT_CONTROLLER_PRIVACY)
#define PDU_AC_SIZE_EXTRA 2
#define PDU_AC_SIZE_EXTRA 3
#else
#define PDU_AC_SIZE_EXTRA 1
#endif /* CONFIG_BT_CONTROLLER_PRIVACY */