From fc602c4dc6676def5e8b1b936bb84e6e5eda6642 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Sat, 14 Nov 2020 08:20:10 +0100 Subject: Wire HCIACLData::l2cap_frame/SMPPDUMsg from HCIHandler -> DBTAdapter -> DBTDevice incl deduction of SMPPairingState and PairingMode - Added: AdapterStatusListener::devicePairingState(...): Notifying user about a changed PairingState - HCIHandler's HCISMPMsgCallback: Pass HCIACLData::l2cap_frame, allowing final receiver (DBTDevice) to learn about initiator/responder role. - DBTAdapter -- Added Mgmt SMP related callbacks -- Added SMPMsgCallback from HCIHandler, to be forwarded to DBTDevice for actual SMPPairingState handling, tracking state and SMPPDUMsg details. - DBTDevice -- Add API to set/get pairing passkey and numeric comparison -- Expose current SMPPairingState -- DBTDevice hciSMPMsgCallback(..): Track underlying PairingState details, received from HCIHandler -> DBTAdapter -> this, and deduce PairingMode via getPairingMode(..) using both devices AuthReqs, IOCaps and OOBFlag. --- api/direct_bt/DBTAdapter.hpp | 26 ++++++++++- api/direct_bt/DBTDevice.hpp | 108 ++++++++++++++++++++++++++++++++++++------- api/direct_bt/HCIHandler.hpp | 2 +- 3 files changed, 118 insertions(+), 18 deletions(-) (limited to 'api') diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp index 35081820..616a1883 100644 --- a/api/direct_bt/DBTAdapter.hpp +++ b/api/direct_bt/DBTAdapter.hpp @@ -128,6 +128,18 @@ namespace direct_bt { */ virtual void deviceConnected(std::shared_ptr device, const uint16_t handle, const uint64_t timestamp) = 0; + /** + * An already connected DBTDevice's SMPPairingState has changed. + *

+ * If currentMode == PairingMode::NONE, the device is not paired, otherwise it is paired using the given PairingMode. + *

