From 2074c30c51119806665a3b01d4effff5e0b99483 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 25 Apr 2017 19:54:09 +0200 Subject: [PATCH 01/11] nimble/host: Store local controller supported features X-Original-Commit: f01074c4d664441c01313d5e1a26323ea7a45e30 --- nimble/host/include/host/ble_hs_hci.h | 2 ++ nimble/host/src/ble_hs_hci.c | 13 +++++++++++++ nimble/host/src/ble_hs_hci_priv.h | 21 +++++++++++++++++++++ nimble/host/src/ble_hs_startup.c | 6 +++++- 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/nimble/host/include/host/ble_hs_hci.h b/nimble/host/include/host/ble_hs_hci.h index 13ab6029d..4b3607457 100644 --- a/nimble/host/include/host/ble_hs_hci.h +++ b/nimble/host/include/host/ble_hs_hci.h @@ -20,6 +20,8 @@ #ifndef H_BLE_HS_HCI_ #define H_BLE_HS_HCI_ +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index 23735ab61..912927e23 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -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) { diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 1310cf5c3..22886bc46 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -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); diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index 947dd6f25..52042d7b6 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -20,6 +20,7 @@ #include #include #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; } From 06e878246ae4c4d35a0310de5c67578c6ec16fea Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 26 Apr 2017 00:05:44 +0200 Subject: [PATCH 02/11] nimble/host: Store peer supported features X-Original-Commit: 8a9141f6c9c3c71d6700c1ea2b4ad963b9876873 --- nimble/host/src/ble_gap.c | 41 ++++++++++++++++++++++++++++++ nimble/host/src/ble_gap_priv.h | 1 + nimble/host/src/ble_hs_conn_priv.h | 2 ++ nimble/host/src/ble_hs_hci_cmd.c | 22 ++++++++++++++++ nimble/host/src/ble_hs_hci_evt.c | 23 +++++++++++++++++ nimble/host/src/ble_hs_hci_priv.h | 3 +++ nimble/include/nimble/hci_common.h | 9 +++++++ 7 files changed, 101 insertions(+) diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index ab1013f7a..0de26493c 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -1182,6 +1182,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 +1328,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) diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index 8525e6556..8dc5785df 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -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); diff --git a/nimble/host/src/ble_hs_conn_priv.h b/nimble/host/src/ble_hs_conn_priv.h index 4c5164600..56bc6d3c5 100644 --- a/nimble/host/src/ble_hs_conn_priv.h +++ b/nimble/host/src/ble_hs_conn_priv.h @@ -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; diff --git a/nimble/host/src/ble_hs_hci_cmd.c b/nimble/host/src/ble_hs_hci_cmd.c index 95282a6cb..25c76e3bd 100644 --- a/nimble/host/src/ble_hs_hci_cmd.c +++ b/nimble/host/src/ble_hs_hci_cmd.c @@ -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; +} diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index a0be58284..3c942106d 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -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) diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 22886bc46..3dafd77d8 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -241,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 diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 9b5712eb4..c828a3fa9 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -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 { From abf66381a4b83f68930b7ba6312fb9849dc3ebb6 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 25 Apr 2017 19:55:42 +0200 Subject: [PATCH 03/11] nimble/host: Use features to check parameters update procedure We can check features used on connection to figure out what is the proper proceduer to update connection parameters (LL or L2CAP). Checking for specific error code from LE Connection Update is not really reliable and works probably only with Nimble controller which uses this specific error code. X-Original-Commit: 683ed916cb447ce56b687d20aa58076ec3771e35 --- nimble/host/src/ble_gap.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 0de26493c..382fe3cfa 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -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" /** @@ -3476,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; @@ -3516,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(); From 6b3e53c552b97f1be332c9022d72f0898a896199 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 25 Apr 2017 18:33:04 +0200 Subject: [PATCH 04/11] nimble/controller: Fix LE Connection Update status code in slave role LE Connection Update called on slave when both sides do not support Connection Parameters Request procedure should return "command disallowed" error code. The "unknown HCI command" suggests that this command is not supported at all which is not correct. X-Original-Commit: ca655b536be7178557f7925622fe6bc29ce4808d --- nimble/controller/src/ble_ll_conn_hci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index d5cf8acf1..78a07512f 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -815,7 +815,7 @@ 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_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 { From 770b40e5abab4dd158250e18deacf9fed1d961e8 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 2 May 2017 13:47:28 +0200 Subject: [PATCH 05/11] nimble/controller: Enable Connection Parameters Request procedure We support it so there is no reason to have it disabled. X-Original-Commit: dc44ca021a0fb6755bcdd7987d880a427ff465f2 --- nimble/controller/syscfg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index 0e13ad747..7fab9c890 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -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: > From db989bf770af1fb77bbb8ea82fd9caf627d268eb Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Mon, 3 Jul 2017 16:11:50 +0200 Subject: [PATCH 06/11] nimble/controller: Fix features handling Octets 2-8 in LL_FEATURE_REQ and LL_FEATURE_RSP shall be always set to features supported by controller which sends PDU. Only 1st octet shall be set to features supported by both controllers. This patch renames "common_features" to "conn_features" to indicate that this stores features used on connection (as called by spec) and introduces new "remote_features" which caches remaining 7 octets of remote features so we can properly reply on LL and HCI. X-Original-Commit: b661780a48470bbd10fcef833c81240bf5bc6487 --- .../include/controller/ble_ll_conn.h | 3 ++- nimble/controller/src/ble_ll_conn.c | 3 ++- nimble/controller/src/ble_ll_conn_hci.c | 2 +- nimble/controller/src/ble_ll_ctrl.c | 27 +++++++++++++------ nimble/controller/src/ble_ll_hci_ev.c | 3 ++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h index 33079eda9..08ec11fdc 100644 --- a/nimble/controller/include/controller/ble_ll_conn.h +++ b/nimble/controller/include/controller/ble_ll_conn.h @@ -228,7 +228,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; diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index 494e04172..6461ba83a 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -1821,7 +1821,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; diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index 78a07512f..d95373023 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -813,7 +813,7 @@ 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_CMD_DISALLOWED; } diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index 9b4253e6e..0b9aae2ad 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -1530,7 +1530,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 +1547,23 @@ 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; return rsp_opcode; } @@ -2132,7 +2142,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,8 +2211,9 @@ 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); /* 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); @@ -2321,7 +2332,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; } } diff --git a/nimble/controller/src/ble_ll_hci_ev.c b/nimble/controller/src/ble_ll_hci_ev.c index 70ba68f9c..6abfdd6d5 100644 --- a/nimble/controller/src/ble_ll_hci_ev.c +++ b/nimble/controller/src/ble_ll_hci_ev.c @@ -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); } } From 0a9a60b06f862d61ecf75949fc40dd0801bec265 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Mon, 3 Jul 2017 16:22:47 +0200 Subject: [PATCH 07/11] nimble/controller: Refactor remote features handling This patch changes the way we handle features exchange in controller. On new connection, the controller will automatically initiate features exchange and store complete features mask. This makes used features available immediately after connection. Also we cache remote's features so the LE Read Remote Supported Features command does not initiate features exchange procedure at any time and will always return cached data. Initial Data Length Update procedure is removed as it should be now started after features exchange is completed - this will be added soon. X-Original-Commit: c5177bd24239ae17ea260ccce459c70697205e9a --- .../include/controller/ble_ll_conn.h | 4 ++ nimble/controller/src/ble_ll_conn.c | 43 +++++++++++++------ nimble/controller/src/ble_ll_conn_hci.c | 13 +++--- nimble/controller/src/ble_ll_conn_priv.h | 1 + nimble/controller/src/ble_ll_ctrl.c | 17 +++++++- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h index 08ec11fdc..451f70924 100644 --- a/nimble/controller/include/controller/ble_ll_conn.h +++ b/nimble/controller/include/controller/ble_ll_conn.h @@ -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)); @@ -292,6 +294,8 @@ struct ble_ll_conn_sm struct os_callout auth_pyld_timer; #endif + struct os_callout rd_features_timer; + /* * XXX: a note on all these structures for control procedures. First off, * all of these need to be ifdef'd to save memory. Another thing to diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index 6461ba83a..864b94464 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -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 * @@ -1900,6 +1916,11 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm); #endif + os_callout_init(&connsm->rd_features_timer, + &g_ble_ll_data.ll_evq, + ble_ll_conn_rd_features_timer_cb, + connsm); + ble_ll_conn_calc_itvl_ticks(connsm); /* Add to list of active connections */ @@ -1985,6 +2006,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) os_callout_stop(&connsm->auth_pyld_timer); #endif + os_callout_stop(&connsm->rd_features_timer); + /* Remove from the active connection list */ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); @@ -2031,6 +2054,10 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) } } + if (connsm->csmflags.cfbit.pending_hci_rd_features) { + ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNK_CONN_ID); + } + /* Put connection state machine back on free list */ STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); @@ -2362,19 +2389,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 { @@ -2384,6 +2398,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; diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index d95373023..c864d30ba 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -761,15 +761,14 @@ 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; + + os_callout_reset(&connsm->rd_features_timer, 0); return BLE_ERR_SUCCESS; } diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index 60f7aa273..5bbb71915 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -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); diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index 0b9aae2ad..d701ceebf 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -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; } } } @@ -1565,6 +1569,9 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, put_le32(rspbuf + 1, our_feat); rspbuf[1] = connsm->conn_features; + /* We now have remote features */ + connsm->csmflags.cfbit.rxd_features = 1; + return rsp_opcode; } @@ -2213,11 +2220,17 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_FEATURE_RSP: connsm->conn_features = dptr[0]; memcpy(connsm->remote_features, dptr + 1, 7); + /* We now have remote features */ + connsm->csmflags.cfbit.rxd_features = 1; /* Stop the control procedure */ 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); From 64edc2d2be296c401f044a880dd5b32409106bd2 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Mon, 3 Jul 2017 12:17:09 +0200 Subject: [PATCH 08/11] nimble/controller: Initiate data length update if remote supports it We initiate data length update procedure as soon as we receive features from remote and know that this is supported on connection. This fixes issue with some crippled controllers which do not indicate DLE support but will reply with LL_LENGTH_RSP but with broken payload (e.g. the one in Sony Xperia Z5). This would result in LL timeout since we properly ignore broken PDU. X-Original-Commit: 456682623f454710824ad97213ab7576ddeca4e9 --- nimble/controller/src/ble_ll_ctrl.c | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index d701ceebf..909f33d74 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -1517,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. @@ -1569,8 +1590,11 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, put_le32(rspbuf + 1, our_feat); rspbuf[1] = connsm->conn_features; - /* We now have remote features */ - connsm->csmflags.cfbit.rxd_features = 1; + /* 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; } @@ -2220,8 +2244,11 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_FEATURE_RSP: connsm->conn_features = dptr[0]; memcpy(connsm->remote_features, dptr + 1, 7); - /* We now have remote features */ - connsm->csmflags.cfbit.rxd_features = 1; + /* 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 */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); From e26219dfb5ca03cc158efd4396e40793bdc84c14 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 4 Jul 2017 11:54:10 +0200 Subject: [PATCH 09/11] nimble/controller: Update supported HCI commands mask X-Original-Commit: 3605631b8c22cda30224856169af480e1f5e0878 --- .../include/controller/ble_ll_hci.h | 2 +- nimble/controller/src/ble_ll_supp_cmd.c | 186 +++++++++++++++++- 2 files changed, 183 insertions(+), 5 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_hci.h b/nimble/controller/include/controller/ble_ll_hci.h index 0083c86e0..0ac195ad1 100644 --- a/nimble/controller/include/controller/ble_ll_hci.h +++ b/nimble/controller/include/controller/ble_ll_hci.h @@ -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. */ diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c index e1a675656..7383a66c2 100644 --- a/nimble/controller/src/ble_ll_supp_cmd.c +++ b/nimble/controller/src/ble_ll_supp_cmd.c @@ -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, }; From 28e54f55d2712c7cc5b8d23f4e10b7c11bdba26e Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 5 Jul 2017 11:03:58 +0200 Subject: [PATCH 10/11] nimble/controller: Remove callout for HCI Read Remote Features event We don't need this callout - it's enough that we wait until end of conn event and send an event from there. X-Original-Commit: 75ba1ad07189835a309a8b71c44d2f34278ef33c --- .../include/controller/ble_ll_conn.h | 2 -- nimble/controller/src/ble_ll_conn.c | 29 ++++++++++++++----- nimble/controller/src/ble_ll_conn_hci.c | 2 -- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h index 451f70924..ab8c5205f 100644 --- a/nimble/controller/include/controller/ble_ll_conn.h +++ b/nimble/controller/include/controller/ble_ll_conn.h @@ -294,8 +294,6 @@ struct ble_ll_conn_sm struct os_callout auth_pyld_timer; #endif - struct os_callout rd_features_timer; - /* * XXX: a note on all these structures for control procedures. First off, * all of these need to be ifdef'd to save memory. Another thing to diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index 864b94464..53fdca606 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -1916,11 +1916,6 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm); #endif - os_callout_init(&connsm->rd_features_timer, - &g_ble_ll_data.ll_evq, - ble_ll_conn_rd_features_timer_cb, - connsm); - ble_ll_conn_calc_itvl_ticks(connsm); /* Add to list of active connections */ @@ -2006,8 +2001,6 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) os_callout_stop(&connsm->auth_pyld_timer); #endif - os_callout_stop(&connsm->rd_features_timer); - /* Remove from the active connection list */ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); @@ -2036,6 +2029,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 @@ -2054,8 +2057,13 @@ 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 */ @@ -2533,6 +2541,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; + } } /** diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index c864d30ba..c7543b18b 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -768,8 +768,6 @@ ble_ll_conn_hci_read_rem_features(uint8_t *cmdbuf) connsm->csmflags.cfbit.pending_hci_rd_features = 1; - os_callout_reset(&connsm->rd_features_timer, 0); - return BLE_ERR_SUCCESS; } From f0a0e6867375c6d4d486c5e14b4f19f4e4e5dcaa Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Tue, 4 Jul 2017 14:33:32 +0200 Subject: [PATCH 11/11] nimble/host: Do not enable unnecessary events from controller We only need few events enabled from controller since we're LE-only stack - no need to enable almost all of them. X-Original-Commit: 9654153e6daeaeb62999e3cdc6f4ca6df850cf19 --- nimble/host/src/ble_hs_startup.c | 36 +------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index 52042d7b6..311f06ca4 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -141,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;