diff options
author | Sven Gothel <[email protected]> | 2020-11-23 16:45:16 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-11-23 16:45:16 +0100 |
commit | 652e3fc523ac62abddc1afba8468ac601a153464 (patch) | |
tree | 577d68c4284a2431720acf7d9f1177e4d581acb7 /src | |
parent | bb51c620dac82f4b0fb7769a7cdeafc2dc6f77cd (diff) |
Enc/Auth: Allow full PairingMode modulation via BTSecurityLevel and 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.
....
Diffstat (limited to 'src')
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 138 | ||||
-rw-r--r-- | src/direct_bt/DBTDevice.cpp | 141 |
2 files changed, 218 insertions, 61 deletions
diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp index bcc23d17..8d8da919 100644 --- a/src/direct_bt/DBTAdapter.cpp +++ b/src/direct_bt/DBTAdapter.cpp @@ -201,7 +201,9 @@ bool DBTAdapter::validateDevInfo() noexcept { ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::CONNECT_FAILED, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvConnectFailedHCI)) && ok; ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::DEVICE_DISCONNECTED, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvDeviceDisconnectedHCI)) && ok; ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::DEVICE_FOUND, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvDeviceFoundHCI)) && ok; - ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::LE_REMOTE_USER_FEATURES, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvLERemoteUserFeaturesHCI)) && ok; + ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::HCI_LE_REMOTE_USR_FEATURES, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvHCILERemoteUserFeaturesHCI)) && ok; + ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::HCI_ENC_CHANGED, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvHCIEncryptionChangedHCI)) && ok; + ok = hci.addMgmtEventCallback(MgmtEvent::Opcode::HCI_ENC_KEY_REFRESH_COMPLETE, jau::bindMemberFunc(this, &DBTAdapter::mgmtEvHCIEncryptionKeyRefreshCompleteHCI)) && ok; if( !ok ) { ERR_PRINT("Could not add all required MgmtEventCallbacks to HCIHandler: %s of %s", hci.toString().c_str(), toString().c_str()); @@ -309,6 +311,12 @@ void DBTAdapter::poweredOff() noexcept { hci.setCurrentScanType(ScanType::NONE); currentMetaScanType = ScanType::NONE; + // ensure all hci states are reset. + hci.clearAllStates(); + + io_capability_defaultval = SMPIOCapability::UNSET; + io_capability_device_ptr = nullptr; + DBG_PRINT("DBTAdapter::poweredOff: XXX"); } @@ -332,20 +340,74 @@ std::shared_ptr<NameAndShortName> DBTAdapter::setLocalName(const std::string &na } bool DBTAdapter::setDiscoverable(bool value) noexcept { - AdapterSetting current_settings; + AdapterSetting current_settings { AdapterSetting::NONE } ; return MgmtStatus::SUCCESS == mgmt.setDiscoverable(dev_id, value ? 0x01 : 0x00, 10 /* timeout seconds */, current_settings); } bool DBTAdapter::setBondable(bool value) noexcept { - AdapterSetting current_settings; + AdapterSetting current_settings { AdapterSetting::NONE } ; return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, value ? 1 : 0, current_settings); } bool DBTAdapter::setPowered(bool value) noexcept { - AdapterSetting current_settings; + AdapterSetting current_settings { AdapterSetting::NONE } ; return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, value ? 1 : 0, current_settings); } +bool DBTAdapter::setConnIOCapability(const DBTDevice & device, const SMPIOCapability io_cap, const bool blocking) noexcept { + const DBTDevice * exp_null_device = nullptr; // C++11, exp as value since C++20 + const uint32_t timeout_ms = 10000; // FIXME: Configurable? + const uint32_t poll_period_ms = 125; + uint32_t td = 0; + while( !io_capability_device_ptr.compare_exchange_strong(exp_null_device, &device) ) { + if( blocking ) { + if( timeout_ms <= td ) { + return false; + } + std::this_thread::sleep_for(std::chrono::milliseconds(poll_period_ms)); + td += poll_period_ms; + } else { + return false; + } + } + SMPIOCapability o; + const bool res = mgmt.setIOCapability(dev_id, io_cap, o); + DBG_PRINT("DBTAdapter::setConnIOCapability: result %d: %s -> %s, %s", + res, getSMPIOCapabilityString(o).c_str(), getSMPIOCapabilityString(io_cap).c_str(), + device.toString(false).c_str()); + if( res ) { + io_capability_defaultval = o; + return true; + } else { + io_capability_device_ptr = nullptr; + return false; + } +} + +bool DBTAdapter::resetConnIOCapability(const DBTDevice & device) noexcept { + SMPIOCapability pre_io_cap { SMPIOCapability::UNSET }; + return resetConnIOCapability(device, pre_io_cap); +} + +bool DBTAdapter::resetConnIOCapability(const DBTDevice & device, SMPIOCapability& pre_io_cap) noexcept { + if( nullptr != io_capability_device_ptr && device == *io_capability_device_ptr ) { + const SMPIOCapability v = io_capability_defaultval; + io_capability_defaultval = SMPIOCapability::UNSET; + io_capability_device_ptr = nullptr; + SMPIOCapability o; + const bool res = mgmt.setIOCapability(dev_id, v, o); + DBG_PRINT("DBTAdapter::resetConnIOCapability: result %d: %s -> %s, %s", + res, getSMPIOCapabilityString(o).c_str(), getSMPIOCapabilityString(v).c_str(), + device.toString(false).c_str()); + if( res ) { + pre_io_cap = o; + } + return res; + } else { + return false; + } +} + HCIStatusCode DBTAdapter::reset() noexcept { if( !isValid() ) { ERR_PRINT("DBTAdapter::reset(): Adapter invalid: %s, %s", aptrHexString(this).c_str(), toString().c_str()); @@ -704,6 +766,7 @@ void DBTAdapter::removeDevice(DBTDevice & device) noexcept { WORDY_PRINT("DBTAdapter::removeDevice: Start %s", toString(false).c_str()); const HCIStatusCode status = device.disconnect(HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION); WORDY_PRINT("DBTAdapter::removeDevice: disconnect %s, %s", getHCIStatusCodeString(status).c_str(), toString(false).c_str()); + resetConnIOCapability(device); removeConnectedDevice(device); // usually done in DBTAdapter::mgmtEvDeviceDisconnectedHCI removeDiscoveredDevice(device); // usually done in DBTAdapter::mgmtEvDeviceDisconnectedHCI WORDY_PRINT("DBTAdapter::removeDevice: End %s", toString(false).c_str()); @@ -947,6 +1010,8 @@ bool DBTAdapter::mgmtEvDeviceConnectedHCI(std::shared_ptr<MgmtEvent> e) noexcept new_connect = 3; } + const SMPIOCapability io_cap_conn = mgmt.getIOCapability(dev_id); + EIRDataType updateMask = device->update(ad_report); if( addConnectedDevice(device) ) { // track device, if not done yet if( 0 == new_connect ) { @@ -970,7 +1035,7 @@ bool DBTAdapter::mgmtEvDeviceConnectedHCI(std::shared_ptr<MgmtEvent> e) noexcept device->toString().c_str()); } - device->notifyConnected(device, event.getHCIHandle()); + device->notifyConnected(device, event.getHCIHandle(), io_cap_conn); int i=0; jau::for_each_cow(statusListenerList, [&](std::shared_ptr<AdapterStatusListener> &l) { @@ -1004,6 +1069,7 @@ bool DBTAdapter::mgmtEvConnectFailedHCI(std::shared_ptr<MgmtEvent> e) noexcept { dev_id, event.toString().c_str(), jau::uint16HexString(handle).c_str(), device->toString().c_str()); + resetConnIOCapability(*device); device->notifyDisconnected(); removeConnectedDevice(*device); @@ -1028,8 +1094,8 @@ bool DBTAdapter::mgmtEvConnectFailedHCI(std::shared_ptr<MgmtEvent> e) noexcept { return true; } -bool DBTAdapter::mgmtEvLERemoteUserFeaturesHCI(std::shared_ptr<MgmtEvent> e) noexcept { - const MgmtEvtLERemoteUserFeatures &event = *static_cast<const MgmtEvtLERemoteUserFeatures *>(e.get()); +bool DBTAdapter::mgmtEvHCILERemoteUserFeaturesHCI(std::shared_ptr<MgmtEvent> e) noexcept { + const MgmtEvtHCILERemoteUserFeatures &event = *static_cast<const MgmtEvtHCILERemoteUserFeatures *>(e.get()); std::shared_ptr<DBTDevice> device = findConnectedDevice(event.getAddress(), event.getAddressType()); if( nullptr != device ) { @@ -1045,6 +1111,31 @@ bool DBTAdapter::mgmtEvLERemoteUserFeaturesHCI(std::shared_ptr<MgmtEvent> e) noe return true; } +bool DBTAdapter::mgmtEvHCIEncryptionChangedHCI(std::shared_ptr<MgmtEvent> e) noexcept { + const MgmtEvtHCIEncryptionChanged &event = *static_cast<const MgmtEvtHCIEncryptionChanged *>(e.get()); + + std::shared_ptr<DBTDevice> device = findConnectedDevice(event.getAddress(), event.getAddressType()); + if( nullptr != device ) { + device->updatePairingState(device, SMPPairingState::PROCESS_COMPLETED, e); + } else { + WORDY_PRINT("DBTAdapter::EventHCI:EncryptionChanged(dev_id %d): Device not tracked: %s", + dev_id, event.toString().c_str()); + } + return true; +} +bool DBTAdapter::mgmtEvHCIEncryptionKeyRefreshCompleteHCI(std::shared_ptr<MgmtEvent> e) noexcept { + const MgmtEvtHCIEncryptionKeyRefreshComplete &event = *static_cast<const MgmtEvtHCIEncryptionKeyRefreshComplete *>(e.get()); + + std::shared_ptr<DBTDevice> device = findConnectedDevice(event.getAddress(), event.getAddressType()); + if( nullptr != device ) { + device->updatePairingState(device, SMPPairingState::PROCESS_COMPLETED, e); + } else { + WORDY_PRINT("DBTAdapter::EventHCI:EncryptionKeyRefreshComplete(dev_id %d): Device not tracked: %s", + dev_id, event.toString().c_str()); + } + return true; +} + bool DBTAdapter::mgmtEvDeviceDisconnectedHCI(std::shared_ptr<MgmtEvent> e) noexcept { const MgmtEvtDeviceDisconnected &event = *static_cast<const MgmtEvtDeviceDisconnected *>(e.get()); @@ -1059,6 +1150,7 @@ bool DBTAdapter::mgmtEvDeviceDisconnectedHCI(std::shared_ptr<MgmtEvent> e) noexc dev_id, event.toString().c_str(), jau::uint16HexString(event.getHCIHandle()).c_str(), device->toString().c_str()); + resetConnIOCapability(*device); device->notifyDisconnected(); removeConnectedDevice(*device); @@ -1215,15 +1307,8 @@ bool DBTAdapter::mgmtEvUserConfirmRequestMgmt(std::shared_ptr<MgmtEvent> e) noex event.toString().c_str()); return true; } - // FIXME: Pass confirm_hint and value - const SMPPairingState pstate = SMPPairingState::NUMERIC_COMPARE_EXPECTED; - - DBG_PRINT("DBTAdapter:mgmt:SMP: dev_id %d: address[%s, %s]: state %s, %s", - dev_id, event.getAddress().toString().c_str(), getBDAddressTypeString(event.getAddressType()).c_str(), - getSMPPairingStateString(pstate).c_str(), - event.toString().c_str()); - - updatePairingState(device, pstate, e->getTimestamp()); + // FIXME: Pass confirm_hint and value? + device->updatePairingState(device, SMPPairingState::NUMERIC_COMPARE_EXPECTED, e); return true; } bool DBTAdapter::mgmtEvUserPasskeyRequestMgmt(std::shared_ptr<MgmtEvent> e) noexcept { @@ -1236,29 +1321,10 @@ bool DBTAdapter::mgmtEvUserPasskeyRequestMgmt(std::shared_ptr<MgmtEvent> e) noex event.toString().c_str()); return true; } - const SMPPairingState pstate = SMPPairingState::PASSKEY_EXPECTED; - - DBG_PRINT("DBTAdapter:mgmt:SMP: dev_id %d: address[%s, %s]: state %s, %s", - dev_id, event.getAddress().toString().c_str(), getBDAddressTypeString(event.getAddressType()).c_str(), - getSMPPairingStateString(pstate).c_str(), - event.toString().c_str()); - - updatePairingState(device, pstate, e->getTimestamp()); + device->updatePairingState(device, SMPPairingState::PASSKEY_EXPECTED, e); return true; } -void DBTAdapter::updatePairingState(std::shared_ptr<DBTDevice> device, const SMPPairingState pstate, uint64_t timestamp) noexcept -{ - PairingMode pmode; - if( device->updatePairingState_locked(pstate, pmode) ) { - sendDevicePairingState(device, pstate, pmode, timestamp); - } else { - WORDY_PRINT("DBTAdapter::updatePairingState: dev_id %d: Unchanged: state %s, %s", dev_id, - getSMPPairingStateString(pstate).c_str(), - device->toString().c_str()); - } -} - bool DBTAdapter::hciSMPMsgCallback(const EUI48& address, BDAddressType addressType, std::shared_ptr<const SMPPDUMsg> msg, const HCIACLData::l2cap_frame& source) noexcept { std::shared_ptr<DBTDevice> device = findConnectedDevice(address, addressType); diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp index 8c5b42a8..c52a9bf3 100644 --- a/src/direct_bt/DBTDevice.cpp +++ b/src/direct_bt/DBTDevice.cpp @@ -142,7 +142,8 @@ std::string DBTDevice::toString(bool includeDiscoveredServices) const noexcept { std::string out("Device[address["+getAddressString()+", "+getBDAddressTypeString(getAddressType())+leaddrtype+"], name['"+name+ "'], age[total "+std::to_string(t0-ts_creation)+", ldisc "+std::to_string(t0-ts_last_discovery)+", lup "+std::to_string(t0-ts_last_update)+ "]ms, connected["+std::to_string(allowDisconnect)+"/"+std::to_string(isConnected)+", handle "+jau::uint16HexString(hciConnHandle)+ - "], security "+getBTSecurityLevelString(pairing_data.sec_level).c_str()+", pairing "+getPairingModeString(pairing_data.mode).c_str()+", rssi "+std::to_string(getRSSI())+ + ", sec[lvl "+getBTSecurityLevelString(pairing_data.sec_level_conn).c_str()+", io "+getSMPIOCapabilityString(pairing_data.ioCap_conn).c_str()+ + ", pairing "+getPairingModeString(pairing_data.mode).c_str()+"]], rssi "+std::to_string(getRSSI())+ ", tx-power "+std::to_string(tx_power)+ ", appearance "+jau::uint16HexString(static_cast<uint16_t>(appearance))+" ("+getAppearanceCatString(appearance)+ "), "+msdstr+", "+javaObjectToString()+"]"); @@ -388,14 +389,17 @@ HCIStatusCode DBTDevice::connectDefault() } } -void DBTDevice::notifyConnected(std::shared_ptr<DBTDevice> sthis, const uint16_t handle) noexcept { +void DBTDevice::notifyConnected(std::shared_ptr<DBTDevice> sthis, const uint16_t handle, const SMPIOCapability io_cap) noexcept { // coming from connected callback, update state and spawn-off connectGATT in background if appropriate (LE) - DBG_PRINT("DBTDevice::notifyConnected: handle %s -> %s, %s", - jau::uint16HexString(hciConnHandle).c_str(), jau::uint16HexString(handle).c_str(), toString().c_str()); + DBG_PRINT("DBTDevice::notifyConnected: handle %s -> %s, io %s -> %s, %s", + jau::uint16HexString(hciConnHandle).c_str(), jau::uint16HexString(handle).c_str(), + getSMPIOCapabilityString(pairing_data.ioCap_conn).c_str(), getSMPIOCapabilityString(io_cap).c_str(), + toString(false).c_str()); clearSMPStates(); allowDisconnect = true; isConnected = true; hciConnHandle = handle; + pairing_data.ioCap_conn = io_cap; (void)sthis; // not used yet } @@ -411,13 +415,20 @@ void DBTDevice::notifyLEFeatures(std::shared_ptr<DBTDevice> sthis, const LEFeatu } void DBTDevice::processL2CAPSetup(std::shared_ptr<DBTDevice> sthis) { - DBG_PRINT("DBTDevice::processL2CAPSetup: %s", toString().c_str()); + // FIXME: Deadlocks SMP process while @ l2cap_att.setBTSecurityLevel() -> SMP + **MGMT::PASSKEY_REQ** -> l2cap_att.connect()-completion, + // i.e. l2cap_att.setBTSecurityLevel() (or its connect() process security callbacks. + // const std::lock_guard<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor + (void)sthis; + DBG_PRINT("DBTDevice::processL2CAPSetup: Start %s", toString(false).c_str()); if( isLEAddressType() && !l2cap_att.isOpen() ) { const bool responderLikesEncryption = pairing_data.res_requested_sec || isLEFeaturesBitSet(le_features, LEFeatures::LE_Encryption); const BTSecurityLevel sec_level_user = pairing_data.sec_level_user; - BTSecurityLevel sec_level = pairing_data.sec_level; + const SMPIOCapability io_cap = pairing_data.ioCap_conn; + BTSecurityLevel sec_level { BTSecurityLevel::UNSET }; if( BTSecurityLevel::UNSET != sec_level_user ) { sec_level = sec_level_user; + } else if( SMPIOCapability::NO_INPUT_NO_OUTPUT == io_cap ) { + sec_level = BTSecurityLevel::ENC_ONLY; // no auth w/o I/O } else { if( responderLikesEncryption && adapter.hasSecureConnections() ) { sec_level = BTSecurityLevel::ENC_AUTH_FIPS; @@ -427,25 +438,26 @@ void DBTDevice::processL2CAPSetup(std::shared_ptr<DBTDevice> sthis) { sec_level = BTSecurityLevel::NONE; } } - const bool l2cap_open = l2cap_att.open(*this); - const bool l2cap_sec = l2cap_open && l2cap_att.setBTSecurityLevel(sec_level); // initiates hciSMPMsgCallback() if sec_level > BT_SECURITY_LOW + pairing_data.sec_level_conn = sec_level; + const bool l2cap_open = l2cap_att.open(*this, sec_level); // initiates hciSMPMsgCallback() if sec_level > BT_SECURITY_LOW + const bool l2cap_auth = l2cap_open && BTSecurityLevel::ENC_ONLY < sec_level; #if SMP_SUPPORTED_BY_OS - const bool smp_sec = connectSMP(sthis, sec_level); + const bool smp_auth = connectSMP(sthis, sec_level) && BTSecurityLevel::ENC_ONLY < sec_level; #else - const bool smp_sec = false; + const bool smp_auth = false; #endif - DBG_PRINT("DBTDevice::processL2CAPSetup: sec_level %s, connect[smp %d, l2cap[open %d, sec %d]], %s", - getBTSecurityLevelString(sec_level).c_str(), smp_sec, l2cap_open, l2cap_sec, toString().c_str()); + DBG_PRINT("DBTDevice::processL2CAPSetup: lvl %s, io %s, connect[smp auth %d, l2cap[open %d, auth %d]]", + getBTSecurityLevelString(sec_level).c_str(), getSMPIOCapabilityString(io_cap).c_str(), + smp_auth, l2cap_open, l2cap_auth); + + adapter.resetConnIOCapability(*this); + if( !l2cap_open ) { + pairing_data.sec_level_conn = BTSecurityLevel::NONE; disconnect(HCIStatusCode::INTERNAL_FAILURE); - } else if( !l2cap_sec && !smp_sec ) { - // No security and hence no SMP dialogue, i.e. hciSMPMsgCallback(): - pairing_data.sec_level = BTSecurityLevel::NONE; - processDeviceReady(sthis, jau::getCurrentMilliseconds()); - } else { - pairing_data.sec_level = sec_level; } } + DBG_PRINT("DBTDevice::processL2CAPSetup: End %s", toString(false).c_str()); } void DBTDevice::processDeviceReady(std::shared_ptr<DBTDevice> sthis, const uint64_t timestamp) { @@ -457,9 +469,15 @@ void DBTDevice::processDeviceReady(std::shared_ptr<DBTDevice> sthis, const uint6 } } -bool DBTDevice::updatePairingState_locked(SMPPairingState state, PairingMode& current_mode) noexcept { +bool DBTDevice::updatePairingState(std::shared_ptr<DBTDevice> sthis, SMPPairingState state, std::shared_ptr<MgmtEvent> evt) noexcept { const std::lock_guard<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor PairingMode mode = pairing_data.mode; + bool is_device_ready = false; + + DBG_PRINT("DBTDevice::updatePairingState.0: state %s -> %s, %s, %s", + getSMPPairingStateString(pairing_data.state).c_str(), getSMPPairingStateString(state).c_str(), + evt->toString().c_str(), toString(false).c_str()); + if( pairing_data.state != state ) { // Potentially force update PairingMode by forced state change, assuming being the initiator. // FIXME: Initiator and responder role might need more specific determination and documentation. @@ -473,15 +491,39 @@ bool DBTDevice::updatePairingState_locked(SMPPairingState state, PairingMode& cu case SMPPairingState::OOB_EXPECTED: mode = PairingMode::OUT_OF_BAND; break; + case SMPPairingState::PROCESS_COMPLETED: + if( BTSecurityLevel::ENC_ONLY >= pairing_data.sec_level_conn ) { + // no auth, done + mode = PairingMode::JUST_WORKS; + is_device_ready = true; + } else { + // requires SMP auth: reset, no change + state = pairing_data.state; + } + break; default: // nop break; } + DBG_PRINT("DBTDevice::updatePairingState.1: state %s -> %s, mode %s -> %s, ready %d", + getSMPPairingStateString(pairing_data.state).c_str(), getSMPPairingStateString(state).c_str(), + getPairingModeString(pairing_data.mode).c_str(), getPairingModeString(mode).c_str(), is_device_ready); + } + + if( pairing_data.state != state ) { pairing_data.mode = mode; pairing_data.state = state; - current_mode = mode; + + adapter.sendDevicePairingState(sthis, state, mode, evt->getTimestamp()); + + if( is_device_ready ) { + std::thread dc(&DBTDevice::processDeviceReady, this, sthis, evt->getTimestamp()); // @suppress("Invalid arguments") + dc.detach(); + } + DBG_PRINT("DBTDevice::updatePairingState.2: Complete: state %s", getSMPPairingStateString(state).c_str()); return true; + } else { + DBG_PRINT("DBTDevice::updatePairingState.3: Unchanged: state %s", getSMPPairingStateString(state).c_str()); } - current_mode = mode; return false; } @@ -499,6 +541,7 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ switch( opc ) { case SMPPDUMsg::Opcode::PAIRING_FAILED: { +#if 0 pmode = PairingMode::NONE; pstate = SMPPairingState::FAILED; pairing_data.res_requested_sec = false; @@ -510,11 +553,14 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ pairing_data.sec_level = sec_level; } const bool l2cap_close = l2cap_att.close(); - const bool l2cap_open = l2cap_att.open(*this); + const bool l2cap_open = l2cap_att.open(*this, sec_level); is_device_ready = l2cap_open; DBG_PRINT("DBTDevice:hci:SMP: l2cap ATT reopen: ready %d, sec_level %s, l2cap[close %d, open %d], %s", is_device_ready, getBTSecurityLevelString(sec_level).c_str(), l2cap_close, l2cap_open, toString(false).c_str()); +#else + pstate = SMPPairingState::FAILED; +#endif } break; @@ -600,10 +646,11 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ return; } - DBG_PRINT("DBTDevice:hci:SMP: address[%s, %s]: state %s -> %s, mode %s -> %s, %s, %s", + DBG_PRINT("DBTDevice:hci:SMP: address[%s, %s]: state %s -> %s, mode %s -> %s, ready %d, %s, %s", address.toString().c_str(), getBDAddressTypeString(addressType).c_str(), getSMPPairingStateString(old_pstate).c_str(), getSMPPairingStateString(pstate).c_str(), getPairingModeString(old_pmode).c_str(), getPairingModeString(pmode).c_str(), + is_device_ready, msg->toString().c_str(), source.toString().c_str()); pairing_data.mode = pmode; @@ -617,6 +664,46 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ } } +bool DBTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level, const bool blocking) noexcept { + DBG_PRINT("DBTDevice::setSecurityLevel: %s -> %s, %s", + getBTSecurityLevelString(pairing_data.sec_level_user).c_str(), + getBTSecurityLevelString(sec_level).c_str(), toString(false).c_str()); + + if( !isValid() || isConnected || allowDisconnect ) { + return false; + } + pairing_data.sec_level_user = sec_level; + + if( BTSecurityLevel::ENC_ONLY >= sec_level && !adapter.isConnIOCapabilitySet() ) + { + // Adjust SMPIOCapability to match the no_auth BTSecurityLevel <= BTSecurityLevel::ENC_ONLY, + // if connect hasn't been issued and setIOCapability() not used yet. + return setConnIOCapability( SMPIOCapability::NO_INPUT_NO_OUTPUT, blocking); + } else { + return true; + } +} + +bool DBTDevice::setConnIOCapability(const SMPIOCapability io_cap, const bool blocking) noexcept { + if( !isValid() || isConnected || allowDisconnect ) { + return false; + } + return adapter.setConnIOCapability(*this, io_cap, blocking); +} + +bool DBTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, const bool blocking) noexcept { + DBG_PRINT("DBTDevice::setConnSecurity: %s -> %s, %s, %s", + getBTSecurityLevelString(pairing_data.sec_level_user).c_str(), + getBTSecurityLevelString(sec_level).c_str(), + getSMPIOCapabilityString(io_cap).c_str(), toString(false).c_str()); + + if( !isValid() || isConnected || allowDisconnect ) { + return false; + } + pairing_data.sec_level_user = sec_level; + return adapter.setConnIOCapability(*this, io_cap, blocking); +} + HCIStatusCode DBTDevice::setPairingPasskey(const uint32_t passkey) noexcept { const std::lock_guard<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor @@ -668,9 +755,12 @@ HCIStatusCode DBTDevice::setPairingNumericComparison(const bool positive) noexce void DBTDevice::clearSMPStates() noexcept { const std::lock_guard<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor - pairing_data.sec_level = BTSecurityLevel::UNSET; - pairing_data.mode = PairingMode::NONE; + pairing_data.ioCap_conn=SMPIOCapability::UNSET; + pairing_data.sec_level_conn = BTSecurityLevel::UNSET; + pairing_data.sec_level_user = BTSecurityLevel::UNSET; + pairing_data.state = SMPPairingState::NONE; + pairing_data.mode = PairingMode::NONE; pairing_data.res_requested_sec = false; pairing_data.authReqs_resp = SMPAuthReqs::NONE; @@ -981,5 +1071,6 @@ exit: } void DBTDevice::remove() noexcept { + clearSMPStates(); adapter.removeDevice(*this); } |