diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index 61cc70095..d2cdc4a0f 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -2402,6 +2402,17 @@ struct ble_gap_ext_adv_params { /** If enable scan request notification */ unsigned int scan_req_notif:1; +#if MYNEWT_VAL(BLE_DBAF) + /** If use ADV_DECISION_IND on the primary advertising channel */ + unsigned int use_decision_pdus:1; + + /** If include AdvA in the extended header of all decision PDUs */ + unsigned int decision_include_adv_a:1; + + /** If include ADI in the extended header of all decision PDUs */ + unsigned int decision_include_adi:1; +#endif + /** Minimum advertising interval in 0.625ms units, if 0 stack use sane * defaults */ @@ -2553,6 +2564,38 @@ int ble_gap_ext_adv_remove(uint8_t instance); */ int ble_gap_ext_adv_clear(void); +#if MYNEWT_VAL(BLE_DBAF) +/** + * Set decision data for an advertising set (DBAF). + * + * @param instance Advertising set handle (0x00-0xEF) + * @param decision_type_flags Decision_Type_Flags (bit0 = Resolvable Tag) + * @param data Decision data (Resolvable Tag = hash || prand) + * @param data_len Length of data, 0-8 + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_decision_data(uint8_t instance, uint8_t decision_type_flags, + const uint8_t *data, uint8_t data_len); + +/** + * Set decision instructions used when scanning or initiating (DBAF). + * + * Controller supports at least 8 tests. Test_Flags[0] bit0 must be 1. + * + * @param num_tests Number of tests (1-8) + * @param test_flags Per-test flags (num_tests octets) + * @param test_fields Per-test fields (num_tests octets) + * @param test_params Per-test parameters (num_tests * 16 octets) + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_decision_instructions(uint8_t num_tests, + const uint8_t *test_flags, + const uint8_t *test_fields, + const uint8_t *test_params); +#endif + /** * Indicates whether an advertisement procedure is currently in progress on * the specified Instance @@ -3178,6 +3221,9 @@ int ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, * - BLE_HCI_SCAN_FILT_NO_WL_INITA * - BLE_HCI_SCAN_FILT_USE_WL_INITA * - BLE_HCI_SCAN_FILT_MAX + * DBAF (Core 6.0) may OR bits 2-3: + * - BLE_HCI_SCAN_FILT_DECISION_ALL + * - BLE_HCI_SCAN_FILT_DECISION_ONLY * This parameter is ignored unless * @p filter_duplicates is set. * @param limited If limited discovery procedure should be used. @@ -3335,6 +3381,30 @@ int ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handl const struct ble_gap_conn_params *phy_2m_conn_params, const struct ble_gap_conn_params *phy_coded_conn_params, ble_gap_event_fn *cb, void *cb_arg); + +#if MYNEWT_VAL(BLE_DBAF) +/** + * Same as ble_gap_connect_with_synced(), with an explicit Initiator_Filter_Policy. + * + * filter_policy 0 or 1 keeps the historical choice (peer NULL -> Filter Accept + * List, otherwise the peer address). + * + * Policies 2-4 are rejected. Core Vol 4 Part E 7.8.66: when Advertising_Handle + * and Subevent are not 0xFF, the controller ignores Initiator_Filter_Policy and + * connects to the supplied peer address. Use ble_gap_ext_connect_dbaf() for + * DBAF initiator policies. + * + * @return BLE_HS_EINVAL if filter_policy is greater than 1. + */ +int ble_gap_connect_with_synced_dbaf(uint8_t own_addr_type, + uint8_t advertising_handle, uint8_t subevent, + const ble_addr_t *peer_addr, int32_t duration_ms, + uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t filter_policy, ble_gap_event_fn *cb, void *cb_arg); +#endif #endif /** * Initiates an extended connect procedure. @@ -3394,6 +3464,31 @@ int ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, const struct ble_gap_conn_params *phy_coded_conn_params, ble_gap_event_fn *cb, void *cb_arg); +#if MYNEWT_VAL(BLE_DBAF) && MYNEWT_VAL(BLE_EXT_ADV) +/** + * Same as ble_gap_ext_connect(), with an explicit Initiator_Filter_Policy. + * + * Do not add this policy to ble_gap_conn_params. Callers fill that struct + * field by field, so a new byte is uninitialized stack garbage. + * + * filter_policy 0 or 1 keeps the historical choice (peer NULL -> Filter Accept + * List, otherwise the peer address). Values 2-4 are the Core 6.0 DBAF policies + * (BLE_HCI_CONN_FILT_DECISION_ONLY / FAL_ALL_PDUS / DECISION_AND_FAL). + * Peer_Address is ignored by the controller for 2-4 (Vol 4 Part E 7.8.66). + * + * @return BLE_HS_EINVAL if filter_policy is greater than 4; + * BLE_HS_ENOTSUP if filter_policy is 2-4 and the controller does not + * support Decision-Based Advertising Filtering (LE feature bit 42). + */ +int ble_gap_ext_connect_dbaf(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t filter_policy, + ble_gap_event_fn *cb, void *cb_arg); +#endif + #if MYNEWT_VAL(OPTIMIZE_MULTI_CONN) /** * @brief Enable the optimization of multiple connections. diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 83246d433..e7ee24c91 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -155,6 +155,9 @@ struct ble_gap_connect_reattempt_ctxt { uint8_t phy_mask; struct ble_gap_conn_params conn_params_2m; struct ble_gap_conn_params conn_params_coded; +#if MYNEWT_VAL(BLE_DBAF) + uint8_t dbaf_filter_policy; +#endif #endif // MYNEWT_VAL(BLE_EXT_ADV) #if MYNEWT_VAL(BLE_PERIODIC_ADV) ble_addr_t periodic_addr; @@ -225,6 +228,10 @@ struct ble_gap_master_state { #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) uint8_t synchronized:1; uint8_t timeout_cancel_pending:1; +#endif +#if MYNEWT_VAL(BLE_DBAF) + /* Effective Initiator_Filter_Policy sent to the controller. */ + uint8_t filt_policy; #endif ble_addr_t peer_addr; } conn; @@ -1679,6 +1686,9 @@ ble_gap_master_reset_state(void) #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) ble_gap_master.conn.synchronized = 0; ble_gap_master.conn.timeout_cancel_pending = 0; +#endif +#if MYNEWT_VAL(BLE_DBAF) + ble_gap_master.conn.filt_policy = BLE_HCI_CONN_FILT_NO_WL; #endif memset(&ble_gap_master.conn.peer_addr, 0, sizeof(ble_gap_master.conn.peer_addr)); @@ -1741,6 +1751,16 @@ ble_gap_master_conn_matches_slave_complete(const struct ble_gap_conn_complete *e return false; } +#if MYNEWT_VAL(BLE_DBAF) + /* Policies 2-4 ignore Peer_Address (Core Vol 4 Part E 7.8.66). Policy 2 + * does not use the Filter Accept List, so using_wl is false and would + * otherwise compare an address the controller will not honor. + */ + if (ble_gap_master.conn.filt_policy >= BLE_HCI_CONN_FILT_DECISION_ONLY) { + return false; + } +#endif + evt_addr.type = evt->peer_addr_type; memcpy(evt_addr.val, evt->peer_addr, BLE_DEV_ADDR_LEN); @@ -2001,6 +2021,17 @@ ble_gap_master_connect_reattempt(uint16_t conn_handle) #endif // MYNEWT_VAL(OPTIMIZE_MULTI_CONN) #if MYNEWT_VAL(BLE_EXT_ADV) +#if MYNEWT_VAL(BLE_DBAF) + rc = ble_gap_ext_connect_dbaf(ble_conn_reattempt.own_addr_type, + (ble_conn_reattempt.peer_addr_present == 1 ? &ble_conn_reattempt.peer_addr : NULL), + ble_conn_reattempt.duration_ms, ble_conn_reattempt.phy_mask, + ble_conn_reattempt.phy_mask & BLE_GAP_LE_PHY_1M_MASK ? &ble_conn_reattempt.conn_params_1m : NULL, + ble_conn_reattempt.phy_mask & BLE_GAP_LE_PHY_2M_MASK ? &ble_conn_reattempt.conn_params_2m : NULL, + ble_conn_reattempt.phy_mask & BLE_GAP_LE_PHY_CODED_MASK ? &ble_conn_reattempt.conn_params_coded : NULL, + ble_conn_reattempt.dbaf_filter_policy, + ble_conn_reattempt.cb, + ble_conn_reattempt.cb_arg); +#else rc = ble_gap_ext_connect(ble_conn_reattempt.own_addr_type, (ble_conn_reattempt.peer_addr_present == 1 ? &ble_conn_reattempt.peer_addr : NULL), ble_conn_reattempt.duration_ms, ble_conn_reattempt.phy_mask, @@ -2009,6 +2040,7 @@ ble_gap_master_connect_reattempt(uint16_t conn_handle) ble_conn_reattempt.phy_mask & BLE_GAP_LE_PHY_CODED_MASK ? &ble_conn_reattempt.conn_params_coded : NULL, ble_conn_reattempt.cb, ble_conn_reattempt.cb_arg); +#endif #else rc = ble_gap_connect(ble_conn_reattempt.own_addr_type, (ble_conn_reattempt.peer_addr_present == 1 ? &ble_conn_reattempt.peer_addr : NULL), @@ -5699,6 +5731,17 @@ ble_gap_set_ext_adv_params(struct ble_hci_le_set_ext_adv_params_cp *cmd, if (params->include_tx_power) { cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR; } +#if MYNEWT_VAL(BLE_DBAF) + if (params->use_decision_pdus) { + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_USE_DECISION; + } + if (params->decision_include_adv_a) { + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_DEC_INCL_ADVA; + } + if (params->decision_include_adi) { + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_DEC_INCL_ADI; + } +#endif if (params->legacy_pdu) { cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; @@ -5918,13 +5961,37 @@ ble_gap_ext_adv_params_validate(const struct ble_gap_ext_adv_params *params) BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL); return BLE_HS_EINVAL; } +#if MYNEWT_VAL(BLE_DBAF) + if (params->use_decision_pdus || + params->decision_include_adv_a || + params->decision_include_adi) { + BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL); + return BLE_HS_EINVAL; + } +#endif } +#if MYNEWT_VAL(BLE_DBAF) + if ((params->decision_include_adv_a || params->decision_include_adi) && + !params->use_decision_pdus) { + BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL); + return BLE_HS_EINVAL; + } +#endif + if (params->directed) { if (params->scannable && params->connectable) { BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL); return BLE_HS_EINVAL; } +#if MYNEWT_VAL(BLE_DBAF) + /* Decision PDUs are permitted only for undirected advertising + * (Core Spec Vol 6 Part B 2.3.1.11, Table 2.10). */ + if (params->use_decision_pdus) { + BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL); + return BLE_HS_EINVAL; + } +#endif } if (!params->legacy_pdu) { @@ -6657,6 +6724,106 @@ ble_gap_ext_adv_clear(void) return 0; } +#if MYNEWT_VAL(BLE_DBAF) +int +ble_gap_set_decision_data(uint8_t instance, uint8_t decision_type_flags, + const uint8_t *data, uint8_t data_len) +{ + uint8_t buf[sizeof(struct ble_hci_le_set_decision_data_cp) + + BLE_HCI_DECISION_DATA_MAX_LEN]; + struct ble_hci_le_set_decision_data_cp *cmd = (void *)buf; + uint16_t opcode; + uint8_t len; + + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + + if ((ble_hs_hci_get_le_supported_feat() & BLE_HS_HCI_LE_FEAT_DBAF) == 0) { + return BLE_HS_ENOTSUP; + } + + if (instance > 0xEF) { + return BLE_HS_EINVAL; + } + + if (data_len > BLE_HCI_DECISION_DATA_MAX_LEN) { + return BLE_HS_EINVAL; + } + + if (data_len > 0 && data == NULL) { + return BLE_HS_EINVAL; + } + + if ((decision_type_flags & BLE_HCI_DECISION_TYPE_RESOLVABLE_TAG) && + data_len < 6) { + return BLE_HS_EINVAL; + } + + memset(buf, 0, sizeof(buf)); + cmd->adv_handle = instance; + cmd->decision_type_flags = decision_type_flags; + cmd->decision_data_len = data_len; + if (data_len > 0) { + memcpy(cmd->decision_data, data, data_len); + } + + len = sizeof(*cmd) + data_len; + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DECISION_DATA); + + return ble_hs_hci_cmd_tx(opcode, cmd, len, NULL, 0); +} + +int +ble_gap_set_decision_instructions(uint8_t num_tests, + const uint8_t *test_flags, + const uint8_t *test_fields, + const uint8_t *test_params) +{ + uint8_t buf[sizeof(struct ble_hci_le_set_decision_instructions_cp) + + BLE_HCI_DECISION_MAX_TESTS * sizeof(struct ble_hci_le_decision_test)]; + struct ble_hci_le_set_decision_instructions_cp *cmd = (void *)buf; + uint16_t opcode; + uint8_t i; + uint8_t len; + + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + + if ((ble_hs_hci_get_le_supported_feat() & BLE_HS_HCI_LE_FEAT_DBAF) == 0) { + return BLE_HS_ENOTSUP; + } + + if (num_tests == 0 || num_tests > BLE_HCI_DECISION_MAX_TESTS) { + return BLE_HS_EINVAL; + } + + if (test_flags == NULL || test_fields == NULL || test_params == NULL) { + return BLE_HS_EINVAL; + } + + if ((test_flags[0] & BLE_HCI_DECISION_TEST_FLAGS_NEW_GROUP) == 0) { + return BLE_HS_EINVAL; + } + + memset(buf, 0, sizeof(buf)); + cmd->num_tests = num_tests; + for (i = 0; i < num_tests; i++) { + cmd->tests[i].test_flags = test_flags[i]; + cmd->tests[i].test_field = test_fields[i]; + memcpy(cmd->tests[i].test_params, + test_params + (i * BLE_HCI_DECISION_TEST_PARAM_LEN), + BLE_HCI_DECISION_TEST_PARAM_LEN); + } + + len = sizeof(*cmd) + num_tests * sizeof(struct ble_hci_le_decision_test); + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DECISION_INSTRUCTIONS); + + return ble_hs_hci_cmd_tx(opcode, cmd, len, NULL, 0); +} +#endif + #if MYNEWT_VAL(BLE_PERIODIC_ADV) static int ble_gap_periodic_adv_params_tx(uint8_t instance, @@ -7957,6 +8124,23 @@ int ble_gap_periodic_adv_sync_subev(uint16_t sync_handle, uint8_t include_tx_pow *****************************************************************************/ #if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN +#if MYNEWT_VAL(BLE_DBAF) +static int +ble_gap_ext_scan_filter_policy_valid(uint8_t filter_policy) +{ + /* bits 4-7 reserved (must be 0). */ + if (filter_policy & 0xF0) { + return 0; + } + /* bits 2-3: 0b00 / 0b01 / 0b11 valid; 0b10 reserved. */ + if (((filter_policy >> 2) & 0x03) == 0x02) { + return 0; + } + /* bits 0-1: all values 0-3 valid per spec. */ + return 1; +} +#endif + static int ble_gap_ext_disc_tx_params(uint8_t own_addr_type, uint8_t filter_policy, const struct ble_hs_hci_ext_scan_param *uncoded_params, @@ -7973,10 +8157,25 @@ ble_gap_ext_disc_tx_params(uint8_t own_addr_type, uint8_t filter_policy, } /* Check scanner filter policy */ +#if MYNEWT_VAL(BLE_DBAF) + if (!ble_gap_ext_scan_filter_policy_valid(filter_policy)) { +#else if (filter_policy > BLE_HCI_SCAN_FILT_MAX) { +#endif return BLE_ERR_INV_HCI_CMD_PARMS; } +#if MYNEWT_VAL(BLE_DBAF) + /* Bits 2-3 are Decision-Based Advertising Filtering. A controller without + * LE feature bit 42 must not be sent these values (Core Vol 4 Part E + * 7.8.64, error 0x11). Values 0-3 keep the historical scan filter policy. + */ + if ((filter_policy & BLE_HCI_SCAN_FILT_DECISION_MASK) != 0 && + (ble_hs_hci_get_le_supported_feat() & BLE_HS_HCI_LE_FEAT_DBAF) == 0) { + return BLE_HS_ENOTSUP; + } +#endif + cmd = (void *) buf; params = cmd->scans; @@ -8929,6 +9128,55 @@ ble_gap_check_conn_params(uint8_t phy, const struct ble_gap_conn_params *params) } #endif +#if MYNEWT_VAL(BLE_DBAF) && \ + (MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) || \ + (MYNEWT_VAL(BLE_EXT_ADV) && MYNEWT_VAL(BLE_ROLE_CENTRAL))) +static int +ble_gap_dbaf_initiator_filter_policy(const ble_addr_t *peer_addr, + uint8_t req_policy, + uint8_t *out_policy) +{ + uint8_t policy; + + if (out_policy == NULL) { + return BLE_HS_EINVAL; + } + + if (req_policy > BLE_HCI_CONN_FILT_MAX) { + *out_policy = BLE_HCI_CONN_FILT_NO_WL; + return BLE_HS_EINVAL; + } + + /* Core Vol 4 Part E 7.8.66: a controller without DBAF shall return + * Unsupported Feature or Parameter Value (0x11) for policies other than + * 0x00 or 0x01. Reject here so those values are never sent. + * 0 and 1 keep the historical peer-address / Filter Accept List choice. + */ + if (req_policy > BLE_HCI_CONN_FILT_USE_WL && + (ble_hs_hci_get_le_supported_feat() & BLE_HS_HCI_LE_FEAT_DBAF) == 0) { + *out_policy = BLE_HCI_CONN_FILT_NO_WL; + return BLE_HS_ENOTSUP; + } + + policy = (peer_addr == NULL) ? BLE_HCI_CONN_FILT_USE_WL : + BLE_HCI_CONN_FILT_NO_WL; + if (req_policy > BLE_HCI_CONN_FILT_USE_WL) { + policy = req_policy; + } + + *out_policy = policy; + return 0; +} + +static int +ble_gap_initiator_policy_uses_fal(uint8_t policy) +{ + return policy == BLE_HCI_CONN_FILT_USE_WL || + policy == BLE_HCI_CONN_FILT_FAL_ALL_PDUS || + policy == BLE_HCI_CONN_FILT_DECISION_AND_FAL; +} +#endif + #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) static int ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, @@ -8936,7 +9184,11 @@ ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr, uint8_t phy_mask, const struct ble_gap_conn_params *phy_1m_conn_params, const struct ble_gap_conn_params *phy_2m_conn_params, - const struct ble_gap_conn_params *phy_coded_conn_params) + const struct ble_gap_conn_params *phy_coded_conn_params +#if MYNEWT_VAL(BLE_DBAF) + , uint8_t filter_policy +#endif +) { struct ble_hci_le_ext_create_conn_v2_cp *cmd; struct conn_params *params; @@ -8962,7 +9214,9 @@ ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, * peer address type and peer address fields are ignored by the * controller; fill them with dummy values. */ +#if !MYNEWT_VAL(BLE_DBAF) cmd->filter_policy = BLE_HCI_CONN_FILT_USE_WL; +#endif cmd->peer_addr_type = 0; memset(cmd->peer_addr, 0, sizeof(cmd->peer_addr)); } else { @@ -8971,11 +9225,17 @@ ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, return BLE_ERR_INV_HCI_CMD_PARMS; } +#if !MYNEWT_VAL(BLE_DBAF) cmd->filter_policy = BLE_HCI_CONN_FILT_NO_WL; +#endif cmd->peer_addr_type = peer_addr->type; memcpy(cmd->peer_addr, peer_addr->val, sizeof(cmd->peer_addr)); } +#if MYNEWT_VAL(BLE_DBAF) + cmd->filter_policy = filter_policy; +#endif + cmd->own_addr_type = own_addr_type; cmd->init_phy_mask = phy_mask; @@ -9045,6 +9305,17 @@ ble_gap_ext_conn_create_conn_synced_tx(uint8_t own_addr_type, } +#if MYNEWT_VAL(BLE_DBAF) +static int +ble_gap_connect_with_synced_policy(uint8_t own_addr_type, uint8_t advertising_handle, + uint8_t subevent, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t dbaf_filter_policy, + ble_gap_event_fn *cb, void *cb_arg) +#else int ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, uint8_t subevent, const ble_addr_t *peer_addr, @@ -9053,8 +9324,12 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, const struct ble_gap_conn_params *phy_2m_conn_params, const struct ble_gap_conn_params *phy_coded_conn_params, ble_gap_event_fn *cb, void *cb_arg) +#endif { uint32_t duration_ticks = 0; +#if MYNEWT_VAL(BLE_DBAF) + uint8_t policy; +#endif int rc; STATS_INC(ble_gap_stats, initiate); @@ -9139,6 +9414,16 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, goto done; } +#if MYNEWT_VAL(BLE_DBAF) + policy = (peer_addr == NULL) ? BLE_HCI_CONN_FILT_USE_WL : + BLE_HCI_CONN_FILT_NO_WL; + rc = ble_gap_dbaf_initiator_filter_policy(peer_addr, dbaf_filter_policy, + &policy); + if (rc != 0) { + goto done; + } +#endif + /* XXX: Verify conn_params. */ rc = ble_hs_id_use_addr(own_addr_type); @@ -9150,7 +9435,12 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, ble_gap_master.cb = cb; ble_gap_master.cb_arg = cb_arg; +#if MYNEWT_VAL(BLE_DBAF) + ble_gap_master.conn.filt_policy = policy; + ble_gap_master.conn.using_wl = ble_gap_initiator_policy_uses_fal(policy); +#else ble_gap_master.conn.using_wl = peer_addr == NULL; +#endif ble_gap_master.conn.our_addr_type = own_addr_type; ble_gap_master.conn.synchronized = 1; if (peer_addr != NULL) { @@ -9164,7 +9454,11 @@ ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, rc = ble_gap_ext_conn_create_conn_synced_tx(own_addr_type,advertising_handle,subevent, peer_addr, phy_mask, phy_1m_conn_params, phy_2m_conn_params, - phy_coded_conn_params); + phy_coded_conn_params +#if MYNEWT_VAL(BLE_DBAF) + , policy +#endif + ); if (rc != 0) { ble_gap_master_reset_state(); goto done; @@ -9187,6 +9481,52 @@ done: return rc; } + +#if MYNEWT_VAL(BLE_DBAF) +int +ble_gap_connect_with_synced(uint8_t own_addr_type, uint8_t advertising_handle, + uint8_t subevent, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg) +{ + return ble_gap_connect_with_synced_policy(own_addr_type, advertising_handle, + subevent, peer_addr, duration_ms, + phy_mask, phy_1m_conn_params, + phy_2m_conn_params, + phy_coded_conn_params, 0, cb, + cb_arg); +} + +int +ble_gap_connect_with_synced_dbaf(uint8_t own_addr_type, + uint8_t advertising_handle, uint8_t subevent, + const ble_addr_t *peer_addr, int32_t duration_ms, + uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t filter_policy, ble_gap_event_fn *cb, void *cb_arg) +{ + /* Core Vol 4 Part E 7.8.66: Initiator_Filter_Policy is ignored when + * Advertising_Handle and Subevent are not 0xFF, so DBAF policies do not + * apply. Accepting them would mark the Filter Accept List busy and skip + * peer-address matching while the controller still uses Peer_Address. + */ + if (filter_policy > BLE_HCI_CONN_FILT_USE_WL) { + return BLE_HS_EINVAL; + } + + return ble_gap_connect_with_synced_policy(own_addr_type, advertising_handle, + subevent, peer_addr, duration_ms, + phy_mask, phy_1m_conn_params, + phy_2m_conn_params, + phy_coded_conn_params, + filter_policy, cb, cb_arg); +} +#endif #endif #if MYNEWT_VAL(BLE_EXT_ADV) @@ -9197,7 +9537,11 @@ ble_gap_ext_conn_create_tx( uint8_t own_addr_type, const ble_addr_t *peer_addr, uint8_t phy_mask, const struct ble_gap_conn_params *phy_1m_conn_params, const struct ble_gap_conn_params *phy_2m_conn_params, - const struct ble_gap_conn_params *phy_coded_conn_params) + const struct ble_gap_conn_params *phy_coded_conn_params +#if MYNEWT_VAL(BLE_DBAF) + , uint8_t filter_policy +#endif +) { struct ble_hci_le_ext_create_conn_cp *cmd; struct conn_params *params; @@ -9224,7 +9568,9 @@ ble_gap_ext_conn_create_tx( * peer address type and peer address fields are ignored by the * controller; fill them with dummy values. */ +#if !MYNEWT_VAL(BLE_DBAF) cmd->filter_policy = BLE_HCI_CONN_FILT_USE_WL; +#endif cmd->peer_addr_type = 0; memset(cmd->peer_addr, 0, sizeof(cmd->peer_addr)); } else { @@ -9233,11 +9579,17 @@ ble_gap_ext_conn_create_tx( return BLE_ERR_INV_HCI_CMD_PARMS; } +#if !MYNEWT_VAL(BLE_DBAF) cmd->filter_policy = BLE_HCI_CONN_FILT_NO_WL; +#endif cmd->peer_addr_type = peer_addr->type; memcpy(cmd->peer_addr, peer_addr->val, sizeof(cmd->peer_addr)); } +#if MYNEWT_VAL(BLE_DBAF) + cmd->filter_policy = filter_policy; +#endif + cmd->own_addr_type = own_addr_type; cmd->init_phy_mask = phy_mask; @@ -9408,6 +9760,16 @@ ble_gap_ext_conn_create_tx( * connected; * Other nonzero on error. */ +#if MYNEWT_VAL(BLE_DBAF) +static int +ble_gap_ext_connect_policy(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t dbaf_filter_policy, + ble_gap_event_fn *cb, void *cb_arg) +#else int ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, int32_t duration_ms, uint8_t phy_mask, @@ -9415,9 +9777,13 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, const struct ble_gap_conn_params *phy_2m_conn_params, const struct ble_gap_conn_params *phy_coded_conn_params, ble_gap_event_fn *cb, void *cb_arg) +#endif { #if MYNEWT_VAL(BLE_ROLE_CENTRAL) ble_npl_time_t duration_ticks; +#if MYNEWT_VAL(BLE_DBAF) + uint8_t policy; +#endif int rc; STATS_INC(ble_gap_stats, initiate); @@ -9518,6 +9884,16 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, goto done; } +#if MYNEWT_VAL(BLE_DBAF) + policy = (peer_addr == NULL) ? BLE_HCI_CONN_FILT_USE_WL : + BLE_HCI_CONN_FILT_NO_WL; + rc = ble_gap_dbaf_initiator_filter_policy(peer_addr, dbaf_filter_policy, + &policy); + if (rc != 0) { + goto done; + } +#endif + /* XXX: Verify conn_params. */ rc = ble_hs_id_use_addr(own_addr_type); @@ -9529,7 +9905,12 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, ble_gap_master.cb = cb; ble_gap_master.cb_arg = cb_arg; +#if MYNEWT_VAL(BLE_DBAF) + ble_gap_master.conn.filt_policy = policy; + ble_gap_master.conn.using_wl = ble_gap_initiator_policy_uses_fal(policy); +#else ble_gap_master.conn.using_wl = peer_addr == NULL; +#endif ble_gap_master.conn.our_addr_type = own_addr_type; #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) ble_gap_master.conn.synchronized = 0; @@ -9577,12 +9958,19 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, ble_conn_reattempt.cb = cb; ble_conn_reattempt.cb_arg = cb_arg; +#if MYNEWT_VAL(BLE_DBAF) + ble_conn_reattempt.dbaf_filter_policy = dbaf_filter_policy; +#endif #endif rc = ble_gap_ext_conn_create_tx(own_addr_type, peer_addr, phy_mask, phy_1m_conn_params, phy_2m_conn_params, - phy_coded_conn_params); + phy_coded_conn_params +#if MYNEWT_VAL(BLE_DBAF) + , policy +#endif + ); if (rc != 0) { ble_gap_master_reset_state(); goto done; @@ -9602,10 +9990,44 @@ done: } return rc; #else +#if MYNEWT_VAL(BLE_DBAF) + (void)dbaf_filter_policy; +#endif return BLE_HS_ENOTSUP; #endif } + +#if MYNEWT_VAL(BLE_DBAF) +int +ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + ble_gap_event_fn *cb, void *cb_arg) +{ + return ble_gap_ext_connect_policy(own_addr_type, peer_addr, duration_ms, + phy_mask, phy_1m_conn_params, + phy_2m_conn_params, phy_coded_conn_params, + 0, cb, cb_arg); +} + +int +ble_gap_ext_connect_dbaf(uint8_t own_addr_type, const ble_addr_t *peer_addr, + int32_t duration_ms, uint8_t phy_mask, + const struct ble_gap_conn_params *phy_1m_conn_params, + const struct ble_gap_conn_params *phy_2m_conn_params, + const struct ble_gap_conn_params *phy_coded_conn_params, + uint8_t filter_policy, + ble_gap_event_fn *cb, void *cb_arg) +{ + return ble_gap_ext_connect_policy(own_addr_type, peer_addr, duration_ms, + phy_mask, phy_1m_conn_params, + phy_2m_conn_params, phy_coded_conn_params, + filter_policy, cb, cb_arg); +} +#endif #endif int @@ -9716,6 +10138,11 @@ ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, ble_gap_master.cb = cb; ble_gap_master.cb_arg = cb_arg; ble_gap_master.conn.using_wl = peer_addr == NULL; +#if MYNEWT_VAL(BLE_DBAF) + ble_gap_master.conn.filt_policy = (peer_addr == NULL) ? + BLE_HCI_CONN_FILT_USE_WL : + BLE_HCI_CONN_FILT_NO_WL; +#endif ble_gap_master.conn.our_addr_type = own_addr_type; #if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES) ble_gap_master.conn.synchronized = 0; diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index 9e8295513..fea52f74f 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -1044,6 +1044,11 @@ ble_hs_hci_set_le_supported_feat(uint64_t feat) uint64_t ble_hs_hci_get_le_supported_feat(void) { +#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) + if (!ble_hs_hci_ctx) { + return 0; + } +#endif return ble_hs_hci_sup_feat; } diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 3dd373a5c..a7bf76967 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -45,6 +45,8 @@ struct os_mbuf; #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) +/* Bit 42: Decision-Based Advertising Filtering (Core Vol 6 Part B 4.6). */ +#define BLE_HS_HCI_LE_FEAT_DBAF (1ULL << 42) struct ble_hs_hci_ack { int bha_status; /* A BLE_HS_E<...> error; NOT a naked HCI code. */ diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 67c7acd19..881001c9e 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -1318,6 +1318,40 @@ struct ble_hci_le_set_ext_adv_params_v2_cp { uint8_t sec_phy_opt; } __attribute__((packed)); +/* HCI LE Set Decision Data (OCF 0x0080), Core 6.0 Vol 4 Part E 7.8.144 */ +#define BLE_HCI_OCF_LE_SET_DECISION_DATA (0x0080) +#define BLE_HCI_DECISION_DATA_MAX_LEN (8) +#define BLE_HCI_DECISION_TYPE_RESOLVABLE_TAG (0x01) +struct ble_hci_le_set_decision_data_cp { + uint8_t adv_handle; + uint8_t decision_type_flags; + uint8_t decision_data_len; + uint8_t decision_data[0]; +} __attribute__((packed)); + +/* HCI LE Set Decision Instructions (OCF 0x0081), Core 6.0 Vol 4 Part E 7.8.145 */ +#define BLE_HCI_OCF_LE_SET_DECISION_INSTRUCTIONS (0x0081) +#define BLE_HCI_DECISION_MAX_TESTS (8) +#define BLE_HCI_DECISION_TEST_PARAM_LEN (16) +#define BLE_HCI_DECISION_TEST_FLAGS_NEW_GROUP (0x01) +#define BLE_HCI_DECISION_TEST_FLAGS_PASS_IF_OK (0x02) +#define BLE_HCI_DECISION_TEST_FLAGS_PASS_IF_FAIL (0x04) +#define BLE_HCI_DECISION_TEST_FLAGS_PASS_IF_ABSENT (0x08) +#define BLE_HCI_DECISION_TEST_FIELD_RESOLVABLE_TAG (0) +#define BLE_HCI_DECISION_TEST_FIELD_ADV_MODE (6) +#define BLE_HCI_DECISION_TEST_FIELD_RSSI (7) +#define BLE_HCI_DECISION_TEST_FIELD_PATH_LOSS (8) +#define BLE_HCI_DECISION_TEST_FIELD_ADVA (9) +struct ble_hci_le_decision_test { + uint8_t test_flags; + uint8_t test_field; + uint8_t test_params[BLE_HCI_DECISION_TEST_PARAM_LEN]; +} __attribute__((packed)); +struct ble_hci_le_set_decision_instructions_cp { + uint8_t num_tests; + struct ble_hci_le_decision_test tests[0]; +} __attribute__((packed)); + #define BLE_HCI_OCF_LE_SET_PERIODIC_ADV_SUBEV_DATA (0x0082) struct periodic_adv_subevents { uint8_t subevent; @@ -1814,6 +1848,11 @@ struct ble_hci_vs_set_event_mask_cp { #define BLE_HCI_SCAN_FILT_NO_WL_INITA (2) #define BLE_HCI_SCAN_FILT_USE_WL_INITA (3) #define BLE_HCI_SCAN_FILT_MAX (3) +/* Scanning_Filter_Policy bits 2-3 (Core 6.0 DBAF). Combine with bits 0-1. */ +#define BLE_HCI_SCAN_FILT_DECISION_NONE (0x00) +#define BLE_HCI_SCAN_FILT_DECISION_ALL (0x04) +#define BLE_HCI_SCAN_FILT_DECISION_ONLY (0x0C) +#define BLE_HCI_SCAN_FILT_DECISION_MASK (0x0C) /* Whitelist commands */ #define BLE_HCI_ADD_WHITE_LIST_LEN (7) @@ -1824,7 +1863,10 @@ struct ble_hci_vs_set_event_mask_cp { #define BLE_HCI_CONN_ITVL (1250) /* usecs */ #define BLE_HCI_CONN_FILT_NO_WL (0) #define BLE_HCI_CONN_FILT_USE_WL (1) -#define BLE_HCI_CONN_FILT_MAX (1) +#define BLE_HCI_CONN_FILT_DECISION_ONLY (2) +#define BLE_HCI_CONN_FILT_FAL_ALL_PDUS (3) +#define BLE_HCI_CONN_FILT_DECISION_AND_FAL (4) +#define BLE_HCI_CONN_FILT_MAX (4) /* Bluetooth Core Spec minimum connection interval (7.5 ms in 1.25 ms units). */ #define BLE_HCI_CONN_ITVL_MIN (0x0006) /* Host-side validation floor for connection interval (1.25 ms units). When @@ -1909,7 +1951,13 @@ struct ble_hci_vs_set_event_mask_cp { #define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY (0x0010) #define BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV (0x0020) #define BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR (0x0040) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_USE_DECISION (0x0080) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_DEC_INCL_ADVA (0x0100) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_DEC_INCL_ADI (0x0200) +#define BLE_HCI_LE_SET_EXT_ADV_PROP_DECISION_MASK (0x0380) #define BLE_HCI_LE_SET_EXT_ADV_PROP_MASK (0x7F) +/* Full Core 6.0 property mask including decision-PDU bits (host-side DBAF). */ +#define BLE_HCI_LE_SET_EXT_ADV_PROP_MASK_DBAF (0x03FF) #define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND (0x0013) #define BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR (0x0015)