diff options
author | 2022-07-01 15:49:06 +0000 | |
---|---|---|
committer | 2022-07-15 21:27:20 +0000 | |
commit | e3929d792d50f701cbaf24d70a0f72a02c63f2d1 (patch) | |
tree | 72437c0ac5759406b7b0faf3f0308272e50019ba | |
parent | 82b06cbec63d2f437a75e1bc929014553d16888b (diff) |
eatt: Handle L2CAP collision on EATT
When Android is a Central and collision is detected, Android will
send another request to the remote device after local request is
completed.
If Android is a Peripheral, it will let Central to setup EATT, however
for PTS test case, it will handle collision assumint local CID limit
equal 5.
This can be enabled with
PTS_EattPeripheralCollionSupport=true
Bug: 236216322
Bug: 237746679
Test: atest BluetoothInstrumentationTests
Test: PTS
Tag: #stability
Change-Id: Iada26e11de5b1e2631389e280417a4616d3795cd
-rw-r--r-- | system/conf/bt_stack.conf | 3 | ||||
-rw-r--r-- | system/internal_include/stack_config.h | 1 | ||||
-rw-r--r-- | system/main/stack_config.cc | 8 | ||||
-rw-r--r-- | system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc | 3 | ||||
-rw-r--r-- | system/profile/avrcp/tests/avrcp_device_test.cc | 3 | ||||
-rw-r--r-- | system/stack/Android.bp | 3 | ||||
-rw-r--r-- | system/stack/eatt/eatt.cc | 6 | ||||
-rw-r--r-- | system/stack/eatt/eatt_impl.h | 126 | ||||
-rw-r--r-- | system/stack/test/btm/stack_btm_test.cc | 3 | ||||
-rw-r--r-- | system/stack/test/eatt/eatt_test.cc | 17 | ||||
-rw-r--r-- | system/stack/test/gatt/mock_gatt_utils_ref.cc | 3 | ||||
-rw-r--r-- | system/stack/test/gatt/stack_gatt_test.cc | 2 | ||||
-rw-r--r-- | system/stack/test/stack_smp_test.cc | 3 | ||||
-rw-r--r-- | system/test/common/stack_config.cc | 3 |
14 files changed, 151 insertions, 33 deletions
diff --git a/system/conf/bt_stack.conf b/system/conf/bt_stack.conf index 785b2919aa..942dfdcd1e 100644 --- a/system/conf/bt_stack.conf +++ b/system/conf/bt_stack.conf @@ -53,6 +53,9 @@ TRC_HID_DEV=2 # Start EATT on unecrypted link #PTS_ConnectEattUnencrypted=true +# Force EATT implementation to connect EATT as a peripheral for collision test case +#PTS_EattPeripheralCollionSupport=true + # Disable BR/EDR discovery after LE pairing to avoid cross key derivation errors #PTS_DisableSDPOnLEPair=true diff --git a/system/internal_include/stack_config.h b/system/internal_include/stack_config.h index a3d185dc60..53dd186a70 100644 --- a/system/internal_include/stack_config.h +++ b/system/internal_include/stack_config.h @@ -37,6 +37,7 @@ typedef struct { bool (*get_pts_connect_eatt_unconditionally)(void); bool (*get_pts_connect_eatt_before_encryption)(void); bool (*get_pts_unencrypt_broadcast)(void); + bool (*get_pts_eatt_peripheral_collision_support)(void); config_t* (*get_all)(void); } stack_config_t; diff --git a/system/main/stack_config.cc b/system/main/stack_config.cc index e805cf7e90..90c293ed0f 100644 --- a/system/main/stack_config.cc +++ b/system/main/stack_config.cc @@ -38,6 +38,8 @@ const char* PTS_CONNECT_EATT_UNCONDITIONALLY = "PTS_ConnectEattUncondictionally"; const char* PTS_CONNECT_EATT_UNENCRYPTED = "PTS_ConnectEattUnencrypted"; const char* PTS_BROADCAST_UNENCRYPTED = "PTS_BroadcastUnencrypted"; +const char* PTS_EATT_PERIPHERAL_COLLISION_SUPPORT = + "PTS_EattPeripheralCollionSupport"; static std::unique_ptr<config_t> config; } // namespace @@ -135,6 +137,11 @@ static bool get_pts_unencrypt_broadcast(void) { PTS_BROADCAST_UNENCRYPTED, false); } +static bool get_pts_eatt_peripheral_collision_support(void) { + return config_get_bool(*config, CONFIG_DEFAULT_SECTION, + PTS_EATT_PERIPHERAL_COLLISION_SUPPORT, false); +} + static config_t* get_all(void) { return config.get(); } const stack_config_t interface = {get_trace_config_enabled, @@ -148,6 +155,7 @@ const stack_config_t interface = {get_trace_config_enabled, get_pts_connect_eatt_unconditionally, get_pts_connect_eatt_before_encryption, get_pts_unencrypt_broadcast, + get_pts_eatt_peripheral_collision_support, get_all}; const stack_config_t* stack_config_get_interface(void) { return &interface; } diff --git a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc index 4389833471..441bf5c1d0 100644 --- a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc +++ b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc @@ -59,7 +59,8 @@ const stack_config_t interface = {nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr}; + nullptr, nullptr, + nullptr}; void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {} diff --git a/system/profile/avrcp/tests/avrcp_device_test.cc b/system/profile/avrcp/tests/avrcp_device_test.cc index f6dd75b0da..2bbc39ad4e 100644 --- a/system/profile/avrcp/tests/avrcp_device_test.cc +++ b/system/profile/avrcp/tests/avrcp_device_test.cc @@ -55,7 +55,8 @@ const stack_config_t interface = {nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr}; + nullptr, nullptr, + nullptr}; // TODO (apanicke): All the tests below are just basic positive unit tests. // Add more tests to increase code coverage. diff --git a/system/stack/Android.bp b/system/stack/Android.bp index cdb4ae71cd..3297591b24 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -640,6 +640,7 @@ cc_test { "packages/modules/Bluetooth/system/utils/include", ], srcs: crypto_toolbox_srcs + [ + ":TestCommonMainHandler", ":TestMockStackBtm", "gatt/gatt_db.cc", "gatt/gatt_sr_hash.cc", @@ -742,6 +743,7 @@ cc_test { "test/common/mock_l2cap_layer.cc", "test/gatt/mock_gatt_utils_ref.cc", "test/eatt/eatt_test.cc", + ":TestCommonMainHandler", ":TestCommonStackConfig", ], shared_libs: [ @@ -1036,6 +1038,7 @@ cc_test { ], srcs: [ ":OsiCompatSources", + ":TestCommonMainHandler", ":TestCommonStackConfig", ":TestMockBta", ":TestMockBtif", diff --git a/system/stack/eatt/eatt.cc b/system/stack/eatt/eatt.cc index 1aa79f0f9f..a023026309 100644 --- a/system/stack/eatt/eatt.cc +++ b/system/stack/eatt/eatt.cc @@ -45,6 +45,7 @@ struct EattExtension::impl { reg_info_.pL2CA_DisconnectInd_Cb = eatt_disconnect_ind; reg_info_.pL2CA_Error_Cb = eatt_error_cb; reg_info_.pL2CA_DataInd_Cb = eatt_data_ind; + reg_info_.pL2CA_CreditBasedCollisionInd_Cb = eatt_collision_ind; if (L2CA_RegisterLECoc(BT_PSM_EATT, reg_info_, BTM_SEC_NONE, {}) == 0) { LOG(ERROR) << __func__ << " cannot register EATT"; @@ -94,6 +95,11 @@ struct EattExtension::impl { p_cfg); } + static void eatt_collision_ind(const RawAddress& bd_addr) { + auto p_eatt_impl = GetImplInstance(); + if (p_eatt_impl) p_eatt_impl->eatt_l2cap_collision_ind(bd_addr); + } + static void eatt_error_cb(uint16_t lcid, uint16_t reason) { auto p_eatt_impl = GetImplInstance(); if (p_eatt_impl) p_eatt_impl->eatt_l2cap_error_cb(lcid, reason); diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h index 385ec430b6..0a2c2afd1d 100644 --- a/system/stack/eatt/eatt_impl.h +++ b/system/stack/eatt/eatt_impl.h @@ -33,6 +33,7 @@ #include "stack/btm/btm_sec.h" #include "stack/gatt/gatt_int.h" #include "stack/include/bt_hdr.h" +#include "stack/include/btu.h" // do_in_main_thread #include "stack/l2cap/l2c_int.h" #include "types/raw_address.h" @@ -50,9 +51,9 @@ class eatt_device { tGATT_TCB* eatt_tcb_; std::map<uint16_t, std::shared_ptr<EattChannel>> eatt_channels; - + bool collision; eatt_device(const RawAddress& bd_addr, uint16_t mtu, uint16_t mps) - : rx_mtu_(mtu), rx_mps_(mps), eatt_tcb_(nullptr) { + : rx_mtu_(mtu), rx_mps_(mps), eatt_tcb_(nullptr), collision(false) { bda_ = bd_addr; } }; @@ -175,6 +176,49 @@ struct eatt_impl { LOG(INFO) << __func__ << " Channel connected CID " << loghex(cid); } + + /* Android let Central to create EATT (PTS initiates EATT). Some PTS test + * cases wants Android to do it anyway (Android initiates EATT). + */ + if (stack_config_get_interface() + ->get_pts_eatt_peripheral_collision_support()) { + connect_eatt_wrap(eatt_dev); + } + } + + void eatt_retry_after_collision_if_needed(eatt_device* eatt_dev) { + if (!eatt_dev->collision) { + LOG_DEBUG("No collision."); + return; + } + /* We are here, because remote device wanted to create channels when + * Android proceed its own EATT creation. How to handle it is described + * here: BT Core 5.3, Volume 3, Part G, 5.4 + */ + LOG_INFO( + "EATT collision detected. If we are Central we will retry right " + "away"); + + eatt_dev->collision = false; + uint8_t role = L2CA_GetBleConnRole(eatt_dev->bda_); + if (role == HCI_ROLE_CENTRAL) { + LOG_INFO("Retrying EATT setup due to previous collision for device %s", + eatt_dev->bda_.ToString().c_str()); + connect_eatt_wrap(eatt_dev); + } else if (stack_config_get_interface() + ->get_pts_eatt_peripheral_collision_support()) { + /* This is only for the PTS. Android does not setup EATT when is a + * peripheral. + */ + bt_status_t status = do_in_main_thread_delayed( + FROM_HERE, + base::BindOnce(&eatt_impl::connect_eatt_wrap, base::Unretained(this), + std::move(eatt_dev)), + base::TimeDelta::FromMilliseconds(500)); + + LOG_INFO("Scheduled peripheral connect eatt for device with status: %d", + (int)status); + } } void eatt_l2cap_connect_cfm(const RawAddress& bda, uint16_t lcid, @@ -209,6 +253,7 @@ struct eatt_impl { eatt_dev->eatt_tcb_->eatt++; LOG(INFO) << __func__ << " Channel connected CID " << loghex(lcid); + eatt_retry_after_collision_if_needed(eatt_dev); } void eatt_l2cap_reconfig_completed(const RawAddress& bda, uint16_t lcid, @@ -237,6 +282,17 @@ struct eatt_impl { channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED); } + void eatt_l2cap_collision_ind(const RawAddress& bda) { + eatt_device* eatt_dev = find_device_by_address(bda); + if (!eatt_dev) { + LOG_ERROR("Device %s not available anymore:", bda.ToString().c_str()); + return; + } + /* Remote wanted to setup channels as well. Let's retry remote's request + * when we are done with ours.*/ + eatt_dev->collision = true; + } + void eatt_l2cap_error_cb(uint16_t lcid, uint16_t reason) { LOG(INFO) << __func__ << " cid: " << loghex(lcid) << " reason " << loghex(reason); @@ -266,6 +322,8 @@ struct eatt_impl { << static_cast<uint8_t>(channel->state_); break; } + + eatt_retry_after_collision_if_needed(eatt_dev); } void eatt_l2cap_disconnect_ind(uint16_t lcid, bool please_confirm) { @@ -317,7 +375,22 @@ struct eatt_impl { return eatt_dev; } - void connect_eatt(eatt_device* eatt_dev) { + void connect_eatt_wrap(eatt_device* eatt_dev) { + if (stack_config_get_interface() + ->get_pts_eatt_peripheral_collision_support()) { + /* For PTS case, lets assume we support only 5 channels */ + LOG_INFO("Number of existing channels %d", + (int)eatt_dev->eatt_channels.size()); + connect_eatt(eatt_dev, L2CAP_CREDIT_BASED_MAX_CIDS - + (int)eatt_dev->eatt_channels.size()); + return; + } + + connect_eatt(eatt_dev); + } + + void connect_eatt(eatt_device* eatt_dev, + uint8_t num_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS) { /* Let us use maximum possible mps */ if (eatt_dev->rx_mps_ == EATT_MIN_MTU_MPS) eatt_dev->rx_mps_ = controller_get_interface()->get_acl_data_size_ble(); @@ -326,9 +399,12 @@ struct eatt_impl { .mtu = eatt_dev->rx_mtu_, .mps = eatt_dev->rx_mps_, .credits = L2CAP_LE_CREDIT_DEFAULT, - .number_of_channels = L2CAP_CREDIT_BASED_MAX_CIDS, + .number_of_channels = num_of_channels, }; + LOG_INFO("Connecting device %s, cnt count %d", + eatt_dev->bda_.ToString().c_str(), num_of_channels); + /* Warning! CIDs in Android are unique across the ACL connections */ std::vector<uint16_t> connecting_cids = L2CA_ConnectCreditBasedReq(psm_, eatt_dev->bda_, &local_coc_cfg); @@ -615,7 +691,7 @@ struct eatt_impl { return; } - connect_eatt(eatt_dev); + connect_eatt_wrap(eatt_dev); } void disconnect_channel(uint16_t cid) { L2CA_DisconnectReq(cid); } @@ -659,6 +735,7 @@ struct eatt_impl { } eatt_dev->eatt_tcb_->eatt = 0; eatt_dev->eatt_tcb_ = nullptr; + eatt_dev->collision = false; } void connect(const RawAddress& bd_addr) { @@ -670,8 +747,8 @@ struct eatt_impl { return; } - LOG(INFO) << __func__ << " device " << bd_addr << " role" - << (role == HCI_ROLE_CENTRAL ? "central" : "peripheral"); + LOG_INFO("Device %s, role %s", bd_addr.ToString().c_str(), + (role == HCI_ROLE_CENTRAL ? "central" : "peripheral")); if (eatt_dev) { /* We are reconnecting device we know that support EATT. @@ -685,31 +762,30 @@ struct eatt_impl { return; } - connect_eatt(eatt_dev); + connect_eatt_wrap(eatt_dev); return; } /* This is needed for L2CAP test cases */ if (stack_config_get_interface()->get_pts_connect_eatt_unconditionally()) { - /* For PTS just start connecting EATT right away, */ + /* For PTS just start connecting EATT right away */ eatt_device* eatt_dev = add_eatt_device(bd_addr); - connect_eatt(eatt_dev); - } else { - if (gatt_profile_get_eatt_support(bd_addr)) { - LOG_DEBUG("Eatt is supported for device %s", - bd_addr.ToString().c_str()); - supported_features_cb(role, bd_addr, - BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK); - return; - } + connect_eatt_wrap(eatt_dev); + return; + } - /* If we don't know yet, read GATT server supported features. */ - if (gatt_cl_read_sr_supp_feat_req( - bd_addr, base::BindOnce(&eatt_impl::supported_features_cb, - base::Unretained(this), role)) == false) { - LOG_INFO("Read server supported features failed for device %s", - bd_addr.ToString().c_str()); - } + if (gatt_profile_get_eatt_support(bd_addr)) { + LOG_DEBUG("Eatt is supported for device %s", bd_addr.ToString().c_str()); + supported_features_cb(role, bd_addr, BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK); + return; + } + + /* If we don't know yet, read GATT server supported features. */ + if (gatt_cl_read_sr_supp_feat_req( + bd_addr, base::BindOnce(&eatt_impl::supported_features_cb, + base::Unretained(this), role)) == false) { + LOG_INFO("Read server supported features failed for device %s", + bd_addr.ToString().c_str()); } } diff --git a/system/stack/test/btm/stack_btm_test.cc b/system/stack/test/btm/stack_btm_test.cc index ae8bd9359a..e278e44869 100644 --- a/system/stack/test/btm/stack_btm_test.cc +++ b/system/stack/test/btm/stack_btm_test.cc @@ -74,6 +74,7 @@ bool get_pts_force_eatt_for_notifications(void) { return false; } bool get_pts_connect_eatt_unconditionally(void) { return false; } bool get_pts_connect_eatt_before_encryption(void) { return false; } bool get_pts_unencrypt_broadcast(void) { return false; } +bool get_pts_eatt_peripheral_collision_support(void) { return false; } config_t* get_all(void) { return nullptr; } const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; } @@ -92,6 +93,8 @@ stack_config_t mock_stack_config{ .get_pts_connect_eatt_before_encryption = get_pts_connect_eatt_before_encryption, .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast, + .get_pts_eatt_peripheral_collision_support = + get_pts_eatt_peripheral_collision_support, .get_all = get_all, }; const stack_config_t* stack_config_get_interface(void) { diff --git a/system/stack/test/eatt/eatt_test.cc b/system/stack/test/eatt/eatt_test.cc index 98d5a10d9e..fbd060fdad 100644 --- a/system/stack/test/eatt/eatt_test.cc +++ b/system/stack/test/eatt/eatt_test.cc @@ -62,7 +62,8 @@ const RawAddress test_address({0x11, 0x11, 0x11, 0x11, 0x11, 0x11}); class EattTest : public testing::Test { protected: - void ConnectDeviceEattSupported(int num_of_accepted_connections) { + void ConnectDeviceEattSupported(int num_of_accepted_connections, + bool collision = false) { ON_CALL(gatt_interface_, ClientReadSupportedFeatures) .WillByDefault( [](const RawAddress& addr, @@ -80,6 +81,14 @@ class EattTest : public testing::Test { eatt_instance_->Connect(test_address); + if (collision) { + EXPECT_CALL(l2cap_interface_, + ConnectCreditBasedReq(BT_PSM_EATT, test_address, _)) + .Times(1); + + l2cap_app_info_.pL2CA_CreditBasedCollisionInd_Cb(test_address); + } + int i = 0; for (uint16_t cid : test_local_cids) { EattChannel* channel = @@ -509,4 +518,10 @@ TEST_F(EattTest, DoubleDisconnect) { /* Force second disconnect */ eatt_instance_->Disconnect(test_address); } + +TEST_F(EattTest, TestCollisionHandling) { + ConnectDeviceEattSupported(0, true /* collision*/); + ConnectDeviceEattSupported(5, true /* collision*/); +} + } // namespace diff --git a/system/stack/test/gatt/mock_gatt_utils_ref.cc b/system/stack/test/gatt/mock_gatt_utils_ref.cc index cb01fd6d80..d416e98906 100644 --- a/system/stack/test/gatt/mock_gatt_utils_ref.cc +++ b/system/stack/test/gatt/mock_gatt_utils_ref.cc @@ -21,9 +21,6 @@ #include "types/raw_address.h" #include "utils/include/bt_utils.h" -/** stack/btu/btu_task.cc, indirect reference, gatt_utils.cc -> libosi */ -bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; } - /** stack/gatt/connection_manager.cc */ namespace connection_manager { bool background_connect_remove(uint8_t app_id, const RawAddress& address) { diff --git a/system/stack/test/gatt/stack_gatt_test.cc b/system/stack/test/gatt/stack_gatt_test.cc index 7e977713ff..38d6cc6647 100644 --- a/system/stack/test/gatt/stack_gatt_test.cc +++ b/system/stack/test/gatt/stack_gatt_test.cc @@ -33,8 +33,6 @@ std::map<std::string, int> mock_function_count_map; void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {} -bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; } - class StackGattTest : public ::testing::Test {}; namespace { diff --git a/system/stack/test/stack_smp_test.cc b/system/stack/test/stack_smp_test.cc index 2a20b6e1f0..abf10b9edf 100644 --- a/system/stack/test/stack_smp_test.cc +++ b/system/stack/test/stack_smp_test.cc @@ -49,6 +49,7 @@ bool get_pts_force_eatt_for_notifications(void) { return false; } bool get_pts_connect_eatt_unconditionally(void) { return false; } bool get_pts_connect_eatt_before_encryption(void) { return false; } bool get_pts_unencrypt_broadcast(void) { return false; } +bool get_pts_eatt_peripheral_collision_support(void) { return false; } config_t* get_all(void) { return nullptr; } const packet_fragmenter_t* packet_fragmenter_get_interface() { return nullptr; } @@ -67,6 +68,8 @@ stack_config_t mock_stack_config{ .get_pts_connect_eatt_before_encryption = get_pts_connect_eatt_before_encryption, .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast, + .get_pts_eatt_peripheral_collision_support = + get_pts_eatt_peripheral_collision_support, .get_all = get_all, }; const stack_config_t* stack_config_get_interface(void) { diff --git a/system/test/common/stack_config.cc b/system/test/common/stack_config.cc index aed9525489..becbabd496 100644 --- a/system/test/common/stack_config.cc +++ b/system/test/common/stack_config.cc @@ -34,6 +34,7 @@ bool get_pts_force_eatt_for_notifications(void) { return false; } bool get_pts_connect_eatt_unconditionally(void) { return false; } bool get_pts_connect_eatt_before_encryption(void) { return false; } bool get_pts_unencrypt_broadcast(void) { return false; } +bool get_pts_eatt_peripheral_collision_support(void) { return false; } struct config_t; config_t* get_all(void) { return nullptr; } struct packet_fragmenter_t; @@ -54,6 +55,8 @@ stack_config_t mock_stack_config{ .get_pts_connect_eatt_before_encryption = get_pts_connect_eatt_before_encryption, .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast, + .get_pts_eatt_peripheral_collision_support = + get_pts_eatt_peripheral_collision_support, .get_all = get_all, }; |