+ * @param device the device which PairingMode has been changed. + * @param state the current SMPPairingState of the connected device, see DBTDevice::getCurrentPairingState() + * @param mode the current PairingMode of the connected device, see DBTDevice::getCurrentPairingMode() + * @param timestamp the time in monotonic milliseconds when this event occurred. See BasicTypes::getCurrentMilliseconds(). + */ + virtual void devicePairingState(std::shared_ptr device, const SMPPairingState state, const PairingMode mode, const uint64_t timestamp) = 0; + /** * DBTDevice got disconnected * @param device the device which has been disconnected with zeroed connection handle. @@ -224,6 +236,7 @@ namespace direct_bt { uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t supervision_timeout); friend HCIStatusCode DBTDevice::connectBREDR(const uint16_t pkt_type, const uint16_t clock_offset, const uint8_t role_switch); + friend void DBTDevice::hciSMPMsgCallback(std::shared_ptr sthis, std::shared_ptr msg, const HCIACLData::l2cap_frame& source) noexcept; friend std::vector> DBTDevice::getGATTServices() noexcept; bool addConnectedDevice(const std::shared_ptr & device) noexcept; @@ -254,7 +267,18 @@ namespace direct_bt { bool mgmtEvDeviceDiscoveringAny(std::shared_ptr e, const bool hciSourced) noexcept; - bool hciSMPMsgCallback(const EUI48& address, BDAddressType addressType, uint16_t handle, std::shared_ptr msg) noexcept; + bool mgmtEvPinCodeRequestMgmt(std::shared_ptr e) noexcept; + bool mgmtEvUserConfirmRequestMgmt(std::shared_ptr e) noexcept; + bool mgmtEvUserPasskeyRequestMgmt(std::shared_ptr e) noexcept; + bool mgmtEvAuthFailedMgmt(std::shared_ptr e) noexcept; + bool mgmtEvDeviceUnpairedMgmt(std::shared_ptr e) noexcept; + + bool updatePairingStateAndMode(std::shared_ptr device, + const SMPPairingState old_pstate, const SMPPairingState new_pstate, + const PairingMode old_pmode, const PairingMode new_pmode, uint64_t timestamp) noexcept; + bool hciSMPMsgCallback(const EUI48& address, BDAddressType addressType, + std::shared_ptr msg, const HCIACLData::l2cap_frame& source) noexcept; + bool sendDevicePairingState(std::shared_ptr device, const SMPPairingState state, const PairingMode mode, uint64_t timestamp) noexcept; void startDiscoveryBackground() noexcept; void checkDiscoveryState() noexcept; diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp index 790522db..1830fd7d 100644 --- a/api/direct_bt/DBTDevice.hpp +++ b/api/direct_bt/DBTDevice.hpp @@ -77,6 +77,19 @@ namespace direct_bt { std::atomic isConnected; std::atomic allowDisconnect; // allowDisconnect = isConnected || 'isConnectIssued' + struct PairingData { + SMPPairingState state; + PairingMode mode; + uint32_t passkey; + SMPAuthReqs authReqs_init, authReqs_resp; + SMPIOCapability ioCap_init, ioCap_resp; + SMPOOBDataFlag oobFlag_init, oobFlag_resp; + uint8_t maxEncsz_init, maxEncsz_resp; + }; + PairingData pairing_data; + std::mutex mtx_pairing; + + DBTDevice(DBTAdapter & adapter, EInfoReport const & r); /** Add advertised service (GAP discovery) */ @@ -94,7 +107,6 @@ namespace direct_bt { void notifyDisconnected() noexcept; void notifyConnected(const uint16_t handle) noexcept; - void notifySMPMsg(std::shared_ptr msg) noexcept; /** * Returns a newly established GATT connection. @@ -107,6 +119,13 @@ namespace direct_bt { */ bool connectGATT() noexcept; + void updatePairingStateAndMode(SMPPairingState state, PairingMode mode) noexcept; + + /** + * Forwarded from HCIHandler -> DBTAdapter -> this DBTDevice + */ + void hciSMPMsgCallback(std::shared_ptr sthis, std::shared_ptr msg, const HCIACLData::l2cap_frame& source) noexcept; + /** * Will be performed within disconnect() and notifyDisconnected(). */ @@ -128,6 +147,8 @@ namespace direct_bt { */ void disconnectSMP(int caller) noexcept; + void clearSMPStates() noexcept; + /** * Will be performed after connectLE(..) via notifyConnected(), * issuing connectSMP() and connectGATT() off thread. @@ -377,38 +398,93 @@ namespace direct_bt { HCIStatusCode disconnect(const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION ) noexcept; /** - * The device is securely paired with PasskeyEntry or JustWorks. + * Method sets the given passkey entry, see PairingMode::PASSKEY_ENTRY. + *

+ * Call this method if the device shall be securely paired with PairingMode::PASSKEY_ENTRY, + * when notified via AdapterStatusListener::devicePairingState(). *

- * The device must be connected before pairing, see connectDefault(). + * If returning HCIStatusCode::SUCCESS, caller shall continue listening to AdapterStatusListener::devicePairingState() + * to wait for either SMPPairingState::PROCESS_COMPLETED or SMPPairingState::FAILED. *

+ * @param passkey used for PairingMode::PASSKEY_ENTRY method. + * Will be encrypted before sending to counter-party. + * + * @return HCIStatusCode::SUCCESS if the command has been accepted, otherwise HCIStatusCode may disclose reason for rejection. + * @see PairingMode + * @see SMPPairingState + * @see AdapterStatusListener::devicePairingState() + * @see setPairingPasskey() + * @see setPairingNumericComparison() + * @see getCurrentPairingMode() + * @see getCurrentPairingState() + */ + HCIStatusCode setPairingPasskey(const uint32_t passkey) noexcept; + + HCIStatusCode setPairingPasskeyNegative() noexcept; + + uint32_t getPairingPasskey() const noexcept; + + /** + * Method sets the numeric comparison result, see PairingMode::NUMERIC_COMPARISON. *

- * If passkey is an empty string, JustWorks method is being used, otherwise PasskeyEntry. + * Call this method if the device shall be securely paired with PairingMode::NUMERIC_COMPARISON, + * when notified via AdapterStatusListener::devicePairingState(). + *

+ * If returning HCIStatusCode::SUCCESS, caller shall continue listening to AdapterStatusListener::devicePairingState() + * to wait for either SMPPairingState::PROCESS_COMPLETED or SMPPairingState::FAILED. *

- * @param passkey optional secret used for PasskeyEntry method. - * Will be encrypted before sending to counterparty. - * Can be an empty string, in which case JustWork method is used. + * @param equal used for PairingMode::NUMERIC_COMPARISON method. + * Will be encrypted before sending to counter-party. * * @return HCIStatusCode::SUCCESS if the command has been accepted, otherwise HCIStatusCode may disclose reason for rejection. + * @see PairingMode + * @see SMPPairingState + * @see AdapterStatusListener::devicePairingState() + * @see setPairingPasskey() + * @see setPairingNumericComparison() + * @see getCurrentPairingMode() + * @see getCurrentPairingState() */ - HCIStatusCode pair(const std::string & passkey); + HCIStatusCode setPairingNumericComparison(const bool equal) noexcept; /** - * Returns a vector of supported PairingMode by the device. + * Returns the current PairingMode used by the device. + *

+ * If the device is not paired, the current mode is PairingMode::NONE. + *

+ *

+ * If the Pairing Feature Exchange is completed, i.e. SMPPairingState::FEATURE_EXCHANGE_COMPLETED, + * as notified by AdapterStatusListener::devicePairingState(), + * the current mode reflects the currently used PairingMode. + *

*

- * The device must be connected before querying this status, see connectDefault(). FIXME? + * In case the Pairing Feature Exchange is in progress, the current mode is PairingMode::NEGOTIATING. *

- * @return vector of supported PairingMode, empty if pairing is not supported. + * @return current PairingMode. + * @see PairingMode + * @see SMPPairingState + * @see AdapterStatusListener::devicePairingState() + * @see setPairingPasskey() + * @see setPairingNumericComparison() + * @see getCurrentPairingMode() + * @see getCurrentPairingState() */ - std::vector getSupportedPairingModes(); + PairingMode getCurrentPairingMode() const noexcept; /** - * Returns a vector of required PairingMode by the device. + * Returns the current SMPPairingState. *

- * The device must be connected before querying this status, see connectDefault(). FIXME? + * If the device is not paired, the current state is SMPPairingState::NONE. *

- * @return vector of required PairingMode, empty if pairing is not required. + * @see PairingMode + * @see SMPPairingState + * @see AdapterStatusListener::devicePairingState() + * @see setPairingPasskey() + * @see setPairingNumericComparison() + * @see getCurrentPairingMode() + * @see getCurrentPairingState() */ - std::vector getRequiredPairingModes(); + SMPPairingState getCurrentPairingState() const noexcept; /** * Disconnects this device via disconnect(..) if getConnected()==true diff --git a/api/direct_bt/HCIHandler.hpp b/api/direct_bt/HCIHandler.hpp index aed5ee08..ed1515e1 100644 --- a/api/direct_bt/HCIHandler.hpp +++ b/api/direct_bt/HCIHandler.hpp @@ -148,7 +148,7 @@ namespace direct_bt { }; typedef jau::FunctionDef> HCISMPMsgCallback; + std::shared_ptr, const HCIACLData::l2cap_frame& /* source */> HCISMPMsgCallback; typedef jau::cow_vector HCISMPMsgCallbackList; /** -- cgit v1.2.3