Merge pull request #375 from andrzej-kaczmarek/bt5-featexch

Nimble: improvements on controller/peer features handling

X-Original-Commit: 087e80189a8b52018ecba2d5aa81b40fcbb5fc14
This commit is contained in:
Andrzej Kaczmarek
2017-07-05 23:33:16 +02:00
committed by GitHub
19 changed files with 466 additions and 95 deletions
@@ -124,6 +124,8 @@ union ble_ll_conn_sm_flags {
uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */
uint32_t aux_conn_req: 1;
uint32_t aux_conn_rsp: 1;
uint32_t rxd_features:1;
uint32_t pending_hci_rd_features:1;
} cfbit;
uint32_t conn_flags;
} __attribute__((packed));
@@ -228,7 +230,8 @@ struct ble_ll_conn_sm
uint8_t disconnect_reason;
uint8_t rxd_disconnect_reason;
uint8_t vers_nr;
uint32_t common_features;
uint8_t conn_features;
uint8_t remote_features[7];
uint16_t pending_ctrl_procs;
uint16_t event_cntr;
uint16_t completed_pkts;
@@ -25,7 +25,7 @@ extern "C" {
#endif
/* For supported commands */
#define BLE_LL_SUPP_CMD_LEN (36)
#define BLE_LL_SUPP_CMD_LEN (40)
extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN];
/* The largest event the controller will send. */
+47 -14
View File
@@ -1596,6 +1596,22 @@ ble_ll_conn_auth_pyld_timer_cb(struct os_event *ev)
ble_ll_conn_auth_pyld_timer_start(connsm);
}
void
ble_ll_conn_rd_features_timer_cb(struct os_event *ev)
{
struct ble_ll_conn_sm *connsm;
connsm = (struct ble_ll_conn_sm *)ev->ev_arg;
if (!connsm->csmflags.cfbit.pending_hci_rd_features ||
!connsm->csmflags.cfbit.rxd_features) {
return;
}
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/**
* Start (or restart) the authenticated payload timer
*
@@ -1819,7 +1835,8 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
connsm->event_cntr = 0;
connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
connsm->disconnect_reason = 0;
connsm->common_features = 0;
connsm->conn_features = 0;
memset(connsm->remote_features, 0, sizeof(connsm->remote_features));
connsm->vers_nr = 0;
connsm->comp_id = 0;
connsm->sub_vers_nr = 0;
@@ -2010,6 +2027,16 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/* Connection state machine is now idle */
connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
/*
* If we have features and there's pending HCI command, send an event before
* disconnection event so it does make sense to host.
*/
if (connsm->csmflags.cfbit.pending_hci_rd_features &&
connsm->csmflags.cfbit.rxd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/*
* We need to send a disconnection complete event or a connection complete
* event when the connection ends. We send a connection complete event
@@ -2028,6 +2055,15 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
}
}
/*
* If there is still pending read features request HCI command, send an
* event to complete it.
*/
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNK_CONN_ID);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
/* Put connection state machine back on free list */
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
@@ -2359,19 +2395,6 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
CONN_F_CTRLR_PHY_UPDATE(connsm) = 1;
}
#endif
/*
* Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
* exceeds the minimum, data length procedure needs to occur
*/
if ((connsm->max_tx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
(connsm->max_rx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
(connsm->max_tx_time > BLE_LL_CONN_SUPP_TIME_MIN) ||
(connsm->max_rx_time > BLE_LL_CONN_SUPP_TIME_MIN)) {
/* Start the data length update procedure */
if (ble_ll_read_supp_features() & BLE_LL_FEAT_DATA_LEN_EXT) {
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
}
}
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
ble_ll_adv_send_conn_comp_ev(connsm, rxhdr);
} else {
@@ -2381,6 +2404,9 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
ble_ll_hci_ev_le_csa(connsm);
#endif
}
/* Initiate features exchange */
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
}
return rc;
@@ -2513,6 +2539,13 @@ ble_ll_conn_event_end(struct os_event *ev)
/* If we have completed packets, send an event */
ble_ll_conn_num_comp_pkts_event_send(connsm);
/* If we have features and there's pending HCI command, send an event */
if (connsm->csmflags.cfbit.pending_hci_rd_features &&
connsm->csmflags.cfbit.rxd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
}
/**
+6 -9
View File
@@ -761,15 +761,12 @@ ble_ll_conn_hci_read_rem_features(uint8_t *cmdbuf)
return BLE_ERR_UNK_CONN_ID;
}
/* See if we support this feature */
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
if ((ble_ll_read_supp_features() & BLE_LL_FEAT_SLAVE_INIT) == 0) {
return BLE_ERR_UNKNOWN_HCI_CMD;
}
/* If already pending exit with error */
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
return BLE_ERR_CMD_DISALLOWED;
}
/* Start the control procedure */
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
connsm->csmflags.cfbit.pending_hci_rd_features = 1;
return BLE_ERR_SUCCESS;
}
@@ -813,9 +810,9 @@ ble_ll_conn_hci_update(uint8_t *cmdbuf)
}
/* See if this feature is supported on both sides */
if ((connsm->common_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) {
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
return BLE_ERR_UNKNOWN_HCI_CMD;
return BLE_ERR_CMD_DISALLOWED;
}
ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE;
} else {
+1
View File
@@ -151,6 +151,7 @@ void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
int ble_ll_conn_hci_chk_conn_params(uint16_t itvl_min, uint16_t itvl_max,
uint16_t latency, uint16_t spvn_tmo);
int ble_ll_conn_hci_read_rem_features(uint8_t *cmdbuf);
int ble_ll_conn_hci_read_rem_features_complete(void);
int ble_ll_conn_hci_rd_rssi(uint8_t *cmdbuf, uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_rd_chan_map(uint8_t *cmdbuf, uint8_t *rspbuf,
uint8_t *rsplen);
+61 -10
View File
@@ -433,7 +433,11 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) {
ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
} else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm,
BLE_ERR_UNSUPP_REM_FEATURE);
}
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
}
}
@@ -1513,6 +1517,27 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
return rsp_opcode;
}
static void
ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm)
{
if (!(connsm->conn_features & BLE_LL_FEAT_DATA_LEN_EXT)) {
return;
}
/*
* Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
* exceeds the minimum, data length procedure needs to occur
*/
if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) &&
(connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) &&
(connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) &&
(connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) {
return;
}
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
}
/**
* Called when we receive a feature request or a slave initiated feature
* request.
@@ -1530,7 +1555,7 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
uint8_t *rspbuf, uint8_t opcode)
{
uint8_t rsp_opcode;
uint32_t remote_feat;
uint32_t our_feat;
/*
* Only accept slave feature requests if we are a master and feature
@@ -1547,13 +1572,29 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
}
}
remote_feat = get_le32(dptr);
our_feat = ble_ll_read_supp_features();
/* Set common features and reply */
rsp_opcode = BLE_LL_CTRL_FEATURE_RSP;
connsm->common_features = remote_feat & ble_ll_read_supp_features();
/*
* 1st octet of features should be common features of local and remote
* controller - we call this 'connection features'
* remaining octets are features of controller which sends PDU, in this case
* it's our controller
*
* See: Vol 6, Part B, section 2.4.2.10
*/
connsm->conn_features = dptr[0] & our_feat;
memset(rspbuf + 1, 0, 8);
put_le32(rspbuf + 1, connsm->common_features);
put_le32(rspbuf + 1, our_feat);
rspbuf[1] = connsm->conn_features;
/* If this is the first time we received remote features, try to start DLE */
if (!connsm->csmflags.cfbit.rxd_features) {
ble_ll_ctrl_initiate_dle(connsm);
connsm->csmflags.cfbit.rxd_features = 1;
}
return rsp_opcode;
}
@@ -2132,7 +2173,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
features = ble_ll_read_supp_features();
if ((features & feature) == 0) {
if (opcode == BLE_LL_CTRL_ENC_REQ) {
if (connsm->common_features & BLE_LL_FEAT_EXTENDED_REJ) {
if (connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) {
rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT;
rspbuf[1] = opcode;
rspbuf[2] = BLE_ERR_UNSUPP_REM_FEATURE;
@@ -2201,12 +2242,22 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
break;
/* XXX: check to see if ctrl procedure was running? Do we care? */
case BLE_LL_CTRL_FEATURE_RSP:
connsm->conn_features = dptr[0];
memcpy(connsm->remote_features, dptr + 1, 7);
/* If this is the first time we received remote features, try to start DLE */
if (!connsm->csmflags.cfbit.rxd_features) {
ble_ll_ctrl_initiate_dle(connsm);
connsm->csmflags.cfbit.rxd_features = 1;
}
/* Stop the control procedure */
connsm->common_features = dptr[0];
if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG);
}
/* Send event to host if pending features read */
if (connsm->csmflags.cfbit.pending_hci_rd_features) {
ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS);
connsm->csmflags.cfbit.pending_hci_rd_features = 0;
}
break;
case BLE_LL_CTRL_VERSION_IND:
rsp_opcode = ble_ll_ctrl_rx_version_ind(connsm, dptr, rspdata);
@@ -2321,7 +2372,7 @@ ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode,
rspbuf = om->om_data;
opcode = BLE_LL_CTRL_REJECT_IND_EXT;
if (rej_opcode == BLE_LL_CTRL_ENC_REQ) {
if ((connsm->common_features & BLE_LL_FEAT_EXTENDED_REJ) == 0) {
if ((connsm->conn_features & BLE_LL_FEAT_EXTENDED_REJ) == 0) {
opcode = BLE_LL_CTRL_REJECT_IND;
}
}
+2 -1
View File
@@ -198,7 +198,8 @@ ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status)
evbuf[3] = status;
put_le16(evbuf + 4, connsm->conn_handle);
memset(evbuf + 6, 0, BLE_HCI_RD_LOC_SUPP_FEAT_RSPLEN);
put_le32(evbuf + 6, connsm->common_features);
evbuf[6] = connsm->conn_features;
memcpy(evbuf + 7, connsm->remote_features, 7);
ble_ll_hci_event_send(evbuf);
}
}
+182 -4
View File
@@ -128,11 +128,13 @@
/* Octet 28 */
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
#define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0)
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2)
#else
#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0)
#endif
#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1)
#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_READ_SUPP_STATES (1 << 3)
#define BLE_SUPP_CMD_LE_RX_TEST (0 << 4)
#define BLE_SUPP_CMD_LE_TX_TEST (0 << 5)
@@ -152,8 +154,13 @@
/* Octet 33 */
#define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4)
#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) == 1)
#define BLE_SUPP_CMD_LE_SET_DATALEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_33 \
( \
@@ -163,9 +170,176 @@
BLE_SUPP_CMD_LE_RD_SUGG_DATALEN \
)
/* Octet 34 */
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) == 1)
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0)
#else
#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0)
#endif
#define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1)
#define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (1 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (1 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (1 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (1 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (1 << 7)
#else
#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (0 << 6)
#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_34 \
( \
BLE_SUPP_CMD_LE_WR_SUGG_DATALEN | \
BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK | \
BLE_SUPP_CMD_LE_GENERATE_DH_KEY | \
BLE_SUPP_CMD_LE_ADD_RESOLV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST | \
BLE_SUPP_CMD_LE_RD_RESOLV_SIZE | \
BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR \
)
/* Octet 35 */
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (1 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (1 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (1 << 2)
#else
#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (0 << 0)
#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (0 << 1)
#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (0 << 2)
#endif
#define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3)
#define BLE_LL_SUPP_CMD_OCTET_35 (BLE_SUPP_CMD_LE_RD_MAX_DATALEN)
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
#define BLE_SUPP_CMD_LE_READ_PHY (1 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (1 << 6)
#else
#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4)
#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5)
#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6)
#endif
#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (0 << 7)
#define BLE_LL_SUPP_CMD_OCTET_35 \
( \
BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR | \
BLE_SUPP_CMD_LE_SET_ADDR_RES_EN | \
BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO | \
BLE_SUPP_CMD_LE_RD_MAX_DATALEN | \
BLE_SUPP_CMD_LE_READ_PHY | \
BLE_SUPP_CMD_LE_SET_DEFAULT_PHY | \
BLE_SUPP_CMD_LE_SET_PHY | \
BLE_SUPP_CMD_LE_ENHANCED_RX_TEST \
)
/* Octet 36 */
#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) == 1)
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (1 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (1 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (1 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (0 << 1)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (0 << 4)
#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (0 << 5)
#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (0 << 6)
#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_36 \
( \
BLE_SUPP_CMD_LE_ENHANCED_TX_TEST | \
BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP | \
BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE | \
BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN | \
BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS \
)
/* Octet 37 */
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) == 1)
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1)
#else
#define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0)
#define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1)
#endif
#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (0 << 2)
#define BLE_SUPP_CMD_LE_SET_PADV_DATA (0 << 3)
#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) == 1)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5)
#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6)
#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_37 \
( \
BLE_SUPP_CMD_LE_REMOVE_ADVS | \
BLE_SUPP_CMD_LE_CLEAR_ADVS | \
BLE_SUPP_CMD_LE_SET_PADV_PARAM | \
BLE_SUPP_CMD_LE_SET_PADV_DATA | \
BLE_SUPP_CMD_LE_SET_PADV_ENABLE | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM | \
BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE | \
BLE_SUPP_CMD_LE_EXT_CREATE_CONN \
)
/* Octet 38 */
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (0 << 1)
#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (0 << 2)
#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (0 << 3)
#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (0 << 4)
#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (0 << 5)
#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (0 << 6)
#define BLE_SUPP_CMD_LE_RD_TX_POWER (0 << 7)
#define BLE_LL_SUPP_CMD_OCTET_38 \
( \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC | \
BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C | \
BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC | \
BLE_SUPP_CMD_LE_ADD_PADV_LIST | \
BLE_SUPP_CMD_LE_REMOVE_PADV_LIST | \
BLE_SUPP_CMD_LE_CLEAR_PADV_LIST | \
BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE | \
BLE_SUPP_CMD_LE_RD_TX_POWER \
)
/* Octet 39 */
#define BLE_SUPP_CMD_LE_RD_RF_PATH_COMP (0 << 0)
#define BLE_SUPP_CMD_LE_WR_RF_PATH_COMP (0 << 1)
#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (1 << 2)
#else
#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (0 << 2)
#endif
#define BLE_LL_SUPP_CMD_OCTET_39 \
( \
BLE_SUPP_CMD_LE_RD_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_WR_RF_PATH_COMP | \
BLE_SUPP_CMD_LE_SET_PRIVACY_MODE \
)
/* Defines the array of supported commands */
const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
@@ -204,6 +378,10 @@ const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
0,
0, /* Octet 32 */
BLE_LL_SUPP_CMD_OCTET_33,
0,
BLE_LL_SUPP_CMD_OCTET_35
BLE_LL_SUPP_CMD_OCTET_34,
BLE_LL_SUPP_CMD_OCTET_35,
BLE_LL_SUPP_CMD_OCTET_36,
BLE_LL_SUPP_CMD_OCTET_37,
BLE_LL_SUPP_CMD_OCTET_38,
BLE_LL_SUPP_CMD_OCTET_39,
};
+1 -1
View File
@@ -188,7 +188,7 @@ syscfg.defs:
This option enables/disables the connection parameter request
procedure. This is implemented in the controller but is disabled
by default.
value: '0'
value: '1'
BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG:
description: >
+2
View File
@@ -20,6 +20,8 @@
#ifndef H_BLE_HS_HCI_
#define H_BLE_HS_HCI_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
+59 -18
View File
@@ -25,6 +25,7 @@
#include "mem/mem.h"
#include "nimble/nimble_opt.h"
#include "host/ble_hs_adv.h"
#include "host/ble_hs_hci.h"
#include "ble_hs_priv.h"
/**
@@ -1182,6 +1183,26 @@ ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc)
ble_gap_disc_report(desc);
}
#endif
static int
ble_gap_rd_rem_sup_feat_tx(uint16_t handle)
{
uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_RD_REM_FEAT_LEN];
int rc;
rc = ble_hs_hci_cmd_build_le_read_remote_feat(handle, buf, sizeof buf);
if (rc != 0) {
return BLE_HS_EUNKNOWN;
}
rc = ble_hs_hci_cmd_tx_empty_ack(buf);
if (rc != 0) {
return rc;
}
return 0;
}
/**
* Processes an incoming connection-complete HCI event.
*/
@@ -1308,9 +1329,30 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt)
event.connect.status = 0;
ble_gap_call_conn_event_cb(&event, evt->connection_handle);
ble_gap_rd_rem_sup_feat_tx(evt->connection_handle);
return 0;
}
void
ble_gap_rx_rd_rem_sup_feat_complete(struct hci_le_rd_rem_supp_feat_complete *evt)
{
#if !NIMBLE_BLE_CONNECT
return;
#endif
struct ble_hs_conn *conn;
ble_hs_lock();
conn = ble_hs_conn_find(evt->connection_handle);
if (conn != NULL && evt->status == 0) {
conn->supported_feat = get_le32(evt->features);
}
ble_hs_unlock();
}
int
ble_gap_rx_l2cap_update_req(uint16_t conn_handle,
struct ble_gap_upd_params *params)
@@ -3435,8 +3477,11 @@ ble_gap_update_params(uint16_t conn_handle,
struct ble_gap_update_entry *entry;
struct ble_gap_update_entry *dup;
struct ble_hs_conn *conn;
int l2cap_update;
int rc;
l2cap_update = 0;
/* Validate parameters with a spec */
if (!ble_gap_validate_conn_params(params)) {
return BLE_HS_EINVAL;
@@ -3475,32 +3520,28 @@ ble_gap_update_params(uint16_t conn_handle,
ble_gap_log_update(conn_handle, params);
BLE_HS_LOG(INFO, "\n");
rc = ble_gap_update_tx(conn_handle, params);
/* If our controller reports that it doesn't support the update procedure,
* and we are the slave, fail over to the L2CAP update procedure.
/*
* If LL update procedure is not supported on this connection and we are the
* slave, fail over to the L2CAP update procedure.
*/
if (rc == BLE_HS_HCI_ERR(BLE_ERR_UNKNOWN_HCI_CMD) &&
!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
ble_gap_update_to_l2cap(params, &l2cap_params);
if ((conn->supported_feat & BLE_HS_HCI_LE_FEAT_CONN_PARAM_REQUEST) == 0 &&
!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
l2cap_update = 1;
rc = 0;
} else {
rc = ble_gap_update_tx(conn_handle, params);
}
done:
ble_hs_unlock();
if (rc == 0) {
if (!l2cap_update) {
ble_hs_timer_resched();
} else {
/* If the l2cap_params struct is populated, the only error is that the
* controller doesn't support the connection parameters request
* procedure. In this case, fallback to the L2CAP update procedure.
*/
if (l2cap_params.itvl_min != 0) {
rc = ble_l2cap_sig_update(conn_handle,
&l2cap_params,
ble_gap_update_l2cap_cb, NULL);
}
ble_gap_update_to_l2cap(params, &l2cap_params);
rc = ble_l2cap_sig_update(conn_handle, &l2cap_params,
ble_gap_update_l2cap_cb, NULL);
}
ble_hs_lock();
+1
View File
@@ -78,6 +78,7 @@ extern STATS_SECT_DECL(ble_gap_stats) ble_gap_stats;
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);
void ble_gap_rx_rd_rem_sup_feat_complete(struct hci_le_rd_rem_supp_feat_complete *evt);
int ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt);
void ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt);
void ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt);
+2
View File
@@ -50,6 +50,8 @@ struct ble_hs_conn {
uint16_t bhc_supervision_timeout;
uint8_t bhc_master_clock_accuracy;
uint32_t supported_feat;
ble_hs_conn_flags_t bhc_flags;
struct ble_l2cap_chan_list bhc_channels;
+13
View File
@@ -34,6 +34,7 @@ static struct os_sem ble_hs_hci_sem;
static uint8_t *ble_hs_hci_ack;
static uint16_t ble_hs_hci_buf_sz;
static uint8_t ble_hs_hci_max_pkts;
static uint32_t ble_hs_hci_sup_feat;
#if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS)
static ble_hs_hci_phony_ack_fn *ble_hs_hci_phony_ack_cb;
@@ -455,6 +456,18 @@ err:
return rc;
}
void
ble_hs_hci_set_le_supported_feat(uint32_t feat)
{
ble_hs_hci_sup_feat = feat;
}
uint32_t
ble_hs_hci_get_le_supported_feat(void)
{
return ble_hs_hci_sup_feat;
}
void
ble_hs_hci_init(void)
{
+22
View File
@@ -1839,3 +1839,25 @@ ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr,
return ble_hs_hci_cmd_body_set_random_addr(&r_addr,
dst + BLE_HCI_CMD_HDR_LEN);
}
static void
ble_hs_hci_cmd_body_le_read_remote_feat(uint16_t handle, uint8_t *dst)
{
put_le16(dst, handle);
}
int
ble_hs_hci_cmd_build_le_read_remote_feat(uint16_t handle, uint8_t *dst,
int dst_len)
{
BLE_HS_DBG_ASSERT(
dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_RD_REM_FEAT_LEN);
ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_REM_FEAT,
BLE_HCI_CONN_RD_REM_FEAT_LEN, dst);
dst += BLE_HCI_CMD_HDR_LEN;
ble_hs_hci_cmd_body_le_read_remote_feat(handle, dst);
return 0;
}
+23
View File
@@ -48,6 +48,7 @@ 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;
static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_rd_rem_used_feat_complete;
/* Statistics */
struct host_hci_stats
@@ -97,6 +98,8 @@ static const struct ble_hs_hci_evt_le_dispatch_entry
{ 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 },
{ BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT,
ble_hs_hci_evt_le_rd_rem_used_feat_complete },
};
#define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \
@@ -455,6 +458,26 @@ ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len)
return 0;
}
static int
ble_hs_hci_evt_le_rd_rem_used_feat_complete(uint8_t subevent, uint8_t *data,
int len)
{
struct hci_le_rd_rem_supp_feat_complete evt;
if (len < BLE_HCI_LE_RD_REM_USED_FEAT_LEN) {
return BLE_HS_ECONTROLLER;
}
evt.subevent_code = data[0];
evt.status = data[1];
evt.connection_handle = get_le16(data + 2);
memcpy(evt.features, data + 4, 8);
ble_gap_rx_rd_rem_sup_feat_complete(&evt);
return 0;
}
#if MYNEWT_VAL(BLE_EXT_ADV)
static int
ble_hs_hci_decode_legacy_type(uint16_t evt_type)
+24
View File
@@ -28,6 +28,24 @@ extern "C" {
struct ble_hs_conn;
struct os_mbuf;
#define BLE_HS_HCI_LE_FEAT_ENCRYPTION (0x00000001)
#define BLE_HS_HCI_LE_FEAT_CONN_PARAM_REQUEST (0x00000002)
#define BLE_HS_HCI_LE_FEAT_EXT_REJECT (0x00000004)
#define BLE_HS_HCI_LE_FEAT_SLAVE_FEAT_EXCHANGE (0x00000008)
#define BLE_HS_HCI_LE_FEAT_PING (0x00000010)
#define BLE_HS_HCI_LE_FEAT_DATA_PACKET_LENGTH_EXT (0x00000020)
#define BLE_HS_HCI_LE_FEAT_LL_PRIVACY (0x00000040)
#define BLE_HS_HCI_LE_FEAT_EXT_SCANNER_FILTER_POLICIES (0x00000080)
#define BLE_HS_HCI_LE_FEAT_2M_PHY (0x00000100)
#define BLE_HS_HCI_LE_FEAT_STABLE_MOD_INDEX_TX (0x00000200)
#define BLE_HS_HCI_LE_FEAT_STABLE_MOD_INDEX_RX (0x00000400)
#define BLE_HS_HCI_LE_FEAT_CODED_PHY (0x00000800)
#define BLE_HS_HCI_LE_FEAT_EXT_ADV (0x00001000)
#define BLE_HS_HCI_LE_FEAT_PERIODIC_ADV (0x00002000)
#define BLE_HS_HCI_LE_FEAT_CSA2 (0x00004000)
#define BLE_HS_HCI_LE_FEAT_POWER_CLASS_1 (0x00008000)
#define BLE_HS_HCI_LE_FEAT_MIN_NUM_USED_CHAN (0x00010000)
struct ble_hs_hci_ack {
int bha_status; /* A BLE_HS_E<...> error; NOT a naked HCI code. */
uint8_t *bha_params;
@@ -57,6 +75,9 @@ int ble_hs_hci_cmd_tx_empty_ack(void *cmd);
void ble_hs_hci_rx_ack(uint8_t *ack_ev);
void ble_hs_hci_init(void);
void ble_hs_hci_set_le_supported_feat(uint32_t feat);
uint32_t ble_hs_hci_get_le_supported_feat(void);
#if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS)
typedef int ble_hs_hci_phony_ack_fn(uint8_t *ack, int ack_buf_len);
void ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb);
@@ -220,6 +241,9 @@ int ble_hs_hci_cmd_build_le_set_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
#if MYNEWT_VAL(BLE_EXT_ADV)
#endif
int ble_hs_hci_cmd_build_le_read_remote_feat(uint16_t handle, uint8_t *dst,
int dst_len);
#ifdef __cplusplus
}
#endif
+6 -36
View File
@@ -20,6 +20,7 @@
#include <stddef.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_hs_hci.h"
#include "ble_hs_priv.h"
static int
@@ -28,6 +29,7 @@ ble_hs_startup_le_read_sup_f_tx(void)
uint8_t ack_params[BLE_HCI_RD_LOC_SUPP_FEAT_RSPLEN];
uint8_t buf[BLE_HCI_CMD_HDR_LEN];
uint8_t ack_params_len;
uint32_t feat;
int rc;
ble_hs_hci_cmd_build_le_read_loc_supp_feat(buf, sizeof buf);
@@ -41,7 +43,9 @@ ble_hs_startup_le_read_sup_f_tx(void)
return BLE_HS_ECONTROLLER;
}
/* XXX: Do something with the supported features bit map. */
/* For now 32-bits of features is enough */
feat = get_le32(ack_params);
ble_hs_hci_set_le_supported_feat(feat);
return 0;
}
@@ -137,47 +141,13 @@ ble_hs_startup_set_evmask_tx(void)
/**
* Enable the following events:
* 0x0000000000000001 Inquiry Complete Event
* 0x0000000000000002 Inquiry Result Event
* 0x0000000000000004 Connection Complete Event
* 0x0000000000000008 Connection Request Event
* 0x0000000000000010 Disconnection Complete Event
* 0x0000000000000020 Authentication Complete Event
* 0x0000000000000040 Remote Name Request Complete Event
* 0x0000000000000080 Encryption Change Event
* 0x0000000000000100 Change Connection Link Key Complete Event
* 0x0000000000000200 Master Link Key Complete Event
* 0x0000000000000400 Read Remote Supported Features Complete Event
* 0x0000000000000800 Read Remote Version Information Complete Event
* 0x0000000000001000 QoS Setup Complete Event
* 0x0000000000002000 Reserved
* 0x0000000000004000 Reserved
* 0x0000000000008000 Hardware Error Event
* 0x0000000000010000 Flush Occurred Event
* 0x0000000000020000 Role Change Event
* 0x0000000000040000 Reserved
* 0x0000000000080000 Mode Change Event
* 0x0000000000100000 Return Link Keys Event
* 0x0000000000200000 PIN Code Request Event
* 0x0000000000400000 Link Key Request Event
* 0x0000000000800000 Link Key Notification Event
* 0x0000000001000000 Loopback Command Event
* 0x0000000002000000 Data Buffer Overflow Event
* 0x0000000004000000 Max Slots Change Event
* 0x0000000008000000 Read Clock Offset Complete Event
* 0x0000000010000000 Connection Packet Type Changed Event
* 0x0000000020000000 QoS Violation Event
* 0x0000000040000000 Page Scan Mode Change Event [deprecated]
* 0x0000000080000000 Page Scan Repetition Mode Change Event
* 0x0000000100000000 Flow Specification Complete Event
* 0x0000000200000000 Inquiry Result with RSSI Event
* 0x0000000400000000 Read Remote Extended Features Complete Event
* 0x0000080000000000 Synchronous Connection Complete Event
* 0x0000100000000000 Synchronous Connection Changed Event
* 0x0000800000000000 Encryption Key Refresh Complete Event
* 0x2000000000000000 LE Meta-Event
*/
ble_hs_hci_cmd_build_set_event_mask(0x20009807ffffffff, buf, sizeof buf);
ble_hs_hci_cmd_build_set_event_mask(0x2000000002008090, buf, sizeof buf);
rc = ble_hs_hci_cmd_tx_empty_ack(buf);
if (rc != 0) {
return rc;
+9
View File
@@ -967,6 +967,15 @@ struct hci_le_conn_param_req
uint16_t timeout;
};
/* Read Remote Supported Features complete LE meta subevent */
struct hci_le_rd_rem_supp_feat_complete
{
uint8_t subevent_code;
uint8_t status;
uint16_t connection_handle;
uint8_t features[8];
};
/* LE long term key request event (note: fields out of order). */
struct hci_le_lt_key_req
{