Bluetooth: controller: LE Enhanced Connection Complete

Implement the LE Enhanced Connection Complete HCI event, but include it
only when controller-based privacy is enabled, since it is only relevant
with it.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2017-08-03 12:52:35 +02:00 committed by Johan Hedberg
commit b2a76be25b
5 changed files with 129 additions and 29 deletions

View file

@ -1820,31 +1820,73 @@ static void le_scan_req_received(struct pdu_data *pdu_data, u8_t *b,
static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle, static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle,
struct net_buf *buf) struct net_buf *buf)
{ {
struct bt_hci_evt_le_conn_complete *sep; struct bt_hci_evt_le_conn_complete *lecc;
struct radio_le_conn_cmplt *radio_cc; struct radio_le_conn_cmplt *radio_cc;
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_BLUETOOTH_CONTROLLER_PRIVACY)
!(le_event_mask & BT_EVT_MASK_LE_ENH_CONN_COMPLETE))) {
#else
1)) {
#endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
return; return;
} }
radio_cc = (struct radio_le_conn_cmplt *) (pdu_data->payload.lldata); radio_cc = (struct radio_le_conn_cmplt *) (pdu_data->payload.lldata);
sep = meta_evt(buf, BT_HCI_EVT_LE_CONN_COMPLETE, sizeof(*sep));
sep->status = radio_cc->status;
sep->handle = sys_cpu_to_le16(handle);
sep->role = radio_cc->role;
sep->peer_addr.type = radio_cc->peer_addr_type;
memcpy(&sep->peer_addr.a.val[0], &radio_cc->peer_addr[0], BDADDR_SIZE);
sep->interval = sys_cpu_to_le16(radio_cc->interval);
sep->latency = sys_cpu_to_le16(radio_cc->latency);
sep->supv_timeout = sys_cpu_to_le16(radio_cc->timeout);
sep->clock_accuracy = radio_cc->mca;
if (!radio_cc->status) { if (!radio_cc->status) {
conn_count++; conn_count++;
} }
#if defined(CONFIG_BLUETOOTH_CONTROLLER_PRIVACY)
if (le_event_mask & BT_EVT_MASK_LE_ENH_CONN_COMPLETE) {
struct bt_hci_evt_le_enh_conn_complete *leecc;
leecc = meta_evt(buf, BT_HCI_EVT_LE_ENH_CONN_COMPLETE,
sizeof(*leecc));
leecc->status = radio_cc->status;
leecc->handle = sys_cpu_to_le16(handle);
leecc->role = radio_cc->role;
leecc->peer_addr.type = radio_cc->peer_addr_type;
memcpy(&leecc->peer_addr.a.val[0], &radio_cc->peer_addr[0],
BDADDR_SIZE);
/* Note: this could be an RPA set as the random address by
* the Host instead of generated by the controller. That said,
* this should make no difference. */
if ((radio_cc->own_addr_type) &&
((radio_cc->own_addr[5] & 0xc0) == 0x40)) {
memcpy(&leecc->local_rpa.val[0], &radio_cc->own_addr[0],
BDADDR_SIZE);
} else {
memset(&leecc->local_rpa.val[0], 0x0, BDADDR_SIZE);
}
memcpy(&leecc->peer_rpa.val[0], &radio_cc->peer_rpa[0],
BDADDR_SIZE);
leecc->interval = sys_cpu_to_le16(radio_cc->interval);
leecc->latency = sys_cpu_to_le16(radio_cc->latency);
leecc->supv_timeout = sys_cpu_to_le16(radio_cc->timeout);
leecc->clock_accuracy = radio_cc->mca;
return;
}
#endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
lecc = meta_evt(buf, BT_HCI_EVT_LE_CONN_COMPLETE, sizeof(*lecc));
lecc->status = radio_cc->status;
lecc->handle = sys_cpu_to_le16(handle);
lecc->role = radio_cc->role;
lecc->peer_addr.type = radio_cc->peer_addr_type;
memcpy(&lecc->peer_addr.a.val[0], &radio_cc->peer_addr[0], BDADDR_SIZE);
lecc->interval = sys_cpu_to_le16(radio_cc->interval);
lecc->latency = sys_cpu_to_le16(radio_cc->latency);
lecc->supv_timeout = sys_cpu_to_le16(radio_cc->timeout);
lecc->clock_accuracy = radio_cc->mca;
} }
static void disconn_complete(struct pdu_data *pdu_data, u16_t handle, static void disconn_complete(struct pdu_data *pdu_data, u16_t handle,

View file

@ -810,7 +810,8 @@ static inline u32_t isr_rx_adv(u8_t devmatch_ok, u8_t devmatch_id,
FILTER_IDX_NONE; FILTER_IDX_NONE;
#else #else
u8_t rl_idx = FILTER_IDX_NONE; u8_t rl_idx = FILTER_IDX_NONE;
#endif #endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
pdu_adv = (struct pdu_adv *)radio_pkt_scratch_get(); pdu_adv = (struct pdu_adv *)radio_pkt_scratch_get();
_pdu_adv = (struct pdu_adv *)&_radio.advertiser.adv_data.data _pdu_adv = (struct pdu_adv *)&_radio.advertiser.adv_data.data
[_radio.advertiser.adv_data.first][0]; [_radio.advertiser.adv_data.first][0];
@ -924,14 +925,35 @@ static inline u32_t isr_rx_adv(u8_t devmatch_ok, u8_t devmatch_id,
(struct radio_le_conn_cmplt *)&pdu_data->payload; (struct radio_le_conn_cmplt *)&pdu_data->payload;
radio_le_conn_cmplt->status = 0x00; radio_le_conn_cmplt->status = 0x00;
radio_le_conn_cmplt->role = 0x01; radio_le_conn_cmplt->role = 0x01;
radio_le_conn_cmplt->peer_addr_type = pdu_adv->tx_addr; #if defined(CONFIG_BLUETOOTH_CONTROLLER_PRIVACY)
memcpy(&radio_le_conn_cmplt->peer_addr[0],
&pdu_adv->payload.connect_ind.init_addr[0],
BDADDR_SIZE);
radio_le_conn_cmplt->own_addr_type = pdu_adv->rx_addr; radio_le_conn_cmplt->own_addr_type = pdu_adv->rx_addr;
memcpy(&radio_le_conn_cmplt->own_addr[0], memcpy(&radio_le_conn_cmplt->own_addr[0],
&pdu_adv->payload.connect_ind.adv_addr[0], BDADDR_SIZE); &pdu_adv->payload.connect_ind.adv_addr[0], BDADDR_SIZE);
radio_le_conn_cmplt->peer_irk_index = irkmatch_id; if (rl_idx != FILTER_IDX_NONE) {
/* TODO: store rl_idx instead if safe */
/* Store identity address */
ctrl_id_addr_get(rl_idx,
&radio_le_conn_cmplt->peer_addr_type,
&radio_le_conn_cmplt->peer_addr[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
radio_le_conn_cmplt->peer_addr_type += 2;
/* Store peer RPA */
memcpy(&radio_le_conn_cmplt->peer_rpa[0],
&pdu_adv->payload.connect_ind.init_addr[0],
BDADDR_SIZE);
} else {
memset(&radio_le_conn_cmplt->peer_rpa[0], 0x0,
BDADDR_SIZE);
#else
if (1) {
#endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
radio_le_conn_cmplt->peer_addr_type = pdu_adv->tx_addr;
memcpy(&radio_le_conn_cmplt->peer_addr[0],
&pdu_adv->payload.connect_ind.init_addr[0],
BDADDR_SIZE);
}
radio_le_conn_cmplt->interval = radio_le_conn_cmplt->interval =
pdu_adv->payload.connect_ind.lldata.interval; pdu_adv->payload.connect_ind.lldata.interval;
radio_le_conn_cmplt->latency = radio_le_conn_cmplt->latency =
@ -1171,7 +1193,8 @@ static inline bool isr_scan_init_check(struct pdu_adv *pdu, u8_t rl_idx)
} }
static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id, static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
u8_t irkmatch_id, u8_t rl_idx, u8_t rssi_ready) u8_t irkmatch_ok, u8_t irkmatch_id, u8_t rl_idx,
u8_t rssi_ready)
{ {
struct pdu_adv *pdu_adv_rx; struct pdu_adv *pdu_adv_rx;
@ -1317,15 +1340,38 @@ static inline u32_t isr_rx_scan(u8_t devmatch_ok, u8_t devmatch_id,
(struct radio_le_conn_cmplt *)&pdu_data->payload; (struct radio_le_conn_cmplt *)&pdu_data->payload;
radio_le_conn_cmplt->status = 0x00; radio_le_conn_cmplt->status = 0x00;
radio_le_conn_cmplt->role = 0x00; radio_le_conn_cmplt->role = 0x00;
radio_le_conn_cmplt->peer_addr_type = pdu_adv_tx->rx_addr; #if defined(CONFIG_BLUETOOTH_CONTROLLER_PRIVACY)
memcpy(&radio_le_conn_cmplt->peer_addr[0],
&pdu_adv_tx->payload.connect_ind.adv_addr[0],
BDADDR_SIZE);
radio_le_conn_cmplt->own_addr_type = pdu_adv_tx->tx_addr; radio_le_conn_cmplt->own_addr_type = pdu_adv_tx->tx_addr;
memcpy(&radio_le_conn_cmplt->own_addr[0], memcpy(&radio_le_conn_cmplt->own_addr[0],
&pdu_adv_tx->payload.connect_ind.init_addr[0], &pdu_adv_tx->payload.connect_ind.init_addr[0],
BDADDR_SIZE); BDADDR_SIZE);
radio_le_conn_cmplt->peer_irk_index = irkmatch_id;
if (irkmatch_ok && rl_idx != FILTER_IDX_NONE) {
/* TODO: store rl_idx instead if safe */
/* Store identity address */
ctrl_id_addr_get(rl_idx,
&radio_le_conn_cmplt->peer_addr_type,
&radio_le_conn_cmplt->peer_addr[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
radio_le_conn_cmplt->peer_addr_type += 2;
/* Store peer RPA */
memcpy(&radio_le_conn_cmplt->peer_rpa[0],
&pdu_adv_tx->payload.connect_ind.adv_addr[0],
BDADDR_SIZE);
} else {
memset(&radio_le_conn_cmplt->peer_rpa[0], 0x0,
BDADDR_SIZE);
#else
if (1) {
#endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
radio_le_conn_cmplt->peer_addr_type =
pdu_adv_tx->rx_addr;
memcpy(&radio_le_conn_cmplt->peer_addr[0],
&pdu_adv_tx->payload.connect_ind.adv_addr[0],
BDADDR_SIZE);
}
radio_le_conn_cmplt->interval = _radio.scanner.conn_interval; radio_le_conn_cmplt->interval = _radio.scanner.conn_interval;
radio_le_conn_cmplt->latency = _radio.scanner. conn_latency; radio_le_conn_cmplt->latency = _radio.scanner. conn_latency;
radio_le_conn_cmplt->timeout = _radio.scanner.conn_timeout; radio_le_conn_cmplt->timeout = _radio.scanner.conn_timeout;
@ -3104,8 +3150,8 @@ static inline void isr_radio_state_rx(u8_t trx_done, u8_t crc_ok,
#endif #endif
if (crc_ok && if (crc_ok &&
isr_rx_scan_check(irkmatch_ok, devmatch_ok, rl_idx)) { isr_rx_scan_check(irkmatch_ok, devmatch_ok, rl_idx)) {
err = isr_rx_scan(devmatch_ok, devmatch_id, irkmatch_id, err = isr_rx_scan(devmatch_ok, devmatch_id, irkmatch_ok,
rl_idx, rssi_ready); irkmatch_id, rl_idx, rssi_ready);
} else { } else {
err = 1; err = 1;
} }

View file

@ -271,9 +271,11 @@ struct radio_le_conn_cmplt {
u8_t role; u8_t role;
u8_t peer_addr_type; u8_t peer_addr_type;
u8_t peer_addr[BDADDR_SIZE]; u8_t peer_addr[BDADDR_SIZE];
#if defined(CONFIG_BLUETOOTH_CONTROLLER_PRIVACY)
u8_t peer_rpa[BDADDR_SIZE];
u8_t own_addr_type; u8_t own_addr_type;
u8_t own_addr[BDADDR_SIZE]; u8_t own_addr[BDADDR_SIZE];
u8_t peer_irk_index; #endif /* CONFIG_BLUETOOTH_CONTROLLER_PRIVACY */
u16_t interval; u16_t interval;
u16_t latency; u16_t latency;
u16_t timeout; u16_t timeout;

View file

@ -447,6 +447,15 @@ bool ctrl_rl_idx_allowed(u8_t irkmatch_ok, u8_t rl_idx)
return !rl[rl_idx].pirk || rl[rl_idx].dev; return !rl[rl_idx].pirk || rl[rl_idx].dev;
} }
void ctrl_id_addr_get(u8_t rl_idx, u8_t *id_addr_type, u8_t *id_addr)
{
LL_ASSERT(rl_idx < CONFIG_BLUETOOTH_CONTROLLER_RL_SIZE);
LL_ASSERT(rl[rl_idx].taken);
*id_addr_type = rl[rl_idx].id_addr_type;
memcpy(id_addr, rl[rl_idx].id_addr.val, BDADDR_SIZE);
}
bool ctrl_rl_addr_allowed(u8_t id_addr_type, u8_t *id_addr, u8_t *rl_idx) bool ctrl_rl_addr_allowed(u8_t id_addr_type, u8_t *id_addr, u8_t *rl_idx)
{ {
int i, j; int i, j;

View file

@ -23,6 +23,7 @@ bt_addr_t *ctrl_lrpa_get(u8_t rl_idx);
u8_t *ctrl_irks_get(u8_t *count); u8_t *ctrl_irks_get(u8_t *count);
u8_t ctrl_rl_idx(bool whitelist, u8_t devmatch_id); u8_t ctrl_rl_idx(bool whitelist, u8_t devmatch_id);
u8_t ctrl_rl_irk_idx(u8_t irkmatch_id); u8_t ctrl_rl_irk_idx(u8_t irkmatch_id);
void ctrl_id_addr_get(u8_t rl_idx, u8_t *id_addr_type, u8_t *id_addr);
bool ctrl_irk_whitelisted(u8_t rl_idx); bool ctrl_irk_whitelisted(u8_t rl_idx);
bool ctrl_rl_enabled(void); bool ctrl_rl_enabled(void);