Bluetooth: controller: Fix Read Peer RPA Command

There are 2 possible interpretations regarding the address to return in
response to the Read Peer RPA HCI Command:

1) The RPA that the local controller generates to be used in certain
packets it sends
2) The RPA generated and used by the peer device in its packets

We used to return 1) but our interpretation turned out to be incorrect
when reading the HCI test specification, so this commit switches to
returning 2).

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2017-08-22 14:01:54 +02:00
commit 94bab6ca8c
3 changed files with 43 additions and 11 deletions

View file

@ -1202,7 +1202,7 @@ static void le_read_peer_rpa(struct net_buf *buf, struct net_buf **evt)
bt_addr_le_copy(&peer_id_addr, &cmd->peer_id_addr); bt_addr_le_copy(&peer_id_addr, &cmd->peer_id_addr);
rp = cmd_complete(evt, sizeof(*rp)); rp = cmd_complete(evt, sizeof(*rp));
rp->status = ll_rl_prpa_get(&peer_id_addr, &rp->peer_rpa); rp->status = ll_rl_crpa_get(&peer_id_addr, &rp->peer_rpa);
} }
static void le_read_local_rpa(struct net_buf *buf, struct net_buf **evt) static void le_read_local_rpa(struct net_buf *buf, struct net_buf **evt)
@ -1686,6 +1686,16 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
s8_t *prssi; s8_t *prssi;
#if defined(CONFIG_BT_CTLR_PRIVACY)
rl_idx = b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len + 1];
/* Update current RPA */
if (adv->tx_addr) {
ll_rl_crpa_set(0x00, NULL, rl_idx,
&adv->payload.adv_ind.addr[0]);
}
#endif
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT)) { if (!(event_mask & BT_EVT_MASK_LE_META_EVENT)) {
return; return;
} }
@ -1735,8 +1745,6 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
dir_info->evt_type = c_adv_type[PDU_ADV_TYPE_DIRECT_IND]; dir_info->evt_type = c_adv_type[PDU_ADV_TYPE_DIRECT_IND];
#if defined(CONFIG_BT_CTLR_PRIVACY) #if defined(CONFIG_BT_CTLR_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()) { if (rl_idx < ll_rl_size_get()) {
/* Store identity address */ /* Store identity address */
ll_rl_id_addr_get(rl_idx, &dir_info->addr.type, ll_rl_id_addr_get(rl_idx, &dir_info->addr.type,
@ -1917,6 +1925,13 @@ static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle,
struct bt_hci_evt_le_conn_complete *lecc; struct bt_hci_evt_le_conn_complete *lecc;
struct radio_le_conn_cmplt *radio_cc; struct radio_le_conn_cmplt *radio_cc;
radio_cc = (struct radio_le_conn_cmplt *) (pdu_data->payload.lldata);
#if defined(CONFIG_BT_CTLR_PRIVACY)
/* Update current RPA */
ll_rl_crpa_set(radio_cc->peer_addr_type, &radio_cc->peer_addr[0],
0xff, &radio_cc->peer_rpa[0]);
#endif
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
(!(le_event_mask & BT_EVT_MASK_LE_CONN_COMPLETE) && (!(le_event_mask & BT_EVT_MASK_LE_CONN_COMPLETE) &&
#if defined(CONFIG_BT_CTLR_PRIVACY) #if defined(CONFIG_BT_CTLR_PRIVACY)
@ -1927,8 +1942,6 @@ static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle,
return; return;
} }
radio_cc = (struct radio_le_conn_cmplt *) (pdu_data->payload.lldata);
if (!radio_cc->status) { if (!radio_cc->status) {
conn_count++; conn_count++;
} }

View file

@ -46,7 +46,8 @@ u32_t ll_rl_clear(void);
u32_t ll_rl_add(bt_addr_le_t *id_addr, const u8_t pirk[16], u32_t ll_rl_add(bt_addr_le_t *id_addr, const u8_t pirk[16],
const u8_t lirk[16]); const u8_t lirk[16]);
u32_t ll_rl_remove(bt_addr_le_t *id_addr); u32_t ll_rl_remove(bt_addr_le_t *id_addr);
u32_t ll_rl_prpa_get(bt_addr_le_t *id_addr, bt_addr_t *prpa); void ll_rl_crpa_set(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx, u8_t *crpa);
u32_t ll_rl_crpa_get(bt_addr_le_t *id_addr, bt_addr_t *crpa);
u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa); u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa);
u32_t ll_rl_enable(u8_t enable); u32_t ll_rl_enable(u8_t enable);
void ll_rl_timeout_set(u16_t timeout); void ll_rl_timeout_set(u16_t timeout);

View file

@ -56,6 +56,7 @@ static struct rl_dev {
u8_t local_irk[16]; u8_t local_irk[16];
u8_t pirk_idx; u8_t pirk_idx;
bt_addr_t curr_rpa;
bt_addr_t peer_rpa; bt_addr_t peer_rpa;
bt_addr_t *local_rpa; bt_addr_t *local_rpa;
@ -751,6 +752,7 @@ u32_t ll_rl_add(bt_addr_le_t *id_addr, const u8_t pirk[16],
memcpy(rl[i].local_irk, lirk, 16); memcpy(rl[i].local_irk, lirk, 16);
rl[i].local_rpa = NULL; rl[i].local_rpa = NULL;
} }
memset(rl[i].curr_rpa.val, 0x00, sizeof(rl[i].curr_rpa));
rl[i].rpas_ready = 0; rl[i].rpas_ready = 0;
/* Default to Network Privacy */ /* Default to Network Privacy */
rl[i].dev = 0; rl[i].dev = 0;
@ -813,19 +815,35 @@ u32_t ll_rl_remove(bt_addr_le_t *id_addr)
return BT_HCI_ERR_UNKNOWN_CONN_ID; return BT_HCI_ERR_UNKNOWN_CONN_ID;
} }
u32_t ll_rl_prpa_get(bt_addr_le_t *id_addr, bt_addr_t *prpa) void ll_rl_crpa_set(u8_t id_addr_type, u8_t *id_addr, u8_t rl_idx, u8_t *crpa)
{
if ((crpa[5] & 0xc0) == 0x40) {
if (id_addr) {
/* find the device and return its RPA */
rl_idx = ll_rl_find(id_addr_type, id_addr, NULL);
}
if (rl_idx < ARRAY_SIZE(rl) && rl[rl_idx].taken) {
memcpy(rl[rl_idx].curr_rpa.val, crpa,
sizeof(bt_addr_t));
}
}
}
u32_t ll_rl_crpa_get(bt_addr_le_t *id_addr, bt_addr_t *crpa)
{ {
u8_t i; u8_t i;
/* find the device and return its RPA */ /* find the device and return its RPA */
i = ll_rl_find(id_addr->type, id_addr->a.val, NULL); i = ll_rl_find(id_addr->type, id_addr->a.val, NULL);
if (i < ARRAY_SIZE(rl)) { if (i < ARRAY_SIZE(rl) &&
bt_addr_copy(prpa, &rl[i].peer_rpa); mem_nz(rl[i].curr_rpa.val, sizeof(rl[i].curr_rpa.val))) {
return 0; bt_addr_copy(crpa, &rl[i].curr_rpa);
return 0;
} }
return BT_HCI_ERR_UNKNOWN_CONN_ID; return BT_HCI_ERR_UNKNOWN_CONN_ID;
} }
u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa) u32_t ll_rl_lrpa_get(bt_addr_le_t *id_addr, bt_addr_t *lrpa)