summaryrefslogtreecommitdiffstats
path: root/src/direct_bt/DBTDevice.cpp
Commit message (Collapse)AuthorAgeFilesLines
* Security: Re-enable auth-failure (try w/o security); Resolve ↵Sven Gothel2020-11-231-27/+23
| | | | | | | | | | | | | | | | | | | L2CAPComm::open() BT_SECURITY deadlock Re-enable auth-failure (try w/o security) from hciSMPMsgCallback() Resolve L2CAPComm::open() BT_SECURITY deadlock - set sec_level after connect() within L2CAPComm::open() - see macro SET_BT_SECURITY_POST_CONNECT in L2CAPComm.cpp - L2CAPComm::setBTSecurityLevel() ignores unchanged BT_SECURITY value. Otherwise it fails on BTSecurityLevel::NONE, don't ask - don't know, even after BlueZ/Kernel review. Working w/ DBTScanner10: - Device w/o security: No special settings in commandline - Device w/ Secure Connection SMP: Only set passkey in commandline - Device w/ legacy encryption only (no auth): Set BTSecurityLevel::ENC_ONLY or SMPIOCapabilities::NO_INPUT_NO_OUTPUT or both.
* Enc/Auth: Allow full PairingMode modulation via BTSecurityLevel and ↵Sven Gothel2020-11-231-25/+116
| | | | | | | | | | | | | | | | | | | | SMPIOCapability: Like force JUST_WORKS by BTSecurityLevel::ENC_ONLY or SMPIOCapability::NO_INPUT_NO_OUTPUT To allow non-auth encryption mode, user _must_ set BTSecurityLevel, SMPIOCapability or both appropriately. Otherwise BlueZ/Kernel will chose authenticated SMP negotiation. - DBTDevice::setConnSecurityLevel(): Will adjust SMPIOCapability automatically, if not yet set - DBTDevice::setConnIOCapability() and DBTDevice::setConnSecurity(): Perform plain setting - DBTDevice::processL2CAPSetup(): Sets BTSecurityLevel appropriately either if no-auth SMPIOCapability::NO_INPUT_NO_OUTPUT is chosen, or based on LE_Enc feature bit and/or SC capability. Using new HCI ENCRYPT_CHANGE and ENCRYPT_KEY_REFRESH_COMPLETE, for non-auth BTSecurityLevel::ENC_ONLY endpoint to set SMPPairingState::PROCESS_COMPLETED + PairingMode::JUST_WORKS. Note: In the non-auth legacy mode, the SMP (ACL.SMP) is not being used. ....
* DBTDevice: [DBG,ERR,..]_PRINT: Use toString(false) instead toString(), skip ↵Sven Gothel2020-11-231-41/+41
| | | | UUID output for more brief debug output
* DBTDevice toString(): Add BTSecurityLevelSven Gothel2020-11-211-1/+1
|
* Use new BTSecurityLevel instead of uint8_t BT_SECURITY value; DBTDevice: Add ↵Sven Gothel2020-11-191-14/+30
| | | | [set|get]SecurityLevel() using BTSecurityLevel, overriding auto-determined mode.
* DBTDevice::updatePairingState_locked(): Add FIXME note about PairingMode ↵Sven Gothel2020-11-171-1/+2
| | | | force update (initiator role)
* DBTDevice::updatePairingState_locked(..): Potentially force update ↵Sven Gothel2020-11-171-1/+18
| | | | PairingMode by forced state change (PASSKEY*, NUMERIC_COMPARE*, OOB*)
* Native/Java: Adjust PairingMode/State enum naming in code and API doc; Fix ↵Sven Gothel2020-11-171-1/+1
| | | | | | | *Device::setPairingPasskey(..) and setPairingNumericComparison(..) API doc (act upon state) PairingState::NUMERIC_COMPARISON_EXPECTED -> NUMERIC_COMPARE_EXPECTED and use PairingMode::PASSKEY_ENTRY_ini, PairingMode::NUMERIC_COMPARE_ini in API doc.
* Fix minor compiler error: DBTScanner10.java: complete using ↵Sven Gothel2020-11-171-0/+2
| | | | executeOffThread(..) editing; SMPHandler: Avoid unused arguments
* Align SMPHandler::establishSecurity(..), DBTDevice::connectSMP(..) with ↵Sven Gothel2020-11-171-15/+13
| | | | | | | | | | L2CAPComm::setBTSecurityLevel() for DBTDevice::processL2CAPSetup() sec_level > BT_SECURITY_LOW is now required to start security negotiation (not just > 0), matching BT_SECURITY API. This change aligns the tentative SMPHandler and conditionally disabled code with current state. SMPHandler::establishSecurity(..) needs to be implemented for non BlueZ platforms or when SMP is accessible under BlueZ.
* L2CAPComm::setBTSecurityLevel() only returns true if sec_level > 0 setting ↵Sven Gothel2020-11-171-6/+6
| | | | was successful! DBTDevice::processL2CAPSetup: Direct processDeviceReady() if !l2cap_Sec
* DBTDevice.cpp: Add comment re setBTSecurityLevel() -> hciSMPMsgCallback()Sven Gothel2020-11-161-2/+2
|
* DBTDevice::hciSMPMsgCallback(): Remove dead-code case do_disconnectSven Gothel2020-11-161-4/+0
|
* DBTDevice.cpp: Just move notifyDisconnect(), disconnect() and remove() to ↵Sven Gothel2020-11-161-88/+88
| | | | EOF, more lifecycle/reading-order aligned.
* DBTDevice: Document workflow from connect -> ready. Add processDeviceReady() ↵Sven Gothel2020-11-161-16/+14
| | | | w/o security directly from processL2CAPSetup()
* DBTDevice::processNotifyConnected() -> processL2CAPSetup(), which also uses ↵Sven Gothel2020-11-161-7/+8
| | | | | | | | | the now tracked 'responder requested security' SMP hint. 'const bool responderLikesEncryption = pairing_data.res_requested_sec || isLEFeaturesBitSet(le_features, LEFeatures::LE_Encryption)' takes into account the responder device desire for security/encryption as expressed via SMPPDUMsg::Opcode::SECURITY_REQUEST.
* DBTDevice: Handle l2cap open/security within processNotifyConnected thread, ↵Sven Gothel2020-11-161-41/+31
| | | | | | | | | | spawn-off @ notifyLEFeatures, using LEFeatures::LE_Encryption - Move set BT_SECURITY from DBTManager -> L2CAPComm. Notable: setBTSecurityLevel(level) shall happen _after_ l2cap open and connect! - Performing l2cap handling after LE_REMOTE_USER_FEATURES allows us to turn-off security completely, if remote device does not support LE_Encryption.
* AdapterStatusListener add deviceReady(..) giving a clear 'start to use' ↵Sven Gothel2020-11-151-17/+81
| | | | | | | | | | | | | | | | | | event; Wire HCI LE_REMOTE_USER_FEATURES -> DBTDevice; .. - DBTAdapter/Device: updatePairingStateAndMode() -> updatePairingState(), simplifying locked access - DBTDevice::notifyConnected: Set BT_SECURITY w/ a sec_level on l2cap_att socket - hciSMPMsgCallback: -- FAIL: reopen l2cap_att (remove security settings) and try without security/encryption -- issue deviceReady(..) if appropriate - Adapt dbt_scanner10 example to deviceReady(..) - TODO: -- AdapterStatusListener::deviceReady(..) forwarding to Java -- Validate GATT operation on encryption
* L2CAPComm: Allow multiple open/close cycles during lifetime, required to ↵Sven Gothel2020-11-151-6/+32
| | | | | | | | re-establish l2cap channel on changed security/encryption - DBTDevice -- Aggregating L2CAPComm instance, open/close and passing to GATTHandler -- add LEFeatures le_features field, incl notify update hook
* DBTDevice: lock-free 'getCurrentPairing[Mode|State]()' -> ↵Sven Gothel2020-11-151-20/+0
| | | | 'getPairing[Mode|State]()'; Don't store passkey.
* Wire HCIACLData::l2cap_frame/SMPPDUMsg from HCIHandler -> DBTAdapter -> ↵Sven Gothel2020-11-141-12/+183
| | | | | | | | | | | | | | | | | | | | 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.
* Generalize SMPMsg: HCISMPSecurityReqCallbackList -> HCISMPMsgCallbackList ↵Sven Gothel2020-11-111-1/+5
| | | | (access all) and forward to matching DBTDevice
* HCITypes.hpp: Add HCIACLData incl l2cap_frame providing potential SMPPDUMsg ↵Sven Gothel2020-11-111-6/+0
| | | | | | | | | | | | | (SMP) incl. facility in HCIHandler (read and callbacks) As noted in commit 6f3e08562f4f990b579ff2540d25dac06beea15a, we can't connect directly to the L2CAP/SMP channel. However, it is possible to access the SMP messages through the HCI layer, grabing the ACL Data's L2CAP packets. The latter may expose an SMP (via CID). This finally allows us to put our SMPPDUMsg to use and hence provide a HCISMPSecurityReqCallback facility in HCIHandler.
* SMPHandler: Add define SMP_SUPPORTED_BY_OS and have DBTDevice exclude ↵Sven Gothel2020-11-081-1/+10
| | | | compilation/usage if false, removing costs.
* Adding tentative SMPHandler (WIP for non Linux/BlueZ platforms or when ↵Sven Gothel2020-11-081-14/+76
| | | | | | | | | | | | | | | | supported) On our current target platform Linux/BlueZ, access to the existing SMP implementation via L2CAP (socket) is sadly prohibited. Linux/BlueZ currently only allows L2CAP sockets for LE devices for the ATT protocol, determined by L2CAP_CID_ATT. Therefor we have to use Linux/BlueZ manager control channel's API to access the SMP implementation. However, the SMPHandler and used SMPPDUMsg types may be used on other platforms. Hence implementation shall be completed for these later on.
* Refine/add state queries in [DBT|Bluetooth]Adapter, BluetoothManagerSven Gothel2020-10-251-9/+9
| | | | | | | | | | | | | | | | [DBT|Bluetooth]Adapter: C++ and Java: Redefine/add state queries: - isValid(): true if this adapter references are valid and hasn't been DBTAdapter::close() 'ed - isPowered(): true if DBTAdapter::isValid(), HCIHandler::isOpen() and AdapterSetting::POWERED state is set - isSuspended(): true if DBTAdapter::isValid(), HCIHandler::isOpen() and AdapterSetting::POWERED state is not set - dev_id / getDevID(): Added definition, added method + implementation to Java BluetoothAdapter: Java - getPowered() -> getPoweredState() - to differentiate with isPowered() BluetoothManager: Java - getAdapter(dev_id) added - setDefaultAdapter(..) implementation removed in DBTManager -> nonsense - getDefaultAdapter(): DBT: Return 1st isPowered() adapter (redfinition, aligned with C++)
* More graceful takedown @ powered-off: Don't attempt futile HCI disconnect ↵Sven Gothel2020-10-231-2/+7
| | | | | | (DBTDevice) or stopDiscovery (DBTAdapter) commands Note: stopDiscovery and disconnected events will be sent!
* DBTDevice: Have shared GattGenericAccessSvc owned by GATTHandler, similar to ↵Sven Gothel2020-10-191-3/+8
| | | | services.
* DBTDevice::dtor: Don't recurse back into remove() -> adapter removeDevice(), ↵Sven Gothel2020-10-191-1/+0
| | | | | | | | that is how it potentially has been deleted! This fix also gives us the opportunity back to use a simple mutex for mtx_sharedDevices. Also add dedicated close() for better leak testing.
* DBTDevice/DBTAdapter: Move WORDY_PRINT to adapter::removeDevice(..)Sven Gothel2020-10-181-2/+0
|
* Extract common C++ Support Library inclusive Java JNI Binding to sub-project ↵Sven Gothel2020-10-161-16/+16
| | | | jaucpp, namespace jau
* HCIHandler::[le_]create_conn(): Wait for pending DISCONN_COMPLETE, which ↵Sven Gothel2020-10-151-12/+0
| | | | | | | | | | | | | | | | | caused sporadic CONNECTION_ALREADY_EXISTS connection failures Since direct_bt's DBTDevice::disconnect() does not wait for DISCONN_COMPLETE, so might a user application not wait. A 'too fast' [le_]create_conn attempt while DISCONN_COMPLETE has not been received yet from a pending disconnect call, leads to CONNECTION_ALREADY_EXISTS failure. This change tracks the pending disconnect commands and waits up to HCI_COMMAND_COMPLETE_REPLY_TIMEOUT (10s default) for receiving the DISCONN_COMPLETE. Resolved the sporadic issue testing with cpp and java scanner10, e.g.: "../scripts/run-dbt_scanner10.sh -disconnect -count 10 -quiet -mac C0:26:DA:01:DA:B1"
* DBTDevice::remove()/DBTAdapter::removeDevice(): Add some WORDY_PRINT(..)Sven Gothel2020-10-151-0/+2
|
* DBTDevice::disconnectGATT: Show caller in DBG_PRINTSven Gothel2020-10-151-5/+5
|
* DBTAdapter Cleanup: Use aggregated HCIHandler @ ctor; Use default adapter ↵Sven Gothel2020-10-141-12/+12
| | | | semantics (1st POWERED)
* DBTDevice: Remove redundant 'toString()' in DBT_PRINT and exception.Sven Gothel2020-10-131-4/+4
|
* helgrind 'lock order': DBTDevice: Don't abuse mtx_connect in ↵Sven Gothel2020-10-071-56/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | notify[Connected|Disconnected]() callbacks or in GATTHandler lifecycle GATTHandler lifecycle has its own minimal mutex, mtx_gattHandler, no more [ab]using mtx_connect. To avoid 'lock order' issues and hence potential deadlocks: - GATTHandler construction happens now via connectGATT() into notifyConnect off-thread for LE devices. - GATTHandler disconnectGATT() happens at disconnect() upfront above the mtx_connect lock or at notifyDisconnect() the latest. - notify[Connected|Disconnected]() callbacks don't hold mtx_connect, as they only set atomic flags and notifyConnected() may issue connectGATT() off-thread (see above) Have allowDisconnect before isConnected in notify[Connected|Disconnected](), as it is queried before. Have disconnectGATT() be called last in notifyDisconnected(), as allowDisconnect and isConnected have precedent and connectGATT() queries both to avoid ctor attempt if not connected or disconnecting. getGATTService() and pingGATT() now just use getGATTHandler(), implemented merely as 'user methods', either the GATTHandler was created at notifyConnected() and hence exists or not. connectGATT(): Add noexcept as GATTHandler ctor is also noexcept; also don't throw an exception. This renders connectGATT() suitable to be excecuted off-thread.
* DBTAdapter, Device, HCIHandler: SEND (manual) EVENTs off-thread, mimic ↵alt_sendeventSven Gothel2020-09-261-6/+5
| | | | normal event delivered via HCIHandler's reader thread
* DBTDevice, GATTHandler, ..: Ensure take-down (dtor, disconnect, remove*) ↵Sven Gothel2020-09-251-15/+10
| | | | | | | | code path is fully noexcept. Note that the default dtor is noexcept by specification since C++11. GATTService and childs were marked noexcept earlier.
* DBTDevice::disconnect(): Remove arg 'ioErrorCause'. This is the final ↵Sven Gothel2020-09-251-14/+14
| | | | | | | cleanup from the self-inflicted disconnect event lag due to huge supervisor timeout Note that this patch won't compile, as 'noexcept' has been introduced, which will be reflected in the followp commit (ensure instance 'take down' is on 'noexcept' code path).
* GATTNumbers: Concluding review: API doc, better naming, have optional data ↵Sven Gothel2020-09-241-2/+2
| | | | and erroneous missing data handle nicely (no crash)
* DBTDevice::disconnect(): Simplification, !isConnected is OK, only send event ↵Sven Gothel2020-09-241-29/+39
| | | | | | | | | | | | on HCIStatusCode error; decouple notifyDisconnect() Have notifyDisconnect() cleanup itself, no abusing disconnect(). !isConnected is OK, b/c a disconnect event could have come before the user issuance. Only send event on HCIStatusCode error, not on 'ioErrorCause' (WIP, testing - supervision timeout related). After proving 'ioErrorCause' has no impact anymore, we shall drop it from method.
* HCIHandler::disconnect(): Drop notion of 'ioErrorCause' as it is no more ↵Sven Gothel2020-09-241-1/+1
| | | | used, moved up to DBTDevice::disconnect()
* HCIHandler::disconnect: Move 'manual' sending of last-resort disconnected ↵Sven Gothel2020-09-231-6/+8
| | | | event to caller (DBTDevice) to cover HCIHandler == nullptr (power-off)
* DBTDevice::disconnect: Send MgmtEvtDeviceDisconnected to adapter if HCI is ↵Sven Gothel2020-09-231-0/+6
| | | | already dead (powered-off)
* LE Secure Connections: Initial API to support secure pairing with varying ↵Sven Gothel2020-09-221-0/+15
| | | | | | | | | | | PairingModes (C++, Java) For now, DBTDevice has a NOP implementation, i.e. returning zero length vectors (or arrays in Java) for supported and required PairingMode. The pair(String passkey) simply returns HCIStatusCode::INTERNAL_FAILURE; Intention is to validate the new API entry with our application.
* DBTDevice::getGATTServices() noexcept: Much catch potential exception from ↵Sven Gothel2020-09-191-4/+9
| | | | | | | GATTHandler::discoverCompletePrimaryServices(..) avoiding abort DBTDevice::getGATTServices() noexcept: API doc says, "returns an empty list if an error occurred". .
* Fix GATT* Object relationship incl weak back-reference (GATTHandler was ↵Sven Gothel2020-09-191-1/+1
| | | | | | | | | | | | | | | | | | skipped >= GATTService); GATTHandler owned by DBTDevice, always. GATTService and childs might need access to their GATTHandler, not just DBTDevice. This relationship always existed, but was skipped. Also emphasize that GATTHandler is always owned by DBTDevice, hence has a weak back-reference to the same. Fixed in ATTPDUTypes C++ Direct-BT API doc overview. Further impact: - GATTService has a weak back-reference to GATTHandler instead of DBTDevice, DBTDevice reference will then be picked up from GATTHandler, the usual. - GATTHandler::discoverPrimaryServices(..), discoverCompletePrimaryServices(..) needs to receive GATTHandler's shared_ptr from owner and caller to build the back-reference in GATTService
* C++ direct_bt: Fix throw expressionsSven Gothel2020-09-191-1/+1
| | | | | | Validated all 'throw ' expressions within src/ java/jni/ test/ examples/. We are not Java here - duh! :)
* DBTDevice: pingGATT and getGATTServices handle exceptions, hence mark both ↵Sven Gothel2020-09-181-1/+1
| | | | 'noexcept'