From d17582e5dc9e380a12ac54ea6ba154f46c468a21 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 23 Oct 2023 08:19:24 +0200 Subject: HCIHandler: Add support for HCI resolvable functions: add, del, clear, read.., set.. NOTE that the following seem not to be supported in Linux/BlueZ: - LE_READ_PEER_RESOLV_ADDR - LE_READ_LOCAL_RESOLV_ADDR The others are coded within BlueZ, but I received 0x01 UNKNOWN_COMMAND as a HCIStatusCode Used kernel for analysis: - bluetooth-next 2022-04-01 - 38a1944deda4d96ca04b9aaa51ee5ae879b61aa0 --- src/direct_bt/HCIHandler.cpp | 106 +++++++++++++++++++++++++++++++++++++++++++ src/direct_bt/HCITypes.cpp | 7 +++ 2 files changed, 113 insertions(+) (limited to 'src/direct_bt') diff --git a/src/direct_bt/HCIHandler.cpp b/src/direct_bt/HCIHandler.cpp index 21f3c573..c99539b8 100644 --- a/src/direct_bt/HCIHandler.cpp +++ b/src/direct_bt/HCIHandler.cpp @@ -749,6 +749,7 @@ HCIHandler::HCIHandler(const uint16_t dev_id_, const BTMode btMode_) noexcept HCIComm::filter_set_event(number(HCIEventType::CMD_STATUS), &filter_mask); HCIComm::filter_set_event(number(HCIEventType::HARDWARE_ERROR), &filter_mask); HCIComm::filter_set_event(number(HCIEventType::ENCRYPT_KEY_REFRESH_COMPLETE), &filter_mask); + // HCIComm::filter_set_event(number(HCIEventType::IO_CAPABILITY_REQUEST), &filter_mask); // HCIComm::filter_set_event(number(HCIEventType::IO_CAPABILITY_RESPONSE), &filter_mask); HCIComm::filter_set_event(number(HCIEventType::LE_META), &filter_mask); @@ -1499,6 +1500,111 @@ HCIStatusCode HCIHandler::disconnect(const uint16_t conn_handle, const BDAddress return status; } +HCIStatusCode HCIHandler::le_add_to_resolv_list(const BDAddressAndType& peerIdentityAddressAndType, + jau::uint128_t& peer_irk, jau::uint128_t& local_irk) noexcept { + HCIStatusCode status; + HCIStructCommand req0(HCIOpcode::LE_ADD_TO_RESOLV_LIST); + hci_cp_le_add_to_resolv_list * cp = req0.getWStruct(); + cp->bdaddr_type = static_cast(peerIdentityAddressAndType.type); + cp->bdaddr = jau::cpu_to_le(peerIdentityAddressAndType.address); + jau::put_uint128(cp->peer_irk, 0, peer_irk, true /* le */); + jau::put_uint128(cp->local_irk, 0, local_irk, true /* le */); + const hci_rp_status * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } + return status; +} + +HCIStatusCode HCIHandler::le_del_from_resolv_list(const BDAddressAndType& peerIdentityAddressAndType) noexcept { + HCIStatusCode status; + HCIStructCommand req0(HCIOpcode::LE_DEL_FROM_RESOLV_LIST); + hci_cp_le_del_from_resolv_list * cp = req0.getWStruct(); + cp->bdaddr_type = static_cast(peerIdentityAddressAndType.type); + cp->bdaddr = jau::cpu_to_le(peerIdentityAddressAndType.address); + const hci_rp_status * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } + return status; +} + +HCIStatusCode HCIHandler::le_clear_resolv_list() noexcept { + HCIStatusCode status; + HCICommand req0(HCIOpcode::LE_CLEAR_RESOLV_LIST, 0); + const hci_rp_status * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } + return status; +} + +HCIStatusCode HCIHandler::le_read_resolv_list_size(uint32_t& size_res) noexcept { + size_res = 0; + HCIStatusCode status; + HCICommand req0(HCIOpcode::LE_READ_RESOLV_LIST_SIZE, 0); + const hci_rp_le_read_resolv_list_size * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } else if( nullptr != ev_res && HCIStatusCode::SUCCESS != status ) { + size_res = ev_res->size; + } + return status; +} + +HCIStatusCode HCIHandler::le_read_peer_resolv_addr(const BDAddressAndType& peerIdentityAddressAndType, + jau::EUI48& peerResolvableAddress) noexcept { + peerResolvableAddress.clear(); + HCIStatusCode status; + HCIStructCommand req0(HCIOpcode::LE_READ_PEER_RESOLV_ADDR); + hci_cp_le_read_peer_resolv_addr * cp = req0.getWStruct(); + cp->peer_id_addr_type = static_cast(peerIdentityAddressAndType.type); + cp->peer_id_addr = jau::cpu_to_le(peerIdentityAddressAndType.address); + const hci_rp_le_read_peer_resolv_addr * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } else if( nullptr != ev_res && HCIStatusCode::SUCCESS != status ) { + peerResolvableAddress = jau::le_to_cpu(ev_res->peer_resolv_addr); + } + return status; +} + +HCIStatusCode HCIHandler::le_read_local_resolv_addr(const BDAddressAndType& peerIdentityAddressAndType, + jau::EUI48& localResolvableAddress) noexcept { + localResolvableAddress.clear(); + HCIStatusCode status; + HCIStructCommand req0(HCIOpcode::LE_READ_LOCAL_RESOLV_ADDR); + hci_cp_le_read_local_resolv_addr * cp = req0.getWStruct(); + cp->peer_id_addr_type = static_cast(peerIdentityAddressAndType.type); + cp->peer_id_addr = jau::cpu_to_le(peerIdentityAddressAndType.address); + const hci_rp_le_read_local_resolv_addr * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } else if( nullptr != ev_res && HCIStatusCode::SUCCESS != status ) { + localResolvableAddress = jau::le_to_cpu(ev_res->local_resolv_addr); + } + return status; +} + +HCIStatusCode HCIHandler::le_set_addr_resolv_enable(const bool enable) noexcept { + HCIStatusCode status; + HCIStructCommand req0(HCIOpcode::LE_SET_ADDR_RESOLV_ENABLE); + hci_cp_le_set_addr_resolv_enable * cp = req0.getWStruct(); + cp->enable = enable ? 0x01 : 0x00; + const hci_rp_status * ev_res; + std::unique_ptr ev = processCommandComplete(req0, &ev_res, &status, true /* quiet */); + if( nullptr == ev || nullptr == ev_res || HCIStatusCode::SUCCESS != status ) { + ERR_PRINT("%s: 0x%x (%s) - %s", to_string(req0.getOpcode()), number(status), to_string(status).c_str(), toString().c_str()); + } + return status; +} + HCIStatusCode HCIHandler::le_read_phy(const uint16_t conn_handle, const BDAddressAndType& peerAddressAndType, LE_PHYs& resTx, LE_PHYs& resRx) noexcept { if( !is_set(le_ll_feats, LE_Features::LE_2M_PHY) ) { diff --git a/src/direct_bt/HCITypes.cpp b/src/direct_bt/HCITypes.cpp index 63c69c7f..d4a78381 100644 --- a/src/direct_bt/HCITypes.cpp +++ b/src/direct_bt/HCITypes.cpp @@ -199,6 +199,13 @@ std::string to_string(const HCIOGF op) noexcept { X(LE_ENABLE_ENC) \ X(LE_LTK_REPLY_ACK) \ X(LE_LTK_REPLY_REJ) \ + X(LE_ADD_TO_RESOLV_LIST) \ + X(LE_DEL_FROM_RESOLV_LIST) \ + X(LE_CLEAR_RESOLV_LIST) \ + X(LE_READ_RESOLV_LIST_SIZE) \ + X(LE_READ_PEER_RESOLV_ADDR) \ + X(LE_READ_LOCAL_RESOLV_ADDR) \ + X(LE_SET_ADDR_RESOLV_ENABLE) \ X(LE_READ_PHY) \ X(LE_SET_DEFAULT_PHY) \ X(LE_SET_PHY) \ -- cgit v1.2.3