diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:09:35 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:09:35 +0000 |
commit | 7fb2d8a93ad374f3bd859d1dbd1ed3bcbd1d066d (patch) | |
tree | c052800eec2c144799e89e3e978069f8529366e9 | |
parent | 89755b16ff683f94472bb6aff47082720e4f628a (diff) | |
parent | 44d82eaeeab4e822c74c5f4721aac1e911b735fa (diff) | |
download | bt-android10-mainline-networking-release.tar.gz |
Snap for 6001391 from 44d82eaeeab4e822c74c5f4721aac1e911b735fa to qt-aml-networking-releaseandroid-mainline-10.0.0_r6android10-mainline-networking-release
Change-Id: I0d4ec91534b53072b53f99f326a09d8ab5dc291a
200 files changed, 6872 insertions, 1220 deletions
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl index 6bda14bfc..fa2b063aa 100644 --- a/binder/android/bluetooth/IBluetooth.aidl +++ b/binder/android/bluetooth/IBluetooth.aidl @@ -35,12 +35,14 @@ import android.os.ResultReceiver; */ interface IBluetooth { + @UnsupportedAppUsage boolean isEnabled(); int getState(); boolean enable(); boolean enableNoAutoConnect(); boolean disable(); + @UnsupportedAppUsage String getAddress(); ParcelUuid[] getUuids(); boolean setName(in String name); @@ -79,10 +81,12 @@ interface IBluetooth String getRemoteName(in BluetoothDevice device); int getRemoteType(in BluetoothDevice device); + @UnsupportedAppUsage String getRemoteAlias(in BluetoothDevice device); boolean setRemoteAlias(in BluetoothDevice device, in String name); int getRemoteClass(in BluetoothDevice device); ParcelUuid[] getRemoteUuids(in BluetoothDevice device); + @UnsupportedAppUsage boolean fetchRemoteUuids(in BluetoothDevice device); boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid); int getBatteryLevel(in BluetoothDevice device); @@ -102,6 +106,7 @@ interface IBluetooth int getSimAccessPermission(in BluetoothDevice device); boolean setSimAccessPermission(in BluetoothDevice device, int value); + @UnsupportedAppUsage void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState); void registerCallback(in IBluetoothCallback callback); diff --git a/binder/android/bluetooth/IBluetoothA2dp.aidl b/binder/android/bluetooth/IBluetoothA2dp.aidl index 6606a1b53..9cbd9cabe 100644 --- a/binder/android/bluetooth/IBluetoothA2dp.aidl +++ b/binder/android/bluetooth/IBluetoothA2dp.aidl @@ -27,14 +27,20 @@ import android.bluetooth.BluetoothDevice; */ interface IBluetoothA2dp { // Public API + @UnsupportedAppUsage boolean connect(in BluetoothDevice device); + @UnsupportedAppUsage boolean disconnect(in BluetoothDevice device); + @UnsupportedAppUsage List<BluetoothDevice> getConnectedDevices(); + @UnsupportedAppUsage List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + @UnsupportedAppUsage int getConnectionState(in BluetoothDevice device); boolean setActiveDevice(in BluetoothDevice device); BluetoothDevice getActiveDevice(); boolean setPriority(in BluetoothDevice device, int priority); + @UnsupportedAppUsage int getPriority(in BluetoothDevice device); boolean isAvrcpAbsoluteVolumeSupported(); oneway void setAvrcpAbsoluteVolume(int volume); diff --git a/binder/android/bluetooth/IBluetoothGatt.aidl b/binder/android/bluetooth/IBluetoothGatt.aidl index c9e1c4bc8..016eeff95 100644 --- a/binder/android/bluetooth/IBluetoothGatt.aidl +++ b/binder/android/bluetooth/IBluetoothGatt.aidl @@ -71,8 +71,10 @@ interface IBluetoothGatt { void registerSync(in ScanResult scanResult, in int skip, in int timeout, in IPeriodicAdvertisingCallback callback); void unregisterSync(in IPeriodicAdvertisingCallback callback); + @UnsupportedAppUsage void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback); + @UnsupportedAppUsage void unregisterClient(in int clientIf); void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport, in boolean opportunistic, in int phy); void clientDisconnect(in int clientIf, in String address); diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl index 0f6954cd1..c59cab1c3 100644 --- a/binder/android/bluetooth/IBluetoothHeadset.aidl +++ b/binder/android/bluetooth/IBluetoothHeadset.aidl @@ -29,8 +29,10 @@ import android.bluetooth.BluetoothDevice; */ interface IBluetoothHeadset { // Public API + @UnsupportedAppUsage List<BluetoothDevice> getConnectedDevices(); List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + @UnsupportedAppUsage int getConnectionState(in BluetoothDevice device); boolean startVoiceRecognition(in BluetoothDevice device); boolean stopVoiceRecognition(in BluetoothDevice device); @@ -40,9 +42,13 @@ interface IBluetoothHeadset { in String arg); // Hidden API + @UnsupportedAppUsage boolean connect(in BluetoothDevice device); + @UnsupportedAppUsage boolean disconnect(in BluetoothDevice device); + @UnsupportedAppUsage boolean setPriority(in BluetoothDevice device, int priority); + @UnsupportedAppUsage int getPriority(in BluetoothDevice device); int getAudioState(in BluetoothDevice device); boolean isAudioOn(); diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl index 2e1270048..faf78d828 100644 --- a/binder/android/bluetooth/IBluetoothManager.aidl +++ b/binder/android/bluetooth/IBluetoothManager.aidl @@ -31,13 +31,16 @@ interface IBluetoothManager { IBluetooth registerAdapter(in IBluetoothManagerCallback callback); void unregisterAdapter(in IBluetoothManagerCallback callback); + @UnsupportedAppUsage void registerStateChangeCallback(in IBluetoothStateChangeCallback callback); + @UnsupportedAppUsage void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); boolean enable(String packageName); boolean enableNoAutoConnect(String packageName); boolean disable(String packageName, boolean persist); int getState(); + @UnsupportedAppUsage IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); diff --git a/build/Android.bp b/build/Android.bp index c5ee79f53..32c0f31c0 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -29,9 +29,10 @@ fluoride_defaults { }, } +// Fuzzable defaults are the subset of defaults that are used in fuzzing, which +// requires no shared libraries, and no explicit sanitization. fluoride_defaults { - name: "fluoride_types_defaults", - defaults: ["libchrome_support_defaults"], + name: "fluoride_types_defaults_fuzzable", cflags: [ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))", "-fvisibility=hidden", @@ -54,15 +55,22 @@ fluoride_defaults { } fluoride_defaults { - name: "fluoride_defaults", + name: "fluoride_types_defaults", + defaults: [ + "fluoride_types_defaults_fuzzable", + "libchrome_support_defaults" + ], +} + +fluoride_defaults { + name: "fluoride_defaults_fuzzable", target: { android: { test_config_template: ":BluetoothTestConfigTemplate", }, }, - defaults: ["fluoride_types_defaults"], + defaults: ["fluoride_types_defaults_fuzzable"], header_libs: ["libbluetooth_headers"], - shared_libs: ["libstatslog"], static_libs: [ "libbluetooth-types", "libbt-platform-protos-lite", @@ -73,6 +81,15 @@ fluoride_defaults { }, } +fluoride_defaults { + name: "fluoride_defaults", + defaults: ["fluoride_defaults_fuzzable", "fluoride_types_defaults"], + shared_libs: ["libstatslog"], + sanitize: { + misc_undefined: ["bounds"], + }, +} + // Enables code coverage for a set of source files. Must be combined with // "clang_coverage_bin" in order to work. See //test/gen_coverage.py for more information // on generating code coverage. diff --git a/embdrv/sbc/decoder/srce/decoder-sbc.c b/embdrv/sbc/decoder/srce/decoder-sbc.c index 20c5b67b7..50168b5f2 100644 --- a/embdrv/sbc/decoder/srce/decoder-sbc.c +++ b/embdrv/sbc/decoder/srce/decoder-sbc.c @@ -33,6 +33,12 @@ #define SPECIALIZE_READ_SAMPLES_JOINT +#if __has_attribute(fallthrough) +#define __fallthrough __attribute__((__fallthrough__)) +#else +#define __fallthrough +#endif + /** * Scans through a buffer looking for a codec syncword. If the decoder has been * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search @@ -413,7 +419,7 @@ uint8_t OI_CODEC_SBC_FrameCount(OI_BYTE* frameData, uint32_t frameBytes) { case SBC_DUAL_CHANNEL: frameLen *= 2; - /* fall through */ + __fallthrough; default: if (mode == SBC_MONO) { diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py index 059c82c1e..45c20773f 100644 --- a/gd/cert/gd_base_test.py +++ b/gd/cert/gd_base_test.py @@ -70,7 +70,6 @@ class GdBaseTestClass(BaseTestClass): builtin=True) def teardown_class(self): - self.unregister_controllers() if self.rootcanal_running: self.rootcanal_process.send_signal(signal.SIGINT) rootcanal_return_code = self.rootcanal_process.wait() diff --git a/gd/hci/Android.bp b/gd/hci/Android.bp index 675a72e7b..8784a49e7 100644 --- a/gd/hci/Android.bp +++ b/gd/hci/Android.bp @@ -11,6 +11,7 @@ filegroup { "device_database.cc", "hci_layer.cc", "le_advertising_manager.cc", + "le_scanning_manager.cc", ], } @@ -29,6 +30,8 @@ filegroup { "dual_device_test.cc", "hci_layer_test.cc", "hci_packets_test.cc", + "le_advertising_manager_test.cc", + "le_scanning_manager_test.cc", ], } diff --git a/gd/hci/acl_manager.cc b/gd/hci/acl_manager.cc index a2cb801ac..c60cf058d 100644 --- a/gd/hci/acl_manager.cc +++ b/gd/hci/acl_manager.cc @@ -30,6 +30,8 @@ namespace bluetooth { namespace hci { +constexpr uint16_t kQualcommDebugHandle = 0xedc; + using common::Bind; using common::BindOnce; @@ -85,15 +87,8 @@ struct AclManager::impl { hci_layer_->RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGED, Bind(&impl::on_connection_packet_type_changed, common::Unretained(this)), handler_); - hci_layer_->RegisterEventHandler(EventCode::MASTER_LINK_KEY_COMPLETE, - Bind(&impl::on_master_link_key_complete, common::Unretained(this)), handler_); hci_layer_->RegisterEventHandler(EventCode::AUTHENTICATION_COMPLETE, Bind(&impl::on_authentication_complete, common::Unretained(this)), handler_); - hci_layer_->RegisterEventHandler(EventCode::ENCRYPTION_CHANGE, - Bind(&impl::on_encryption_change, common::Unretained(this)), handler_); - hci_layer_->RegisterEventHandler(EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE, - Bind(&impl::on_change_connection_link_key_complete, common::Unretained(this)), - handler_); hci_layer_->RegisterEventHandler(EventCode::READ_CLOCK_OFFSET_COMPLETE, Bind(&impl::on_read_clock_offset_complete, common::Unretained(this)), handler_); hci_layer_->RegisterEventHandler(EventCode::MODE_CHANGE, Bind(&impl::on_mode_change, common::Unretained(this)), @@ -228,6 +223,9 @@ struct AclManager::impl { return; } uint16_t handle = packet->GetHandle(); + if (handle == kQualcommDebugHandle) { + return; + } auto connection_pair = acl_connections_.find(handle); if (connection_pair == acl_connections_.end()) { LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), handle); diff --git a/gd/hci/acl_manager_test.cc b/gd/hci/acl_manager_test.cc index 3c5704d47..8b2cb3271 100644 --- a/gd/hci/acl_manager_test.cc +++ b/gd/hci/acl_manager_test.cc @@ -73,11 +73,11 @@ class TestController : public Controller { acl_cb_handler_ = handler; } - uint16_t GetControllerAclPacketLength() override { + uint16_t GetControllerAclPacketLength() const override { return acl_buffer_length_; } - uint16_t GetControllerNumAclPacketBuffers() override { + uint16_t GetControllerNumAclPacketBuffers() const override { return total_acl_buffers_; } @@ -676,17 +676,6 @@ TEST_F(AclManagerTest, acl_send_data_credits) { connection->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE); } -TEST_F(AclManagerWithConnectionTest, send_master_link_key) { - acl_manager_->MasterLinkKey(KeyFlag::TEMPORARY); - auto packet = test_hci_layer_->GetCommandPacket(OpCode::MASTER_LINK_KEY); - auto command_view = MasterLinkKeyView::Create(packet); - ASSERT(command_view.IsValid()); - EXPECT_EQ(command_view.GetKeyFlag(), KeyFlag::TEMPORARY); - - EXPECT_CALL(mock_acl_manager_callbacks_, OnMasterLinkKeyComplete(0x123, KeyFlag::TEMPORARY)); - test_hci_layer_->IncomingEvent(MasterLinkKeyCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, KeyFlag::TEMPORARY)); -} - TEST_F(AclManagerWithConnectionTest, send_switch_role) { acl_manager_->SwitchRole(connection_->GetAddress(), Role::SLAVE); auto packet = test_hci_layer_->GetCommandPacket(OpCode::SWITCH_ROLE); @@ -744,28 +733,6 @@ TEST_F(AclManagerWithConnectionTest, send_authentication_requested) { test_hci_layer_->IncomingEvent(AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_)); } -TEST_F(AclManagerWithConnectionTest, send_set_connection_encryption) { - connection_->SetConnectionEncryption(Enable::ENABLED); - auto packet = test_hci_layer_->GetCommandPacket(OpCode::SET_CONNECTION_ENCRYPTION); - auto command_view = SetConnectionEncryptionView::Create(packet); - ASSERT(command_view.IsValid()); - EXPECT_EQ(command_view.GetEncryptionEnable(), Enable::ENABLED); - - EXPECT_CALL(mock_connection_management_callbacks_, OnEncryptionChange(EncryptionEnabled::BR_EDR_AES_CCM)); - test_hci_layer_->IncomingEvent( - EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, handle_, EncryptionEnabled::BR_EDR_AES_CCM)); -} - -TEST_F(AclManagerWithConnectionTest, send_change_connection_link_key) { - connection_->ChangeConnectionLinkKey(); - auto packet = test_hci_layer_->GetCommandPacket(OpCode::CHANGE_CONNECTION_LINK_KEY); - auto command_view = ChangeConnectionLinkKeyView::Create(packet); - ASSERT(command_view.IsValid()); - - EXPECT_CALL(mock_connection_management_callbacks_, OnChangeConnectionLinkKeyComplete); - test_hci_layer_->IncomingEvent(ChangeConnectionLinkKeyCompleteBuilder::Create(ErrorCode::SUCCESS, handle_)); -} - TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) { connection_->ReadClockOffset(); auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_CLOCK_OFFSET); diff --git a/gd/hci/controller.cc b/gd/hci/controller.cc index 6ebe8956d..d9610645f 100644 --- a/gd/hci/controller.cc +++ b/gd/hci/controller.cc @@ -696,50 +696,50 @@ void Controller::RegisterCompletedAclPacketsCallback(Callback<void(uint16_t /* h impl_->RegisterCompletedAclPacketsCallback(cb, handler); // TODO hsz: why here? } -std::string Controller::GetControllerLocalName() { +std::string Controller::GetControllerLocalName() const { return impl_->local_name_; } -LocalVersionInformation Controller::GetControllerLocalVersionInformation() { +LocalVersionInformation Controller::GetControllerLocalVersionInformation() const { return impl_->local_version_information_; } -std::array<uint8_t, 64> Controller::GetControllerLocalSupportedCommands() { +std::array<uint8_t, 64> Controller::GetControllerLocalSupportedCommands() const { return impl_->local_supported_commands_; } -uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() { +uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() const { return impl_->maximum_page_number_; } -uint64_t Controller::GetControllerLocalSupportedFeatures() { +uint64_t Controller::GetControllerLocalSupportedFeatures() const { return impl_->local_supported_features_; } -uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) { +uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) const { if (page_number <= impl_->maximum_page_number_) { return impl_->extended_lmp_features_array_[page_number]; } return 0x00; } -uint16_t Controller::GetControllerAclPacketLength() { +uint16_t Controller::GetControllerAclPacketLength() const { return impl_->acl_buffer_length_; } -uint16_t Controller::GetControllerNumAclPacketBuffers() { +uint16_t Controller::GetControllerNumAclPacketBuffers() const { return impl_->acl_buffers_; } -uint8_t Controller::GetControllerScoPacketLength() { +uint8_t Controller::GetControllerScoPacketLength() const { return impl_->sco_buffer_length_; } -uint16_t Controller::GetControllerNumScoPacketBuffers() { +uint16_t Controller::GetControllerNumScoPacketBuffers() const { return impl_->sco_buffers_; } -Address Controller::GetControllerMacAddress() { +Address Controller::GetControllerMacAddress() const { return impl_->mac_address_; } @@ -813,35 +813,35 @@ void Controller::LeSetEventMask(uint64_t le_event_mask) { GetHandler()->Post(common::BindOnce(&impl::le_set_event_mask, common::Unretained(impl_.get()), le_event_mask)); } -LeBufferSize Controller::GetControllerLeBufferSize() { +LeBufferSize Controller::GetControllerLeBufferSize() const { return impl_->le_buffer_size_; } -uint64_t Controller::GetControllerLeLocalSupportedFeatures() { +uint64_t Controller::GetControllerLeLocalSupportedFeatures() const { return impl_->le_local_supported_features_; } -uint64_t Controller::GetControllerLeSupportedStates() { +uint64_t Controller::GetControllerLeSupportedStates() const { return impl_->le_supported_states_; } -LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() { +LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() const { return impl_->le_maximum_data_length_; } -uint16_t Controller::GetControllerLeMaximumAdvertisingDataLength() { +uint16_t Controller::GetControllerLeMaximumAdvertisingDataLength() const { return impl_->le_maximum_advertising_data_length_; } -uint16_t Controller::GetControllerLeNumberOfSupportedAdverisingSets() { +uint16_t Controller::GetControllerLeNumberOfSupportedAdverisingSets() const { return impl_->le_number_supported_advertising_sets_; } -VendorCapabilities Controller::GetControllerVendorCapabilities() { +VendorCapabilities Controller::GetControllerVendorCapabilities() const { return impl_->vendor_capabilities_; } -bool Controller::IsSupported(bluetooth::hci::OpCode op_code) { +bool Controller::IsSupported(bluetooth::hci::OpCode op_code) const { return impl_->is_supported(op_code); } diff --git a/gd/hci/controller.h b/gd/hci/controller.h index 3a4ee1c13..3f2d2cd6a 100644 --- a/gd/hci/controller.h +++ b/gd/hci/controller.h @@ -34,27 +34,27 @@ class Controller : public Module { virtual void RegisterCompletedAclPacketsCallback( common::Callback<void(uint16_t /* handle */, uint16_t /* num_packets */)> cb, os::Handler* handler); - virtual std::string GetControllerLocalName(); + virtual std::string GetControllerLocalName() const; - virtual LocalVersionInformation GetControllerLocalVersionInformation(); + virtual LocalVersionInformation GetControllerLocalVersionInformation() const; - virtual std::array<uint8_t, 64> GetControllerLocalSupportedCommands(); + virtual std::array<uint8_t, 64> GetControllerLocalSupportedCommands() const; - virtual uint64_t GetControllerLocalSupportedFeatures(); + virtual uint64_t GetControllerLocalSupportedFeatures() const; - virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber(); + virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const; - virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number); + virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const; - virtual uint16_t GetControllerAclPacketLength(); + virtual uint16_t GetControllerAclPacketLength() const; - virtual uint16_t GetControllerNumAclPacketBuffers(); + virtual uint16_t GetControllerNumAclPacketBuffers() const; - virtual uint8_t GetControllerScoPacketLength(); + virtual uint8_t GetControllerScoPacketLength() const; - virtual uint16_t GetControllerNumScoPacketBuffers(); + virtual uint16_t GetControllerNumScoPacketBuffers() const; - virtual Address GetControllerMacAddress(); + virtual Address GetControllerMacAddress() const; virtual void SetEventMask(uint64_t event_mask); @@ -86,21 +86,21 @@ class Controller : public Module { // LE controller commands virtual void LeSetEventMask(uint64_t le_event_mask); - LeBufferSize GetControllerLeBufferSize(); + virtual LeBufferSize GetControllerLeBufferSize() const; - uint64_t GetControllerLeLocalSupportedFeatures(); + virtual uint64_t GetControllerLeLocalSupportedFeatures() const; - uint64_t GetControllerLeSupportedStates(); + virtual uint64_t GetControllerLeSupportedStates() const; - LeMaximumDataLength GetControllerLeMaximumDataLength(); + virtual LeMaximumDataLength GetControllerLeMaximumDataLength() const; - uint16_t GetControllerLeMaximumAdvertisingDataLength(); + virtual uint16_t GetControllerLeMaximumAdvertisingDataLength() const; - uint16_t GetControllerLeNumberOfSupportedAdverisingSets(); + virtual uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const; - VendorCapabilities GetControllerVendorCapabilities(); + virtual VendorCapabilities GetControllerVendorCapabilities() const; - bool IsSupported(OpCode op_code); + virtual bool IsSupported(OpCode op_code) const; static const ModuleFactory Factory; diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl index 911bc789a..255306cd2 100644 --- a/gd/hci/hci_packets.pdl +++ b/gd/hci/hci_packets.pdl @@ -2203,9 +2203,11 @@ packet LeSetRandomAddressComplete : CommandComplete (command_op_code = LE_SET_RA status : ErrorCode, } -enum AdvertisingFilterPolicy : 1 { +enum AdvertisingFilterPolicy : 2 { ALL_DEVICES = 0, // Default - ONLY_WHITE_LISTED_DEVICES = 1, + WHITELISTED_SCAN = 1, + WHITELISTED_CONNECT = 2, + WHITELISTED_SCAN_AND_CONNECT = 3, } enum PeerAddressType : 8 { @@ -2616,12 +2618,33 @@ packet LeSetPeriodicAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_P _payload_, // placeholder (unimplemented) } -packet LeSetExtendedScanParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) { - _payload_, // placeholder (unimplemented) +packet LeSetExtendedScanParameters : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) { + le_scan_type : LeScanType, + le_scan_interval : 32, // 0x0004-0x00FFFFFF Default 0x10 (10ms) + le_scan_window : 32, // 0x004-0xFFFF Default 0x10 (10ms) + own_address_type : AddressType, + scanning_filter_policy : LeSetScanningFilterPolicy, } -packet LeSetExtendedScanEnable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) { - _payload_, // placeholder (unimplemented) +packet LeSetExtendedScanParametersComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) { + status : ErrorCode, +} + +enum FilterDuplicates : 8 { + DISABLED = 0, + ENABLED = 1, + RESET_EACH_PERIOD = 2, +} + +packet LeSetExtendedScanEnable : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) { + enable : Enable, + filter_duplicates : FilterDuplicates, + duration : 16, // 0 - Scan continuously, N * 10 ms + period : 16, // 0 - Scan continuously, N * 1.28 sec +} + +packet LeSetExtendedScanEnableComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_ENABLE) { + status : ErrorCode, } packet LeExtendedCreateConnection : LeConnectionManagementCommand (op_code = LE_EXTENDED_CREATE_CONNECTION) { @@ -2728,11 +2751,11 @@ packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 { } enum SubOcf : 8 { - SET_ADVT_PARAM = 0x01, - SET_ADVT_DATA = 0x02, - SET_ADVT_SCAN_RESP = 0x03, - SET_ADVT_RANDOM_ADDR = 0x04, - SET_ADVT_ENABLE = 0x05, + SET_PARAM = 0x01, + SET_DATA = 0x02, + SET_SCAN_RESP = 0x03, + SET_RANDOM_ADDR = 0x04, + SET_ENABLE = 0x05, } packet LeMultiAdvt : LeAdvertisingCommand (op_code = LE_MULTI_ADVT) { @@ -2740,12 +2763,12 @@ packet LeMultiAdvt : LeAdvertisingCommand (op_code = LE_MULTI_ADVT) { _body_, } -packet LeMultiAdvtParamComplete : CommandComplete (command_op_code = LE_MULTI_ADVT) { +packet LeMultiAdvtComplete : CommandComplete (command_op_code = LE_MULTI_ADVT) { status : ErrorCode, sub_cmd : SubOcf, } -packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_ADVT_PARAM) { +packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_PARAM) { interval_min : 16, interval_max : 16, type : AdvertisingEventType, @@ -2759,30 +2782,45 @@ packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_ADVT_PARAM) { tx_power : 8, } -packet LeMultiAdvtParamSetData : LeMultiAdvt (sub_cmd = SET_ADVT_DATA) { +packet LeMultiAdvtParamComplete : LeMultiAdvtComplete (sub_cmd = SET_PARAM) { +} + +packet LeMultiAdvtSetData : LeMultiAdvt (sub_cmd = SET_DATA) { _size_(advertising_data) : 8, advertising_data : GapData[], _padding_[31], // Zero padding to 31 bytes of advertising_data advertising_instance : 8, } -packet LeMultiAdvtParamSetScanResp : LeMultiAdvt (sub_cmd = SET_ADVT_SCAN_RESP) { +packet LeMultiAdvtSetDataComplete : LeMultiAdvtComplete (sub_cmd = SET_DATA) { +} + +packet LeMultiAdvtSetScanResp : LeMultiAdvt (sub_cmd = SET_SCAN_RESP) { _size_(advertising_data) : 8, advertising_data : GapData[], _padding_[31], // Zero padding to 31 bytes of advertising_data advertising_instance : 8, } -packet LeMultiAdvtParamSetRandomAddr : LeMultiAdvt (sub_cmd = SET_ADVT_RANDOM_ADDR) { +packet LeMultiAdvtSetScanRespComplete : LeMultiAdvtComplete (sub_cmd = SET_SCAN_RESP) { +} + +packet LeMultiAdvtSetRandomAddr : LeMultiAdvt (sub_cmd = SET_RANDOM_ADDR) { random_address : Address, advertising_instance : 8, } -packet LeMultiAdvtParamSetEnable : LeMultiAdvt (sub_cmd = SET_ADVT_ENABLE) { +packet LeMultiAdvtSetRandomAddrComplete : LeMultiAdvtComplete (sub_cmd = SET_RANDOM_ADDR) { +} + +packet LeMultiAdvtSetEnable : LeMultiAdvt (sub_cmd = SET_ENABLE) { advertising_enable : Enable, // Default DISABLED advertising_instance : 8, } +packet LeMultiAdvtSetEnableComplete : LeMultiAdvtComplete (sub_cmd = SET_ENABLE) { +} + packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) { _payload_, // placeholder (unimplemented) } @@ -2816,8 +2854,16 @@ packet LeEnergyInfo : VendorCommand (op_code = LE_ENERGY_INFO) { _payload_, // placeholder (unimplemented) } -packet LeExtendedScanParams : VendorCommand (op_code = LE_EXTENDED_SCAN_PARAMS) { - _payload_, // placeholder (unimplemented) +packet LeExtendedScanParams : LeScanningCommand (op_code = LE_EXTENDED_SCAN_PARAMS) { + le_scan_type : LeScanType, + le_scan_interval : 32, // 0x0004-0x4000 Default 0x10 (10ms) + le_scan_window : 32, // Default 0x10 (10ms) + own_address_type : AddressType, + scanning_filter_policy : LeSetScanningFilterPolicy, +} + +packet LeExtendedScanParamsComplete : CommandComplete (command_op_code = LE_EXTENDED_SCAN_PARAMS) { + status : ErrorCode, } packet ControllerDebugInfo : VendorCommand (op_code = CONTROLLER_DEBUG_INFO) { diff --git a/gd/hci/le_advertising_manager.cc b/gd/hci/le_advertising_manager.cc index a77611346..35e30a707 100644 --- a/gd/hci/le_advertising_manager.cc +++ b/gd/hci/le_advertising_manager.cc @@ -30,6 +30,12 @@ namespace hci { const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); }); +enum class AdvertisingApiType { + LE_4_0 = 1, + ANDROID_HCI = 2, + LE_5_0 = 3, +}; + struct Advertiser { os::Handler* handler; common::Callback<void(Address, AddressType)> scan_callback; @@ -37,14 +43,22 @@ struct Advertiser { }; struct LeAdvertisingManager::impl { - impl(Module* module, os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) - : registered_handler_(nullptr), module_(module), module_handler_(handler), hci_layer_(hci_layer), - controller_(controller), le_advertising_interface_(nullptr), num_instances_(0) {} + impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {} - void start() { + void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) { + module_handler_ = handler; + hci_layer_ = hci_layer; + controller_ = controller; le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface( common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_); num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets(); + if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) { + advertising_api_type_ = AdvertisingApiType::LE_5_0; + } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { + advertising_api_type_ = AdvertisingApiType::ANDROID_HCI; + } else { + advertising_api_type_ = AdvertisingApiType::LE_4_0; + } } size_t GetNumberOfAdvertisingInstances() const { @@ -87,7 +101,7 @@ struct LeAdvertisingManager::impl { AdvertiserId id = 0; { std::unique_lock lock(id_mutex_); - while (id < num_instances_ && advertising_sets_.count(id) == 0) { + while (id < num_instances_ && advertising_sets_.count(id) != 0) { id++; } } @@ -112,48 +126,72 @@ struct LeAdvertisingManager::impl { advertising_sets_[id].scan_callback = scan_callback; advertising_sets_[id].set_terminated_callback = set_terminated_callback; advertising_sets_[id].handler = handler; - if (!controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { - le_advertising_interface_->EnqueueCommand( - hci::LeSetAdvertisingParametersBuilder::Create(config.interval_min, config.interval_max, config.event_type, - config.address_type, config.peer_address_type, - config.peer_address, config.channel_map, config.filter_policy), - common::BindOnce(impl::check_enable_status), module_handler_); - le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingDataBuilder::Create(config.advertisement), - common::BindOnce(impl::check_enable_status), module_handler_); - le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address), - common::BindOnce(impl::check_enable_status), module_handler_); - if (!config.scan_response.empty()) { - le_advertising_interface_->EnqueueCommand(hci::LeSetScanResponseDataBuilder::Create(config.scan_response), - common::BindOnce(impl::check_enable_status), module_handler_); - } - le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingDataBuilder::Create(config.advertisement), - common::BindOnce(impl::check_enable_status), module_handler_); - return; + switch (advertising_api_type_) { + case (AdvertisingApiType::LE_4_0): + le_advertising_interface_->EnqueueCommand( + hci::LeSetAdvertisingParametersBuilder::Create( + config.interval_min, config.interval_max, config.event_type, config.address_type, + config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy), + common::BindOnce(impl::check_status<LeSetAdvertisingParametersCompleteView>), module_handler_); + le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address), + common::BindOnce(impl::check_status<LeSetRandomAddressCompleteView>), + module_handler_); + if (!config.scan_response.empty()) { + le_advertising_interface_->EnqueueCommand( + hci::LeSetScanResponseDataBuilder::Create(config.scan_response), + common::BindOnce(impl::check_status<LeSetScanResponseDataCompleteView>), module_handler_); + } + le_advertising_interface_->EnqueueCommand( + hci::LeSetAdvertisingDataBuilder::Create(config.advertisement), + common::BindOnce(impl::check_status<LeSetAdvertisingDataCompleteView>), module_handler_); + le_advertising_interface_->EnqueueCommand( + hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED), + common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_); + break; + case (AdvertisingApiType::ANDROID_HCI): + le_advertising_interface_->EnqueueCommand( + hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type, + config.address_type, config.peer_address_type, config.peer_address, + config.channel_map, config.filter_policy, id, config.tx_power), + common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); + le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetDataBuilder::Create(config.advertisement, id), + common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), + module_handler_); + if (!config.scan_response.empty()) { + le_advertising_interface_->EnqueueCommand( + hci::LeMultiAdvtSetScanRespBuilder::Create(config.scan_response, id), + common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); + } + le_advertising_interface_->EnqueueCommand( + hci::LeMultiAdvtSetRandomAddrBuilder::Create(config.random_address, id), + common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_); + le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetEnableBuilder::Create(Enable::ENABLED, id), + common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), + module_handler_); + break; + case (AdvertisingApiType::LE_5_0): { + ExtendedAdvertisingConfig new_config; + AdvertisingConfig* base_config_ptr = &new_config; + *(base_config_ptr) = config; + create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler); + } break; } - le_advertising_interface_->EnqueueCommand( - hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type, - config.address_type, config.peer_address_type, config.peer_address, - config.channel_map, config.filter_policy, id, config.tx_power), - common::BindOnce(impl::check_enable_status), module_handler_); - le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED), - common::BindOnce(impl::check_enable_status), module_handler_); } void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback, const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) { - if (!controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) { + if (advertising_api_type_ != AdvertisingApiType::LE_5_0) { create_advertiser(id, config, scan_callback, set_terminated_callback, handler); return; - } else { - LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented."); } + LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented."); /* le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min, config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address, - config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_enable_status), + config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_status), module_handler_); */ advertising_sets_[id].scan_callback = scan_callback; @@ -167,14 +205,15 @@ struct LeAdvertisingManager::impl { return; } le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED), - common::BindOnce(impl::check_enable_status), module_handler_); + common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), + module_handler_); std::unique_lock lock(id_mutex_); advertising_sets_.erase(advertising_set); } common::Callback<void(Address, AddressType)> scan_callback_; common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_; - os::Handler* registered_handler_; + os::Handler* registered_handler_{nullptr}; Module* module_; os::Handler* module_handler_; hci::HciLayer* hci_layer_; @@ -185,21 +224,21 @@ struct LeAdvertisingManager::impl { std::mutex id_mutex_; size_t num_instances_; - static void check_enable_status(CommandCompleteView view) { + AdvertisingApiType advertising_api_type_{0}; + + template <class View> + static void check_status(CommandCompleteView view) { ASSERT(view.IsValid()); - auto status_view = LeSetAdvertisingEnableCompleteView::Create(view); + auto status_view = View::Create(view); ASSERT(status_view.IsValid()); if (status_view.GetStatus() != ErrorCode::SUCCESS) { LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str()); - return; } } }; -const AdvertiserId LeAdvertisingManager::kInvalidId = -1; - LeAdvertisingManager::LeAdvertisingManager() { - pimpl_ = std::make_unique<impl>(this, GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>()); + pimpl_ = std::make_unique<impl>(this); } void LeAdvertisingManager::ListDependencies(ModuleList* list) { @@ -208,7 +247,7 @@ void LeAdvertisingManager::ListDependencies(ModuleList* list) { } void LeAdvertisingManager::Start() { - pimpl_->start(); + pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>()); } void LeAdvertisingManager::Stop() { @@ -225,10 +264,12 @@ AdvertiserId LeAdvertisingManager::CreateAdvertiser( if (config.peer_address == Address::kEmpty) { if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS || config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) { + LOG_WARN("Peer address can not be empty"); return kInvalidId; } if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND || config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) { + LOG_WARN("Peer address can not be empty for directed advertising"); return kInvalidId; } } @@ -244,11 +285,34 @@ AdvertiserId LeAdvertisingManager::CreateAdvertiser( AdvertiserId LeAdvertisingManager::CreateAdvertiser( const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback, const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) { + if (config.directed) { + if (config.peer_address == Address::kEmpty) { + LOG_INFO("Peer address can not be empty for directed advertising"); + return kInvalidId; + } + } + if (config.channel_map == 0) { + LOG_INFO("At least one channel must be set in the map"); + return kInvalidId; + } + if (!config.legacy_pdus) { + if (config.connectable && config.scannable) { + LOG_INFO("Extended advertising PDUs can not be connectable and scannable"); + return kInvalidId; + } + if (config.high_duty_directed_connectable) { + LOG_INFO("Extended advertising PDUs can not be high duty cycle"); + return kInvalidId; + } + } + if (config.interval_min > config.interval_max) { + LOG_INFO("Advertising interval: min (%hu) > max (%hu)", config.interval_min, config.interval_max); + return kInvalidId; + } AdvertiserId id = pimpl_->allocate_advertiser(); if (id == kInvalidId) { return id; } - // Add error checking here GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config, scan_callback, set_terminated_callback, handler)); return id; diff --git a/gd/hci/le_advertising_manager.h b/gd/hci/le_advertising_manager.h index 90199e6f4..2cbfc5944 100644 --- a/gd/hci/le_advertising_manager.h +++ b/gd/hci/le_advertising_manager.h @@ -59,7 +59,7 @@ using AdvertiserId = int32_t; class LeAdvertisingManager : public bluetooth::Module { public: - static const AdvertiserId kInvalidId; + static constexpr AdvertiserId kInvalidId = -1; LeAdvertisingManager(); size_t GetNumberOfAdvertisingInstances() const; diff --git a/gd/hci/le_advertising_manager_test.cc b/gd/hci/le_advertising_manager_test.cc new file mode 100644 index 000000000..c4f40ad22 --- /dev/null +++ b/gd/hci/le_advertising_manager_test.cc @@ -0,0 +1,356 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/le_advertising_manager.h" + +#include <algorithm> +#include <chrono> +#include <future> +#include <map> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "common/bind.h" +#include "hci/address.h" +#include "hci/controller.h" +#include "hci/hci_layer.h" +#include "os/thread.h" +#include "packet/raw_builder.h" + +namespace bluetooth { +namespace hci { +namespace { + +using packet::kLittleEndian; +using packet::PacketView; +using packet::RawBuilder; + +PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) { + auto bytes = std::make_shared<std::vector<uint8_t>>(); + BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + return packet::PacketView<packet::kLittleEndian>(bytes); +} + +class TestController : public Controller { + public: + bool IsSupported(OpCode op_code) const override { + return supported_opcodes_.count(op_code) == 1; + } + + void AddSupported(OpCode op_code) { + supported_opcodes_.insert(op_code); + } + + uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const override { + return num_advertisers; + } + + uint16_t num_advertisers{0}; + + protected: + void Start() override {} + void Stop() override {} + void ListDependencies(ModuleList* list) override {} + + private: + std::set<OpCode> supported_opcodes_{}; +}; + +class TestHciLayer : public HciLayer { + public: + TestHciLayer() { + RegisterEventHandler(EventCode::COMMAND_COMPLETE, + base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr); + RegisterEventHandler(EventCode::COMMAND_STATUS, + base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr); + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override { + command_queue_.push_back(std::move(command)); + command_status_callbacks.push_back(std::move(on_status)); + if (command_promise_ != nullptr) { + command_promise_->set_value(command_queue_.size()); + command_promise_.reset(); + } + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override { + command_queue_.push_back(std::move(command)); + command_complete_callbacks.push_back(std::move(on_complete)); + if (command_promise_ != nullptr) { + command_promise_->set_value(command_queue_.size()); + command_promise_.reset(); + } + } + + std::future<size_t> GetCommandFuture() { + ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); + command_promise_ = std::make_unique<std::promise<size_t>>(); + return command_promise_->get_future(); + } + + std::unique_ptr<CommandPacketBuilder> GetLastCommand() { + ASSERT(!command_queue_.empty()); + auto last = std::move(command_queue_.front()); + command_queue_.pop_front(); + return last; + } + + ConnectionManagementCommandView GetCommandPacket(OpCode op_code) { + auto packet_view = GetPacketView(GetLastCommand()); + CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); + ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); + ASSERT(command.IsValid()); + EXPECT_EQ(command.GetOpCode(), op_code); + + return command; + } + + void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler, + os::Handler* handler) override { + registered_events_[event_code] = event_handler; + } + + void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler, + os::Handler* handler) override { + registered_le_events_[subevent_code] = event_handler; + } + + void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + ASSERT_TRUE(event.IsValid()); + EventCode event_code = event.GetEventCode(); + ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code); + registered_events_[event_code].Run(event); + } + + void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + LeMetaEventView meta_event_view = LeMetaEventView::Create(event); + ASSERT_TRUE(meta_event_view.IsValid()); + SubeventCode subevent_code = meta_event_view.GetSubeventCode(); + ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end()) + << SubeventCodeText(subevent_code); + registered_le_events_[subevent_code].Run(meta_event_view); + } + + void CommandCompleteCallback(EventPacketView event) { + CommandCompleteView complete_view = CommandCompleteView::Create(event); + ASSERT(complete_view.IsValid()); + std::move(command_complete_callbacks.front()).Run(complete_view); + command_complete_callbacks.pop_front(); + } + + void CommandStatusCallback(EventPacketView event) { + CommandStatusView status_view = CommandStatusView::Create(event); + ASSERT(status_view.IsValid()); + std::move(command_status_callbacks.front()).Run(status_view); + command_status_callbacks.pop_front(); + } + + void ListDependencies(ModuleList* list) override {} + void Start() override {} + void Stop() override {} + + private: + std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_; + std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_; + std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks; + std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks; + + std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_; + mutable std::mutex mutex_; + std::unique_ptr<std::promise<size_t>> command_promise_{}; +}; + +class LeAdvertisingManagerTest : public ::testing::Test { + protected: + void SetUp() override { + test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry + test_controller_ = new TestController; + test_controller_->AddSupported(param_opcode_); + fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); + fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); + client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); + ASSERT_NE(client_handler_, nullptr); + test_controller_->num_advertisers = 1; + fake_registry_.Start<LeAdvertisingManager>(&thread_); + le_advertising_manager_ = + static_cast<LeAdvertisingManager*>(fake_registry_.GetModuleUnderTest(&LeAdvertisingManager::Factory)); + } + + void TearDown() override { + fake_registry_.SynchronizeModuleHandler(&LeAdvertisingManager::Factory, std::chrono::milliseconds(20)); + fake_registry_.StopAll(); + } + + TestModuleRegistry fake_registry_; + TestHciLayer* test_hci_layer_ = nullptr; + TestController* test_controller_ = nullptr; + os::Thread& thread_ = fake_registry_.GetTestThread(); + LeAdvertisingManager* le_advertising_manager_ = nullptr; + os::Handler* client_handler_ = nullptr; + + const common::Callback<void(Address, AddressType)> scan_callback = + common::Bind(&LeAdvertisingManagerTest::on_scan, common::Unretained(this)); + const common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback = + common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this)); + + std::future<Address> GetOnScanPromise() { + ASSERT_LOG(address_promise_ == nullptr, "Promises promises ... Only one at a time"); + address_promise_ = std::make_unique<std::promise<Address>>(); + return address_promise_->get_future(); + } + void on_scan(Address address, AddressType address_type) { + if (address_promise_ == nullptr) { + return; + } + address_promise_->set_value(address); + address_promise_.reset(); + } + + std::future<ErrorCode> GetSetTerminatedPromise() { + ASSERT_LOG(set_terminated_promise_ == nullptr, "Promises promises ... Only one at a time"); + set_terminated_promise_ = std::make_unique<std::promise<ErrorCode>>(); + return set_terminated_promise_->get_future(); + } + void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) { + if (set_terminated_promise_ != nullptr) { + return; + } + set_terminated_promise_->set_value(error_code); + set_terminated_promise_.reset(); + } + + std::unique_ptr<std::promise<Address>> address_promise_{}; + std::unique_ptr<std::promise<ErrorCode>> set_terminated_promise_{}; + + OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS}; +}; + +class LeAndroidHciAdvertisingManagerTest : public LeAdvertisingManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_MULTI_ADVT; + LeAdvertisingManagerTest::SetUp(); + test_controller_->num_advertisers = 3; + } +}; + +class LeExtendedAdvertisingManagerTest : public LeAdvertisingManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS; + LeAdvertisingManagerTest::SetUp(); + test_controller_->num_advertisers = 5; + } +}; + +TEST_F(LeAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeAndroidHciAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeExtendedAdvertisingManagerTest, startup_teardown) {} + +TEST_F(LeAdvertisingManagerTest, create_advertiser_test) { + AdvertisingConfig advertising_config{}; + advertising_config.event_type = AdvertisingEventType::ADV_IND; + advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + + auto next_command_future = test_hci_layer_->GetCommandFuture(); + auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, + client_handler_); + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + std::vector<OpCode> adv_opcodes = { + OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS, OpCode::LE_SET_SCAN_RESPONSE_DATA, + OpCode::LE_SET_ADVERTISING_DATA, OpCode::LE_SET_ADVERTISING_ENABLE, + }; + auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + size_t num_commands = next_command_future.get(); + for (size_t i = 0; i < adv_opcodes.size(); i++) { + auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]); + std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)}; + test_hci_layer_->IncomingEvent( + CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector))); + if (i < adv_opcodes.size() - 1 && --num_commands == 1) { + next_command_future = test_hci_layer_->GetCommandFuture(); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + num_commands = next_command_future.get(); + } + } +} + +TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) { + AdvertisingConfig advertising_config{}; + advertising_config.event_type = AdvertisingEventType::ADV_IND; + advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS; + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + advertising_config.advertisement = gap_data; + advertising_config.scan_response = gap_data; + + auto next_command_future = test_hci_layer_->GetCommandFuture(); + auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback, + client_handler_); + ASSERT_NE(LeAdvertisingManager::kInvalidId, id); + std::vector<SubOcf> sub_ocf = { + SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE, + }; + auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + size_t num_commands = next_command_future.get(); + for (size_t i = 0; i < sub_ocf.size(); i++) { + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT); + std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])}; + test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT, + std::make_unique<RawBuilder>(success_vector))); + if (i < sub_ocf.size() - 1 && --num_commands == 1) { + next_command_future = test_hci_layer_->GetCommandFuture(); + result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + ASSERT_NE(std::future_status::timeout, result); + num_commands = next_command_future.get(); + } + } +} + +} // namespace +} // namespace hci +} // namespace bluetooth diff --git a/gd/hci/le_report.h b/gd/hci/le_report.h new file mode 100644 index 000000000..7dc075f8e --- /dev/null +++ b/gd/hci/le_report.h @@ -0,0 +1,83 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <memory> + +#include "hci/hci_packets.h" + +namespace bluetooth::hci { + +class LeReport { + public: + explicit LeReport(const LeAdvertisingReport& advertisement) + : report_type_(ReportType::ADVERTISING_EVENT), advertising_event_type_(advertisement.event_type_), + address_(advertisement.address_), address_type_(advertisement.address_type_), rssi_(advertisement.rssi_), + gap_data_(advertisement.advertising_data_) {} + explicit LeReport(const LeDirectedAdvertisingReport& advertisement) + : report_type_(ReportType::DIRECTED_ADVERTISING_EVENT), address_(advertisement.address_), + rssi_(advertisement.rssi_) {} + explicit LeReport(const LeExtendedAdvertisingReport& advertisement) + : report_type_(ReportType::EXTENDED_ADVERTISING_EVENT), address_(advertisement.address_), + rssi_(advertisement.rssi_), gap_data_(advertisement.advertising_data_) {} + virtual ~LeReport() = default; + + enum class ReportType { + ADVERTISING_EVENT = 1, + DIRECTED_ADVERTISING_EVENT = 2, + EXTENDED_ADVERTISING_EVENT = 3, + }; + const ReportType report_type_; + + ReportType GetReportType() const { + return report_type_; + } + + // Advertising Event + const AdvertisingEventType advertising_event_type_{}; + const Address address_{}; + const AddressType address_type_{}; + const uint8_t rssi_; + const std::vector<GapData> gap_data_{}; +}; + +class DirectedLeReport : public LeReport { + public: + explicit DirectedLeReport(const LeDirectedAdvertisingReport& advertisement) + : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {} + explicit DirectedLeReport(const LeExtendedAdvertisingReport& advertisement) + : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {} + + const DirectAdvertisingAddressType direct_address_type_{}; +}; + +class ExtendedLeReport : public DirectedLeReport { + public: + explicit ExtendedLeReport(const LeExtendedAdvertisingReport& advertisement) + : DirectedLeReport(advertisement), connectable_(advertisement.connectable_), scannable_(advertisement.scannable_), + directed_(advertisement.directed_), scan_response_(advertisement.scan_response_), + complete_(advertisement.data_status_ == DataStatus::COMPLETE), + truncated_(advertisement.data_status_ == DataStatus::TRUNCATED) {} + + // Extended + bool connectable_; + bool scannable_; + bool directed_; + bool scan_response_; + bool complete_; + bool truncated_; +}; +} // namespace bluetooth::hci
\ No newline at end of file diff --git a/gd/hci/le_scanning_interface.h b/gd/hci/le_scanning_interface.h index 4d93f251c..97a676625 100644 --- a/gd/hci/le_scanning_interface.h +++ b/gd/hci/le_scanning_interface.h @@ -38,6 +38,12 @@ class LeScanningInterface { static constexpr hci::SubeventCode LeScanningEvents[] = { hci::SubeventCode::SCAN_TIMEOUT, + hci::SubeventCode::ADVERTISING_REPORT, + hci::SubeventCode::DIRECTED_ADVERTISING_REPORT, + hci::SubeventCode::EXTENDED_ADVERTISING_REPORT, + hci::SubeventCode::PERIODIC_ADVERTISING_REPORT, + hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED, + hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST, }; }; } // namespace hci diff --git a/gd/hci/le_scanning_manager.cc b/gd/hci/le_scanning_manager.cc new file mode 100644 index 000000000..1562dd626 --- /dev/null +++ b/gd/hci/le_scanning_manager.cc @@ -0,0 +1,247 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <memory> +#include <mutex> +#include <set> + +#include "hci/controller.h" +#include "hci/hci_layer.h" +#include "hci/hci_packets.h" +#include "hci/le_scanning_interface.h" +#include "hci/le_scanning_manager.h" +#include "module.h" +#include "os/handler.h" +#include "os/log.h" + +namespace bluetooth { +namespace hci { + +const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); }); + +enum class ScanApiType { + LE_4_0 = 1, + ANDROID_HCI = 2, + LE_5_0 = 3, +}; + +struct LeScanningManager::impl { + impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {} + + void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) { + module_handler_ = handler; + hci_layer_ = hci_layer; + controller_ = controller; + le_scanning_interface_ = hci_layer_->GetLeScanningInterface( + common::Bind(&LeScanningManager::impl::handle_scan_results, common::Unretained(this)), module_handler_); + if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) { + api_type_ = ScanApiType::LE_5_0; + } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) { + api_type_ = ScanApiType::ANDROID_HCI; + } else { + api_type_ = ScanApiType::LE_4_0; + } + configure_scan(); + } + + void handle_scan_results(LeMetaEventView event) { + switch (event.GetSubeventCode()) { + case hci::SubeventCode::ADVERTISING_REPORT: + handle_advertising_report<LeAdvertisingReportView, LeAdvertisingReport, LeReport>( + LeAdvertisingReportView::Create(event)); + break; + case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT: + handle_advertising_report<LeDirectedAdvertisingReportView, LeDirectedAdvertisingReport, DirectedLeReport>( + LeDirectedAdvertisingReportView::Create(event)); + break; + case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT: + handle_advertising_report<LeExtendedAdvertisingReportView, LeExtendedAdvertisingReport, ExtendedLeReport>( + LeExtendedAdvertisingReportView::Create(event)); + break; + case hci::SubeventCode::SCAN_TIMEOUT: + if (registered_callback_ != nullptr) { + registered_callback_->handler->Post( + common::BindOnce(&LeScanningManagerCallbacks::on_timeout, common::Unretained(registered_callback_))); + registered_callback_ = nullptr; + } + break; + default: + LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str()); + } + } + + template <class EventType, class ReportStructType, class ReportType> + void handle_advertising_report(EventType event_view) { + if (registered_callback_ == nullptr) { + LOG_INFO("Dropping advertising event (no registered handler)"); + return; + } + if (!event_view.IsValid()) { + LOG_INFO("Dropping invalid advertising event"); + return; + } + std::vector<ReportStructType> report_vector = event_view.GetAdvertisingReports(); + if (report_vector.empty()) { + LOG_INFO("Zero results in advertising event"); + return; + } + std::vector<std::shared_ptr<LeReport>> param; + param.reserve(report_vector.size()); + for (const ReportStructType& report : report_vector) { + param.push_back(std::shared_ptr<LeReport>(static_cast<LeReport*>(new ReportType(report)))); + } + registered_callback_->handler->Post(common::BindOnce(&LeScanningManagerCallbacks::on_advertisements, + common::Unretained(registered_callback_), param)); + } + + void configure_scan() { + switch (api_type_) { + case ScanApiType::LE_5_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetExtendedScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, + own_address_type_, filter_policy_), + common::BindOnce(impl::check_status), module_handler_); + break; + case ScanApiType::ANDROID_HCI: + le_scanning_interface_->EnqueueCommand( + hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, + filter_policy_), + common::BindOnce(impl::check_status), module_handler_); + + break; + case ScanApiType::LE_4_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_, + filter_policy_), + common::BindOnce(impl::check_status), module_handler_); + break; + } + } + + void start_scan(LeScanningManagerCallbacks* le_scanning_manager_callbacks) { + registered_callback_ = le_scanning_manager_callbacks; + switch (api_type_) { + case ScanApiType::LE_5_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetExtendedScanEnableBuilder::Create(Enable::ENABLED, + FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), + common::BindOnce(impl::check_status), module_handler_); + break; + case ScanApiType::ANDROID_HCI: + case ScanApiType::LE_4_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */), + common::BindOnce(impl::check_status), module_handler_); + break; + } + } + + void stop_scan(common::Callback<void()> on_stopped) { + if (registered_callback_ == nullptr) { + return; + } + registered_callback_->handler->Post(std::move(on_stopped)); + switch (api_type_) { + case ScanApiType::LE_5_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetExtendedScanEnableBuilder::Create(Enable::DISABLED, + FilterDuplicates::DISABLED /* filter duplicates */, 0, 0), + common::BindOnce(impl::check_status), module_handler_); + registered_callback_->handler = nullptr; + break; + case ScanApiType::ANDROID_HCI: + case ScanApiType::LE_4_0: + le_scanning_interface_->EnqueueCommand( + hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */), + common::BindOnce(impl::check_status), module_handler_); + registered_callback_->handler = nullptr; + break; + } + } + + ScanApiType api_type_; + + LeScanningManagerCallbacks* registered_callback_; + Module* module_; + os::Handler* module_handler_; + hci::HciLayer* hci_layer_; + hci::Controller* controller_; + hci::LeScanningInterface* le_scanning_interface_; + + uint32_t interval_ms_{1000}; + uint16_t window_ms_{1000}; + AddressType own_address_type_{AddressType::PUBLIC_DEVICE_ADDRESS}; + LeSetScanningFilterPolicy filter_policy_{LeSetScanningFilterPolicy::ACCEPT_ALL}; + + static void check_status(CommandCompleteView view) { + switch (view.GetCommandOpCode()) { + case (OpCode::LE_SET_SCAN_ENABLE): { + auto status_view = LeSetScanEnableCompleteView::Create(view); + ASSERT(status_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + } break; + case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): { + auto status_view = LeSetExtendedScanEnableCompleteView::Create(view); + ASSERT(status_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + } break; + case (OpCode::LE_SET_SCAN_PARAMETERS): { + auto status_view = LeSetScanParametersCompleteView::Create(view); + ASSERT(status_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + } break; + case (OpCode::LE_EXTENDED_SCAN_PARAMS): { + auto status_view = LeExtendedScanParamsCompleteView::Create(view); + ASSERT(status_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + } break; + case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): { + auto status_view = LeSetExtendedScanParametersCompleteView::Create(view); + ASSERT(status_view.IsValid()); + ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS); + } break; + default: + LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str()); + } + } +}; + +LeScanningManager::LeScanningManager() { + pimpl_ = std::make_unique<impl>(this); +} + +void LeScanningManager::ListDependencies(ModuleList* list) { + list->add<hci::HciLayer>(); + list->add<hci::Controller>(); +} + +void LeScanningManager::Start() { + pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>()); +} + +void LeScanningManager::Stop() { + pimpl_.reset(); +} + +void LeScanningManager::StartScan(LeScanningManagerCallbacks* callbacks) { + GetHandler()->Post(common::Bind(&impl::start_scan, common::Unretained(pimpl_.get()), callbacks)); +} + +void LeScanningManager::StopScan(common::Callback<void()> on_stopped) { + GetHandler()->Post(common::Bind(&impl::stop_scan, common::Unretained(pimpl_.get()), on_stopped)); +} + +} // namespace hci +} // namespace bluetooth
\ No newline at end of file diff --git a/gd/hci/le_scanning_manager.h b/gd/hci/le_scanning_manager.h new file mode 100644 index 000000000..1de0f0862 --- /dev/null +++ b/gd/hci/le_scanning_manager.h @@ -0,0 +1,60 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <memory> + +#include "common/callback.h" +#include "hci/hci_packets.h" +#include "hci/le_report.h" +#include "module.h" + +namespace bluetooth { +namespace hci { + +class LeScanningManagerCallbacks { + public: + virtual ~LeScanningManagerCallbacks() = default; + virtual void on_advertisements(std::vector<std::shared_ptr<LeReport>>) = 0; + virtual void on_timeout() = 0; + os::Handler* handler; +}; + +class LeScanningManager : public bluetooth::Module { + public: + LeScanningManager(); + + void StartScan(LeScanningManagerCallbacks* callbacks); + + void StopScan(common::Callback<void()> on_stopped); + + static const ModuleFactory Factory; + + protected: + void ListDependencies(ModuleList* list) override; + + void Start() override; + + void Stop() override; + + private: + struct impl; + std::unique_ptr<impl> pimpl_; + DISALLOW_COPY_AND_ASSIGN(LeScanningManager); +}; + +} // namespace hci +} // namespace bluetooth
\ No newline at end of file diff --git a/gd/hci/le_scanning_manager_test.cc b/gd/hci/le_scanning_manager_test.cc new file mode 100644 index 000000000..e5e461e9b --- /dev/null +++ b/gd/hci/le_scanning_manager_test.cc @@ -0,0 +1,336 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hci/le_scanning_manager.h" + +#include <algorithm> +#include <chrono> +#include <future> +#include <map> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "common/bind.h" +#include "hci/address.h" +#include "hci/controller.h" +#include "hci/hci_layer.h" +#include "os/thread.h" +#include "packet/raw_builder.h" + +namespace bluetooth { +namespace hci { +namespace { + +using packet::kLittleEndian; +using packet::PacketView; +using packet::RawBuilder; + +PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) { + auto bytes = std::make_shared<std::vector<uint8_t>>(); + BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + return packet::PacketView<packet::kLittleEndian>(bytes); +} + +class TestController : public Controller { + public: + bool IsSupported(OpCode op_code) const override { + return supported_opcodes_.count(op_code) == 1; + } + + void AddSupported(OpCode op_code) { + supported_opcodes_.insert(op_code); + } + + protected: + void Start() override {} + void Stop() override {} + void ListDependencies(ModuleList* list) override {} + + private: + std::set<OpCode> supported_opcodes_{}; +}; + +class TestHciLayer : public HciLayer { + public: + TestHciLayer() { + RegisterEventHandler(EventCode::COMMAND_COMPLETE, + base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr); + RegisterEventHandler(EventCode::COMMAND_STATUS, + base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr); + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override { + command_queue_.push(std::move(command)); + command_status_callbacks.push_front(std::move(on_status)); + if (command_promise_ != nullptr) { + command_promise_->set_value(); + command_promise_.reset(); + } + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override { + command_queue_.push(std::move(command)); + command_complete_callbacks.push_front(std::move(on_complete)); + if (command_promise_ != nullptr) { + command_promise_->set_value(); + command_promise_.reset(); + } + } + + std::future<void> GetCommandFuture() { + ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time"); + command_promise_ = std::make_unique<std::promise<void>>(); + return command_promise_->get_future(); + } + + std::unique_ptr<CommandPacketBuilder> GetLastCommand() { + ASSERT(!command_queue_.empty()); + auto last = std::move(command_queue_.front()); + command_queue_.pop(); + return last; + } + + ConnectionManagementCommandView GetCommandPacket(OpCode op_code) { + auto packet_view = GetPacketView(GetLastCommand()); + CommandPacketView command_packet_view = CommandPacketView::Create(packet_view); + ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view); + ASSERT(command.IsValid()); + EXPECT_EQ(command.GetOpCode(), op_code); + + return command; + } + + void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler, + os::Handler* handler) override { + registered_events_[event_code] = event_handler; + } + + void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler, + os::Handler* handler) override { + registered_le_events_[subevent_code] = event_handler; + } + + void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + ASSERT_TRUE(event.IsValid()); + EventCode event_code = event.GetEventCode(); + ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code); + registered_events_[event_code].Run(event); + } + + void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + LeMetaEventView meta_event_view = LeMetaEventView::Create(event); + ASSERT_TRUE(meta_event_view.IsValid()); + SubeventCode subevent_code = meta_event_view.GetSubeventCode(); + ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end()) + << SubeventCodeText(subevent_code); + registered_le_events_[subevent_code].Run(meta_event_view); + } + + void CommandCompleteCallback(EventPacketView event) { + CommandCompleteView complete_view = CommandCompleteView::Create(event); + ASSERT(complete_view.IsValid()); + std::move(command_complete_callbacks.front()).Run(complete_view); + command_complete_callbacks.pop_front(); + } + + void CommandStatusCallback(EventPacketView event) { + CommandStatusView status_view = CommandStatusView::Create(event); + ASSERT(status_view.IsValid()); + std::move(command_status_callbacks.front()).Run(status_view); + command_status_callbacks.pop_front(); + } + + void ListDependencies(ModuleList* list) override {} + void Start() override {} + void Stop() override {} + + private: + std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_; + std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_; + std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks; + std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks; + + std::queue<std::unique_ptr<CommandPacketBuilder>> command_queue_; + mutable std::mutex mutex_; + std::unique_ptr<std::promise<void>> command_promise_{}; +}; + +class LeScanningManagerTest : public ::testing::Test { + protected: + void SetUp() override { + test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry + test_controller_ = new TestController; + test_controller_->AddSupported(param_opcode_); + fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); + fake_registry_.InjectTestModule(&Controller::Factory, test_controller_); + client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); + ASSERT_NE(client_handler_, nullptr); + mock_callbacks_.handler = client_handler_; + std::future<void> config_future = test_hci_layer_->GetCommandFuture(); + fake_registry_.Start<LeScanningManager>(&thread_); + le_scanning_manager = + static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory)); + config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000))); + HandleConfiguration(); + } + + void TearDown() override { + fake_registry_.SynchronizeModuleHandler(&LeScanningManager::Factory, std::chrono::milliseconds(20)); + fake_registry_.StopAll(); + } + + virtual void HandleConfiguration() { + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_SCAN_PARAMETERS); + test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + } + + TestModuleRegistry fake_registry_; + TestHciLayer* test_hci_layer_ = nullptr; + TestController* test_controller_ = nullptr; + os::Thread& thread_ = fake_registry_.GetTestThread(); + LeScanningManager* le_scanning_manager = nullptr; + os::Handler* client_handler_ = nullptr; + + class MockLeScanningManagerCallbacks : public LeScanningManagerCallbacks { + public: + MOCK_METHOD(void, on_advertisements, (std::vector<std::shared_ptr<LeReport>>), (override)); + MOCK_METHOD(void, on_timeout, (), (override)); + } mock_callbacks_; + + OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS}; +}; + +class LeAndroidHciScanningManagerTest : public LeScanningManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS; + LeScanningManagerTest::SetUp(); + } + + void HandleConfiguration() override { + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_EXTENDED_SCAN_PARAMS); + test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + } +}; + +class LeExtendedScanningManagerTest : public LeScanningManagerTest { + protected: + void SetUp() override { + param_opcode_ = OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS; + LeScanningManagerTest::SetUp(); + } + + void HandleConfiguration() override { + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS); + test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS)); + } +}; + +TEST_F(LeScanningManagerTest, startup_teardown) {} + +TEST_F(LeScanningManagerTest, start_scan_test) { + auto next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->StartScan(&mock_callbacks_); + + next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + LeAdvertisingReport report{}; + report.event_type_ = AdvertisingEventType::ADV_IND; + report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS; + Address::FromString("12:34:56:78:9a:bc", report.address_); + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + report.advertising_data_ = gap_data; + + EXPECT_CALL(mock_callbacks_, on_advertisements); + + test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); +} + +TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) { + auto next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->StartScan(&mock_callbacks_); + + next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + LeAdvertisingReport report{}; + report.event_type_ = AdvertisingEventType::ADV_IND; + report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS; + Address::FromString("12:34:56:78:9a:bc", report.address_); + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + report.advertising_data_ = gap_data; + + EXPECT_CALL(mock_callbacks_, on_advertisements); + + test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report})); +} + +TEST_F(LeExtendedScanningManagerTest, start_scan_test) { + auto next_command_future = test_hci_layer_->GetCommandFuture(); + le_scanning_manager->StartScan(&mock_callbacks_); + + next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100))); + auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_ENABLE); + + test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS)); + + LeExtendedAdvertisingReport report{}; + report.connectable_ = 1; + report.scannable_ = 1; + report.address_type_ = DirectAdvertisingAddressType::PUBLIC_DEVICE_ADDRESS; + Address::FromString("12:34:56:78:9a:bc", report.address_); + std::vector<GapData> gap_data{}; + GapData data_item{}; + data_item.data_type_ = GapDataType::FLAGS; + data_item.data_ = {0x34}; + gap_data.push_back(data_item); + data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME; + data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'}; + gap_data.push_back(data_item); + report.advertising_data_ = gap_data; + + EXPECT_CALL(mock_callbacks_, on_advertisements); + + test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report})); +} + +} // namespace +} // namespace hci +} // namespace bluetooth diff --git a/gd/l2cap/classic/cert/simple_l2cap_test.py b/gd/l2cap/classic/cert/simple_l2cap_test.py index 48065c4da..d8a52cd7c 100644 --- a/gd/l2cap/classic/cert/simple_l2cap_test.py +++ b/gd/l2cap/classic/cert/simple_l2cap_test.py @@ -29,6 +29,8 @@ from l2cap.classic.cert import api_pb2 as l2cap_cert_pb2 import time +ASYNC_OP_TIME_SECONDS = 1 # TODO: Use events to synchronize events instead + class SimpleL2capTest(GdBaseTestClass): def setup_test(self): self.device_under_test = self.gd_devices[0] @@ -85,14 +87,14 @@ class SimpleL2capTest(GdBaseTestClass): dut_connection_stream.unsubscribe() self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=0x101, psm=1)) - time.sleep(1) - + time.sleep(ASYNC_OP_TIME_SECONDS) open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest()) cid = open_channels.dcid[0] + self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(scid=cid)) + time.sleep(ASYNC_OP_TIME_SECONDS) dut_packet_stream.subscribe() cert_packet_stream.subscribe() - self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(scid=cid)) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"abc")) dut_packet_stream.assert_event_occurs( @@ -114,7 +116,7 @@ class SimpleL2capTest(GdBaseTestClass): ) self.cert_device.l2cap.SendDisconnectionRequest(l2cap_cert_pb2.DisconnectionRequest(dcid=0x40, scid=101)) - time.sleep(1) + time.sleep(ASYNC_OP_TIME_SECONDS) dut_packet_stream.unsubscribe() cert_packet_stream.unsubscribe() @@ -127,10 +129,37 @@ class SimpleL2capTest(GdBaseTestClass): lambda device: device.remote == self.dut_address ) cert_connection_stream.unsubscribe() - time.sleep(1) + time.sleep(ASYNC_OP_TIME_SECONDS) open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest()) assert len(open_channels.dcid) == 2 + def test_accept_disconnect(self): + """ + L2CAP/COS/CED/BV-07-C + """ + self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=0x01)) + cert_connection_stream = self.cert_device.l2cap.connection_complete_stream + cert_connection_stream.subscribe() + self.device_under_test.l2cap.Connect(self.cert_address) + cert_connection_stream.assert_event_occurs( + lambda device: device.remote == self.dut_address + ) + cert_connection_stream.unsubscribe() + time.sleep(ASYNC_OP_TIME_SECONDS) + cert_packet_stream = self.cert_device.l2cap.packet_stream + cert_packet_stream.subscribe() + open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest()) + cid = open_channels.dcid[0] + disconnection_request_packet = b"\x06\x01\x04\x00\x40\x00\x40\x01" + disconnection_response_packet = b"\x07\x01\x04\x00\x40\x00\x40\x01" + #TODO(b/143374372): Instead of hardcoding this, use packet builder + self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=disconnection_request_packet)) + cert_packet_stream.assert_event_occurs( + lambda packet: disconnection_response_packet in packet.payload + ) + cert_packet_stream.unsubscribe() + time.sleep(ASYNC_OP_TIME_SECONDS) # TODO(b/144186649): Remove this line + def test_basic_operation_request_connection(self): """ L2CAP/COS/CED/BV-01-C [Request Connection] @@ -167,4 +196,28 @@ class SimpleL2capTest(GdBaseTestClass): lambda packet: echo_response_packet in packet.payload ) cert_packet_stream.unsubscribe() + time.sleep(ASYNC_OP_TIME_SECONDS) # TODO(b/144186649): Remove this line + + def test_reject_unknown_command(self): + """ + L2CAP/COS/CED/BI-01-C + """ + cert_connection_stream = self.cert_device.l2cap.connection_complete_stream + cert_connection_stream.subscribe() + self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2)) + self.device_under_test.l2cap.Connect(self.cert_address) + cert_connection_stream.assert_event_occurs( + lambda device: device.remote == self.dut_address + ) + cert_connection_stream.unsubscribe() + cert_packet_stream = self.cert_device.l2cap.packet_stream + cert_packet_stream.subscribe() + invalid_command_packet = b"\xff\x01\x00\x00" + self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=invalid_command_packet)) + command_reject_packet = b"\x01\x01\x02\x00\x00\x00" + cert_packet_stream.assert_event_occurs( + lambda packet: command_reject_packet in packet.payload + ) + cert_packet_stream.unsubscribe() + time.sleep(ASYNC_OP_TIME_SECONDS) # TODO(b/144186649): Remove this line diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc index 47bfd5e93..d81096d5a 100644 --- a/gd/l2cap/classic/internal/dynamic_channel_impl.cc +++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc @@ -81,6 +81,14 @@ std::string DynamicChannelImpl::ToString() { return ss.str(); } +void DynamicChannelImpl::SetOutgoingConfigurationStatus(ConfigurationStatus status) { + outgoing_configuration_status_ = status; +} + +void DynamicChannelImpl::SetIncomingConfigurationStatus(ConfigurationStatus status) { + incoming_configuration_status_ = status; +} + } // namespace internal } // namespace classic } // namespace l2cap diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h index 8a6270a59..1f293eb33 100644 --- a/gd/l2cap/classic/internal/dynamic_channel_impl.h +++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h @@ -65,6 +65,19 @@ class DynamicChannelImpl { return psm_; } + enum class ConfigurationStatus { NOT_CONFIGURED, CONFIGURED }; + + virtual void SetOutgoingConfigurationStatus(ConfigurationStatus status); + virtual void SetIncomingConfigurationStatus(ConfigurationStatus status); + + virtual ConfigurationStatus GetOutgoingConfigurationStatus() const { + return outgoing_configuration_status_; + } + + virtual ConfigurationStatus GetIncomingConfigurationStatus() const { + return incoming_configuration_status_; + } + private: const Psm psm_; const Cid cid_; @@ -83,6 +96,8 @@ class DynamicChannelImpl { static constexpr size_t kChannelQueueSize = 10; common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{ kChannelQueueSize}; + ConfigurationStatus outgoing_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED; + ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED; DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl); }; diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc index 358062bca..d59d72205 100644 --- a/gd/l2cap/classic/internal/link.cc +++ b/gd/l2cap/classic/internal/link.cc @@ -58,7 +58,7 @@ void Link::Disconnect() { std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) { auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy); - scheduler_->AttachChannel(cid, channel->GetQueueDownEnd()); + scheduler_->AttachChannel(cid, channel->GetQueueDownEnd(), cid); return channel; } @@ -86,7 +86,7 @@ std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid re SecurityPolicy security_policy) { auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy); if (channel != nullptr) { - scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd()); + scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid()); } return channel; } @@ -95,7 +95,7 @@ std::shared_ptr<DynamicChannelImpl> Link::AllocateReservedDynamicChannel(Cid res SecurityPolicy security_policy) { auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy); if (channel != nullptr) { - scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd()); + scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid()); } return channel; } diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc index 8475bcc21..47792b08f 100644 --- a/gd/l2cap/classic/internal/signalling_manager.cc +++ b/gd/l2cap/classic/internal/signalling_manager.cc @@ -147,9 +147,7 @@ void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, } send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS, ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE); - std::unique_ptr<DynamicChannel> channel = std::make_unique<DynamicChannel>(new_channel, handler_); SendConfigurationRequest(remote_cid, {}); - dynamic_service_manager_->GetService(psm)->NotifyChannelCreation(std::move(channel)); } void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid, @@ -180,10 +178,8 @@ void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remo handle_send_next_command(); return; } - std::unique_ptr<DynamicChannel> channel = std::make_unique<DynamicChannel>(new_channel, handler_); - dynamic_service_manager_->GetService(pending_psm)->NotifyChannelCreation(std::move(channel)); - SendConfigurationRequest(remote_cid, {}); alarm_.Cancel(); + SendConfigurationRequest(remote_cid, {}); handle_send_next_command(); } @@ -194,10 +190,15 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci LOG_WARN("Configuration request for an unknown channel"); return; } - auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), cid, is_continuation, + auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation, ConfigurationResponseResult::SUCCESS, {}); enqueue_buffer_->Enqueue(std::move(response), handler_); handle_send_next_command(); + channel->SetIncomingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED); + if (channel->GetOutgoingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) { + std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_); + dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel)); + } } void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation, @@ -211,14 +212,18 @@ void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid c auto last_sent_command = std::move(pending_commands_.front()); pending_commands_.pop(); - auto channel = channel_allocator_->FindChannelByRemoteCid(cid); + auto channel = channel_allocator_->FindChannelByCid(cid); if (channel == nullptr) { LOG_WARN("Configuration request for an unknown channel"); handle_send_next_command(); return; } - // TODO(cmanton) verify configuration parameters are satisfied - // TODO(cmanton) Indicate channel is open if config params are agreed upon + channel->SetOutgoingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED); + if (channel->GetIncomingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) { + std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_); + dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel)); + } + alarm_.Cancel(); handle_send_next_command(); } @@ -229,20 +234,21 @@ void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid ci LOG_WARN("Disconnect request for an unknown channel"); return; } - auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), remote_cid, cid); + auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid); enqueue_buffer_->Enqueue(std::move(builder), handler_); channel->OnClosed(hci::ErrorCode::SUCCESS); link_->FreeDynamicChannel(cid); handle_send_next_command(); } -void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid) { +void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) { if (pending_commands_.empty()) { LOG_WARN("Unexpected response: no pending request"); return; } auto last_sent_command = std::move(pending_commands_.front()); pending_commands_.pop(); + alarm_.Cancel(); if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::DISCONNECTION_REQUEST) { @@ -282,6 +288,7 @@ void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketVi return; } LOG_INFO("Echo response received"); + alarm_.Cancel(); handle_send_next_command(); } @@ -322,6 +329,7 @@ void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const I return; } // TODO (hsz): Store the information response + alarm_.Cancel(); handle_send_next_command(); } @@ -433,6 +441,8 @@ void ClassicSignallingManager::on_incoming_packet() { } default: LOG_WARN("Unhandled event 0x%x", static_cast<int>(code)); + auto builder = CommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier()); + enqueue_buffer_->Enqueue(std::move(builder), handler_); return; } } diff --git a/gd/l2cap/internal/scheduler.h b/gd/l2cap/internal/scheduler.h index 7fd3790ee..32d00cfc9 100644 --- a/gd/l2cap/internal/scheduler.h +++ b/gd/l2cap/internal/scheduler.h @@ -48,8 +48,9 @@ class Scheduler { * * @param cid The channel to attach to the scheduler. * @param channel_down_end The ChannelQueueDownEnd associated with the channel to attach to the scheduler. + * @param remote_cid The destination endpoint of the packet. */ - virtual void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end) {} + virtual void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) {} /** * Detach the channel from the scheduler. diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc index 3e68c28fa..2e2677906 100644 --- a/gd/l2cap/internal/scheduler_fifo.cc +++ b/gd/l2cap/internal/scheduler_fifo.cc @@ -30,10 +30,10 @@ Fifo::~Fifo() { } } -void Fifo::AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end) { +void Fifo::AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) { ASSERT(channel_queue_end_map_.find(cid) == channel_queue_end_map_.end()); channel_queue_end_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid), - std::forward_as_tuple(handler_, channel_down_end, this, cid)); + std::forward_as_tuple(handler_, channel_down_end, this, cid, remote_cid)); } void Fifo::DetachChannel(Cid cid) { @@ -55,7 +55,8 @@ std::unique_ptr<Fifo::UpperDequeue> Fifo::link_queue_enqueue_callback() { link_queue_up_end_->UnregisterEnqueue(); link_queue_enqueue_registered_ = false; } - return BasicFrameBuilder::Create(channel_id, std::move(packet)); + Cid remote_channel_id = channel_queue_end_map_.find(channel_id)->second.remote_channel_id_; + return BasicFrameBuilder::Create(remote_channel_id, std::move(packet)); } void Fifo::try_register_link_queue_enqueue() { diff --git a/gd/l2cap/internal/scheduler_fifo.h b/gd/l2cap/internal/scheduler_fifo.h index f5a2415c6..3f14c7554 100644 --- a/gd/l2cap/internal/scheduler_fifo.h +++ b/gd/l2cap/internal/scheduler_fifo.h @@ -42,7 +42,7 @@ class Fifo : public Scheduler { } ~Fifo() override; - void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end) override; + void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) override; void DetachChannel(Cid cid) override; LowerQueueUpEnd* GetLowerQueueUpEnd() const override { return link_queue_up_end_; @@ -53,9 +53,10 @@ class Fifo : public Scheduler { os::Handler* handler_; struct ChannelQueueEndAndBuffer { - ChannelQueueEndAndBuffer(os::Handler* handler, UpperQueueDownEnd* queue_end, Fifo* scheduler, Cid channel_id) + ChannelQueueEndAndBuffer(os::Handler* handler, UpperQueueDownEnd* queue_end, Fifo* scheduler, Cid channel_id, + Cid remote_channel_id) : handler_(handler), queue_end_(queue_end), enqueue_buffer_(queue_end), scheduler_(scheduler), - channel_id_(channel_id) { + channel_id_(channel_id), remote_channel_id_(remote_channel_id) { try_register_dequeue(); } os::Handler* handler_; @@ -65,6 +66,7 @@ class Fifo : public Scheduler { std::queue<std::unique_ptr<UpperDequeue>> dequeue_buffer_; Fifo* scheduler_; Cid channel_id_; + Cid remote_channel_id_; bool is_dequeue_registered_ = false; void try_register_dequeue(); diff --git a/gd/l2cap/internal/scheduler_fifo_test.cc b/gd/l2cap/internal/scheduler_fifo_test.cc index 4ef4f9026..fe4d1498e 100644 --- a/gd/l2cap/internal/scheduler_fifo_test.cc +++ b/gd/l2cap/internal/scheduler_fifo_test.cc @@ -78,8 +78,8 @@ class L2capSchedulerFifoTest : public ::testing::Test { TEST_F(L2capSchedulerFifoTest, receive_packet) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_one_queue_{10}; common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_two_queue_{10}; - fifo_->AttachChannel(1, channel_one_queue_.GetDownEnd()); - fifo_->AttachChannel(2, channel_two_queue_.GetDownEnd()); + fifo_->AttachChannel(1, channel_one_queue_.GetDownEnd(), 1); + fifo_->AttachChannel(2, channel_two_queue_.GetDownEnd(), 2); os::EnqueueBuffer<Scheduler::UpperEnqueue> link_queue_enqueue_buffer{link_queue_.GetDownEnd()}; auto packet_one = CreateSampleL2capPacket(1, {1, 2, 3}); auto packet_two = CreateSampleL2capPacket(2, {4, 5, 6, 7}); @@ -103,8 +103,8 @@ TEST_F(L2capSchedulerFifoTest, receive_packet) { TEST_F(L2capSchedulerFifoTest, send_packet) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_one_queue_{10}; common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_two_queue_{10}; - fifo_->AttachChannel(1, channel_one_queue_.GetDownEnd()); - fifo_->AttachChannel(2, channel_two_queue_.GetDownEnd()); + fifo_->AttachChannel(1, channel_one_queue_.GetDownEnd(), 1); + fifo_->AttachChannel(2, channel_two_queue_.GetDownEnd(), 2); os::EnqueueBuffer<Scheduler::UpperDequeue> channel_one_enqueue_buffer{channel_one_queue_.GetUpEnd()}; os::EnqueueBuffer<Scheduler::UpperDequeue> channel_two_enqueue_buffer{channel_two_queue_.GetUpEnd()}; auto packet_one = std::make_unique<packet::RawBuilder>(); diff --git a/gd/l2cap/internal/scheduler_mock.h b/gd/l2cap/internal/scheduler_mock.h index b49e138d4..616d15634 100644 --- a/gd/l2cap/internal/scheduler_mock.h +++ b/gd/l2cap/internal/scheduler_mock.h @@ -29,7 +29,7 @@ using hci::testing::MockAclConnection; class MockScheduler : public Scheduler { public: - MOCK_METHOD(void, AttachChannel, (Cid cid, UpperQueueDownEnd* channel_down_end), (override)); + MOCK_METHOD(void, AttachChannel, (Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid), (override)); MOCK_METHOD(void, DetachChannel, (Cid cid), (override)); MOCK_METHOD(LowerQueueUpEnd*, GetLowerQueueUpEnd, (), (override, const)); }; @@ -37,4 +37,4 @@ class MockScheduler : public Scheduler { } // namespace testing } // namespace internal } // namespace l2cap -} // namespace bluetooth
\ No newline at end of file +} // namespace bluetooth diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h index cda866be8..85f0280ce 100644 --- a/gd/l2cap/le/internal/link.h +++ b/gd/l2cap/le/internal/link.h @@ -69,7 +69,7 @@ class Link { virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) { auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy); - scheduler_->AttachChannel(cid, channel->GetQueueDownEnd()); + scheduler_->AttachChannel(cid, channel->GetQueueDownEnd(), cid); return channel; } diff --git a/gd/security/Android.bp b/gd/security/Android.bp index ee682b4f8..776246195 100644 --- a/gd/security/Android.bp +++ b/gd/security/Android.bp @@ -7,8 +7,11 @@ filegroup { "pairing_handler_le.cc", "pairing_handler_le_legacy.cc", "pairing_handler_le_secure_connections.cc", + "security_manager.cc", + "internal/security_manager_impl.cc", "security_module.cc", - ] + ":BluetoothSecurityChannelSources", + ], } filegroup { @@ -18,5 +21,6 @@ filegroup { "pairing_handler_le_unittest.cc", "test/fake_l2cap_test.cc", "test/pairing_handler_le_pair_test.cc", - ] + ":BluetoothSecurityChannelTestSources", + ], } diff --git a/gd/security/channel/Android.bp b/gd/security/channel/Android.bp new file mode 100644 index 000000000..653902b15 --- /dev/null +++ b/gd/security/channel/Android.bp @@ -0,0 +1,13 @@ +filegroup { + name: "BluetoothSecurityChannelSources", + srcs: [ + "security_manager_channel.cc", + ] +} + +filegroup { + name: "BluetoothSecurityChannelTestSources", + srcs: [ + "security_manager_channel_unittest.cc", + ] +} diff --git a/gd/security/channel/security_manager_channel.cc b/gd/security/channel/security_manager_channel.cc new file mode 100644 index 000000000..419386d00 --- /dev/null +++ b/gd/security/channel/security_manager_channel.cc @@ -0,0 +1,93 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "security_manager_channel.h" + +#include "security/smp_packets.h" + +using namespace bluetooth::hci; +using namespace bluetooth::packet; +using namespace bluetooth::security::channel; + +void SecurityManagerChannel::SendCommand(std::shared_ptr<hci::Device> device, + std::unique_ptr<SecurityCommandBuilder> command) { + hci_security_interface_->EnqueueCommand( + std::move(command), common::BindOnce(&SecurityManagerChannel::OnCommandComplete, common::Unretained(this)), + handler_); +} + +void SecurityManagerChannel::OnCommandComplete(CommandCompleteView packet) { + ASSERT_LOG(packet.IsValid(), "Received invalid packet: %hx", packet.GetCommandOpCode()); + // TODO(optedoblivion): Verify HCI commands +} + +void SecurityManagerChannel::OnHciEventReceived(EventPacketView packet) { + ASSERT_LOG(listener_ != nullptr, "No listener set!"); + std::shared_ptr<Device> device = nullptr; + auto event = EventPacketView::Create(std::move(packet)); + ASSERT_LOG(event.IsValid(), "Received invalid packet: %hhx", event.GetEventCode()); + const hci::EventCode code = event.GetEventCode(); + switch (code) { + case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE: + listener_->OnChangeConnectionLinkKeyComplete(device, + hci::ChangeConnectionLinkKeyCompleteView::Create(std::move(event))); + break; + case hci::EventCode::MASTER_LINK_KEY_COMPLETE: + listener_->OnMasterLinkKeyComplete(device, hci::MasterLinkKeyCompleteView::Create(std::move(event))); + break; + case hci::EventCode::PIN_CODE_REQUEST: + listener_->OnPinCodeRequest(device, hci::PinCodeRequestView::Create(std::move(event))); + break; + case hci::EventCode::LINK_KEY_REQUEST: + listener_->OnLinkKeyRequest(device, hci::LinkKeyRequestView::Create(std::move(event))); + break; + case hci::EventCode::LINK_KEY_NOTIFICATION: + listener_->OnLinkKeyNotification(device, hci::LinkKeyNotificationView::Create(std::move(event))); + break; + case hci::EventCode::IO_CAPABILITY_REQUEST: + listener_->OnIoCapabilityRequest(device, hci::IoCapabilityRequestView::Create(std::move(event))); + break; + case hci::EventCode::IO_CAPABILITY_RESPONSE: + listener_->OnIoCapabilityResponse(device, IoCapabilityResponseView::Create(std::move(event))); + break; + case hci::EventCode::SIMPLE_PAIRING_COMPLETE: + listener_->OnSimplePairingComplete(device, SimplePairingCompleteView::Create(std::move(event))); + break; + case hci::EventCode::RETURN_LINK_KEYS: + listener_->OnReturnLinkKeys(device, hci::ReturnLinkKeysView::Create(std::move(event))); + break; + case hci::EventCode::ENCRYPTION_CHANGE: + listener_->OnEncryptionChange(device, hci::EncryptionChangeView::Create(std::move(event))); + break; + case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE: + listener_->OnEncryptionKeyRefreshComplete(device, + hci::EncryptionKeyRefreshCompleteView::Create(std::move(event))); + break; + case hci::EventCode::REMOTE_OOB_DATA_REQUEST: + listener_->OnRemoteOobDataRequest(device, hci::RemoteOobDataRequestView::Create(std::move(event))); + break; + case hci::EventCode::USER_PASSKEY_NOTIFICATION: + // listener_->OnUserPasskeyNotification(device, <packet>); + break; + case hci::EventCode::KEYPRESS_NOTIFICATION: + // listener_->OnSendKeypressNotification(device, <packet>); + break; + default: + ASSERT_LOG(false, "Invalid packet received: %hhx", code); + break; + } +} diff --git a/gd/security/channel/security_manager_channel.h b/gd/security/channel/security_manager_channel.h new file mode 100644 index 000000000..6a2b624bb --- /dev/null +++ b/gd/security/channel/security_manager_channel.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0; + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#pragma once + +#include <memory> +#include <vector> + +#include "hci/classic_device.h" +#include "hci/hci_layer.h" +#include "hci/security_interface.h" +#include "security/smp_packets.h" + +namespace bluetooth { +namespace security { +namespace channel { + +using hci::CommandCompleteView; +using hci::EventPacketView; +using hci::SecurityCommandBuilder; +using hci::SecurityCommandView; + +/** + * Interface for listening to the channel for SMP commands. + */ +class ISecurityManagerChannelListener { + public: + virtual ~ISecurityManagerChannelListener() = default; + + virtual void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device, + hci::ChangeConnectionLinkKeyCompleteView packet) = 0; + virtual void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) = 0; + virtual void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) = 0; + virtual void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) = 0; + virtual void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) = 0; + virtual void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet) = 0; + virtual void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet) = 0; + virtual void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet) = 0; + virtual void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet) = 0; + virtual void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet) = 0; + virtual void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device, + hci::EncryptionKeyRefreshCompleteView packet) = 0; + virtual void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet) = 0; +}; + +/** + * Channel for consolidating traffic and making the transport agnostic. + */ +class SecurityManagerChannel { + public: + explicit SecurityManagerChannel(os::Handler* handler, hci::HciLayer* hci_layer) + : listener_(nullptr), + hci_security_interface_(hci_layer->GetSecurityInterface( + common::Bind(&SecurityManagerChannel::OnHciEventReceived, common::Unretained(this)), handler)), + handler_(handler) {} + ~SecurityManagerChannel() { + delete listener_; + } + + /** + * Send a given SMP command over the SecurityManagerChannel + * + * @param device target where command will be sent + * @param command smp command to send + */ + void SendCommand(std::shared_ptr<hci::Device> device, std::unique_ptr<SecurityCommandBuilder> command); + + /** + * Sets the listener to listen for channel events + * + * @param listener the caller interested in events + */ + void SetChannelListener(ISecurityManagerChannelListener* listener) { + listener_ = listener; + } + + /** + * Called when an incoming HCI event happens + * + * @param event_packet + */ + void OnHciEventReceived(EventPacketView packet); + + /** + * Called when an HCI command is completed + * + * @param on_complete + */ + void OnCommandComplete(CommandCompleteView packet); + + private: + ISecurityManagerChannelListener* listener_; + hci::SecurityInterface* hci_security_interface_; + os::Handler* handler_; +}; + +} // namespace channel +} // namespace security +} // namespace bluetooth diff --git a/gd/security/channel/security_manager_channel_unittest.cc b/gd/security/channel/security_manager_channel_unittest.cc new file mode 100644 index 000000000..f34625573 --- /dev/null +++ b/gd/security/channel/security_manager_channel_unittest.cc @@ -0,0 +1,276 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "security_manager_channel.h" + +#include <gtest/gtest.h> + +#include "hci/device.h" +#include "hci/device_database.h" +#include "hci/hci_packets.h" +#include "packet/raw_builder.h" +#include "security/smp_packets.h" +#include "security/test/fake_hci_layer.h" + +namespace bluetooth { +namespace security { +namespace channel { +namespace { + +using bluetooth::security::channel::SecurityManagerChannel; +using hci::AuthenticationRequirements; +using hci::CommandCompleteBuilder; +using hci::Device; +using hci::DeviceDatabase; +using hci::IoCapabilityRequestReplyBuilder; +using hci::IoCapabilityRequestView; +using hci::OobDataPresent; +using hci::OpCode; +using os::Handler; +using os::Thread; +using packet::RawBuilder; + +static DeviceDatabase kDeviceDatabase; + +class TestPayloadBuilder : public PacketBuilder<kLittleEndian> { + public: + ~TestPayloadBuilder() override = default; + size_t size() const override { + return 1; + } + void Serialize(BitInserter& inserter) const override {} + static std::unique_ptr<TestPayloadBuilder> Create() { + return std::unique_ptr<TestPayloadBuilder>(new TestPayloadBuilder()); + } + + private: + TestPayloadBuilder() : PacketBuilder<kLittleEndian>(){}; +}; + +class SecurityManagerChannelCallback : public ISecurityManagerChannelListener { + public: + // HCI + bool receivedChangeConnectionLinkKeyComplete = false; + bool receivedMasterLinkKeyComplete = false; + bool receivedPinCodeRequest = false; + bool receivedLinkKeyRequest = false; + bool receivedLinkKeyNotification = false; + bool receivedIoCapabilityRequest = false; + bool receivedIoCapabilityResponse = false; + bool receivedSimplePairingComplete = false; + bool receivedReturnLinkKeys = false; + bool receivedEncryptionChange = false; + bool receivedEncryptionKeyRefreshComplete = false; + bool receivedRemoteOobDataRequest = false; + + void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device, + hci::ChangeConnectionLinkKeyCompleteView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedChangeConnectionLinkKeyComplete = true; + } + void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedMasterLinkKeyComplete = true; + } + void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedPinCodeRequest = true; + } + void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedLinkKeyRequest = true; + } + void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedLinkKeyNotification = true; + } + void OnIoCapabilityRequest(std::shared_ptr<Device> device, hci::IoCapabilityRequestView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedIoCapabilityRequest = true; + } + void OnIoCapabilityResponse(std::shared_ptr<Device> device, hci::IoCapabilityResponseView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedIoCapabilityResponse = true; + } + void OnSimplePairingComplete(std::shared_ptr<Device> device, hci::SimplePairingCompleteView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedSimplePairingComplete = true; + } + void OnReturnLinkKeys(std::shared_ptr<Device> device, hci::ReturnLinkKeysView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedReturnLinkKeys = true; + } + void OnEncryptionChange(std::shared_ptr<Device> device, hci::EncryptionChangeView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedEncryptionChange = true; + } + void OnEncryptionKeyRefreshComplete(std::shared_ptr<Device> device, hci::EncryptionKeyRefreshCompleteView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedEncryptionKeyRefreshComplete = true; + } + void OnRemoteOobDataRequest(std::shared_ptr<Device> device, hci::RemoteOobDataRequestView packet) { + EXPECT_TRUE(packet.IsValid()); + receivedRemoteOobDataRequest = true; + } +}; + +class SecurityManagerChannelTest : public ::testing::Test { + protected: + void SetUp() override { + device_ = kDeviceDatabase.CreateClassicDevice(hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06})); + handler_ = new Handler(&thread_); + callback_ = new SecurityManagerChannelCallback(); + hci_layer_ = new FakeHciLayer(); + fake_registry_.InjectTestModule(&FakeHciLayer::Factory, hci_layer_); + fake_registry_.Start<FakeHciLayer>(&thread_); + channel_ = new SecurityManagerChannel(handler_, hci_layer_); + channel_->SetChannelListener(callback_); + } + + void TearDown() override { + channel_->SetChannelListener(nullptr); + handler_->Clear(); + fake_registry_.SynchronizeModuleHandler(&FakeHciLayer::Factory, std::chrono::milliseconds(20)); + fake_registry_.StopAll(); + delete handler_; + delete channel_; + delete callback_; + } + + TestModuleRegistry fake_registry_; + Thread& thread_ = fake_registry_.GetTestThread(); + Handler* handler_ = nullptr; + FakeHciLayer* hci_layer_ = nullptr; + SecurityManagerChannel* channel_ = nullptr; + SecurityManagerChannelCallback* callback_ = nullptr; + std::shared_ptr<Device> device_ = nullptr; +}; + +TEST_F(SecurityManagerChannelTest, setup_teardown) {} + +TEST_F(SecurityManagerChannelTest, recv_io_cap_request) { + hci_layer_->IncomingEvent(hci::IoCapabilityRequestBuilder::Create(device_->GetAddress())); + EXPECT_TRUE(callback_->receivedIoCapabilityRequest); +} + +TEST_F(SecurityManagerChannelTest, send_io_cap_request_reply) { + // Arrange + hci::IoCapability io_capability = (hci::IoCapability)0x00; + OobDataPresent oob_present = (OobDataPresent)0x00; + AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00; + auto packet = hci::IoCapabilityRequestReplyBuilder::Create(device_->GetAddress(), io_capability, oob_present, + authentication_requirements); + + // Act + channel_->SendCommand(device_, std::move(packet)); + auto last_command = std::move(hci_layer_->GetLastCommand()->command); + auto command_packet = GetPacketView(std::move(last_command)); + hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet); + + // Assert + EXPECT_TRUE(packet_view.IsValid()); + EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, packet_view.GetOpCode()); +} + +TEST_F(SecurityManagerChannelTest, send_io_cap_request_neg_reply) { + // Arrange + auto packet = + hci::IoCapabilityRequestNegativeReplyBuilder::Create(device_->GetAddress(), hci::ErrorCode::COMMAND_DISALLOWED); + + // Act + channel_->SendCommand(device_, std::move(packet)); + auto last_command = std::move(hci_layer_->GetLastCommand()->command); + auto command_packet = GetPacketView(std::move(last_command)); + hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet); + + // Assert + EXPECT_TRUE(packet_view.IsValid()); + EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode()); +} + +TEST_F(SecurityManagerChannelTest, recv_io_cap_response) { + hci::IoCapability io_capability = (hci::IoCapability)0x00; + OobDataPresent oob_present = (OobDataPresent)0x00; + AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00; + hci_layer_->IncomingEvent(hci::IoCapabilityResponseBuilder::Create(device_->GetAddress(), io_capability, oob_present, + authentication_requirements)); + EXPECT_TRUE(callback_->receivedIoCapabilityResponse); +} + +TEST_F(SecurityManagerChannelTest, recv_pin_code_request) { + hci_layer_->IncomingEvent(hci::PinCodeRequestBuilder::Create(device_->GetAddress())); + EXPECT_TRUE(callback_->receivedPinCodeRequest); +} + +TEST_F(SecurityManagerChannelTest, send_pin_code_request_reply) {} + +TEST_F(SecurityManagerChannelTest, send_pin_code_request_neg_reply) {} + +TEST_F(SecurityManagerChannelTest, recv_user_passkey_notification) {} + +TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_reply) {} + +TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_neg_reply) {} + +TEST_F(SecurityManagerChannelTest, recv_remote_oob_data_request) {} + +TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_reply) {} + +TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_neg_reply) {} + +TEST_F(SecurityManagerChannelTest, send_read_local_oob_data) {} + +TEST_F(SecurityManagerChannelTest, send_read_local_oob_extended_data) {} + +TEST_F(SecurityManagerChannelTest, recv_link_key_request) {} + +TEST_F(SecurityManagerChannelTest, recv_link_key_notification) {} + +TEST_F(SecurityManagerChannelTest, recv_master_link_complete) {} + +TEST_F(SecurityManagerChannelTest, recv_change_connection_link_key_complete) {} + +TEST_F(SecurityManagerChannelTest, recv_return_link_keys) {} + +TEST_F(SecurityManagerChannelTest, send_link_key_reply) {} + +TEST_F(SecurityManagerChannelTest, send_link_key_neg_reply) {} + +TEST_F(SecurityManagerChannelTest, send_read_stored_link_key) {} + +TEST_F(SecurityManagerChannelTest, send_write_stored_link_key) {} + +TEST_F(SecurityManagerChannelTest, send_delete_stored_link_key) {} + +TEST_F(SecurityManagerChannelTest, recv_encryption_change) {} + +TEST_F(SecurityManagerChannelTest, send_refresh_encryption_key) {} + +TEST_F(SecurityManagerChannelTest, send_read_encryption_key_size) {} + +TEST_F(SecurityManagerChannelTest, recv_simple_pairing_complete) {} + +TEST_F(SecurityManagerChannelTest, send_read_simple_pairing_mode) {} + +TEST_F(SecurityManagerChannelTest, send_write_simple_pairing_mode) {} + +TEST_F(SecurityManagerChannelTest, send_keypress_notification) {} + +} // namespace +} // namespace channel +} // namespace security +} // namespace bluetooth diff --git a/gd/security/internal/security_manager_impl.cc b/gd/security/internal/security_manager_impl.cc new file mode 100644 index 000000000..21d8151b9 --- /dev/null +++ b/gd/security/internal/security_manager_impl.cc @@ -0,0 +1,152 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "security_manager_impl.h" + +#include <iostream> +#include <unordered_map> + +#include "os/log.h" +#include "security/pairing/classic_pairing_handler.h" + +using namespace bluetooth::security::internal; +using bluetooth::hci::Device; +using bluetooth::hci::DeviceType; +using bluetooth::security::pairing::PairingHandler; + +namespace { +std::unordered_map<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>> pairing_handler_map_; + +void dispatch_new_pairing_handler(std::shared_ptr<bluetooth::security::record::SecurityRecord> record) { + auto entry = pairing_handler_map_.find(record->GetDevice()); + if (entry != pairing_handler_map_.end()) { + LOG_WARN("Device already has a pairing handler, and is in the middle of pairing!"); + return; + } + std::unique_ptr<PairingHandler> pairing_handler = nullptr; + switch (record->GetDevice()->GetDeviceType()) { + case DeviceType::CLASSIC: + pairing_handler = std::make_unique<bluetooth::security::pairing::ClassicPairingHandler>(record); + break; + default: + ASSERT_LOG(false, "Pairing type %d not implemented!", record->GetDevice()->GetDeviceType()); + } + auto new_entry = std::pair<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>>(record->GetDevice(), + std::move(pairing_handler)); + pairing_handler_map_.insert(std::move(new_entry)); +} +} // namespace + +void SecurityManagerImpl::Init() { + // TODO(optedoblivion): Populate security record memory map from disk + // security_manager_channel_->SetChannelListener(this); +} + +void SecurityManagerImpl::CreateBond(std::shared_ptr<hci::ClassicDevice> device) { + std::string uuid = device->GetUuid(); + // Security record check + // if (device_database_->GetDeviceById(uuid) != nullptr) { + // LOG_WARN("Device already exists in the database"); + // TODO(optedoblivion): Check security record if device is already bonded + // if no security record, need to initiate bonding + // if security record and not bonded, need to initiate bonding + // if security record and is bonded, then do nothing + // } + + // device_database_->AddDevice(device); + // Create security record + // Pass to pairing handler + std::shared_ptr<record::SecurityRecord> record = std::make_shared<record::SecurityRecord>(device); + dispatch_new_pairing_handler(record); + // init the pairing handler + // Update bonded flag on security record + // Update bonded flag on device to BONDING (pairing handler does this) +} + +void SecurityManagerImpl::CancelBond(std::shared_ptr<hci::ClassicDevice> device) { + auto entry = pairing_handler_map_.find(device); + if (entry != pairing_handler_map_.end()) { + pairing_handler_map_.erase(device); + } + // Remove from DB + // device_database_->RemoveDevice(device); + // Remove from map, no longer will the event queue use it + // If currently bonding, cancel pairing handler job + // else, cancel fails +} + +void SecurityManagerImpl::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) { + CancelBond(device); + // Update bonded flag on device to UNBONDED + // Signal disconnect + // Signal unbonding + // Remove security record + // Signal Remove from database +} + +void SecurityManagerImpl::RegisterCallbackListener(ISecurityManagerListener* listener) { + if (listeners_.size() < 1) { + listeners_.push_back(listener); + } else { + bool found = false; + for (auto it = listeners_.begin(); it != listeners_.end(); ++it) { + found = *it == listener; + if (found) break; + } + + if (found) { + LOG_ERROR("Listener has already been registered!"); + } else { + listeners_.push_back(listener); + } + } +} + +void SecurityManagerImpl::UnregisterCallbackListener(ISecurityManagerListener* listener) { + if (listeners_.size() < 1) { + LOG_ERROR("Listener has not been registered!"); + } else { + bool found = false; + auto it = listeners_.begin(); + while (it != listeners_.end()) { + found = *it == listener; + if (found) break; + ++it; + } + if (found) { + listeners_.erase(it); + } + } +} + +void SecurityManagerImpl::FireDeviceBondedCallbacks(std::shared_ptr<Device> device) { + for (auto& iter : listeners_) { + iter->handler_->Post(common::Bind(&ISecurityManagerListener::OnDeviceBonded, common::Unretained(iter), device)); + } +} + +void SecurityManagerImpl::FireBondFailedCallbacks(std::shared_ptr<Device> device) { + for (auto& iter : listeners_) { + iter->handler_->Post(common::Bind(&ISecurityManagerListener::OnDeviceBondFailed, common::Unretained(iter), device)); + } +} + +void SecurityManagerImpl::FireUnbondCallbacks(std::shared_ptr<Device> device) { + for (auto& iter : listeners_) { + iter->handler_->Post(common::Bind(&ISecurityManagerListener::OnDeviceUnbonded, common::Unretained(iter), device)); + } +} diff --git a/gd/security/internal/security_manager_impl.h b/gd/security/internal/security_manager_impl.h index 183cfae3e..13d66b919 100644 --- a/gd/security/internal/security_manager_impl.h +++ b/gd/security/internal/security_manager_impl.h @@ -16,30 +16,139 @@ #pragma once +#include "hci/classic_device.h" #include "l2cap/classic/l2cap_classic_module.h" #include "l2cap/le/l2cap_le_module.h" #include "os/handler.h" +#include "security/channel/security_manager_channel.h" namespace bluetooth { namespace security { namespace internal { -class SecurityManagerImpl { +/** + * Interface for listening to the channel for SMP commands. + */ +class ISecurityManagerListener { + public: + ISecurityManagerListener(os::Handler* handler) : handler_(handler) {} + virtual ~ISecurityManagerListener() = default; + + /** + * Called when a device is successfully bonded. + * + * @param device pointer to the bonded device + */ + virtual void OnDeviceBonded(std::shared_ptr<bluetooth::hci::Device> device); + + /** + * Called when a device is successfully un-bonded. + * + * @param device pointer to the device that is no longer bonded + */ + virtual void OnDeviceUnbonded(std::shared_ptr<bluetooth::hci::Device> device); + + /** + * Called as a result of a failure during the bonding process. + * + * @param device pointer to the device that is no longer bonded + */ + virtual void OnDeviceBondFailed(std::shared_ptr<bluetooth::hci::Device> device); + + bool operator==(const ISecurityManagerListener& rhs) const { + return &*this == &rhs; + } + + os::Handler* handler_ = nullptr; +}; + +class SecurityManagerImpl /*: public channel::ISecurityManagerChannelListener*/ { public: explicit SecurityManagerImpl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module, - l2cap::classic::L2capClassicModule* l2cap_classic_module) + l2cap::classic::L2capClassicModule* l2cap_classic_module, + channel::SecurityManagerChannel* security_manager_channel) : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module), - l2cap_classic_module_(l2cap_classic_module) {} + l2cap_classic_module_(l2cap_classic_module), security_manager_channel_(security_manager_channel) {} virtual ~SecurityManagerImpl() = default; - // All APIs must be invoked in L2CAP layer handler + // All APIs must be invoked in SM layer handler + + /** + * Initialize the security record map from an internal device database. + */ + void Init(); + + /** + * Checks the device for existing bond, if not bonded, initiates pairing. + * + * @param device pointer to device we want to bond with + * @return true if bonded or pairing started successfully, false if currently pairing + */ + void CreateBond(std::shared_ptr<hci::ClassicDevice> device); + + /* void CreateBond(std::shared_ptr<hci::LeDevice> device); */ + + /** + * Cancels the pairing process for this device. + * + * @param device pointer to device with which we want to cancel our bond + * @return <code>true</code> if successfully stopped + */ + void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device); + + /* void CancelBond(std::shared_ptr<hci::LeDevice> device); */ + + /** + * Disassociates the device and removes the persistent LTK + * + * @param device pointer to device we want to forget + * @return true if removed + */ + void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device); + + /* void RemoveBond(std::shared_ptr<hci::LeDevice> device); */ + + /** + * Register to listen for callback events from SecurityManager + * + * @param listener ISecurityManagerListener instance to handle callbacks + */ + void RegisterCallbackListener(ISecurityManagerListener* listener); + + /** + * Unregister listener for callback events from SecurityManager + * + * @param listener ISecurityManagerListener instance to unregister + */ + void UnregisterCallbackListener(ISecurityManagerListener* listener); + + protected: + std::vector<ISecurityManagerListener*> listeners_; + void FireDeviceBondedCallbacks(std::shared_ptr<bluetooth::hci::Device> device); + void FireBondFailedCallbacks(std::shared_ptr<bluetooth::hci::Device> device); + void FireUnbondCallbacks(std::shared_ptr<bluetooth::hci::Device> device); - // TODO: put all API methods here + // ISecurityManagerChannel + void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device, + hci::ChangeConnectionLinkKeyCompleteView packet); + void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet); + void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet); + void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet); + void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet); + void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet); + void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet); + void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet); + void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet); + void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet); + void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device, + hci::EncryptionKeyRefreshCompleteView packet); + void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet); private: os::Handler* security_handler_ __attribute__((unused)); l2cap::le::L2capLeModule* l2cap_le_module_ __attribute__((unused)); l2cap::classic::L2capClassicModule* l2cap_classic_module_ __attribute__((unused)); + channel::SecurityManagerChannel* security_manager_channel_ __attribute__((unused)); }; } // namespace internal } // namespace security diff --git a/gd/security/pairing/classic_pairing_handler.h b/gd/security/pairing/classic_pairing_handler.h new file mode 100644 index 000000000..fc8eed4c7 --- /dev/null +++ b/gd/security/pairing/classic_pairing_handler.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License") override; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#pragma once + +#include "pairing_handler.h" + +#include "security/smp_packets.h" + +using namespace bluetooth::security::pairing; + +namespace bluetooth { +namespace security { +namespace pairing { + +class ClassicPairingHandler : public PairingHandler { + public: + explicit ClassicPairingHandler(std::shared_ptr<record::SecurityRecord> record) : PairingHandler(record) {} + + void Init() { + // Set auth required + // Connect to device + } +}; + +} // namespace pairing +} // namespace security +} // namespace bluetooth diff --git a/gd/security/pairing/pairing_handler.h b/gd/security/pairing/pairing_handler.h new file mode 100644 index 000000000..61cad6258 --- /dev/null +++ b/gd/security/pairing/pairing_handler.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#pragma once + +#include <memory> +#include <vector> + +#include "hci/device.h" +#include "security/channel/security_manager_channel.h" +#include "security/record/security_record.h" +#include "security/smp_packets.h" + +namespace bluetooth { +namespace security { +namespace pairing { + +/** + * Base structure for handling pairing events. + * + * <p>Extend this class in order to implement a new style of pairing. + */ +class PairingHandler { + public: + PairingHandler(std::shared_ptr<record::SecurityRecord> record) : record_(record){}; + virtual ~PairingHandler() = default; + + std::shared_ptr<record::SecurityRecord> GetRecord() { + return record_; + } + + private: + std::shared_ptr<record::SecurityRecord> record_ __attribute__((unused)); +}; + +} // namespace pairing +} // namespace security +} // namespace bluetooth diff --git a/gd/security/record/security_record.h b/gd/security/record/security_record.h new file mode 100644 index 000000000..0c78113ab --- /dev/null +++ b/gd/security/record/security_record.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#pragma once + +#include <memory> + +#include "hci/device.h" + +namespace bluetooth { +namespace security { +namespace record { + +enum BondState { NOT_BONDED, PAIRING, BONDED }; + +class SecurityRecord { + public: + SecurityRecord(std::shared_ptr<hci::Device> device) : device_(device), state_(NOT_BONDED) {} + + /** + * Returns true if the device is bonded to another device + */ + bool IsBonded() { + return state_ == BONDED; + } + + /** + * Returns true if a device is currently pairing to another device + */ + bool IsPairing() { + return state_ == PAIRING; + } + + std::shared_ptr<hci::Device> GetDevice() { + return device_; + } + + private: + const std::shared_ptr<hci::Device> device_; + BondState state_; +}; + +} // namespace record +} // namespace security +} // namespace bluetooth diff --git a/gd/security/security_manager.cc b/gd/security/security_manager.cc new file mode 100644 index 000000000..9a7df85ef --- /dev/null +++ b/gd/security/security_manager.cc @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "security_manager.h" + +#include "os/log.h" + +using namespace bluetooth::security; + +void SecurityManager::Init() { + security_handler_->Post( + common::BindOnce(&internal::SecurityManagerImpl::Init, common::Unretained(security_manager_impl_))); +} + +void SecurityManager::CreateBond(std::shared_ptr<hci::ClassicDevice> device) { + security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CreateBond, + common::Unretained(security_manager_impl_), + std::forward<std::shared_ptr<hci::ClassicDevice>>(device))); +} + +void SecurityManager::CancelBond(std::shared_ptr<hci::ClassicDevice> device) { + security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CancelBond, + common::Unretained(security_manager_impl_), + std::forward<std::shared_ptr<hci::ClassicDevice>>(device))); +} + +void SecurityManager::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) { + security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RemoveBond, + common::Unretained(security_manager_impl_), + std::forward<std::shared_ptr<hci::ClassicDevice>>(device))); +} + +void SecurityManager::RegisterCallbackListener(internal::ISecurityManagerListener* listener) { + security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RegisterCallbackListener, + common::Unretained(security_manager_impl_), + std::forward<internal::ISecurityManagerListener*>(listener))); +} + +void SecurityManager::UnregisterCallbackListener(internal::ISecurityManagerListener* listener) { + security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::UnregisterCallbackListener, + common::Unretained(security_manager_impl_), + std::forward<internal::ISecurityManagerListener*>(listener))); +} diff --git a/gd/security/security_manager.h b/gd/security/security_manager.h index 73992c9e4..bc09c0020 100644 --- a/gd/security/security_manager.h +++ b/gd/security/security_manager.h @@ -18,25 +18,73 @@ #pragma once +#include <memory> +#include <vector> + +#include "hci/device.h" +#include "hci/device_database.h" #include "security/internal/security_manager_impl.h" namespace bluetooth { namespace security { +/** + * Manages the security attributes, pairing, bonding of devices, and the + * encryption/decryption of communications. + */ class SecurityManager { public: - // TODO: put SMP API methods here - friend class SecurityModule; - private: + /** + * Initialize the security record map from an internal device database. + */ + void Init(); + + /** + * Checks the device for existing bond, if not bonded, initiates pairing. + * + * @param device pointer to device we want to bond with + */ + void CreateBond(std::shared_ptr<hci::ClassicDevice> device); + + /** + * Cancels the pairing process for this device. + * + * @param device pointer to device with which we want to cancel our bond + */ + void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device); + + /** + * Disassociates the device and removes the persistent LTK + * + * @param device pointer to device we want to forget + */ + void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device); + + /** + * Register to listen for callback events from SecurityManager + * + * @param listener ISecurityManagerListener instance to handle callbacks + */ + void RegisterCallbackListener(internal::ISecurityManagerListener* listener); + + /** + * Unregister listener for callback events from SecurityManager + * + * @param listener ISecurityManagerListener instance to unregister + */ + void UnregisterCallbackListener(internal::ISecurityManagerListener* listener); + + protected: SecurityManager(os::Handler* security_handler, internal::SecurityManagerImpl* security_manager_impl) : security_handler_(security_handler), security_manager_impl_(security_manager_impl) {} + private: os::Handler* security_handler_ = nullptr; internal::SecurityManagerImpl* security_manager_impl_; DISALLOW_COPY_AND_ASSIGN(SecurityManager); }; } // namespace security -} // namespace bluetooth
\ No newline at end of file +} // namespace bluetooth diff --git a/gd/security/security_module.cc b/gd/security/security_module.cc index 0d9b1cae0..e1d01d7ca 100644 --- a/gd/security/security_module.cc +++ b/gd/security/security_module.cc @@ -14,15 +14,16 @@ * limitations under the License. */ -#define LOG_TAG "smp" +#define LOG_TAG "security" #include <memory> #include "module.h" #include "os/handler.h" #include "os/log.h" -#include "l2cap/classic/l2cap_classic_module.h" +#include "hci/hci_layer.h" #include "l2cap/le/l2cap_le_module.h" +#include "security/channel/security_manager_channel.h" #include "security/internal/security_manager_impl.h" #include "security/security_module.h" @@ -33,23 +34,28 @@ const ModuleFactory SecurityModule::Factory = ModuleFactory([]() { return new Se struct SecurityModule::impl { impl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module, - l2cap::classic::L2capClassicModule* l2cap_classic_module) + l2cap::classic::L2capClassicModule* l2cap_classic_module, hci::HciLayer* hci_layer) : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module), - l2cap_classic_module_(l2cap_classic_module) {} + l2cap_classic_module_(l2cap_classic_module), + security_manager_channel_(new channel::SecurityManagerChannel(security_handler_, hci_layer)) {} + os::Handler* security_handler_; l2cap::le::L2capLeModule* l2cap_le_module_; l2cap::classic::L2capClassicModule* l2cap_classic_module_; - internal::SecurityManagerImpl security_manager_impl{security_handler_, l2cap_le_module_, l2cap_classic_module_}; + channel::SecurityManagerChannel* security_manager_channel_; + internal::SecurityManagerImpl security_manager_impl{security_handler_, l2cap_le_module_, l2cap_classic_module_, + security_manager_channel_}; }; void SecurityModule::ListDependencies(ModuleList* list) { list->add<l2cap::le::L2capLeModule>(); list->add<l2cap::classic::L2capClassicModule>(); + list->add<hci::HciLayer>(); } void SecurityModule::Start() { pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<l2cap::le::L2capLeModule>(), - GetDependency<l2cap::classic::L2capClassicModule>()); + GetDependency<l2cap::classic::L2capClassicModule>(), GetDependency<hci::HciLayer>()); } void SecurityModule::Stop() { diff --git a/gd/security/test/fake_hci_layer.h b/gd/security/test/fake_hci_layer.h new file mode 100644 index 000000000..310a75c45 --- /dev/null +++ b/gd/security/test/fake_hci_layer.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include "common/bind.h" +#include "hci/hci_layer.h" + +namespace bluetooth { +namespace security { + +using common::OnceCallback; +using hci::CommandCompleteView; +using hci::CommandPacketBuilder; +using hci::CommandStatusView; +using hci::EventCode; +using hci::EventPacketBuilder; +using hci::EventPacketView; +using hci::HciLayer; +using os::Handler; + +namespace { + +PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) { + auto bytes = std::make_shared<std::vector<uint8_t>>(); + BitInserter i(*bytes); + bytes->reserve(packet->size()); + packet->Serialize(i); + return packet::PacketView<packet::kLittleEndian>(bytes); +} + +class CommandQueueEntry { + public: + CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet, + OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler) + : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)), + caller_handler(handler) {} + + CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet, + OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler) + : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)), + caller_handler(handler) {} + + std::unique_ptr<CommandPacketBuilder> command; + bool waiting_for_status_; + OnceCallback<void(CommandStatusView)> on_status; + OnceCallback<void(CommandCompleteView)> on_complete; + Handler* caller_handler; +}; + +} // namespace + +class FakeHciLayer : public HciLayer { + public: + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status, + Handler* handler) override { + auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_status), handler); + command_queue_.push(std::move(command_queue_entry)); + } + + void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, + OnceCallback<void(CommandCompleteView)> on_complete, Handler* handler) override { + auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_complete), handler); + command_queue_.push(std::move(command_queue_entry)); + } + + std::unique_ptr<CommandQueueEntry> GetLastCommand() { + EXPECT_FALSE(command_queue_.empty()); + auto last = std::move(command_queue_.front()); + command_queue_.pop(); + return last; + } + + void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler, + Handler* handler) override { + registered_events_[event_code] = event_handler; + } + + void UnregisterEventHandler(EventCode event_code) override { + registered_events_.erase(event_code); + } + + void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) { + auto packet = GetPacketView(std::move(event_builder)); + EventPacketView event = EventPacketView::Create(packet); + EXPECT_TRUE(event.IsValid()); + EventCode event_code = event.GetEventCode(); + EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end()); + registered_events_[event_code].Run(event); + } + + void ListDependencies(ModuleList* list) override {} + void Start() override {} + void Stop() override {} + + private: + std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_; + std::queue<std::unique_ptr<CommandQueueEntry>> command_queue_; +}; + +} // namespace security +} // namespace bluetooth diff --git a/gd/shim/il2cap.h b/gd/shim/il2cap.h index 1c92f9ffe..c4e746359 100644 --- a/gd/shim/il2cap.h +++ b/gd/shim/il2cap.h @@ -16,6 +16,7 @@ #pragma once #include <cstdint> +#include <functional> #include <future> #include <string> #include <vector> @@ -26,20 +27,25 @@ namespace bluetooth { namespace shim { -using OnReadDataReady = std::function<void(uint16_t cid, std::vector<const uint8_t> data)>; -using OnClose = std::function<void(int error_code)>; +using ConnectionClosedCallback = std::function<void(uint16_t cid, int error_code)>; +using Postable = std::function<void(std::function<void(uint16_t cid)>)>; +using ConnectionOpenCallback = std::function<void(uint16_t psm, uint16_t cid, Postable postable)>; +using ReadDataReadyCallback = std::function<void(uint16_t cid, std::vector<const uint8_t> data)>; struct IL2cap { - virtual void RegisterService(uint16_t psm, bool snoop_enabled, std::promise<void> completed) = 0; - virtual void Connect(uint16_t psm, const std::string address, std::promise<uint16_t> completed) = 0; + virtual void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) = 0; + virtual void UnregisterService(uint16_t psm) = 0; + + virtual void CreateConnection(uint16_t psm, const std::string address, std::promise<uint16_t> completed) = 0; + virtual void CloseConnection(uint16_t cid) = 0; + + virtual void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) = 0; + virtual void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) = 0; - virtual void SetOnReadDataReady(uint16_t cid, OnReadDataReady on_data_ready) = 0; virtual bool Write(uint16_t cid, const uint8_t* data, size_t len) = 0; virtual bool WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0; virtual bool WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0; - virtual void SetOnClose(uint16_t cid, OnClose on_close) = 0; - virtual bool IsCongested(uint16_t cid) = 0; virtual ~IL2cap() {} }; diff --git a/gd/shim/l2cap.cc b/gd/shim/l2cap.cc index 3dd98fc11..58b10b562 100644 --- a/gd/shim/l2cap.cc +++ b/gd/shim/l2cap.cc @@ -19,6 +19,7 @@ #include <functional> #include <future> #include <memory> +#include <mutex> #include <queue> #include <unordered_map> #include <vector> @@ -42,10 +43,15 @@ namespace shim { const ModuleFactory L2cap::Factory = ModuleFactory([]() { return new L2cap(); }); -using ChannelInterfaceId = uint16_t; -static const ChannelInterfaceId kInvalidChannelInterfaceId = 0; -static const ChannelInterfaceId kStartChannelInterfaceId = 64; -static const ChannelInterfaceId kMaxChannels = UINT16_MAX - 1; +using ConnectionInterfaceDescriptor = uint16_t; +static const ConnectionInterfaceDescriptor kInvalidConnectionInterfaceDescriptor = 0; +static const ConnectionInterfaceDescriptor kStartConnectionInterfaceDescriptor = 64; +static const ConnectionInterfaceDescriptor kMaxConnections = UINT16_MAX - kStartConnectionInterfaceDescriptor - 1; + +using ServiceInterfaceCallback = + std::function<void(l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result)>; +using ConnectionInterfaceCallback = + std::function<void(l2cap::Psm psm, std::unique_ptr<l2cap::classic::DynamicChannel>)>; std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) { packet::RawBuilder builder; @@ -55,21 +61,21 @@ std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t return payload; } -class ChannelInterface { +class ConnectionInterface { public: - ChannelInterface(ChannelInterfaceId id, std::unique_ptr<l2cap::classic::DynamicChannel> channel, os::Handler* handler) - : channel_interface_id_(id), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_{nullptr} { - channel_->RegisterOnCloseCallback(handler_, common::BindOnce(&ChannelInterface::OnClose, common::Unretained(this))); - channel_->GetQueueUpEnd()->RegisterDequeue(handler_, - common::Bind(&ChannelInterface::OnReadReady, common::Unretained(this))); + ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel, + os::Handler* handler) + : cid_(cid), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_(nullptr), + on_connection_closed_callback_(nullptr), address_(channel_->GetDevice()) { + channel_->RegisterOnCloseCallback( + handler_, common::BindOnce(&ConnectionInterface::OnConnectionClosed, common::Unretained(this))); + channel_->GetQueueUpEnd()->RegisterDequeue( + handler_, common::Bind(&ConnectionInterface::OnReadReady, common::Unretained(this))); dequeue_registered_ = true; } - ~ChannelInterface() { - if (dequeue_registered_) { - channel_->GetQueueUpEnd()->UnregisterDequeue(); - dequeue_registered_ = false; - } + ~ConnectionInterface() { + ASSERT(!dequeue_registered_); } void OnReadReady() { @@ -80,14 +86,13 @@ class ChannelInterface { } std::vector<const uint8_t> data(packet->begin(), packet->end()); ASSERT(on_data_ready_callback_ != nullptr); - on_data_ready_callback_(channel_interface_id_, data); + on_data_ready_callback_(cid_, data); } - void OnClose(hci::ErrorCode error_code) { - LOG_DEBUG("Channel interface closed reason:%s id:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), - channel_interface_id_, channel_->GetDevice().ToString().c_str()); - ASSERT(on_close_callback_ != nullptr); - on_close_callback_(static_cast<int>(error_code)); + void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) { + ASSERT(on_data_ready != nullptr); + ASSERT(on_data_ready_callback_ == nullptr); + on_data_ready_callback_ = on_data_ready; } std::unique_ptr<packet::BasePacketBuilder> WriteReady() { @@ -100,38 +105,47 @@ class ChannelInterface { return data; } - void SetOnReadDataReady(OnReadDataReady on_data_ready) { - ASSERT(on_data_ready_callback_ == nullptr); - on_data_ready_callback_ = on_data_ready; - } - - void SetOnClose(::bluetooth::shim::OnClose on_close) { - ASSERT(on_close == nullptr); - on_close_callback_ = on_close; - } - void Write(std::unique_ptr<packet::RawBuilder> packet) { + LOG_DEBUG("Writing packet cid:%hd size:%zd", cid_, packet->size()); write_queue_.push(std::move(packet)); if (!enqueue_registered_) { enqueue_registered_ = true; - channel_->GetQueueUpEnd()->RegisterEnqueue(handler_, - common::Bind(&ChannelInterface::WriteReady, common::Unretained(this))); + channel_->GetQueueUpEnd()->RegisterEnqueue( + handler_, common::Bind(&ConnectionInterface::WriteReady, common::Unretained(this))); } } void Close() { + if (dequeue_registered_) { + channel_->GetQueueUpEnd()->UnregisterDequeue(); + dequeue_registered_ = false; + } ASSERT(write_queue_.empty()); - channel_->GetQueueUpEnd()->UnregisterDequeue(); channel_->Close(); } + void OnConnectionClosed(hci::ErrorCode error_code) { + LOG_DEBUG("Channel interface closed reason:%s cid:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), cid_, + address_.ToString().c_str()); + ASSERT(on_connection_closed_callback_ != nullptr); + on_connection_closed_callback_(cid_, static_cast<int>(error_code)); + } + + void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) { + ASSERT(on_connection_closed != nullptr); + ASSERT(on_connection_closed_callback_ == nullptr); + on_connection_closed_callback_ = std::move(on_connection_closed); + } + private: - ChannelInterfaceId channel_interface_id_; - std::unique_ptr<l2cap::classic::DynamicChannel> channel_; + const ConnectionInterfaceDescriptor cid_; + const std::unique_ptr<l2cap::classic::DynamicChannel> channel_; os::Handler* handler_; - OnReadDataReady on_data_ready_callback_; - ::bluetooth::shim::OnClose on_close_callback_; + ReadDataReadyCallback on_data_ready_callback_; + ConnectionClosedCallback on_connection_closed_callback_; + + const hci::Address address_; std::queue<std::unique_ptr<packet::PacketBuilder<hci::kLittleEndian>>> write_queue_; @@ -139,95 +153,164 @@ class ChannelInterface { bool dequeue_registered_{false}; }; -struct ChannelInterfaceManager { +struct ConnectionInterfaceManager { public: - ChannelInterfaceId AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel); - void RemoveChannel(ChannelInterfaceId id); + ConnectionInterfaceDescriptor AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel); + void RemoveConnection(ConnectionInterfaceDescriptor cid); - void SetOnReadDataReady(ChannelInterfaceId id, OnReadDataReady on_data_ready); - bool Write(ChannelInterfaceId id, std::unique_ptr<packet::RawBuilder> packet); + void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready); + void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed); - void SetOnClose(ChannelInterfaceId id, OnClose on_close); + bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet); - bool HasResources() const; void SetHandler(os::Handler* handler) { handler_ = handler; } - ChannelInterfaceManager(); + size_t NumberOfActiveConnections() const { + return cid_to_interface_map_.size(); + } + + ConnectionInterfaceManager(); private: - std::unordered_map<ChannelInterfaceId, std::unique_ptr<ChannelInterface>> channel_id_to_interface_map_; - ChannelInterfaceId current_channel_interface_id_; + std::unordered_map<ConnectionInterfaceDescriptor, std::unique_ptr<ConnectionInterface>> cid_to_interface_map_; + ConnectionInterfaceDescriptor current_connection_interface_descriptor_; os::Handler* handler_; - bool Exists(ChannelInterfaceId id) const; + bool HasResources() const; + bool Exists(ConnectionInterfaceDescriptor id) const; + ConnectionInterfaceDescriptor AllocateConnectionInterfaceDescriptor(); }; -ChannelInterfaceManager::ChannelInterfaceManager() : current_channel_interface_id_(kStartChannelInterfaceId) {} +ConnectionInterfaceManager::ConnectionInterfaceManager() + : current_connection_interface_descriptor_(kStartConnectionInterfaceDescriptor) {} + +bool ConnectionInterfaceManager::Exists(ConnectionInterfaceDescriptor cid) const { + return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end(); +} -ChannelInterfaceId ChannelInterfaceManager::AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { - while (!Exists(++current_channel_interface_id_)) { +ConnectionInterfaceDescriptor ConnectionInterfaceManager::AllocateConnectionInterfaceDescriptor() { + ASSERT(HasResources()); + while (Exists(current_connection_interface_descriptor_)) { + if (++current_connection_interface_descriptor_ == kInvalidConnectionInterfaceDescriptor) { + current_connection_interface_descriptor_ = kStartConnectionInterfaceDescriptor; + } } - auto channel_interface = - std::make_unique<ChannelInterface>(current_channel_interface_id_, std::move(channel), handler_); - channel_id_to_interface_map_[current_channel_interface_id_] = std::move(channel_interface); - return current_channel_interface_id_; + return current_connection_interface_descriptor_++; } -void ChannelInterfaceManager::RemoveChannel(ChannelInterfaceId id) { - ASSERT(channel_id_to_interface_map_.erase(id) == 1); +ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel( + std::unique_ptr<l2cap::classic::DynamicChannel> channel) { + if (!HasResources()) { + return kInvalidConnectionInterfaceDescriptor; + } + ConnectionInterfaceDescriptor cid = AllocateConnectionInterfaceDescriptor(); + + auto channel_interface = std::make_unique<ConnectionInterface>(cid, std::move(channel), handler_); + cid_to_interface_map_[cid] = std::move(channel_interface); + return cid; } -bool ChannelInterfaceManager::HasResources() const { - return channel_id_to_interface_map_.size() < kMaxChannels; +void ConnectionInterfaceManager::RemoveConnection(ConnectionInterfaceDescriptor cid) { + ASSERT(cid_to_interface_map_.count(cid) == 1); + cid_to_interface_map_.find(cid)->second->Close(); + cid_to_interface_map_.erase(cid); } -bool ChannelInterfaceManager::Exists(ChannelInterfaceId id) const { - return channel_id_to_interface_map_.find(id) != channel_id_to_interface_map_.end(); +bool ConnectionInterfaceManager::HasResources() const { + return cid_to_interface_map_.size() < kMaxConnections; } -void ChannelInterfaceManager::SetOnReadDataReady(ChannelInterfaceId id, OnReadDataReady on_data_ready) { - ASSERT(Exists(id)); - return channel_id_to_interface_map_[id]->SetOnReadDataReady(on_data_ready); +void ConnectionInterfaceManager::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, + ReadDataReadyCallback on_data_ready) { + ASSERT(Exists(cid)); + return cid_to_interface_map_[cid]->SetReadDataReadyCallback(on_data_ready); } -void ChannelInterfaceManager::SetOnClose(ChannelInterfaceId id, OnClose on_close) { - ASSERT(Exists(id)); - return channel_id_to_interface_map_[id]->SetOnClose(on_close); +void ConnectionInterfaceManager::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, + ConnectionClosedCallback on_closed) { + ASSERT(Exists(cid)); + return cid_to_interface_map_[cid]->SetConnectionClosedCallback(on_closed); } -bool ChannelInterfaceManager::Write(ChannelInterfaceId id, std::unique_ptr<packet::RawBuilder> packet) { - if (!Exists(id)) { +bool ConnectionInterfaceManager::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) { + if (!Exists(cid)) { return false; } - channel_id_to_interface_map_[id]->Write(std::move(packet)); + cid_to_interface_map_[cid]->Write(std::move(packet)); return true; } +class ServiceInterface { + public: + ServiceInterface(uint16_t psm, ServiceInterfaceCallback register_callback, + ConnectionInterfaceCallback connection_callback) + : psm_(psm), register_callback_(register_callback), connection_callback_(connection_callback) {} + + void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, + std::unique_ptr<l2cap::classic::DynamicChannelService> service) { + ASSERT(service_ == nullptr); + ASSERT(psm_ == service->GetPsm()); + LOG_DEBUG("Registration is complete for psm:%hd", psm_); + service_ = std::move(service); + register_callback_(psm_, result); + } + + void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { + LOG_DEBUG("Connection is open to device:%s for psm:%hd", channel->GetDevice().ToString().c_str(), psm_); + connection_callback_(psm_, std::move(channel)); + } + + l2cap::SecurityPolicy GetSecurityPolicy() const { + return security_policy_; + } + + void RegisterService( + std::function<void(l2cap::Psm, l2cap::SecurityPolicy security_policy, + l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete, + l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open)> + func) { + func(psm_, security_policy_, common::BindOnce(&ServiceInterface::OnRegistrationComplete, common::Unretained(this)), + common::Bind(&ServiceInterface::OnConnectionOpen, common::Unretained(this))); + } + + private: + const l2cap::Psm psm_; + std::unique_ptr<l2cap::classic::DynamicChannelService> service_; + const l2cap::SecurityPolicy security_policy_; + ServiceInterfaceCallback register_callback_; + ConnectionInterfaceCallback connection_callback_; +}; + struct L2cap::impl { - void RegisterService(l2cap::Psm psm, std::promise<void> completed); - void Connect(l2cap::Psm psm, hci::Address address, std::promise<uint16_t> completed); + void RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed); + void UnregisterService(l2cap::Psm psm); + + void CreateConnection(l2cap::Psm psm, hci::Address address, std::promise<uint16_t> completed); + void CloseConnection(ConnectionInterfaceDescriptor cid); - void RegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, - std::unique_ptr<l2cap::classic::DynamicChannelService> service); - void LocalConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel); - void RemoteConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel); - void ConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result); + void OnConnectionOpenNever(std::unique_ptr<l2cap::classic::DynamicChannel> channel); + void OnConnectionFailureNever(l2cap::classic::DynamicChannelManager::ConnectionResult result); - bool Write(ChannelInterfaceId cid, std::unique_ptr<packet::RawBuilder> packet); + bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet); impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module); - ChannelInterfaceManager channel_interface_manager_; + ConnectionInterfaceManager connection_interface_manager_; + + void OpenConnection(l2cap::Psm psm, ConnectionInterfaceDescriptor cid); private: L2cap& module_; l2cap::classic::L2capClassicModule* l2cap_module_{nullptr}; - std::unique_ptr<l2cap::classic::DynamicChannelManager> dynamic_channel_manager_; - std::queue<std::promise<void>> register_completed_queue_; - std::queue<std::promise<uint16_t>> connect_completed_queue_; + std::unordered_map<l2cap::Psm, std::shared_ptr<ServiceInterface>> psm_to_service_interface_map_; + std::unordered_map<l2cap::Psm, ConnectionOpenCallback> psm_to_on_open_map_; + + std::mutex mutex_; + std::unordered_map<l2cap::Psm, std::promise<void>> psm_to_register_complete_map_; + std::unordered_map<l2cap::Psm, std::queue<std::promise<uint16_t>>> psm_to_connect_completed_queue_; os::Handler* handler_; }; @@ -236,35 +319,15 @@ L2cap::impl::impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_modul : module_(module), l2cap_module_(l2cap_module) { handler_ = module_.GetHandler(); dynamic_channel_manager_ = l2cap_module_->GetDynamicChannelManager(); - channel_interface_manager_.SetHandler(handler_); + connection_interface_manager_.SetHandler(handler_); } -void L2cap::impl::RegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, - std::unique_ptr<l2cap::classic::DynamicChannelService> service) { - LOG_DEBUG("Registration is complete"); - auto completed = std::move(register_completed_queue_.front()); - register_completed_queue_.pop(); - completed.set_value(); +void L2cap::impl::OnConnectionOpenNever(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { + ASSERT(false); } -void L2cap::impl::LocalConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { - LOG_DEBUG("Local initiated connection is open to connect_queue_size:%zd device:%s", connect_completed_queue_.size(), - channel->GetDevice().ToString().c_str()); - auto completed = std::move(connect_completed_queue_.front()); - connect_completed_queue_.pop(); - if (!channel_interface_manager_.HasResources()) { - completed.set_value(kInvalidChannelInterfaceId); - } - completed.set_value(channel_interface_manager_.AddChannel(std::move(channel))); -} - -void L2cap::impl::RemoteConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { - LOG_DEBUG("Remote initiated connection is open to connect_queue_size:%zd device:%s", connect_completed_queue_.size(), - channel->GetDevice().ToString().c_str()); - // TODO(cmanton) plumb back to legacy somehow -} - -void L2cap::impl::ConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) { +void L2cap::impl::OnConnectionFailureNever(l2cap::classic::DynamicChannelManager::ConnectionResult result) { + ASSERT(false); switch (result.connection_result_code) { case l2cap::classic::DynamicChannelManager::ConnectionResultCode::SUCCESS: LOG_WARN("Connection failed result:success hci:%s", hci::ErrorCodeText(result.hci_error).c_str()); @@ -280,60 +343,131 @@ void L2cap::impl::ConnectionFailure(l2cap::classic::DynamicChannelManager::Conne l2cap::ConnectionResponseResultText(result.l2cap_connection_response_result).c_str()); break; } - auto completed = std::move(connect_completed_queue_.front()); - connect_completed_queue_.pop(); - completed.set_value(kInvalidChannelInterfaceId); } -void L2cap::impl::RegisterService(l2cap::Psm psm, std::promise<void> register_completed) { - l2cap::SecurityPolicy security_policy; - register_completed_queue_.push(std::move(register_completed)); - bool rc = dynamic_channel_manager_->RegisterService( - psm, security_policy, common::BindOnce(&L2cap::impl::RegistrationComplete, common::Unretained(this)), - common::Bind(&L2cap::impl::RemoteConnectionOpen, common::Unretained(this)), handler_); - ASSERT_LOG(rc == true, "Failed to request register classic service"); +void L2cap::impl::OpenConnection(l2cap::Psm psm, ConnectionInterfaceDescriptor cid) { + LOG_INFO("About to call back to client indicating open connection psm:%hd cid:%hd", psm, cid); + psm_to_on_open_map_[psm](psm, cid, [cid](std::function<void(uint16_t cid)> func) { + LOG_DEBUG("About to run postable on this thread and inform sdp that connection is open"); + func(cid); + }); } -void L2cap::impl::Connect(l2cap::Psm psm, hci::Address address, std::promise<uint16_t> connect_completed) { - connect_completed_queue_.push(std::move(connect_completed)); - bool rc = dynamic_channel_manager_->ConnectChannel( - address, psm, common::Bind(&L2cap::impl::LocalConnectionOpen, common::Unretained(this)), - common::Bind(&L2cap::impl::ConnectionFailure, common::Unretained(this)), handler_); - ASSERT_LOG(rc == true, "Failed to request connect classic channel"); +void L2cap::impl::RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed) { + ASSERT(psm_to_service_interface_map_.find(psm) == psm_to_service_interface_map_.end()); + ASSERT(psm_to_register_complete_map_.find(psm) == psm_to_register_complete_map_.end()); + ASSERT(psm_to_on_open_map_.find(psm) == psm_to_on_open_map_.end()); + + psm_to_on_open_map_[psm] = on_open; + + psm_to_service_interface_map_.emplace( + psm, std::make_shared<ServiceInterface>( + psm, + [this](l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result) { + LOG_DEBUG("Service has been registered"); + ASSERT(psm_to_register_complete_map_.find(psm) != psm_to_register_complete_map_.end()); + { + std::unique_lock<std::mutex> lock(mutex_); + auto completed = std::move(psm_to_register_complete_map_[psm]); + psm_to_register_complete_map_.erase(psm); + completed.set_value(); + } + }, + + [this](l2cap::Psm psm, std::unique_ptr<l2cap::classic::DynamicChannel> channel) { + ConnectionInterfaceDescriptor cid = connection_interface_manager_.AddChannel(std::move(channel)); + LOG_DEBUG("Connection has been opened cid:%hd psm:%hd", cid, psm); + { + // If initiated locally unblock requestor that + // we now have a connection by providing the + // cid. + std::unique_lock<std::mutex> lock(mutex_); + if (psm_to_connect_completed_queue_.find(psm) != psm_to_connect_completed_queue_.end()) { + if (!psm_to_connect_completed_queue_[psm].empty()) { + LOG_DEBUG("Locally initiated, so inform waiting client of the cid %hd", cid); + auto completed = std::move(psm_to_connect_completed_queue_[psm].front()); + psm_to_connect_completed_queue_[psm].pop(); + completed.set_value(cid); + } + } + std::this_thread::yield(); + } + if (cid != kInvalidConnectionInterfaceDescriptor) { + handler_->Post(common::BindOnce(&L2cap::impl::OpenConnection, common::Unretained(this), psm, cid)); + } + usleep(10); + })); + + psm_to_service_interface_map_.find(psm)->second->RegisterService( + [this](l2cap::Psm psm, l2cap::SecurityPolicy security_policy, + l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete, + l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open) { + bool rc = dynamic_channel_manager_->RegisterService(psm, security_policy, std::move(on_registration_complete), + on_connection_open, handler_); + ASSERT_LOG(rc == true, "Failed to register classic service"); + }); } -bool L2cap::impl::Write(ChannelInterfaceId cid, std::unique_ptr<packet::RawBuilder> packet) { - return channel_interface_manager_.Write(cid, std::move(packet)); +void L2cap::impl::UnregisterService(l2cap::Psm psm) { + psm_to_service_interface_map_.erase(psm); } -void L2cap::RegisterService(uint16_t raw_psm, bool snoop_enabled, std::promise<void> register_completed) { - if (!snoop_enabled) { - LOG_WARN("UNIMPLEMENTED Cannot disable snooping on psm:%d", raw_psm); +void L2cap::impl::CreateConnection(l2cap::Psm psm, hci::Address address, std::promise<uint16_t> completed) { + LOG_INFO("Creating connection to psm:%hd device:%s", psm, address.ToString().c_str()); + { + std::unique_lock<std::mutex> lock(mutex_); + psm_to_connect_completed_queue_[psm].push(std::move(completed)); } + bool rc = dynamic_channel_manager_->ConnectChannel( + address, psm, common::Bind(&L2cap::impl::OnConnectionOpenNever, common::Unretained(this)), + common::Bind(&L2cap::impl::OnConnectionFailureNever, common::Unretained(this)), handler_); + ASSERT_LOG(rc == true, "Failed to create classic connection channel"); +} - l2cap::Psm psm = raw_psm; - pimpl_->RegisterService(psm, std::move(register_completed)); +void L2cap::impl::CloseConnection(ConnectionInterfaceDescriptor cid) { + connection_interface_manager_.RemoveConnection(cid); } -void L2cap::Connect(uint16_t raw_psm, const std::string address_string, std::promise<uint16_t> connect_completed) { - l2cap::Psm psm = raw_psm; +bool L2cap::impl::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) { + return connection_interface_manager_.Write(cid, std::move(packet)); +} + +void L2cap::RegisterService(uint16_t raw_psm, ConnectionOpenCallback on_open, std::promise<void> completed) { + l2cap::Psm psm{raw_psm}; + pimpl_->RegisterService(psm, on_open, std::move(completed)); +} + +void L2cap::UnregisterService(uint16_t raw_psm) { + l2cap::Psm psm{raw_psm}; + pimpl_->UnregisterService(psm); +} + +void L2cap::CreateConnection(uint16_t raw_psm, const std::string address_string, std::promise<uint16_t> completed) { + l2cap::Psm psm{raw_psm}; hci::Address address; hci::Address::FromString(address_string, address); - return pimpl_->Connect(psm, address, std::move(connect_completed)); + return pimpl_->CreateConnection(psm, address, std::move(completed)); +} + +void L2cap::CloseConnection(uint16_t raw_cid) { + ConnectionInterfaceDescriptor cid(raw_cid); + return pimpl_->CloseConnection(cid); } -void L2cap::SetOnReadDataReady(uint16_t cid, OnReadDataReady on_data_ready) { - pimpl_->channel_interface_manager_.SetOnReadDataReady(static_cast<ChannelInterfaceId>(cid), on_data_ready); +void L2cap::SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) { + pimpl_->connection_interface_manager_.SetReadDataReadyCallback(static_cast<ConnectionInterfaceDescriptor>(cid), + on_data_ready); } -void L2cap::SetOnClose(uint16_t cid, OnClose on_close) { - pimpl_->channel_interface_manager_.SetOnClose(static_cast<ChannelInterfaceId>(cid), on_close); +void L2cap::SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) { + pimpl_->connection_interface_manager_.SetConnectionClosedCallback(static_cast<ConnectionInterfaceDescriptor>(cid), + on_closed); } bool L2cap::Write(uint16_t cid, const uint8_t* data, size_t len) { auto packet = MakeUniquePacket(data, len); - return pimpl_->Write(static_cast<ChannelInterfaceId>(cid), std::move(packet)); + return pimpl_->Write(static_cast<ConnectionInterfaceDescriptor>(cid), std::move(packet)); } bool L2cap::WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) { @@ -346,7 +480,7 @@ bool L2cap::WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) { return false; } -bool L2cap::IsCongested(ChannelInterfaceId cid) { +bool L2cap::IsCongested(ConnectionInterfaceDescriptor cid) { LOG_WARN("UNIMPLEMENTED Congestion check on channels or links"); return false; } diff --git a/gd/shim/l2cap.h b/gd/shim/l2cap.h index 35ea13f01..67a75d9da 100644 --- a/gd/shim/l2cap.h +++ b/gd/shim/l2cap.h @@ -16,6 +16,7 @@ #pragma once #include <cstdint> +#include <functional> #include <future> #include <memory> #include <string> @@ -28,16 +29,19 @@ namespace shim { class L2cap : public bluetooth::Module, public bluetooth::shim::IL2cap { public: - void RegisterService(uint16_t psm, bool snoop_enabled, std::promise<void> register_completed) override; - void Connect(uint16_t psm, const std::string address, std::promise<uint16_t> connect_completed) override; + void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) override; + void UnregisterService(uint16_t psm) override; + + void CreateConnection(uint16_t psm, const std::string address, std::promise<uint16_t> completed) override; + void CloseConnection(uint16_t cid) override; + + void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) override; + void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) override; - void SetOnReadDataReady(uint16_t cid, OnReadDataReady on_data_ready) override; bool Write(uint16_t cid, const uint8_t* data, size_t len) override; bool WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override; bool WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) override; - virtual void SetOnClose(uint16_t cid, OnClose on_close) override; - bool IsCongested(uint16_t cid) override; L2cap() = default; diff --git a/gd/shim/stack.cc b/gd/shim/stack.cc index 3fbc7f995..8b02e6b87 100644 --- a/gd/shim/stack.cc +++ b/gd/shim/stack.cc @@ -52,7 +52,6 @@ struct bluetooth::shim::Stack::impl { ModuleList modules; modules.add<::bluetooth::hal::HciHal>(); modules.add<::bluetooth::hci::AclManager>(); - modules.add<::bluetooth::hci::ClassicSecurityManager>(); modules.add<::bluetooth::l2cap::classic::L2capClassicModule>(); modules.add<::bluetooth::l2cap::le::L2capLeModule>(); modules.add<::bluetooth::neighbor::ConnectabilityModule>(); diff --git a/main/Android.bp b/main/Android.bp index 1ef608fb1..fec664425 100644 --- a/main/Android.bp +++ b/main/Android.bp @@ -123,6 +123,7 @@ cc_library_static { ":LibBluetoothSources", "shim/entry_for_test.cc", ], + host_supported: true, include_dirs: [ "system/bt", "system/bt/bta/include", @@ -137,3 +138,33 @@ cc_library_static { "-DBUILDCFG", ], } + +filegroup { + name: "BluetoothLegacyShimTestSources", + srcs: [ + "shim/l2cap_test.cc", + "shim/test_stack.cc", + ] +} + +cc_test { + name: "bluetooth_test_legacy", + defaults: ["fluoride_defaults", + "fluoride_osi_defaults", + ], + test_suites: ["device-tests"], + host_supported: true, + srcs: [ + ":BluetoothLegacyShimTestSources", + ], + static_libs: [ + "libgmock", + "libbluetooth-for-tests", + "libosi", + ], + shared_libs: [ + "libchrome", + "liblog", + ], +} + diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc index dde3ab894..7623df1e8 100644 --- a/main/shim/l2c_api.cc +++ b/main/shim/l2c_api.cc @@ -21,7 +21,7 @@ #include "main/shim/shim.h" #include "osi/include/log.h" -static bluetooth::shim::L2cap shim_l2cap; +static bluetooth::legacy::shim::L2cap shim_l2cap; /** * Classic Service Registration APIs @@ -60,7 +60,7 @@ uint16_t bluetooth::shim::L2CA_Register(uint16_t client_psm, LOG_INFO(LOG_TAG, "%s classic client_psm:%hd psm:%hd", __func__, client_psm, psm); - shim_l2cap.Register(psm, callbacks, enable_snoop); + shim_l2cap.RegisterService(psm, callbacks, enable_snoop); return client_psm; } @@ -116,7 +116,7 @@ uint16_t bluetooth::shim::L2CA_ErtmConnectReq(uint16_t psm, tL2CAP_ERTM_INFO* p_ertm_info) { CHECK(p_ertm_info == nullptr) << "UNIMPLEMENTED set enhanced retransmission mode config"; - return shim_l2cap.Connect(psm, raw_address); + return shim_l2cap.CreateConnection(psm, raw_address); } uint16_t bluetooth::shim::L2CA_ConnectReq(uint16_t psm, @@ -143,24 +143,20 @@ bool bluetooth::shim::L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id, status, NULL); } -bool bluetooth::shim::L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) { - LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s cid:%hd p_cfg:%p", __func__, cid, p_cfg); - return false; +bool bluetooth::shim::L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) { + return shim_l2cap.ConfigRequest(cid, cfg_info); } -bool bluetooth::shim::L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) { - LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s cid:%hd p_cfg:%p", __func__, cid, p_cfg); - return false; +bool bluetooth::shim::L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) { + return shim_l2cap.ConfigResponse(cid, cfg_info); } bool bluetooth::shim::L2CA_DisconnectReq(uint16_t cid) { - LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s cid:%hd ", __func__, cid); - return false; + return shim_l2cap.DisconnectRequest(cid); } bool bluetooth::shim::L2CA_DisconnectRsp(uint16_t cid) { - LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s cid:%hd ", __func__, cid); - return false; + return shim_l2cap.DisconnectResponse(cid); } /** diff --git a/main/shim/l2cap.cc b/main/shim/l2cap.cc index da4292953..5cf3b92a1 100644 --- a/main/shim/l2cap.cc +++ b/main/shim/l2cap.cc @@ -15,49 +15,69 @@ */ #define LOG_TAG "bt_shim_l2cap" -#include "main/shim/l2cap.h" +#include <cstdint> + #include "main/shim/entry.h" +#include "main/shim/l2cap.h" #include "main/shim/shim.h" #include "osi/include/allocator.h" #include "osi/include/log.h" constexpr size_t kBtHdrSize = sizeof(BT_HDR); +constexpr uint16_t kInvalidConnectionInterfaceDescriptor = 0; -bool bluetooth::shim::PsmData::IsPsmAllocated(uint16_t psm) const { - return psm_to_callback_map.find(psm) != psm_to_callback_map.end(); +bool bluetooth::legacy::shim::PsmData::IsPsmAllocated(uint16_t psm) const { + return psm_to_callback_map_.find(psm) != psm_to_callback_map_.end(); } -bool bluetooth::shim::PsmData::IsPsmRegistered(uint16_t psm) const { - return IsPsmAllocated(psm) && psm_to_callback_map.at(psm) != nullptr; +bool bluetooth::legacy::shim::PsmData::IsPsmRegistered(uint16_t psm) const { + return IsPsmAllocated(psm) && psm_to_callback_map_.at(psm) != nullptr; } -void bluetooth::shim::PsmData::AllocatePsm(uint16_t psm) { +void bluetooth::legacy::shim::PsmData::AllocatePsm(uint16_t psm) { RegisterPsm(psm, nullptr); } -void bluetooth::shim::PsmData::RegisterPsm(uint16_t psm, - const tL2CAP_APPL_INFO* callbacks) { - psm_to_callback_map[psm] = callbacks; +void bluetooth::legacy::shim::PsmData::RegisterPsm( + uint16_t psm, const tL2CAP_APPL_INFO* callbacks) { + psm_to_callback_map_[psm] = callbacks; } -void bluetooth::shim::PsmData::UnregisterPsm(uint16_t psm) { - psm_to_callback_map[psm] = nullptr; +void bluetooth::legacy::shim::PsmData::UnregisterPsm(uint16_t psm) { + psm_to_callback_map_[psm] = nullptr; } -void bluetooth::shim::PsmData::DeallocatePsm(uint16_t psm) { - psm_to_callback_map.erase(psm); +void bluetooth::legacy::shim::PsmData::DeallocatePsm(uint16_t psm) { + psm_to_callback_map_.erase(psm); +} + +const tL2CAP_APPL_INFO* bluetooth::legacy::shim::PsmData::Callbacks( + uint16_t psm) { + if (psm_to_callback_map_.find(psm) == psm_to_callback_map_.end()) { + LOG_WARN(LOG_TAG, "Accessing unknown psm:%hd:", psm); + return nullptr; + } + return psm_to_callback_map_[psm]; } -bluetooth::shim::L2cap::L2cap() +bluetooth::legacy::shim::L2cap::L2cap() : classic_dynamic_psm_(kInitialClassicDynamicPsm), le_dynamic_psm_(kInitialLeDynamicPsm), classic_virtual_psm_(kInitialClassicVirtualPsm) {} -bluetooth::shim::PsmData& bluetooth::shim::L2cap::Le() { return le_; } +bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Le() { + return le_; +} + +bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Classic() { + return classic_; +} -bluetooth::shim::PsmData& bluetooth::shim::L2cap::Classic() { return classic_; } +bool bluetooth::legacy::shim::L2cap::ConnectionExists(uint16_t cid) const { + return cid_to_psm_map_.find(cid) != cid_to_psm_map_.end(); +} -uint16_t bluetooth::shim::L2cap::ConvertClientToRealPsm( +uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm( uint16_t client_psm, bool is_outgoing_only_connection) { if (!is_outgoing_only_connection) { return client_psm; @@ -65,7 +85,8 @@ uint16_t bluetooth::shim::L2cap::ConvertClientToRealPsm( return GetNextVirtualPsm(client_psm); } -uint16_t bluetooth::shim::L2cap::ConvertClientToRealPsm(uint16_t client_psm) { +uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm( + uint16_t client_psm) { if (client_psm_to_real_psm_map_.find(client_psm) == client_psm_to_real_psm_map_.end()) { return client_psm; @@ -73,14 +94,14 @@ uint16_t bluetooth::shim::L2cap::ConvertClientToRealPsm(uint16_t client_psm) { return client_psm_to_real_psm_map_.at(client_psm); } -void bluetooth::shim::L2cap::RemoveClientPsm(uint16_t client_psm) { +void bluetooth::legacy::shim::L2cap::RemoveClientPsm(uint16_t client_psm) { if (client_psm_to_real_psm_map_.find(client_psm) != client_psm_to_real_psm_map_.end()) { client_psm_to_real_psm_map_.erase(client_psm); } } -uint16_t bluetooth::shim::L2cap::GetNextVirtualPsm(uint16_t real_psm) { +uint16_t bluetooth::legacy::shim::L2cap::GetNextVirtualPsm(uint16_t real_psm) { if (real_psm < kInitialClassicDynamicPsm) { return real_psm; } @@ -94,7 +115,7 @@ uint16_t bluetooth::shim::L2cap::GetNextVirtualPsm(uint16_t real_psm) { return classic_virtual_psm_; } -uint16_t bluetooth::shim::L2cap::GetNextDynamicLePsm() { +uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicLePsm() { while (Le().IsPsmAllocated(le_dynamic_psm_)) { le_dynamic_psm_++; if (le_dynamic_psm_ > kFinalLeDynamicPsm) { @@ -104,7 +125,7 @@ uint16_t bluetooth::shim::L2cap::GetNextDynamicLePsm() { return le_dynamic_psm_; } -uint16_t bluetooth::shim::L2cap::GetNextDynamicClassicPsm() { +uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicClassicPsm() { while (Classic().IsPsmAllocated(classic_dynamic_psm_)) { classic_dynamic_psm_ += 2; if (classic_dynamic_psm_ > kFinalClassicDynamicPsm) { @@ -123,89 +144,210 @@ uint16_t bluetooth::shim::L2cap::GetNextDynamicClassicPsm() { return classic_dynamic_psm_; } -void bluetooth::shim::L2cap::Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info, - bool enable_snoop) { +void bluetooth::legacy::shim::L2cap::RegisterService( + uint16_t psm, const tL2CAP_APPL_INFO* callbacks, bool enable_snoop) { LOG_DEBUG(LOG_TAG, "Registering service on psm:%hd", psm); + if (!enable_snoop) { + LOG_WARN(LOG_TAG, "UNIMPLEMENTED Cannot disable snooping on psm:%d", psm); + } + + Classic().RegisterPsm(psm, callbacks); + std::promise<void> register_completed; auto completed = register_completed.get_future(); - bluetooth::shim::GetL2cap()->RegisterService(psm, enable_snoop, - std::move(register_completed)); + bluetooth::shim::GetL2cap()->RegisterService( + psm, + std::bind(&bluetooth::legacy::shim::L2cap::OnConnectionReady, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), + std::move(register_completed)); completed.wait(); LOG_DEBUG(LOG_TAG, "Successfully registered service on psm:%hd", psm); } -uint16_t bluetooth::shim::L2cap::Connect(uint16_t psm, - const RawAddress& raw_address) { +uint16_t bluetooth::legacy::shim::L2cap::CreateConnection( + uint16_t psm, const RawAddress& raw_address) { LOG_DEBUG(LOG_TAG, "Requesting connection to psm:%hd address:%s", psm, raw_address.ToString().c_str()); + if (!Classic().IsPsmRegistered(psm)) { + LOG_WARN(LOG_TAG, "Service must be registered in order to connect psm:%hd", + psm); + return kInvalidConnectionInterfaceDescriptor; + } + std::promise<uint16_t> connect_completed; auto completed = connect_completed.get_future(); - bluetooth::shim::GetL2cap()->Connect(psm, raw_address.ToString(), - std::move(connect_completed)); + bluetooth::shim::GetL2cap()->CreateConnection(psm, raw_address.ToString(), + std::move(connect_completed)); uint16_t cid = completed.get(); - LOG_INFO(LOG_TAG, - "Successfully connected using connection_interface_descriptor:%hd " - "psm:%hd address:%s", - cid, psm, raw_address.ToString().c_str()); + if (cid == kInvalidConnectionInterfaceDescriptor) { + LOG_WARN(LOG_TAG, + "Failed to allocate resources to connect to psm:%hd address:%s", + psm, raw_address.ToString().c_str()); + } else { + LOG_DEBUG(LOG_TAG, + "Successfully started connection to psm:%hd address:%s" + " connection_interface_descriptor:%hd", + psm, raw_address.ToString().c_str(), cid); + CHECK(cid_to_psm_map_.find(cid) == cid_to_psm_map_.end()); + cid_to_psm_map_[cid] = psm; + SetCallbacks(cid, Classic().Callbacks(psm)); + const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm); + CHECK(callbacks != nullptr); + } return cid; } -bool bluetooth::shim::L2cap::IsCongested(uint16_t cid) const { - LOG_WARN(LOG_TAG, "UNIMPLEMENTED checking congestion on a channel"); +void bluetooth::legacy::shim::L2cap::OnConnectionReady( + uint16_t psm, uint16_t cid, + std::function<void(std::function<void(uint16_t c)>)> func) { + LOG_DEBUG( + LOG_TAG, + "l2cap got new connection psm:%hd connection_interface_descriptor:%hd", + psm, cid); + const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm); + if (callbacks == nullptr) { + return; + } + LOG_DEBUG(LOG_TAG, "%s Setting postable map for cid:%d", __func__, cid); + cid_to_postable_map_[cid] = func; + func([&cid, &callbacks](uint16_t cid2) { + LOG_WARN(LOG_TAG, + "Queuing up the connection confirm to the upper stack but really " + "a connection has already been done Cid:%hd Cid2:%hd", + cid, cid2); + callbacks->pL2CA_ConnectCfm_Cb(cid2, 0); + }); +} + +bool bluetooth::legacy::shim::L2cap::IsCongested(uint16_t cid) const { + CHECK(ConnectionExists(cid)); + LOG_WARN(LOG_TAG, "Ignoring checks for congestion on cid:%hd", cid); return false; } -bool bluetooth::shim::L2cap::Write(uint16_t cid, BT_HDR* bt_hdr) { +bool bluetooth::legacy::shim::L2cap::Write(uint16_t cid, BT_HDR* bt_hdr) { + CHECK(ConnectionExists(cid)); + CHECK(bt_hdr != nullptr); const uint8_t* data = bt_hdr->data + bt_hdr->offset; size_t len = bt_hdr->len; + LOG_DEBUG(LOG_TAG, "Writing data cid:%hd len:%zd", cid, len); return bluetooth::shim::GetL2cap()->Write(cid, data, len); } -bool bluetooth::shim::L2cap::WriteFlushable(uint16_t cid, BT_HDR* bt_hdr) { +bool bluetooth::legacy::shim::L2cap::WriteFlushable(uint16_t cid, + BT_HDR* bt_hdr) { + CHECK(ConnectionExists(cid)); + CHECK(bt_hdr != nullptr); const uint8_t* data = bt_hdr->data + bt_hdr->offset; size_t len = bt_hdr->len; return bluetooth::shim::GetL2cap()->WriteFlushable(cid, data, len); } -bool bluetooth::shim::L2cap::WriteNonFlushable(uint16_t cid, BT_HDR* bt_hdr) { +bool bluetooth::legacy::shim::L2cap::WriteNonFlushable(uint16_t cid, + BT_HDR* bt_hdr) { + CHECK(ConnectionExists(cid)); + CHECK(bt_hdr != nullptr); const uint8_t* data = bt_hdr->data + bt_hdr->offset; size_t len = bt_hdr->len; return bluetooth::shim::GetL2cap()->WriteNonFlushable(cid, data, len); } -bool bluetooth::shim::L2cap::SetCallbacks(uint16_t cid, - const tL2CAP_APPL_INFO* callbacks) { - LOG_ASSERT(cid_to_callback_map_.find(cid) != cid_to_callback_map_.end()) - << "Registering multiple channel callbacks " +bool bluetooth::legacy::shim::L2cap::SetCallbacks( + uint16_t cid, const tL2CAP_APPL_INFO* callbacks) { + CHECK(callbacks != nullptr); + CHECK(ConnectionExists(cid)); + LOG_ASSERT(cid_to_callback_map_.find(cid) == cid_to_callback_map_.end()) + << "Already have callbacks registered for " "connection_interface_descriptor:" << cid; cid_to_callback_map_[cid] = callbacks; - bluetooth::shim::GetL2cap()->SetOnReadDataReady( - cid, [this](uint16_t cid, std::vector<const uint8_t> data) { - LOG_INFO(LOG_TAG, - "Got data on connection_interface_descriptor:%hd len:%zd", cid, - data.size()); + bluetooth::shim::GetL2cap()->SetReadDataReadyCallback( + cid, [this](uint16_t cid, std::vector<const uint8_t> data) { + LOG_DEBUG(LOG_TAG, "OnDataReady cid:%hd len:%zd", cid, data.size()); BT_HDR* bt_hdr = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize)); std::copy(data.begin(), data.end(), bt_hdr->data); bt_hdr->len = data.size(); - cid_to_callback_map_[cid]->pL2CA_DataInd_Cb(cid, bt_hdr); }); - bluetooth::shim::GetL2cap()->SetOnClose(cid, [this, &cid](int error_code) { - LOG_DEBUG(LOG_TAG, "Channel closed connection_interface_descriptor:%hd", - cid); - cid_to_callback_map_[cid]->pL2CA_DisconnectInd_Cb(cid, true); - }); + + bluetooth::shim::GetL2cap()->SetConnectionClosedCallback( + cid, [this](uint16_t cid, int error_code) { + LOG_DEBUG(LOG_TAG, "OnChannel closed callback cid:%hd", cid); + cid_to_callback_map_[cid]->pL2CA_DisconnectInd_Cb(cid, true); + }); return true; } -void bluetooth::shim::L2cap::ClearCallbacks(uint16_t cid) { - LOG_ASSERT(cid_to_callback_map_.find(cid) == cid_to_callback_map_.end()) - << "Clearing callbacks that do not exist connection_interface_descriptor:" - << cid; +void bluetooth::legacy::shim::L2cap::ClearCallbacks(uint16_t cid) { + CHECK(ConnectionExists(cid)); cid_to_callback_map_.erase(cid); } + +bool bluetooth::legacy::shim::L2cap::ConnectResponse( + const RawAddress& raw_address, uint8_t signal_id, uint16_t cid, + uint16_t result, uint16_t status, tL2CAP_ERTM_INFO* ertm_info) { + CHECK(ConnectionExists(cid)); + LOG_DEBUG(LOG_TAG, + "%s Silently dropping client connect response as channel is " + "already connected", + __func__); + return true; +} + +bool bluetooth::legacy::shim::L2cap::ConfigRequest( + uint16_t cid, const tL2CAP_CFG_INFO* config_info) { + CHECK(ConnectionExists(cid)); + LOG_INFO(LOG_TAG, "Received config request from upper layer"); + CHECK(cid_to_psm_map_.find(cid) != cid_to_psm_map_.end()); + const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(cid_to_psm_map_[cid]); + CHECK(callbacks != nullptr); + CHECK(cid_to_postable_map_.count(cid) == 1); + + auto func = cid_to_postable_map_[cid]; + func([&cid, &callbacks](uint16_t cid2) { + tL2CAP_CFG_INFO cfg_info{ + .result = L2CAP_CFG_OK, + .mtu_present = false, + .qos_present = false, + .flush_to_present = false, + .fcr_present = false, + .fcs_present = false, + .ext_flow_spec_present = false, + .flags = 0, + }; + LOG_INFO(LOG_TAG, "Config request lambda"); + callbacks->pL2CA_ConfigCfm_Cb(cid, &cfg_info); + callbacks->pL2CA_ConfigInd_Cb(cid, &cfg_info); + }); + return true; +} + +bool bluetooth::legacy::shim::L2cap::ConfigResponse( + uint16_t cid, const tL2CAP_CFG_INFO* config_info) { + CHECK(ConnectionExists(cid)); + LOG_DEBUG( + LOG_TAG, + "%s Silently dropping client config response as channel is already open", + __func__); + return true; +} + +bool bluetooth::legacy::shim::L2cap::DisconnectRequest(uint16_t cid) { + CHECK(ConnectionExists(cid)); + bluetooth::shim::GetL2cap()->CloseConnection(cid); + return true; +} + +bool bluetooth::legacy::shim::L2cap::DisconnectResponse(uint16_t cid) { + CHECK(ConnectionExists(cid)); + LOG_DEBUG(LOG_TAG, + "%s Silently dropping client disconnect response as channel is " + "already disconnected", + __func__); + return true; +} diff --git a/main/shim/l2cap.h b/main/shim/l2cap.h index 6653a4acd..d238a0b79 100644 --- a/main/shim/l2cap.h +++ b/main/shim/l2cap.h @@ -22,6 +22,7 @@ #include "stack/include/l2c_api.h" namespace bluetooth { +namespace legacy { namespace shim { static constexpr uint16_t kInitialClassicDynamicPsm = 0x1001; @@ -41,16 +42,28 @@ using PsmData = struct { void UnregisterPsm(uint16_t psm); void DeallocatePsm(uint16_t psm); + const tL2CAP_APPL_INFO* Callbacks(uint16_t psm); + private: - std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> psm_to_callback_map; + std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> psm_to_callback_map_; }; class L2cap { public: - L2cap(); + void RegisterService(uint16_t psm, const tL2CAP_APPL_INFO* callbacks, + bool enable_snoop); + uint16_t CreateConnection(uint16_t psm, const RawAddress& raw_address); + void OnConnectionReady( + uint16_t psm, uint16_t cid, + std::function<void(std::function<void(uint16_t cid)>)> func); - PsmData& Classic(); - PsmData& Le(); + bool Write(uint16_t cid, BT_HDR* bt_hdr); + bool WriteFlushable(uint16_t cid, BT_HDR* bt_hdr); + bool WriteNonFlushable(uint16_t cid, BT_HDR* bt_hdr); + bool IsCongested(uint16_t cid) const; + + bool SetCallbacks(uint16_t cid, const tL2CAP_APPL_INFO* callbacks); + void ClearCallbacks(uint16_t cid); uint16_t GetNextDynamicClassicPsm(); uint16_t GetNextDynamicLePsm(); @@ -60,16 +73,22 @@ class L2cap { uint16_t ConvertClientToRealPsm(uint16_t psm); void RemoveClientPsm(uint16_t client_psm); - void Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info, bool enable_snoop); - uint16_t Connect(uint16_t psm, const RawAddress& raw_address); + // Legacy API entry points + bool ConnectResponse(const RawAddress& raw_address, uint8_t signal_id, + uint16_t cid, uint16_t result, uint16_t status, + tL2CAP_ERTM_INFO* ertm_info); + bool ConfigRequest(uint16_t cid, const tL2CAP_CFG_INFO* config_info); + bool ConfigResponse(uint16_t cid, const tL2CAP_CFG_INFO* config_info); + bool DisconnectRequest(uint16_t cid); + bool DisconnectResponse(uint16_t cid); - bool Write(uint16_t cid, BT_HDR* bt_hdr); - bool WriteFlushable(uint16_t cid, BT_HDR* bt_hdr); - bool WriteNonFlushable(uint16_t cid, BT_HDR* bt_hdr); - bool IsCongested(uint16_t cid) const; + void Test(void* context); + void Test2(); - bool SetCallbacks(uint16_t cid, const tL2CAP_APPL_INFO* client_callbacks); - void ClearCallbacks(uint16_t cid); + L2cap(); + + PsmData& Classic(); + PsmData& Le(); private: uint16_t GetNextVirtualPsm(uint16_t real_psm); @@ -77,13 +96,20 @@ class L2cap { PsmData classic_; PsmData le_; + bool ConnectionExists(uint16_t cid) const; + uint16_t classic_dynamic_psm_; uint16_t le_dynamic_psm_; uint16_t classic_virtual_psm_; + std::unordered_map<uint16_t, + std::function<void(std::function<void(uint16_t c)>)>> + cid_to_postable_map_; + std::unordered_map<uint16_t, uint16_t> cid_to_psm_map_; std::unordered_map<uint16_t, uint16_t> client_psm_to_real_psm_map_; std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> cid_to_callback_map_; }; } // namespace shim +} // namespace legacy } // namespace bluetooth diff --git a/main/shim/l2cap_test.cc b/main/shim/l2cap_test.cc new file mode 100644 index 000000000..c0f9a7b95 --- /dev/null +++ b/main/shim/l2cap_test.cc @@ -0,0 +1,254 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <cstdint> + +#define LOG_TAG "bt_shim_test" + +#include "osi/include/log.h" +#include "shim/l2cap.h" +#include "shim/test_stack.h" +#include "types/raw_address.h" + +TestStack test_stack_; + +bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() { + return (bluetooth::shim::IStack*)&test_stack_; +} + +namespace bluetooth { +namespace legacy { + +namespace { + +constexpr uint16_t kPsm = 123; +constexpr uint16_t kCid = 987; +constexpr size_t kDataBufferSize = 1024; + +uint8_t bt_hdr_data[] = { + 0x00, 0x00, /* event */ + 0x08, 0x00, /* len */ + 0x00, 0x00, /* offset */ + 0x00, 0x00, /* layer specific */ + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, /* data */ + 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, /* data */ +}; + +class L2capTest; +L2capTest* l2cap_test_ = nullptr; + +class L2capTest : public ::testing::Test { + public: + static shim::L2cap* l2cap_; + + struct { + int L2caConnectCfmCb; + int L2caConnectPndCb; + int L2caConfigIndCb; + int L2caConfigCfmCb; + int L2caDisconnectIndCb; + int L2caDisconnectCfmCb; + int L2caQosViolationIndCb; + int L2caDataIndCb; + int L2caCongestionStatusCb; + int L2caTxCompleteCb; + int L2caCreditsReceivedCb; + } cnt_{ + .L2caConnectCfmCb = 0, + .L2caConnectPndCb = 0, + .L2caConfigIndCb = 0, + .L2caConfigCfmCb = 0, + .L2caDisconnectIndCb = 0, + .L2caDisconnectCfmCb = 0, + .L2caQosViolationIndCb = 0, + .L2caDataIndCb = 0, + .L2caCongestionStatusCb = 0, + .L2caTxCompleteCb = 0, + .L2caCreditsReceivedCb = 0, + }; + + protected: + void SetUp() override { + l2cap_ = new shim::L2cap(); + l2cap_test_ = this; + } + + void TearDown() override { + delete l2cap_; + l2cap_ = nullptr; + } + + uint8_t data_buffer_[kDataBufferSize]; +}; + +shim::L2cap* L2capTest::l2cap_ = nullptr; +// Indication of remotely initiated connection response sent +void L2caConnectIndCb(const RawAddress& raw_address, uint16_t a, uint16_t b, + uint8_t c) { + LOG_INFO(LOG_TAG, "%s", __func__); +} + +// Confirms locally initiated connection request completed +void L2caConnectCfmCb(uint16_t cid, uint16_t result) { + l2cap_test_->cnt_.L2caConnectCfmCb++; + LOG_INFO(LOG_TAG, "%s cid:%hd result:%hd", __func__, cid, result); +} + +void L2caConnectPndCb(uint16_t cid) { + l2cap_test_->cnt_.L2caConnectPndCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +// Indication of remotely initiated configuration response sent +void L2caConfigIndCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) { + l2cap_test_->cnt_.L2caConfigIndCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +// Confirms locally initiated config request completed +void L2caConfigCfmCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) { + l2cap_test_->cnt_.L2caConfigCfmCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +// Indication of remotely initiated disconnection response sent +void L2caDisconnectIndCb(uint16_t cid, bool needs_ack) { + l2cap_test_->cnt_.L2caDisconnectIndCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +// Confirms locally initiated disconnect request completed +void L2caDisconnectCfmCb(uint16_t cid, uint16_t result) { + l2cap_test_->cnt_.L2caDisconnectCfmCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void L2caQosViolationIndCb(const RawAddress& raw_address) { + l2cap_test_->cnt_.L2caQosViolationIndCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void L2caDataIndCb(uint16_t cid, BT_HDR* bt_hdr) { + l2cap_test_->cnt_.L2caDataIndCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void L2caCongestionStatusCb(uint16_t cid, bool is_congested) { + l2cap_test_->cnt_.L2caCongestionStatusCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void L2caTxCompleteCb(uint16_t cid, uint16_t sdu_cnt) { + l2cap_test_->cnt_.L2caTxCompleteCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +void L2caCreditsReceivedCb(uint16_t cid, uint16_t credits_received, + uint16_t credit_count) { + l2cap_test_->cnt_.L2caCreditsReceivedCb++; + LOG_INFO(LOG_TAG, "%s", __func__); +} + +tL2CAP_APPL_INFO test_callbacks{ + .pL2CA_ConnectInd_Cb = L2caConnectIndCb, + .pL2CA_ConnectCfm_Cb = L2caConnectCfmCb, + .pL2CA_ConnectPnd_Cb = L2caConnectPndCb, + .pL2CA_ConfigInd_Cb = L2caConfigIndCb, + .pL2CA_ConfigCfm_Cb = L2caConfigCfmCb, + .pL2CA_DisconnectInd_Cb = L2caDisconnectIndCb, + .pL2CA_DisconnectCfm_Cb = L2caDisconnectCfmCb, + .pL2CA_QoSViolationInd_Cb = L2caQosViolationIndCb, + .pL2CA_DataInd_Cb = L2caDataIndCb, + .pL2CA_CongestionStatus_Cb = L2caCongestionStatusCb, + .pL2CA_TxComplete_Cb = L2caTxCompleteCb, + .pL2CA_CreditsReceived_Cb = L2caCreditsReceivedCb, +}; + +TEST_F(L2capTest, Base) { LOG_INFO(LOG_TAG, "Got test %p", &test_callbacks); } + +TEST_F(L2capTest, Callbacks) { + bool rc = l2cap_->SetCallbacks(kPsm, &test_callbacks); + CHECK(rc == true); +} + +TEST_F(L2capTest, RegisterService) { + l2cap_->RegisterService(123, &test_callbacks, false); +} + +TEST_F(L2capTest, CreateConnection_NotRegistered) { + RawAddress raw_address; + std::string string_address("11:22:33:44:55:66"); + RawAddress::FromString(string_address, raw_address); + uint16_t cid = l2cap_->CreateConnection(123, raw_address); + CHECK(cid == 0); +} + +TEST_F(L2capTest, CreateConnection_Registered) { + test_stack_.test_l2cap_.cid_ = kCid; + l2cap_->RegisterService(123, &test_callbacks, false); + + RawAddress raw_address; + std::string string_address("11:22:33:44:55:66"); + RawAddress::FromString(string_address, raw_address); + uint16_t cid = l2cap_->CreateConnection(123, raw_address); + CHECK(cid != 0); +} + +TEST_F(L2capTest, CreateConnection_WithHandshake) { + test_stack_.test_l2cap_.cid_ = kCid; + l2cap_->RegisterService(kPsm, &test_callbacks, false); + + RawAddress raw_address; + std::string string_address("11:22:33:44:55:66"); + RawAddress::FromString(string_address, raw_address); + uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address); + CHECK(cid != 0); + + { + // Simulate a successful connection response + l2cap_->OnConnectionReady(kPsm, kCid, + [&cid](std::function<void(uint16_t)> func) { + LOG_INFO(LOG_TAG, "In closure cid:%d", cid); + func(cid); + }); + } + CHECK(cnt_.L2caConnectCfmCb == 1); + + CHECK(l2cap_->ConfigRequest(cid, nullptr) == true); + CHECK(cnt_.L2caConfigCfmCb == 1); + + BT_HDR* bt_hdr = (BT_HDR*)bt_hdr_data; + + test_stack_.test_l2cap_.data_buffer_ = data_buffer_; + test_stack_.test_l2cap_.data_buffer_size_ = kDataBufferSize; + + l2cap_->Write(cid, bt_hdr); + + CHECK(data_buffer_[0] == 0x11); + CHECK(data_buffer_[1] == 0x22); + CHECK(data_buffer_[2] == 0x33); + CHECK(data_buffer_[3] == 0x44); + CHECK(data_buffer_[4] == 0x55); + CHECK(data_buffer_[5] == 0x66); + CHECK(data_buffer_[6] == 0x77); + CHECK(data_buffer_[7] == 0x88); + CHECK(data_buffer_[8] == 0x00); +} + +} // namespace +} // namespace legacy +} // namespace bluetooth diff --git a/main/shim/test_stack.cc b/main/shim/test_stack.cc new file mode 100644 index 000000000..7769fa0b0 --- /dev/null +++ b/main/shim/test_stack.cc @@ -0,0 +1,91 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <cstdint> +#include <future> + +#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h" +#include "main/shim/entry.h" +#include "main/shim/test_stack.h" +#include "osi/include/log.h" + +#define ASSERT(condition) \ + do { \ + if (!(condition)) { \ + LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \ + } \ + } while (false) + +void TestGdShimL2cap::RegisterService( + uint16_t psm, bluetooth::shim::ConnectionOpenCallback on_open, + std::promise<void> completed) { + completed.set_value(); +} + +void TestGdShimL2cap::UnregisterService(uint16_t psm) {} + +void TestGdShimL2cap::CreateConnection(uint16_t psm, const std::string address, + std::promise<uint16_t> completed) { + completed.set_value(cid_); +} + +void TestGdShimL2cap::CloseConnection(uint16_t cid) {} + +void TestGdShimL2cap::SetReadDataReadyCallback( + uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) {} + +void TestGdShimL2cap::SetConnectionClosedCallback( + uint16_t cid, bluetooth::shim::ConnectionClosedCallback on_closed) {} + +bool TestGdShimL2cap::Write(uint16_t cid, const uint8_t* data, size_t len) { + ASSERT(data_buffer_ != nullptr); + ASSERT(data_buffer_size_ > len); + memcpy(data_buffer_, data, len); + return write_success_; +} + +bool TestGdShimL2cap::WriteFlushable(uint16_t cid, const uint8_t* data, + size_t len) { + return write_success_; +} + +bool TestGdShimL2cap::WriteNonFlushable(uint16_t cid, const uint8_t* data, + size_t len) { + return write_success_; +} + +bool TestGdShimL2cap::IsCongested(uint16_t cid) { return is_congested_; } + +void TestStack::Start() {} + +void TestStack::Stop() {} + +bluetooth::shim::IController* TestStack::GetController() { return nullptr; } + +bluetooth::shim::IConnectability* TestStack::GetConnectability() { + return nullptr; +} + +bluetooth::shim::IDiscoverability* TestStack::GetDiscoverability() { + return nullptr; +} + +bluetooth::shim::IHciLayer* TestStack::GetHciLayer() { return nullptr; } + +bluetooth::shim::IInquiry* TestStack::GetInquiry() { return nullptr; } + +bluetooth::shim::IL2cap* TestStack::GetL2cap() { return &test_l2cap_; } + +bluetooth::shim::IPage* TestStack::GetPage() { return nullptr; } diff --git a/main/shim/test_stack.h b/main/shim/test_stack.h new file mode 100644 index 000000000..9f90199e1 --- /dev/null +++ b/main/shim/test_stack.h @@ -0,0 +1,66 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <cstdint> +#include <future> + +#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h" +#include "main/shim/entry.h" + +class TestGdShimL2cap : public bluetooth::shim::IL2cap { + public: + uint16_t cid_{0}; + bool write_success_{false}; + bool is_congested_{false}; + uint8_t* data_buffer_{nullptr}; + size_t data_buffer_size_{0}; + + void RegisterService(uint16_t psm, + bluetooth::shim::ConnectionOpenCallback on_open, + std::promise<void> completed) override; + void UnregisterService(uint16_t psm); + void CreateConnection(uint16_t psm, const std::string address, + std::promise<uint16_t> completed) override; + void CloseConnection(uint16_t cid); + void SetReadDataReadyCallback( + uint16_t cid, + bluetooth::shim::ReadDataReadyCallback on_data_ready) override; + void SetConnectionClosedCallback( + uint16_t cid, + bluetooth::shim::ConnectionClosedCallback on_closed) override; + bool Write(uint16_t cid, const uint8_t* data, size_t len) override; + bool WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override; + bool WriteNonFlushable(uint16_t cid, const uint8_t* data, + size_t len) override; + bool IsCongested(uint16_t cid) override; +}; + +class TestStack : public bluetooth::shim::IStack { + public: + TestStack() = default; + + bluetooth::shim::IController* GetController(); + bluetooth::shim::IConnectability* GetConnectability(); + bluetooth::shim::IDiscoverability* GetDiscoverability(); + bluetooth::shim::IHciLayer* GetHciLayer(); + bluetooth::shim::IInquiry* GetInquiry(); + bluetooth::shim::IL2cap* GetL2cap(); + bluetooth::shim::IPage* GetPage(); + + TestGdShimL2cap test_l2cap_; + + void Start(); + void Stop(); +}; diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp index d73a5fb91..515f513e1 100644 --- a/profile/avrcp/Android.bp +++ b/profile/avrcp/Android.bp @@ -62,3 +62,35 @@ cc_test { cflags: ["-DBUILDCFG"], } + +cc_fuzz { + name: "avrcp_device_fuzz", + host_supported: true, + defaults: [ + "fluoride_defaults_fuzzable", + ], + srcs: [ + "tests/avrcp_device_fuzz/avrcp_device_fuzz.cc", + ], + include_dirs: [ + "system/bt", + "system/bt/packet/tests", + "system/bt/btcore/include", + "system/bt/internal_include", + "system/bt/stack/include", + ], + static_libs: [ + "avrcp-target-service", + "lib-bt-packets", + "libbase", + "libchrome", + "libcutils", + "libevent", + "liblog", + "libstatslog", + ], + header_libs: ["libbluetooth_headers"], + corpus: [ + "tests/avrcp_device_fuzz/corpus/*", + ], +} diff --git a/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc new file mode 100644 index 000000000..24a794dfb --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc @@ -0,0 +1,86 @@ +#include <cstddef> +#include <cstdint> + +#include "avrcp_packet.h" +#include "device.h" +#include "packet_test_helper.h" +#include "stack_config.h" + +namespace bluetooth { +namespace avrcp { +class FakeMediaInterface : public MediaInterface { + public: + virtual void SendKeyEvent(uint8_t key, KeyState state) {} + using SongInfoCallback = base::Callback<void(SongInfo)>; + virtual void GetSongInfo(SongInfoCallback info_cb) {} + using PlayStatusCallback = base::Callback<void(PlayStatus)>; + virtual void GetPlayStatus(PlayStatusCallback status_cb) {} + using NowPlayingCallback = + base::Callback<void(std::string, std::vector<SongInfo>)>; + virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {} + using MediaListCallback = + base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>; + virtual void GetMediaPlayerList(MediaListCallback list_cb) {} + using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>; + virtual void GetFolderItems(uint16_t player_id, std::string media_id, + FolderItemsCallback folder_cb) {} + using SetBrowsedPlayerCallback = base::Callback<void( + bool success, std::string root_id, uint32_t num_items)>; + virtual void SetBrowsedPlayer(uint16_t player_id, + SetBrowsedPlayerCallback browse_cb) {} + virtual void PlayItem(uint16_t player_id, bool now_playing, + std::string media_id) {} + virtual void SetActiveDevice(const RawAddress& address) {} + virtual void RegisterUpdateCallback(MediaCallbacks* callback) {} + virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {} +}; + +class FakeVolumeInterface : public VolumeInterface { + public: + virtual void DeviceConnected(const RawAddress& bdaddr) {} + virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {} + virtual void DeviceDisconnected(const RawAddress& bdaddr) {} + virtual void SetVolume(int8_t volume) {} +}; + +class FakeA2dpInterface : public A2dpInterface { + public: + virtual RawAddress active_peer() { return RawAddress(); } + virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) { + return false; + } +}; + +bool get_pts_avrcp_test(void) { return false; } + +const stack_config_t interface = { + nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr}; + +void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + FakeMediaInterface fmi; + FakeVolumeInterface fvi; + FakeA2dpInterface fai; + + std::vector<uint8_t> Packet(Data, Data + Size); + Device device(RawAddress::kAny, true, + base::Bind([](uint8_t, bool, + std::unique_ptr<::bluetooth::PacketBuilder>) {}), + 0xFFFF, 0xFFFF); + device.RegisterInterfaces(&fmi, &fai, &fvi); + + auto browse_request = TestPacketType<BrowsePacket>::Make(Packet); + device.BrowseMessageReceived(1, browse_request); + + auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet); + device.MessageReceived(1, avrcp_request); + return 0; +} +} // namespace avrcp +} // namespace bluetooth + +const stack_config_t* stack_config_get_interface(void) { + return &bluetooth::avrcp::interface; +}
\ No newline at end of file diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response Binary files differnew file mode 100644 index 000000000..f5f982ce9 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request Binary files differnew file mode 100644 index 000000000..581327a4e --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response Binary files differnew file mode 100644 index 000000000..10c757667 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request Binary files differnew file mode 100644 index 000000000..a2226572d --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification Binary files differnew file mode 100644 index 000000000..6ee7661bd --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification Binary files differnew file mode 100644 index 000000000..31d50fb54 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet Binary files differnew file mode 100644 index 000000000..83fa4271f --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request Binary files differnew file mode 100644 index 000000000..3968c03c8 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id Binary files differnew file mode 100644 index 000000000..f3966ed8b --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown Binary files differnew file mode 100644 index 000000000..eada547a4 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id Binary files differnew file mode 100644 index 000000000..21889cafe --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported Binary files differnew file mode 100644 index 000000000..d2cf8a8f0 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full Binary files differnew file mode 100644 index 000000000..d79c1d3bf --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial Binary files differnew file mode 100644 index 000000000..c37c9b696 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full Binary files differnew file mode 100644 index 000000000..2e63febb8 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response Binary files differnew file mode 100644 index 000000000..a09361bff --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response Binary files differnew file mode 100644 index 000000000..f58889a51 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response Binary files differnew file mode 100644 index 000000000..ed25c8c1d --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request Binary files differnew file mode 100644 index 000000000..098fa05d4 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs Binary files differnew file mode 100644 index 000000000..7e27ff9b4 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing Binary files differnew file mode 100644 index 000000000..9eaa35594 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title Binary files differnew file mode 100644 index 000000000..0108fc760 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs Binary files differnew file mode 100644 index 000000000..e8cc8675a --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response Binary files differnew file mode 100644 index 000000000..f7472e05d --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes Binary files differnew file mode 100644 index 000000000..7d706b8f0 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid Binary files differnew file mode 100644 index 000000000..d55d0c4cc --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response Binary files differnew file mode 100644 index 000000000..3553664b7 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request Binary files differnew file mode 100644 index 000000000..2311a4775 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response Binary files differnew file mode 100644 index 000000000..240136fae --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players Binary files differnew file mode 100644 index 000000000..a5b85b78c --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing Binary files differnew file mode 100644 index 000000000..a4a6654bd --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs Binary files differnew file mode 100644 index 000000000..0f9ad75e8 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response Binary files differnew file mode 100644 index 000000000..742da96da --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification Binary files differnew file mode 100644 index 000000000..2f6044b3d --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification Binary files differnew file mode 100644 index 000000000..b643cf47e --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification Binary files differnew file mode 100644 index 000000000..ea6675ea3 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification Binary files differnew file mode 100644 index 000000000..0fb233db6 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification Binary files differnew file mode 100644 index 000000000..b23cf6eb6 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton Binary files differnew file mode 100644 index 000000000..cac9b4ab4 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification Binary files differnew file mode 100644 index 000000000..101bae681 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed Binary files differnew file mode 100644 index 000000000..9e002d211 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released Binary files differnew file mode 100644 index 000000000..5c100e85e --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request Binary files differnew file mode 100644 index 000000000..538a7c046 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response Binary files differnew file mode 100644 index 000000000..1180bcc19 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid Binary files differnew file mode 100644 index 000000000..2a213f0f2 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification Binary files differnew file mode 100644 index 000000000..fa40de4f0 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification Binary files differnew file mode 100644 index 000000000..3e7209b37 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response Binary files differnew file mode 100644 index 000000000..82cc04731 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification Binary files differnew file mode 100644 index 000000000..5119a2d73 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request Binary files differnew file mode 100644 index 000000000..5403b843d --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response Binary files differnew file mode 100644 index 000000000..b30cde20f --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request Binary files differnew file mode 100644 index 000000000..ebe224eba --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request Binary files differnew file mode 100644 index 000000000..a38cfb7ff --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response Binary files differnew file mode 100644 index 000000000..42305244c --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request Binary files differnew file mode 100644 index 000000000..667137b52 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response Binary files differnew file mode 100644 index 000000000..c3a3c9380 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet Binary files differnew file mode 100644 index 000000000..b866ef0f3 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request Binary files differnew file mode 100644 index 000000000..365d337c9 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request Binary files differnew file mode 100644 index 000000000..c7c5b3372 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request Binary files differnew file mode 100644 index 000000000..102d788c6 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request Binary files differnew file mode 100644 index 000000000..4ab0aa80b --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request Binary files differnew file mode 100644 index 000000000..746755510 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request Binary files differnew file mode 100644 index 000000000..bc634e2b3 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request Binary files differnew file mode 100644 index 000000000..a138dc490 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request Binary files differnew file mode 100644 index 000000000..4872d6b05 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet Binary files differnew file mode 100644 index 000000000..0c2a66e27 --- /dev/null +++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc index 868a2a440..8f8e49794 100644 --- a/stack/btm/btm_acl.cc +++ b/stack/btm/btm_acl.cc @@ -50,6 +50,7 @@ #include "device/include/interop.h" #include "hcidefs.h" #include "hcimsgs.h" +#include "log/log.h" #include "l2c_int.h" #include "osi/include/log.h" #include "osi/include/osi.h" @@ -1084,7 +1085,7 @@ void btm_read_remote_features_complete(uint8_t* p) { * Returns void * ******************************************************************************/ -void btm_read_remote_ext_features_complete(uint8_t* p) { +void btm_read_remote_ext_features_complete(uint8_t* p, uint8_t evt_len) { tACL_CONN* p_acl_cb; uint8_t page_num, max_page; uint16_t handle; @@ -1092,6 +1093,14 @@ void btm_read_remote_ext_features_complete(uint8_t* p) { BTM_TRACE_DEBUG("btm_read_remote_ext_features_complete"); + if (evt_len < HCI_EXT_FEATURES_SUCCESS_EVT_LEN) { + android_errorWriteLog(0x534e4554, "141552859"); + BTM_TRACE_ERROR( + "btm_read_remote_ext_features_complete evt length too short. length=%d", + evt_len); + return; + } + ++p; STREAM_TO_UINT16(handle, p); STREAM_TO_UINT8(page_num, p); @@ -1111,6 +1120,13 @@ void btm_read_remote_ext_features_complete(uint8_t* p) { return; } + if (page_num > max_page) { + android_errorWriteLog(0x534e4554, "141552859"); + BTM_TRACE_ERROR("btm_read_remote_ext_features_complete num_page=%d invalid", + page_num); + return; + } + p_acl_cb = &btm_cb.acl_db[acl_idx]; /* Copy the received features page */ diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h index 6b80717c0..ee1d6554a 100644 --- a/stack/btm/btm_int.h +++ b/stack/btm/btm_int.h @@ -119,7 +119,7 @@ extern uint16_t btm_get_acl_disc_reason_code(void); extern tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr, tBT_TRANSPORT transport); extern void btm_read_remote_features_complete(uint8_t* p); -extern void btm_read_remote_ext_features_complete(uint8_t* p); +extern void btm_read_remote_ext_features_complete(uint8_t* p, uint8_t evt_len); extern void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle); extern void btm_read_remote_version_complete(uint8_t* p); diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc index 2035cc676..17fde3bfe 100644 --- a/stack/btu/btu_hcif.cc +++ b/stack/btu/btu_hcif.cc @@ -76,7 +76,8 @@ static void btu_hcif_authentication_comp_evt(uint8_t* p); static void btu_hcif_rmt_name_request_comp_evt(uint8_t* p, uint16_t evt_len); static void btu_hcif_encryption_change_evt(uint8_t* p); static void btu_hcif_read_rmt_features_comp_evt(uint8_t* p); -static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p); +static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p, + uint8_t evt_len); static void btu_hcif_read_rmt_version_comp_evt(uint8_t* p); static void btu_hcif_qos_setup_comp_evt(uint8_t* p); static void btu_hcif_command_complete_evt(BT_HDR* response, void* context); @@ -296,7 +297,7 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) { btu_hcif_read_rmt_features_comp_evt(p); break; case HCI_READ_RMT_EXT_FEATURES_COMP_EVT: - btu_hcif_read_rmt_ext_features_comp_evt(p); + btu_hcif_read_rmt_ext_features_comp_evt(p, hci_evt_len); break; case HCI_READ_RMT_VERSION_COMP_EVT: btu_hcif_read_rmt_version_comp_evt(p); @@ -1212,7 +1213,8 @@ static void btu_hcif_read_rmt_features_comp_evt(uint8_t* p) { * Returns void * ******************************************************************************/ -static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p) { +static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p, + uint8_t evt_len) { uint8_t* p_cur = p; uint8_t status; uint16_t handle; @@ -1220,7 +1222,7 @@ static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p) { STREAM_TO_UINT8(status, p_cur); if (status == HCI_SUCCESS) - btm_read_remote_ext_features_complete(p); + btm_read_remote_ext_features_complete(p, evt_len); else { STREAM_TO_UINT16(handle, p_cur); btm_read_remote_ext_features_failed(status, handle); diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h index 22df8af3b..088f2b36a 100644 --- a/stack/include/hcidefs.h +++ b/stack/include/hcidefs.h @@ -1323,6 +1323,8 @@ typedef struct { #define HCI_FEATURE_BYTES_PER_PAGE 8 +#define HCI_EXT_FEATURES_SUCCESS_EVT_LEN 13 + #define HCI_FEATURES_KNOWN(x) \ (((x)[0] | (x)[1] | (x)[2] | (x)[3] | (x)[4] | (x)[5] | (x)[6] | (x)[7]) != 0) diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp index 3a1871bae..206f3631f 100644 --- a/test/rootcanal/Android.bp +++ b/test/rootcanal/Android.bp @@ -39,9 +39,6 @@ cc_binary { "-Werror", "-DHAS_NO_BDROID_BUILDCFG", ], - generated_headers: [ - "RootCanalGeneratedPackets_h", - ], static_libs: [ "android.hardware.bluetooth-async", "android.hardware.bluetooth-hci", @@ -82,9 +79,6 @@ cc_library_shared { "-Werror", "-DHAS_NO_BDROID_BUILDCFG", ], - generated_headers: [ - "RootCanalGeneratedPackets_h", - ], static_libs: [ "android.hardware.bluetooth-async", "android.hardware.bluetooth-hci", diff --git a/types/class_of_device.h b/types/class_of_device.h index 4c37ebf26..8c2ab37e8 100644 --- a/types/class_of_device.h +++ b/types/class_of_device.h @@ -20,9 +20,6 @@ #include <string> -namespace bluetooth { -namespace types { - /** Bluetooth Class of Device */ class ClassOfDevice final { public: @@ -55,8 +52,3 @@ inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) { os << c.ToString(); return os; } - -} // namespace types -} // namespace bluetooth - -using ::bluetooth::types::ClassOfDevice; // TODO, remove
\ No newline at end of file diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp index d53f20190..d4d554d95 100644 --- a/vendor_libs/test_vendor_lib/Android.bp +++ b/vendor_libs/test_vendor_lib/Android.bp @@ -35,7 +35,6 @@ cc_library_static { "model/setup/test_channel_transport.cc", "model/setup/test_command_handler.cc", "model/setup/test_model.cc", - ":BluetoothPacketSources", ], cflags: [ "-fvisibility=hidden", @@ -48,9 +47,6 @@ cc_library_static { "include", ".", ], - generated_headers: [ - "RootCanalGeneratedPackets_h", - ], include_dirs: [ "system/bt", "system/bt/gd", @@ -124,9 +120,6 @@ cc_test_host { "system/bt", "system/bt/gd", ], - generated_headers: [ - "RootCanalGeneratedPackets_h", - ], shared_libs: [ "liblog", ], @@ -135,17 +128,3 @@ cc_test_host { "libbt-rootcanal", ], } - -genrule { - name: "RootCanalGeneratedPackets_h", - tools: [ - "bluetooth_packetgen", - ], - cmd: "$(location bluetooth_packetgen) --root_namespace=model --include=system/bt/vendor_libs/test_vendor_lib --out=$(genDir) $(in)", - srcs: [ - "packets/link_layer_packets.pdl", - ], - out: [ - "packets/link_layer_packets.h", - ], -} diff --git a/vendor_libs/test_vendor_lib/include/link.h b/vendor_libs/test_vendor_lib/include/link.h new file mode 100644 index 000000000..798bba7ac --- /dev/null +++ b/vendor_libs/test_vendor_lib/include/link.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace test_vendor_lib { +class Link { + public: + static constexpr size_t kSizeBytes = sizeof(uint32_t); + static constexpr size_t kTypeBytes = sizeof(uint8_t); + + enum class PacketType : uint8_t { + UNKNOWN, + ACL, + COMMAND, + DISCONNECT, + ENCRYPT_CONNECTION, + ENCRYPT_CONNECTION_RESPONSE, + EVENT, + INQUIRY, + INQUIRY_RESPONSE, + IO_CAPABILITY_REQUEST, + IO_CAPABILITY_RESPONSE, + IO_CAPABILITY_NEGATIVE_RESPONSE, + LE_ADVERTISEMENT, + LE_CONNECT, + LE_CONNECT_COMPLETE, + LE_SCAN, + LE_SCAN_RESPONSE, + PAGE, + PAGE_RESPONSE, + PAGE_REJECT, + RESPONSE, + SCO, + }; +}; +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc index 21b6eb31b..6e9e77597 100644 --- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc +++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc @@ -67,8 +67,7 @@ std::string DualModeController::GetTypeString() const { return "Simulated Bluetooth Controller"; } -void DualModeController::IncomingPacket( - model::packets::LinkLayerPacketView incoming) { +void DualModeController::IncomingPacket(packets::LinkLayerPacketView incoming) { link_layer_controller_.IncomingPacket(incoming); } @@ -112,8 +111,7 @@ DualModeController::DualModeController(const std::string& properties_filename, u properties_.SetAddress(public_address); link_layer_controller_.RegisterRemoteChannel( - [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, - Phy::Type phy_type) { + [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) { DualModeController::SendLinkLayerPacket(packet, phy_type); }); @@ -209,6 +207,12 @@ DualModeController::DualModeController(const std::string& properties_filename, u SET_HANDLER(OpCode::READ_REMOTE_VERSION_INFORMATION, HciReadRemoteVersionInformation); SET_HANDLER(OpCode::LE_CONNECTION_UPDATE, HciLeConnectionUpdate); SET_HANDLER(OpCode::LE_START_ENCRYPTION, HciLeStartEncryption); + SET_HANDLER(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST, + HciLeAddDeviceToResolvingList); + SET_HANDLER(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, + HciLeRemoveDeviceFromResolvingList); + SET_HANDLER(OpCode::LE_CLEAR_RESOLVING_LIST, HciLeClearResolvingList); + SET_HANDLER(OpCode::LE_SET_PRIVACY_MODE, HciLeSetPrivacyMode); // Testing Commands SET_HANDLER(OpCode::READ_LOOPBACK_MODE, HciReadLoopbackMode); SET_HANDLER(OpCode::WRITE_LOOPBACK_MODE, HciWriteLoopbackMode); @@ -1085,6 +1089,70 @@ void DualModeController::HciLeRemoveDeviceFromWhiteList(packets::PacketView<true SendCommandCompleteSuccess(OpCode::LE_REMOVE_DEVICE_FROM_WHITE_LIST); } +void DualModeController::HciLeClearResolvingList( + packets::PacketView<true> args) { + ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size()); + link_layer_controller_.LeResolvingListClear(); + SendCommandCompleteSuccess(OpCode::LE_CLEAR_RESOLVING_LIST); +} + +void DualModeController::HciLeAddDeviceToResolvingList( + packets::PacketView<true> args) { + ASSERT_LOG(args.size() == 39, "%s size=%zu", __func__, args.size()); + + if (link_layer_controller_.LeResolvingListFull()) { + SendCommandCompleteOnlyStatus(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST, + hci::Status::MEMORY_CAPACITY_EXCEEDED); + return; + } + auto args_itr = args.begin(); + uint8_t addr_type = args_itr.extract<uint8_t>(); + Address address = args_itr.extract<Address>(); + std::array<uint8_t, LinkLayerController::kIrk_size> peerIrk; + std::array<uint8_t, LinkLayerController::kIrk_size> localIrk; + for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size; + irk_ind++) { + peerIrk[irk_ind] = args_itr.extract<uint8_t>(); + } + + for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size; + irk_ind++) { + localIrk[irk_ind] = args_itr.extract<uint8_t>(); + } + + link_layer_controller_.LeResolvingListAddDevice(address, addr_type, peerIrk, + localIrk); + SendCommandCompleteSuccess(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST); +} + +void DualModeController::HciLeRemoveDeviceFromResolvingList( + packets::PacketView<true> args) { + ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size()); + + auto args_itr = args.begin(); + uint8_t addr_type = args_itr.extract<uint8_t>(); + Address address = args_itr.extract<Address>(); + link_layer_controller_.LeResolvingListRemoveDevice(address, addr_type); + SendCommandCompleteSuccess(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST); +} + +void DualModeController::HciLeSetPrivacyMode(packets::PacketView<true> args) { + ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size()); + + auto args_itr = args.begin(); + uint8_t peer_identity_address_type = args_itr.extract<uint8_t>(); + Address peer_identity_address = args_itr.extract<Address>(); + uint8_t privacy_mode = args_itr.extract<uint8_t>(); + + if (link_layer_controller_.LeResolvingListContainsDevice( + peer_identity_address, peer_identity_address_type)) { + link_layer_controller_.LeSetPrivacyMode( + peer_identity_address_type, peer_identity_address, privacy_mode); + } + + SendCommandCompleteSuccess(OpCode::LE_SET_PRIVACY_MODE); +} + /* void DualModeController::HciLeReadRemoteUsedFeaturesRsp(uint16_t handle, uint64_t features) { diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h index 865b446b3..cd3dcfc67 100644 --- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h +++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h @@ -60,8 +60,7 @@ class DualModeController : public Device { virtual std::string GetTypeString() const override; - virtual void IncomingPacket( - model::packets::LinkLayerPacketView incoming) override; + virtual void IncomingPacket(packets::LinkLayerPacketView incoming) override; virtual void TimerTick() override; @@ -380,6 +379,18 @@ class DualModeController : public Device { // 7.8.27 void HciLeReadSupportedStates(packets::PacketView<true> args); + // 7.8.38 + void HciLeAddDeviceToResolvingList(packets::PacketView<true> args); + + // 7.8.39 + void HciLeRemoveDeviceFromResolvingList(packets::PacketView<true> args); + + // 7.8.40 + void HciLeClearResolvingList(packets::PacketView<true> args); + + // 7.8.77 + void HciLeSetPrivacyMode(packets::PacketView<true> args); + // Vendor-specific Commands void HciLeVendorSleepMode(packets::PacketView<true> args); diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc index 3ddb19bbc..93b06ddd8 100644 --- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc +++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc @@ -22,9 +22,20 @@ #include "packets/hci/command_packet_view.h" #include "packets/hci/event_packet_builder.h" #include "packets/hci/sco_packet_builder.h" - -#include "packet/raw_builder.h" -#include "packets/link_layer_packets.h" +#include "packets/link_layer/command_builder.h" +#include "packets/link_layer/command_view.h" +#include "packets/link_layer/disconnect_view.h" +#include "packets/link_layer/encrypt_connection_view.h" +#include "packets/link_layer/inquiry_response_view.h" +#include "packets/link_layer/inquiry_view.h" +#include "packets/link_layer/io_capability_view.h" +#include "packets/link_layer/le_advertisement_view.h" +#include "packets/link_layer/le_connect_complete_view.h" +#include "packets/link_layer/le_connect_view.h" +#include "packets/link_layer/page_reject_view.h" +#include "packets/link_layer/page_response_view.h" +#include "packets/link_layer/page_view.h" +#include "packets/link_layer/response_view.h" using std::vector; using namespace std::chrono; @@ -42,42 +53,25 @@ static uint8_t GetRssi() { return -(rssi); } -void LinkLayerController::SendLeLinkLayerPacket( - std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) { - std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet = - std::move(packet); - ScheduleTask(milliseconds(50), [this, shared_packet]() { - send_to_remote_(std::move(shared_packet), Phy::Type::LOW_ENERGY); - }); +void LinkLayerController::SendLeLinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) { + ScheduleTask(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::LOW_ENERGY); }); } -void LinkLayerController::SendLinkLayerPacket( - std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) { - std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet = - std::move(packet); - ScheduleTask(milliseconds(50), [this, shared_packet]() { - send_to_remote_(std::move(shared_packet), Phy::Type::BR_EDR); - }); +void LinkLayerController::SendLinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) { + ScheduleTask(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::BR_EDR); }); } hci::Status LinkLayerController::SendCommandToRemoteByAddress(hci::OpCode opcode, PacketView<true> args, const Address& remote, bool use_public_address) { + std::shared_ptr<LinkLayerPacketBuilder> command; Address local_address; if (use_public_address) { local_address = properties_.GetAddress(); } else { local_address = properties_.GetLeAddress(); } - - std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = - std::make_unique<bluetooth::packet::RawBuilder>(); - std::vector<uint8_t> payload_bytes(args.begin(), args.end()); - raw_builder_ptr->AddOctets2(static_cast<uint16_t>(opcode)); - raw_builder_ptr->AddOctets(payload_bytes); - - auto command = model::packets::CommandBuilder::Create( - local_address, remote, std::move(raw_builder_ptr)); - + command = LinkLayerPacketBuilder::WrapCommand(CommandBuilder::Create(static_cast<uint16_t>(opcode), args), + local_address, remote); SendLinkLayerPacket(std::move(command)); return hci::Status::SUCCESS; } @@ -98,11 +92,15 @@ hci::Status LinkLayerController::SendAclToRemote(AclPacketView acl_packet) { return hci::Status::UNKNOWN_CONNECTION; } + std::unique_ptr<ViewForwarderBuilder> acl_builder = ViewForwarderBuilder::Create(acl_packet); + Address my_address = properties_.GetAddress(); Address destination = connections_.GetAddress(handle); if (connections_.GetOwnAddressType(handle) != 0) { // If it's not public, it must be LE my_address = properties_.GetLeAddress(); } + std::shared_ptr<LinkLayerPacketBuilder> acl = + LinkLayerPacketBuilder::WrapAcl(std::move(acl_builder), my_address, destination); LOG_INFO("%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle, static_cast<int>(acl_packet.size())); @@ -110,32 +108,11 @@ hci::Status LinkLayerController::SendAclToRemote(AclPacketView acl_packet) { ScheduleTask(milliseconds(5), [this, handle]() { send_event_(EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector()); }); - - auto acl_payload = acl_packet.GetPayload(); - - std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = - std::make_unique<bluetooth::packet::RawBuilder>(); - std::vector<uint8_t> payload_bytes(acl_payload.begin(), acl_payload.end()); - - uint16_t first_two_bytes = - static_cast<uint16_t>(acl_packet.GetHandle()) + - (static_cast<uint16_t>(acl_packet.GetPacketBoundaryFlags()) << 12) + - (static_cast<uint16_t>(acl_packet.GetBroadcastFlags()) << 14); - raw_builder_ptr->AddOctets2(first_two_bytes); - raw_builder_ptr->AddOctets2(static_cast<uint16_t>(payload_bytes.size())); - raw_builder_ptr->AddOctets(payload_bytes); - - auto acl = model::packets::AclPacketBuilder::Create( - my_address, destination, std::move(raw_builder_ptr)); - - SendLinkLayerPacket(std::move(acl)); + SendLinkLayerPacket(acl); return hci::Status::SUCCESS; } -void LinkLayerController::IncomingPacket( - model::packets::LinkLayerPacketView incoming) { - ASSERT(incoming.IsValid()); - +void LinkLayerController::IncomingPacket(LinkLayerPacketView incoming) { // TODO: Resolvable private addresses? if (incoming.GetDestinationAddress() != properties_.GetAddress() && incoming.GetDestinationAddress() != properties_.GetLeAddress() && @@ -145,67 +122,70 @@ void LinkLayerController::IncomingPacket( } switch (incoming.GetType()) { - case model::packets::PacketType::ACL: + case Link::PacketType::ACL: IncomingAclPacket(incoming); break; - case model::packets::PacketType::COMMAND: + case Link::PacketType::COMMAND: IncomingCommandPacket(incoming); break; - case model::packets::PacketType::DISCONNECT: + case Link::PacketType::DISCONNECT: IncomingDisconnectPacket(incoming); break; - case model::packets::PacketType::ENCRYPT_CONNECTION: + case Link::PacketType::ENCRYPT_CONNECTION: IncomingEncryptConnection(incoming); break; - case model::packets::PacketType::ENCRYPT_CONNECTION_RESPONSE: + case Link::PacketType::ENCRYPT_CONNECTION_RESPONSE: IncomingEncryptConnectionResponse(incoming); break; - case model::packets::PacketType::INQUIRY: + case Link::PacketType::INQUIRY: if (inquiry_scans_enabled_) { IncomingInquiryPacket(incoming); } break; - case model::packets::PacketType::INQUIRY_RESPONSE: + case Link::PacketType::INQUIRY_RESPONSE: IncomingInquiryResponsePacket(incoming); break; - case model::packets::PacketType::IO_CAPABILITY_REQUEST: + case Link::PacketType::IO_CAPABILITY_REQUEST: IncomingIoCapabilityRequestPacket(incoming); break; - case model::packets::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE: + case Link::PacketType::IO_CAPABILITY_RESPONSE: + IncomingIoCapabilityResponsePacket(incoming); + break; + case Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE: IncomingIoCapabilityNegativeResponsePacket(incoming); break; - case model::packets::PacketType::LE_ADVERTISEMENT: + case Link::PacketType::LE_ADVERTISEMENT: if (le_scan_enable_ || le_connect_) { IncomingLeAdvertisementPacket(incoming); } break; - case model::packets::PacketType::LE_CONNECT: + case Link::PacketType::LE_CONNECT: IncomingLeConnectPacket(incoming); break; - case model::packets::PacketType::LE_CONNECT_COMPLETE: + case Link::PacketType::LE_CONNECT_COMPLETE: IncomingLeConnectCompletePacket(incoming); break; - case model::packets::PacketType::LE_SCAN: + case Link::PacketType::LE_SCAN: // TODO: Check Advertising flags and see if we are scannable. IncomingLeScanPacket(incoming); break; - case model::packets::PacketType::LE_SCAN_RESPONSE: + case Link::PacketType::LE_SCAN_RESPONSE: if (le_scan_enable_ && le_scan_type_ == 1) { IncomingLeScanResponsePacket(incoming); } break; - case model::packets::PacketType::PAGE: + case Link::PacketType::PAGE: if (page_scans_enabled_) { IncomingPagePacket(incoming); } break; - case model::packets::PacketType::PAGE_RESPONSE: - IncomingPageResponsePacket(incoming); - break; - case model::packets::PacketType::PAGE_REJECT: + case Link::PacketType::PAGE_REJECT: IncomingPageRejectPacket(incoming); break; - case model::packets::PacketType::RESPONSE: + case Link::PacketType::PAGE_RESPONSE: + IncomingPageResponsePacket(incoming); + break; + case Link::PacketType::RESPONSE: IncomingResponsePacket(incoming); break; default: @@ -213,40 +193,26 @@ void LinkLayerController::IncomingPacket( } } -void LinkLayerController::IncomingAclPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingAclPacket(LinkLayerPacketView incoming) { LOG_INFO("Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(), incoming.GetDestinationAddress().ToString().c_str()); - - auto acl = model::packets::AclPacketView::Create(incoming); - ASSERT(acl.IsValid()); - auto payload = acl.GetPayload(); - std::shared_ptr<std::vector<uint8_t>> payload_bytes = - std::make_shared<std::vector<uint8_t>>(payload.begin(), payload.end()); - - AclPacketView acl_view = AclPacketView::Create(payload_bytes); + AclPacketView acl_view = AclPacketView::Create(incoming.GetPayload()); LOG_INFO("%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(), static_cast<int>(acl_view.size())); uint16_t local_handle = connections_.GetHandle(incoming.GetSourceAddress()); LOG_INFO("%s: local handle 0x%x", __func__, local_handle); acl::PacketBoundaryFlagsType boundary_flags = acl_view.GetPacketBoundaryFlags(); acl::BroadcastFlagsType broadcast_flags = acl_view.GetBroadcastFlags(); - std::unique_ptr<RawBuilder> builder = std::make_unique<RawBuilder>(); - std::vector<uint8_t> raw_data(acl_view.GetPayload().begin(), - acl_view.GetPayload().end()); - builder->AddOctets(raw_data); + std::unique_ptr<ViewForwarderBuilder> builder = ViewForwarderBuilder::Create(acl_view.GetPayload()); send_acl_(AclPacketBuilder::Create(local_handle, boundary_flags, broadcast_flags, std::move(builder))->ToVector()); } -void LinkLayerController::IncomingCommandPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingCommandPacket(LinkLayerPacketView incoming) { // TODO: Check the destination address to see if this packet is for me. - auto command = model::packets::CommandView::Create(incoming); - ASSERT(command.IsValid()); - - auto args = command.GetPayload().begin(); + CommandView command = CommandView::GetCommand(incoming); + hci::OpCode opcode = static_cast<hci::OpCode>(command.GetOpcode()); + auto args = command.GetData(); std::vector<uint64_t> response_data; - hci::OpCode opcode = static_cast<hci::OpCode>(args.extract<uint16_t>()); switch (opcode) { case (hci::OpCode::REMOTE_NAME_REQUEST): { @@ -302,26 +268,14 @@ void LinkLayerController::IncomingCommandPacket( LOG_INFO("Dropping unhandled command 0x%04x", static_cast<uint16_t>(opcode)); return; } - - std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = - std::make_unique<bluetooth::packet::RawBuilder>(); - for (uint64_t data : response_data) { - raw_builder_ptr->AddOctets8(data); - } - - auto response = model::packets::ResponseBuilder::Create( - properties_.GetAddress(), incoming.GetSourceAddress(), - static_cast<uint16_t>(opcode), std::move(raw_builder_ptr)); - - SendLinkLayerPacket(std::move(response)); + SendLinkLayerPacket( + LinkLayerPacketBuilder::WrapResponse(ResponseBuilder::Create(static_cast<uint16_t>(opcode), response_data), + properties_.GetAddress(), incoming.GetSourceAddress())); } -void LinkLayerController::IncomingDisconnectPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingDisconnectPacket(LinkLayerPacketView incoming) { LOG_INFO("Disconnect Packet"); - auto disconnect = model::packets::DisconnectView::Create(incoming); - ASSERT(disconnect.IsValid()); - + DisconnectView disconnect = DisconnectView::GetDisconnect(incoming); Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandle(peer); if (handle == acl::kReservedHandle) { @@ -334,10 +288,8 @@ void LinkLayerController::IncomingDisconnectPacket( ScheduleTask(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); }); } -void LinkLayerController::IncomingEncryptConnection( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingEncryptConnection(LinkLayerPacketView incoming) { LOG_INFO("%s", __func__); - // TODO: Check keys Address peer = incoming.GetSourceAddress(); uint16_t handle = connections_.GetHandle(peer); @@ -346,13 +298,11 @@ void LinkLayerController::IncomingEncryptConnection( return; } send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector()); - auto response = model::packets::EncryptConnectionResponseBuilder::Create( - properties_.GetAddress(), peer, security_manager_.GetKey(peer)); - SendLinkLayerPacket(std::move(response)); + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnectionResponse( + EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer)); } -void LinkLayerController::IncomingEncryptConnectionResponse( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingEncryptConnectionResponse(LinkLayerPacketView incoming) { LOG_INFO("%s", __func__); // TODO: Check keys uint16_t handle = connections_.GetHandle(incoming.GetSourceAddress()); @@ -363,119 +313,86 @@ void LinkLayerController::IncomingEncryptConnectionResponse( send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector()); } -void LinkLayerController::IncomingInquiryPacket( - model::packets::LinkLayerPacketView incoming) { - auto inquiry = model::packets::InquiryView::Create(incoming); - ASSERT(inquiry.IsValid()); - - Address peer = incoming.GetSourceAddress(); +void LinkLayerController::IncomingInquiryPacket(LinkLayerPacketView incoming) { + InquiryView inquiry = InquiryView::GetInquiry(incoming); + std::unique_ptr<InquiryResponseBuilder> inquiry_response; + switch (inquiry.GetType()) { + case (Inquiry::InquiryType::STANDARD): + inquiry_response = InquiryResponseBuilder::CreateStandard( + properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset()); + break; - switch (inquiry.GetInquiryType()) { - case (model::packets::InquiryType::STANDARD): { - auto inquiry_response = model::packets::InquiryResponseBuilder::Create( - properties_.GetAddress(), peer, - properties_.GetPageScanRepetitionMode(), - properties_.GetClassOfDevice(), properties_.GetClockOffset()); - SendLinkLayerPacket(std::move(inquiry_response)); - } break; - case (model::packets::InquiryType::RSSI): { - auto inquiry_response = - model::packets::InquiryResponseWithRssiBuilder::Create( - properties_.GetAddress(), peer, - properties_.GetPageScanRepetitionMode(), - properties_.GetClassOfDevice(), properties_.GetClockOffset(), - GetRssi()); - SendLinkLayerPacket(std::move(inquiry_response)); - } break; - case (model::packets::InquiryType::EXTENDED): { - auto inquiry_response = - model::packets::ExtendedInquiryResponseBuilder::Create( - properties_.GetAddress(), peer, - properties_.GetPageScanRepetitionMode(), - properties_.GetClassOfDevice(), properties_.GetClockOffset(), - GetRssi(), properties_.GetExtendedInquiryData()); - SendLinkLayerPacket(std::move(inquiry_response)); + case (Inquiry::InquiryType::RSSI): + inquiry_response = + InquiryResponseBuilder::CreateRssi(properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), + properties_.GetClockOffset(), GetRssi()); + break; - } break; + case (Inquiry::InquiryType::EXTENDED): + inquiry_response = InquiryResponseBuilder::CreateExtended( + properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset(), + GetRssi(), properties_.GetExtendedInquiryData()); + break; default: LOG_WARN("Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType())); return; } - // TODO: Send an Inquiry Response Notification Event 7.7.74 + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response), properties_.GetAddress(), + incoming.GetSourceAddress())); + // TODO: Send an Inquriy Response Notification Event 7.7.74 } -void LinkLayerController::IncomingInquiryResponsePacket( - model::packets::LinkLayerPacketView incoming) { - auto basic_inquiry_response = - model::packets::BasicInquiryResponseView::Create(incoming); - ASSERT(basic_inquiry_response.IsValid()); +void LinkLayerController::IncomingInquiryResponsePacket(LinkLayerPacketView incoming) { + InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(incoming); std::vector<uint8_t> eir; - switch (basic_inquiry_response.GetInquiryType()) { - case (model::packets::InquiryType::STANDARD): { + switch (inquiry_response.GetType()) { + case (Inquiry::InquiryType::STANDARD): { LOG_WARN("Incoming Standard Inquiry Response"); // TODO: Support multiple inquiries in the same packet. - auto inquiry_response = - model::packets::InquiryResponseView::Create(basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); - std::unique_ptr<EventPacketBuilder> inquiry_result = - EventPacketBuilder::CreateInquiryResultEvent(); - bool result_added = inquiry_result->AddInquiryResult( - inquiry_response.GetSourceAddress(), - inquiry_response.GetPageScanRepetitionMode(), - inquiry_response.GetClassOfDevice(), - inquiry_response.GetClockOffset()); - CHECK(result_added); + std::unique_ptr<EventPacketBuilder> inquiry_result = EventPacketBuilder::CreateInquiryResultEvent(); + bool result_added = + inquiry_result->AddInquiryResult(incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(), + inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset()); + ASSERT(result_added); send_event_(inquiry_result->ToVector()); } break; - case (model::packets::InquiryType::RSSI): { + case (Inquiry::InquiryType::RSSI): LOG_WARN("Incoming RSSI Inquiry Response"); - auto inquiry_response = - model::packets::InquiryResponseWithRssiView::Create( - basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent( - incoming.GetSourceAddress(), - inquiry_response.GetPageScanRepetitionMode(), - inquiry_response.GetClassOfDevice(), - inquiry_response.GetClockOffset(), - inquiry_response.GetRssi(), eir) + incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(), + inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir) ->ToVector()); - } break; + break; - case (model::packets::InquiryType::EXTENDED): { + case (Inquiry::InquiryType::EXTENDED): { LOG_WARN("Incoming Extended Inquiry Response"); - auto inquiry_response = - model::packets::ExtendedInquiryResponseView::Create( - basic_inquiry_response); - ASSERT(inquiry_response.IsValid()); - eir = inquiry_response.GetExtendedData(); + auto eir_itr = inquiry_response.GetExtendedData(); + size_t eir_bytes = eir_itr.NumBytesRemaining(); + LOG_WARN("Payload size = %d", static_cast<int>(eir_bytes)); + for (size_t i = 0; i < eir_bytes; i++) { + eir.push_back(eir_itr.extract<uint8_t>()); + } send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent( - incoming.GetSourceAddress(), - inquiry_response.GetPageScanRepetitionMode(), - inquiry_response.GetClassOfDevice(), - inquiry_response.GetClockOffset(), GetRssi(), eir) + incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(), + inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir) ->ToVector()); } break; default: - LOG_WARN("Unhandled Incoming Inquiry Response of type %d", - static_cast<int>(basic_inquiry_response.GetInquiryType())); + LOG_WARN("Unhandled Incoming Inquiry Response of type %d", static_cast<int>(inquiry_response.GetType())); } } -void LinkLayerController::IncomingIoCapabilityRequestPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingIoCapabilityRequestPacket(LinkLayerPacketView incoming) { LOG_DEBUG("%s", __func__); if (!simple_pairing_mode_enabled_) { LOG_WARN("%s: Only simple pairing mode is implemented", __func__); return; } - - auto request = model::packets::IoCapabilityRequestView::Create(incoming); - ASSERT(request.IsValid()); - + auto request = IoCapabilityView::GetIoCapability(incoming); Address peer = incoming.GetSourceAddress(); + uint8_t io_capability = request.GetIoCapability(); uint8_t oob_data_present = request.GetOobDataPresent(); uint8_t authentication_requirements = request.GetAuthenticationRequirements(); @@ -497,38 +414,29 @@ void LinkLayerController::IncomingIoCapabilityRequestPacket( StartSimplePairing(peer); } -void LinkLayerController::IncomingIoCapabilityResponsePacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingIoCapabilityResponsePacket(LinkLayerPacketView incoming) { LOG_DEBUG("%s", __func__); - - auto response = model::packets::IoCapabilityResponseView::Create(incoming); - ASSERT(response.IsValid()); - + auto response = IoCapabilityView::GetIoCapability(incoming); Address peer = incoming.GetSourceAddress(); uint8_t io_capability = response.GetIoCapability(); uint8_t oob_data_present = response.GetOobDataPresent(); uint8_t authentication_requirements = response.GetAuthenticationRequirements(); - security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, - authentication_requirements); + security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements); - send_event_( - EventPacketBuilder::CreateIoCapabilityResponseEvent( - peer, io_capability, oob_data_present, authentication_requirements) - ->ToVector()); + send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present, + authentication_requirements) + ->ToVector()); PairingType pairing_type = security_manager_.GetSimplePairingType(); if (pairing_type != PairingType::INVALID) { - ScheduleTask(milliseconds(5), [this, peer, pairing_type]() { - AuthenticateRemoteStage1(peer, pairing_type); - }); + ScheduleTask(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); }); } else { LOG_INFO("%s: Security Manager returned INVALID", __func__); } } -void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(LinkLayerPacketView incoming) { LOG_DEBUG("%s", __func__); Address peer = incoming.GetSourceAddress(); @@ -537,21 +445,21 @@ void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket( security_manager_.InvalidateIoCapabilities(); } -void LinkLayerController::IncomingLeAdvertisementPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingLeAdvertisementPacket(LinkLayerPacketView incoming) { // TODO: Handle multiple advertisements per packet. Address address = incoming.GetSourceAddress(); - auto advertisement = model::packets::LeAdvertisementView::Create(incoming); - ASSERT(advertisement.IsValid()); - auto adv_type = static_cast<LeAdvertisement::AdvertisementType>( - advertisement.GetAdvertisementType()); - auto address_type = - static_cast<LeAdvertisement::AddressType>(advertisement.GetAddressType()); + LeAdvertisementView advertisement = LeAdvertisementView::GetLeAdvertisementView(incoming); + LeAdvertisement::AdvertisementType adv_type = advertisement.GetAdvertisementType(); + LeAdvertisement::AddressType address_type = advertisement.GetAddressType(); if (le_scan_enable_) { - vector<uint8_t> ad = advertisement.GetData(); - + vector<uint8_t> ad; + auto itr = advertisement.GetData(); + size_t ad_size = itr.NumBytesRemaining(); + for (size_t i = 0; i < ad_size; i++) { + ad.push_back(itr.extract<uint8_t>()); + } std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent(); if (!le_adverts->AddLeAdvertisingReport(adv_type, address_type, address, ad, GetRssi())) { @@ -563,9 +471,9 @@ void LinkLayerController::IncomingLeAdvertisementPacket( // Active scanning if (le_scan_enable_ && le_scan_type_ == 1) { - auto to_send = model::packets::LeScanBuilder::Create( - properties_.GetLeAddress(), address); - SendLeLinkLayerPacket(std::move(to_send)); + std::shared_ptr<LinkLayerPacketBuilder> to_send = + LinkLayerPacketBuilder::WrapLeScan(properties_.GetLeAddress(), address); + SendLeLinkLayerPacket(to_send); } // Connect @@ -582,13 +490,11 @@ void LinkLayerController::IncomingLeAdvertisementPacket( le_connect_ = false; le_scan_enable_ = false; - auto to_send = model::packets::LeConnectBuilder::Create( - properties_.GetLeAddress(), incoming.GetSourceAddress(), - le_connection_interval_min_, le_connection_interval_max_, - le_connection_latency_, le_connection_supervision_timeout_, - static_cast<uint8_t>(le_address_type_)); - - SendLeLinkLayerPacket(std::move(to_send)); + std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeConnect( + LeConnectBuilder::Create(le_connection_interval_min_, le_connection_interval_max_, le_connection_latency_, + le_connection_supervision_timeout_, static_cast<uint8_t>(le_address_type_)), + properties_.GetLeAddress(), incoming.GetSourceAddress()); + SendLeLinkLayerPacket(to_send); } } @@ -608,10 +514,8 @@ void LinkLayerController::HandleLeConnection(Address address, uint8_t address_ty ->ToVector()); } -void LinkLayerController::IncomingLeConnectPacket( - model::packets::LinkLayerPacketView incoming) { - auto connect = model::packets::LeConnectView::Create(incoming); - ASSERT(connect.IsValid()); +void LinkLayerController::IncomingLeConnectPacket(LinkLayerPacketView incoming) { + auto connect = LeConnectView::GetLeConnect(incoming); uint16_t connection_interval = (connect.GetLeConnectionIntervalMax() + connect.GetLeConnectionIntervalMin()) / 2; if (!connections_.CreatePendingLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(connect.GetAddressType()))) { @@ -623,63 +527,54 @@ void LinkLayerController::IncomingLeConnectPacket( static_cast<uint8_t>(properties_.GetLeAdvertisingOwnAddressType()), static_cast<uint8_t>(hci::Role::SLAVE), connection_interval, connect.GetLeConnectionLatency(), connect.GetLeConnectionSupervisionTimeout()); - - auto to_send = model::packets::LeConnectCompleteBuilder::Create( - incoming.GetDestinationAddress(), incoming.GetSourceAddress(), - connection_interval, connect.GetLeConnectionLatency(), - connect.GetLeConnectionSupervisionTimeout(), - properties_.GetLeAdvertisingOwnAddressType()); - SendLeLinkLayerPacket(std::move(to_send)); + std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeConnectComplete( + LeConnectCompleteBuilder::Create(connection_interval, connect.GetLeConnectionLatency(), + connect.GetLeConnectionSupervisionTimeout(), + properties_.GetLeAdvertisingOwnAddressType()), + incoming.GetDestinationAddress(), incoming.GetSourceAddress()); + SendLeLinkLayerPacket(to_send); } -void LinkLayerController::IncomingLeConnectCompletePacket( - model::packets::LinkLayerPacketView incoming) { - auto complete = model::packets::LeConnectCompleteView::Create(incoming); - ASSERT(complete.IsValid()); +void LinkLayerController::IncomingLeConnectCompletePacket(LinkLayerPacketView incoming) { + auto complete = LeConnectCompleteView::GetLeConnectComplete(incoming); HandleLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(complete.GetAddressType()), static_cast<uint8_t>(le_address_type_), static_cast<uint8_t>(hci::Role::MASTER), complete.GetLeConnectionInterval(), complete.GetLeConnectionLatency(), complete.GetLeConnectionSupervisionTimeout()); } -void LinkLayerController::IncomingLeScanPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingLeScanPacket(LinkLayerPacketView incoming) { LOG_INFO("LE Scan Packet"); - - auto to_send = model::packets::LeScanResponseBuilder::Create( - properties_.GetLeAddress(), incoming.GetSourceAddress(), - static_cast<model::packets::AddressType>(properties_.GetLeAddressType()), - static_cast<model::packets::AdvertisementType>( - properties_.GetLeAdvertisementType()), + std::unique_ptr<LeAdvertisementBuilder> response = LeAdvertisementBuilder::Create( + static_cast<LeAdvertisement::AddressType>(properties_.GetLeAddressType()), + static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()), properties_.GetLeScanResponse()); - - SendLeLinkLayerPacket(std::move(to_send)); + std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeScanResponse( + std::move(response), properties_.GetLeAddress(), incoming.GetSourceAddress()); + SendLeLinkLayerPacket(to_send); } -void LinkLayerController::IncomingLeScanResponsePacket( - model::packets::LinkLayerPacketView incoming) { - auto scan_response = model::packets::LeScanResponseView::Create(incoming); - ASSERT(scan_response.IsValid()); - vector<uint8_t> ad = scan_response.GetData(); - auto adv_type = static_cast<LeAdvertisement::AdvertisementType>( - scan_response.GetAdvertisementType()); - auto address_type = - static_cast<LeAdvertisement::AddressType>(scan_response.GetAddressType()); +void LinkLayerController::IncomingLeScanResponsePacket(LinkLayerPacketView incoming) { + LeAdvertisementView scan_response = LeAdvertisementView::GetLeAdvertisementView(incoming); + vector<uint8_t> ad; + auto itr = scan_response.GetData(); + size_t scan_size = itr.NumBytesRemaining(); + for (size_t i = 0; i < scan_size; i++) { + ad.push_back(itr.extract<uint8_t>()); + } std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent(); - if (!le_adverts->AddLeAdvertisingReport( - adv_type, address_type, incoming.GetSourceAddress(), ad, GetRssi())) { + if (!le_adverts->AddLeAdvertisingReport(scan_response.GetAdvertisementType(), scan_response.GetAddressType(), + incoming.GetSourceAddress(), ad, GetRssi())) { LOG_INFO("Couldn't add the scan response."); } else { send_event_(le_adverts->ToVector()); } } -void LinkLayerController::IncomingPagePacket( - model::packets::LinkLayerPacketView incoming) { - auto page = model::packets::PageView::Create(incoming); - ASSERT(page.IsValid()); +void LinkLayerController::IncomingPagePacket(LinkLayerPacketView incoming) { + PageView page = PageView::GetPage(incoming); LOG_INFO("%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str()); if (!connections_.CreatePendingConnection(incoming.GetSourceAddress())) { @@ -693,19 +588,16 @@ void LinkLayerController::IncomingPagePacket( ->ToVector()); } -void LinkLayerController::IncomingPageRejectPacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingPageRejectPacket(LinkLayerPacketView incoming) { LOG_INFO("%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str()); - auto reject = model::packets::PageRejectView::Create(incoming); - ASSERT(reject.IsValid()); + PageRejectView reject = PageRejectView::GetPageReject(incoming); LOG_INFO("%s: Sending CreateConnectionComplete", __func__); send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reject.GetReason()), 0x0eff, incoming.GetSourceAddress(), hci::LinkType::ACL, false) ->ToVector()); } -void LinkLayerController::IncomingPageResponsePacket( - model::packets::LinkLayerPacketView incoming) { +void LinkLayerController::IncomingPageResponsePacket(LinkLayerPacketView incoming) { LOG_INFO("%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str()); uint16_t handle = connections_.CreateConnection(incoming.GetSourceAddress()); if (handle == acl::kReservedHandle) { @@ -717,15 +609,13 @@ void LinkLayerController::IncomingPageResponsePacket( ->ToVector()); } -void LinkLayerController::IncomingResponsePacket( - model::packets::LinkLayerPacketView incoming) { - auto response = model::packets::ResponseView::Create(incoming); - ASSERT(response.IsValid()); +void LinkLayerController::IncomingResponsePacket(LinkLayerPacketView incoming) { + ResponseView response = ResponseView::GetResponse(incoming); // TODO: Check to see if I'm expecting this response. hci::OpCode opcode = static_cast<hci::OpCode>(response.GetOpcode()); - auto args = response.GetPayload().begin(); + auto args = response.GetResponseData(); hci::Status status = static_cast<hci::Status>(args.extract<uint64_t>()); uint16_t handle = connections_.GetHandle(incoming.GetSourceAddress()); @@ -788,21 +678,24 @@ void LinkLayerController::LeAdvertising() { if (duration_cast<milliseconds>(now - last_le_advertisement_) < milliseconds(200)) { return; } + last_le_advertisement_ = now; - auto own_address_type = static_cast<model::packets::AddressType>( - properties_.GetLeAdvertisingOwnAddressType()); + LeAdvertisement::AddressType own_address_type = + static_cast<LeAdvertisement::AddressType>(properties_.GetLeAdvertisingOwnAddressType()); + std::shared_ptr<packets::LinkLayerPacketBuilder> to_send; + std::unique_ptr<packets::LeAdvertisementBuilder> ad; Address advertising_address = Address::kEmpty; - if (own_address_type == model::packets::AddressType::PUBLIC) { + if (own_address_type == LeAdvertisement::AddressType::PUBLIC) { advertising_address = properties_.GetAddress(); - } else if (own_address_type == model::packets::AddressType::RANDOM) { + } else if (own_address_type == LeAdvertisement::AddressType::RANDOM) { advertising_address = properties_.GetLeAddress(); } ASSERT(advertising_address != Address::kEmpty); - auto to_send = model::packets::LeAdvertisementBuilder::Create( - advertising_address, Address::kEmpty, own_address_type, - static_cast<model::packets::AdvertisementType>(own_address_type), - properties_.GetLeAdvertisement()); - SendLeLinkLayerPacket(std::move(to_send)); + ad = packets::LeAdvertisementBuilder::Create(own_address_type, + static_cast<LeAdvertisement::AdvertisementType>(own_address_type), + properties_.GetLeAdvertisement()); + to_send = packets::LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(ad), advertising_address); + SendLeLinkLayerPacket(to_send); } void LinkLayerController::Connections() { @@ -825,9 +718,7 @@ void LinkLayerController::RegisterScoChannel( } void LinkLayerController::RegisterRemoteChannel( - const std::function<void( - std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>& - callback) { + const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>, Phy::Type)>& callback) { send_to_remote_ = callback; } @@ -944,21 +835,16 @@ hci::Status LinkLayerController::IoCapabilityRequestReply(const Address& peer, u security_manager_.SetLocalIoCapability(peer, io_capability, oob_data_present_flag, authentication_requirements); PairingType pairing_type = security_manager_.GetSimplePairingType(); - if (pairing_type != PairingType::INVALID) { ScheduleTask(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); }); - auto packet = model::packets::IoCapabilityResponseBuilder::Create( - properties_.GetAddress(), peer, io_capability, oob_data_present_flag, - authentication_requirements); - SendLinkLayerPacket(std::move(packet)); - + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityResponse( + IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements), + properties_.GetAddress(), peer)); } else { LOG_INFO("%s: Requesting remote capability", __func__); - - auto packet = model::packets::IoCapabilityRequestBuilder::Create( - properties_.GetAddress(), peer, io_capability, oob_data_present_flag, - authentication_requirements); - SendLinkLayerPacket(std::move(packet)); + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityRequest( + IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements), + properties_.GetAddress(), peer)); } return hci::Status::SUCCESS; @@ -971,9 +857,8 @@ hci::Status LinkLayerController::IoCapabilityRequestNegativeReply(const Address& security_manager_.InvalidateIoCapabilities(); - auto packet = model::packets::IoCapabilityNegativeResponseBuilder::Create( - properties_.GetAddress(), peer, static_cast<uint8_t>(reason)); - SendLinkLayerPacket(std::move(packet)); + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse( + IoCapabilityNegativeResponseBuilder::Create(static_cast<uint8_t>(reason)), properties_.GetAddress(), peer)); return hci::Status::SUCCESS; } @@ -1064,9 +949,8 @@ void LinkLayerController::HandleSetConnectionEncryption(const Address& peer, uin return; } - auto packet = model::packets::EncryptConnectionBuilder::Create( - properties_.GetAddress(), peer, security_manager_.GetKey(peer)); - SendLinkLayerPacket(std::move(packet)); + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnection( + EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer)); } hci::Status LinkLayerController::SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable) { @@ -1106,10 +990,10 @@ hci::Status LinkLayerController::AcceptConnectionRequest(const Address& addr, bo } void LinkLayerController::MakeSlaveConnection(const Address& addr, bool try_role_switch) { + std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapPageResponse( + PageResponseBuilder::Create(try_role_switch), properties_.GetAddress(), addr); LOG_INFO("%s sending page response to %s", __func__, addr.ToString().c_str()); - auto to_send = model::packets::PageResponseBuilder::Create( - properties_.GetAddress(), addr, try_role_switch); - SendLinkLayerPacket(std::move(to_send)); + SendLinkLayerPacket(to_send); uint16_t handle = connections_.CreateConnection(addr); if (handle == acl::kReservedHandle) { @@ -1138,10 +1022,10 @@ hci::Status LinkLayerController::RejectConnectionRequest(const Address& addr, ui } void LinkLayerController::RejectSlaveConnection(const Address& addr, uint8_t reason) { - auto to_send = model::packets::PageRejectBuilder::Create( - properties_.GetAddress(), addr, reason); + std::shared_ptr<LinkLayerPacketBuilder> to_send = + LinkLayerPacketBuilder::WrapPageReject(PageRejectBuilder::Create(reason), properties_.GetAddress(), addr); LOG_INFO("%s sending page reject to %s", __func__, addr.ToString().c_str()); - SendLinkLayerPacket(std::move(to_send)); + SendLinkLayerPacket(to_send); ASSERT(reason >= 0x0d && reason <= 0x0f); send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reason), 0xeff, addr, @@ -1155,10 +1039,8 @@ hci::Status LinkLayerController::CreateConnection(const Address& addr, uint16_t, return hci::Status::CONTROLLER_BUSY; } - auto page = model::packets::PageBuilder::Create( - properties_.GetAddress(), addr, properties_.GetClassOfDevice(), - allow_role_switch); - SendLinkLayerPacket(std::move(page)); + std::unique_ptr<PageBuilder> page = PageBuilder::Create(properties_.GetClassOfDevice(), allow_role_switch); + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPage(std::move(page), properties_.GetAddress(), addr)); return hci::Status::SUCCESS; } @@ -1177,9 +1059,9 @@ hci::Status LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) { } const Address& remote = connections_.GetAddress(handle); - auto packet = model::packets::DisconnectBuilder::Create( - properties_.GetAddress(), remote, reason); - SendLinkLayerPacket(std::move(packet)); + std::shared_ptr<LinkLayerPacketBuilder> to_send = + LinkLayerPacketBuilder::WrapDisconnect(DisconnectBuilder::Create(reason), properties_.GetAddress(), remote); + SendLinkLayerPacket(to_send); ASSERT_LOG(connections_.Disconnect(handle), "Disconnecting %hx", handle); ScheduleTask(milliseconds(20), [this, handle]() { @@ -1311,6 +1193,8 @@ void LinkLayerController::LeWhiteListClear() { le_white_list_.clear(); } +void LinkLayerController::LeResolvingListClear() { le_resolving_list_.clear(); } + void LinkLayerController::LeWhiteListAddDevice(Address addr, uint8_t addr_type) { std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type); for (auto dev : le_white_list_) { @@ -1321,6 +1205,30 @@ void LinkLayerController::LeWhiteListAddDevice(Address addr, uint8_t addr_type) le_white_list_.emplace_back(new_tuple); } +void LinkLayerController::LeResolvingListAddDevice( + Address addr, uint8_t addr_type, std::array<uint8_t, kIrk_size> peerIrk, + std::array<uint8_t, kIrk_size> localIrk) { + std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>, + std::array<uint8_t, kIrk_size>> + new_tuple = std::make_tuple(addr, addr_type, peerIrk, localIrk); + for (size_t i = 0; i < le_white_list_.size(); i++) { + auto curr = le_white_list_[i]; + if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) { + le_resolving_list_[i] = new_tuple; + return; + } + } + le_resolving_list_.emplace_back(new_tuple); +} + +void LinkLayerController::LeSetPrivacyMode(uint8_t address_type, Address addr, + uint8_t mode) { + // set mode for addr + LOG_INFO("address type = %d ", address_type); + LOG_INFO("address = %s ", addr.ToString().c_str()); + LOG_INFO("mode = %d ", mode); +} + void LinkLayerController::LeWhiteListRemoveDevice(Address addr, uint8_t addr_type) { // TODO: Add checks to see if advertising, scanning, or a connection request // with the white list is ongoing. @@ -1332,6 +1240,18 @@ void LinkLayerController::LeWhiteListRemoveDevice(Address addr, uint8_t addr_typ } } +void LinkLayerController::LeResolvingListRemoveDevice(Address addr, + uint8_t addr_type) { + // TODO: Add checks to see if advertising, scanning, or a connection request + // with the white list is ongoing. + for (size_t i = 0; i < le_white_list_.size(); i++) { + auto curr = le_white_list_[i]; + if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) { + le_resolving_list_.erase(le_resolving_list_.begin() + i); + } + } +} + bool LinkLayerController::LeWhiteListContainsDevice(Address addr, uint8_t addr_type) { std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type); for (size_t i = 0; i < le_white_list_.size(); i++) { @@ -1342,10 +1262,25 @@ bool LinkLayerController::LeWhiteListContainsDevice(Address addr, uint8_t addr_t return false; } +bool LinkLayerController::LeResolvingListContainsDevice(Address addr, + uint8_t addr_type) { + for (size_t i = 0; i < le_white_list_.size(); i++) { + auto curr = le_white_list_[i]; + if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) { + return true; + } + } + return false; +} + bool LinkLayerController::LeWhiteListFull() { return le_white_list_.size() >= properties_.GetLeWhiteListSize(); } +bool LinkLayerController::LeResolvingListFull() { + return le_resolving_list_.size() >= properties_.GetLeResolvingListSize(); +} + void LinkLayerController::Reset() { inquiry_state_ = Inquiry::InquiryState::STANDBY; last_inquiry_ = steady_clock::now(); @@ -1375,7 +1310,7 @@ void LinkLayerController::InquiryTimeout() { } void LinkLayerController::SetInquiryMode(uint8_t mode) { - inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); + inquiry_mode_ = static_cast<Inquiry::InquiryType>(mode); } void LinkLayerController::SetInquiryLAP(uint64_t lap) { @@ -1392,10 +1327,10 @@ void LinkLayerController::Inquiry() { return; } LOG_INFO("Inquiry "); - - auto packet = model::packets::InquiryBuilder::Create( - properties_.GetAddress(), Address::kEmpty, inquiry_mode_); - SendLinkLayerPacket(std::move(packet)); + std::unique_ptr<InquiryBuilder> inquiry = InquiryBuilder::Create(inquiry_mode_); + std::shared_ptr<LinkLayerPacketBuilder> to_send = + LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry), properties_.GetAddress()); + SendLinkLayerPacket(to_send); last_inquiry_ = now; } diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h index ab7f39342..9adb71463 100644 --- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h +++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h @@ -19,12 +19,14 @@ #include "acl_connection_handler.h" #include "include/hci.h" #include "include/inquiry.h" +#include "include/link.h" #include "include/phy.h" #include "model/devices/device_properties.h" #include "model/setup/async_manager.h" #include "packets/hci/acl_packet_view.h" #include "packets/hci/sco_packet_view.h" -#include "packets/link_layer_packets.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "security_manager.h" #include "types/address.h" @@ -32,6 +34,8 @@ namespace test_vendor_lib { class LinkLayerController { public: + static constexpr size_t kIrk_size = 16; + LinkLayerController(const DeviceProperties& properties) : properties_(properties) {} hci::Status SendCommandToRemoteByAddress(hci::OpCode opcode, packets::PacketView<true> args, const Address& remote, bool use_public_address); @@ -73,7 +77,7 @@ class LinkLayerController { void DisconnectCleanup(uint16_t handle, uint8_t reason); public: - void IncomingPacket(model::packets::LinkLayerPacketView incoming); + void IncomingPacket(packets::LinkLayerPacketView incoming); void TimerTick(); @@ -89,9 +93,7 @@ class LinkLayerController { void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco); void RegisterRemoteChannel( - const std::function<void( - std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>& - send_to_remote); + const std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type)>& send_to_remote); // Set the callbacks for scheduling tasks. void RegisterTaskScheduler( @@ -118,6 +120,14 @@ class LinkLayerController { void LeWhiteListRemoveDevice(Address addr, uint8_t addr_type); bool LeWhiteListContainsDevice(Address addr, uint8_t addr_type); bool LeWhiteListFull(); + void LeResolvingListClear(); + void LeResolvingListAddDevice(Address addr, uint8_t addr_type, + std::array<uint8_t, kIrk_size> peerIrk, + std::array<uint8_t, kIrk_size> localIrk); + void LeResolvingListRemoveDevice(Address addr, uint8_t addr_type); + bool LeResolvingListContainsDevice(Address addr, uint8_t addr_type); + bool LeResolvingListFull(); + void LeSetPrivacyMode(uint8_t address_type, Address addr, uint8_t mode); hci::Status SetLeAdvertisingEnable(uint8_t le_advertising_enable) { le_advertising_enable_ = le_advertising_enable; @@ -206,46 +216,35 @@ class LinkLayerController { hci::Status WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout); protected: - void SendLeLinkLayerPacket( - std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet); - void SendLinkLayerPacket( - std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet); - void IncomingAclPacket(model::packets::LinkLayerPacketView packet); - void IncomingAclAckPacket(model::packets::LinkLayerPacketView packet); - void IncomingCommandPacket(model::packets::LinkLayerPacketView packet); - void IncomingCreateConnectionPacket( - model::packets::LinkLayerPacketView packet); - void IncomingDisconnectPacket(model::packets::LinkLayerPacketView packet); - void IncomingEncryptConnection(model::packets::LinkLayerPacketView packet); - void IncomingEncryptConnectionResponse( - model::packets::LinkLayerPacketView packet); - void IncomingInquiryPacket(model::packets::LinkLayerPacketView packet); - void IncomingInquiryResponsePacket( - model::packets::LinkLayerPacketView packet); - void IncomingIoCapabilityRequestPacket( - model::packets::LinkLayerPacketView packet); - void IncomingIoCapabilityResponsePacket( - model::packets::LinkLayerPacketView packet); - void IncomingIoCapabilityNegativeResponsePacket( - model::packets::LinkLayerPacketView packet); - void IncomingLeAdvertisementPacket( - model::packets::LinkLayerPacketView packet); - void IncomingLeConnectPacket(model::packets::LinkLayerPacketView packet); - void IncomingLeConnectCompletePacket( - model::packets::LinkLayerPacketView packet); - void IncomingLeScanPacket(model::packets::LinkLayerPacketView packet); - void IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView packet); - void IncomingPagePacket(model::packets::LinkLayerPacketView packet); - void IncomingPageRejectPacket(model::packets::LinkLayerPacketView packet); - void IncomingPageResponsePacket(model::packets::LinkLayerPacketView packet); - void IncomingResponsePacket(model::packets::LinkLayerPacketView packet); + void SendLeLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet); + void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet); + void IncomingAclPacket(packets::LinkLayerPacketView packet); + void IncomingAclAckPacket(packets::LinkLayerPacketView packet); + void IncomingCommandPacket(packets::LinkLayerPacketView packet); + void IncomingCreateConnectionPacket(packets::LinkLayerPacketView packet); + void IncomingDisconnectPacket(packets::LinkLayerPacketView packet); + void IncomingEncryptConnection(packets::LinkLayerPacketView packet); + void IncomingEncryptConnectionResponse(packets::LinkLayerPacketView packet); + void IncomingInquiryPacket(packets::LinkLayerPacketView packet); + void IncomingInquiryResponsePacket(packets::LinkLayerPacketView packet); + void IncomingIoCapabilityRequestPacket(packets::LinkLayerPacketView packet); + void IncomingIoCapabilityResponsePacket(packets::LinkLayerPacketView packet); + void IncomingIoCapabilityNegativeResponsePacket(packets::LinkLayerPacketView packet); + void IncomingLeAdvertisementPacket(packets::LinkLayerPacketView packet); + void IncomingLeConnectPacket(packets::LinkLayerPacketView packet); + void IncomingLeConnectCompletePacket(packets::LinkLayerPacketView packet); + void IncomingLeScanPacket(packets::LinkLayerPacketView packet); + void IncomingLeScanResponsePacket(packets::LinkLayerPacketView packet); + void IncomingPagePacket(packets::LinkLayerPacketView packet); + void IncomingPageRejectPacket(packets::LinkLayerPacketView packet); + void IncomingPageResponsePacket(packets::LinkLayerPacketView packet); + void IncomingResponsePacket(packets::LinkLayerPacketView packet); private: const DeviceProperties& properties_; AclConnectionHandler connections_; // Add timestamps? - std::vector<std::shared_ptr<model::packets::LinkLayerPacketBuilder>> - commands_awaiting_responses_; + std::vector<std::shared_ptr<packets::LinkLayerPacketBuilder>> commands_awaiting_responses_; // Timing related state std::vector<AsyncTaskId> controller_events_; @@ -264,14 +263,15 @@ class LinkLayerController { std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_; // Callback to send packets to remote devices. - std::function<void(std::shared_ptr<model::packets::LinkLayerPacketBuilder>, - Phy::Type phy_type)> - send_to_remote_; + std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type phy_type)> send_to_remote_; // LE state std::vector<uint8_t> le_event_mask_; std::vector<std::tuple<Address, uint8_t>> le_white_list_; + std::vector<std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>, + std::array<uint8_t, kIrk_size>>> + le_resolving_list_; uint8_t le_advertising_enable_{false}; std::chrono::steady_clock::time_point last_le_advertisement_; @@ -300,7 +300,7 @@ class LinkLayerController { SecurityManager security_manager_{10}; std::chrono::steady_clock::time_point last_inquiry_; - model::packets::InquiryType inquiry_mode_; + Inquiry::InquiryType inquiry_mode_; Inquiry::InquiryState inquiry_state_; uint64_t inquiry_lap_; uint8_t inquiry_max_responses_; diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.cc b/vendor_libs/test_vendor_lib/model/devices/beacon.cc index 9c948f91b..46f306968 100644 --- a/vendor_libs/test_vendor_lib/model/devices/beacon.cc +++ b/vendor_libs/test_vendor_lib/model/devices/beacon.cc @@ -60,15 +60,12 @@ void Beacon::Initialize(const vector<std::string>& args) { void Beacon::TimerTick() { if (IsAdvertisementAvailable(std::chrono::milliseconds(5000))) { - auto ad = model::packets::LeAdvertisementBuilder::Create( - properties_.GetLeAddress(), Address::kEmpty, - model::packets::AddressType::PUBLIC, - static_cast<model::packets::AdvertisementType>( - properties_.GetLeAdvertisementType()), + std::unique_ptr<packets::LeAdvertisementBuilder> ad = packets::LeAdvertisementBuilder::Create( + LeAdvertisement::AddressType::PUBLIC, + static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()), properties_.GetLeAdvertisement()); - std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send = - std::move(ad); - + std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = + packets::LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(ad), properties_.GetLeAddress()); std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY]; for (std::shared_ptr<PhyLayer> phy : le_phys) { phy->Send(to_send); @@ -76,17 +73,13 @@ void Beacon::TimerTick() { } } -void Beacon::IncomingPacket(model::packets::LinkLayerPacketView packet) { - if (packet.GetDestinationAddress() == properties_.GetLeAddress() && - packet.GetType() == model::packets::PacketType::LE_SCAN) { - auto scan_response = model::packets::LeAdvertisementBuilder::Create( - properties_.GetLeAddress(), packet.GetSourceAddress(), - model::packets::AddressType::PUBLIC, - model::packets::AdvertisementType::SCAN_RESPONSE, +void Beacon::IncomingPacket(packets::LinkLayerPacketView packet) { + if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) { + std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create( + LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE, properties_.GetLeScanResponse()); - std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send = - std::move(scan_response); - + std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse( + std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress()); std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY]; for (auto phy : le_phys) { phy->Send(to_send); diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.h b/vendor_libs/test_vendor_lib/model/devices/beacon.h index 87bb22861..8499ab8d3 100644 --- a/vendor_libs/test_vendor_lib/model/devices/beacon.h +++ b/vendor_libs/test_vendor_lib/model/devices/beacon.h @@ -42,8 +42,7 @@ class Beacon : public Device { // Set the address and advertising interval from string args. virtual void Initialize(const std::vector<std::string>& args) override; - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc index 9f325a477..dcf977f7e 100644 --- a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc +++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc @@ -35,8 +35,7 @@ CarKit::CarKit() : Device(kCarKitPropertiesFile) { link_layer_controller_.RegisterEventChannel([](std::shared_ptr<std::vector<uint8_t>>) {}); link_layer_controller_.RegisterScoChannel([](std::shared_ptr<std::vector<uint8_t>>) {}); link_layer_controller_.RegisterRemoteChannel( - [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, - Phy::Type phy_type) { + [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) { CarKit::SendLinkLayerPacket(packet, phy_type); }); @@ -91,7 +90,7 @@ void CarKit::TimerTick() { link_layer_controller_.TimerTick(); } -void CarKit::IncomingPacket(model::packets::LinkLayerPacketView packet) { +void CarKit::IncomingPacket(packets::LinkLayerPacketView packet) { LOG_WARN("Incoming Packet"); link_layer_controller_.IncomingPacket(packet); } diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.h b/vendor_libs/test_vendor_lib/model/devices/car_kit.h index 6822f27c4..94057ad1a 100644 --- a/vendor_libs/test_vendor_lib/model/devices/car_kit.h +++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.h @@ -45,8 +45,7 @@ class CarKit : public Device { return "car_kit"; } - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/devices/device.cc b/vendor_libs/test_vendor_lib/model/devices/device.cc index 30753d47a..cd7368c8c 100644 --- a/vendor_libs/test_vendor_lib/model/devices/device.cc +++ b/vendor_libs/test_vendor_lib/model/devices/device.cc @@ -63,16 +63,7 @@ bool Device::IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const return ((now + scan_time) >= next_interval); } -void Device::SendLinkLayerPacket( - std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send, - Phy::Type phy_type) { - for (auto phy : phy_layers_[phy_type]) { - phy->Send(to_send); - } -} - -void Device::SendLinkLayerPacket(model::packets::LinkLayerPacketView to_send, - Phy::Type phy_type) { +void Device::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type) { for (auto phy : phy_layers_[phy_type]) { phy->Send(to_send); } diff --git a/vendor_libs/test_vendor_lib/model/devices/device.h b/vendor_libs/test_vendor_lib/model/devices/device.h index 59e547eb7..277ebe13a 100644 --- a/vendor_libs/test_vendor_lib/model/devices/device.h +++ b/vendor_libs/test_vendor_lib/model/devices/device.h @@ -24,10 +24,10 @@ #include "model/devices/device_properties.h" #include "model/setup/phy_layer.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "types/address.h" -#include "packets/link_layer_packets.h" - namespace test_vendor_lib { // Represent a Bluetooth Device @@ -73,13 +73,9 @@ class Device { void UnregisterPhyLayer(Phy::Type phy_type, uint32_t factory_id); - virtual void IncomingPacket(model::packets::LinkLayerPacketView){}; + virtual void IncomingPacket(packets::LinkLayerPacketView){}; - virtual void SendLinkLayerPacket( - std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, - Phy::Type phy_type); - virtual void SendLinkLayerPacket(model::packets::LinkLayerPacketView packet, - Phy::Type phy_type); + virtual void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type); protected: std::map<Phy::Type, std::vector<std::shared_ptr<PhyLayer>>> phy_layers_; diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc index 6cb71e3a8..2a4a970fd 100644 --- a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc +++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc @@ -45,10 +45,19 @@ bool ParseUint16t(base::StringPiece value, uint16_t* field) { namespace test_vendor_lib { DeviceProperties::DeviceProperties(const std::string& file_name) - : acl_data_packet_size_(1024), sco_data_packet_size_(255), num_acl_data_packets_(10), num_sco_data_packets_(10), - version_(static_cast<uint8_t>(hci::Version::V4_1)), revision_(0), - lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)), manufacturer_name_(0), lmp_pal_subversion_(0), - le_data_packet_length_(27), num_le_data_packets_(15), le_white_list_size_(15) { + : acl_data_packet_size_(1024), + sco_data_packet_size_(255), + num_acl_data_packets_(10), + num_sco_data_packets_(10), + version_(static_cast<uint8_t>(hci::Version::V4_1)), + revision_(0), + lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)), + manufacturer_name_(0), + lmp_pal_subversion_(0), + le_data_packet_length_(27), + num_le_data_packets_(15), + le_white_list_size_(15), + le_resolving_list_size_(15) { std::string properties_raw; ASSERT(Address::FromString("BB:BB:BB:BB:BB:AD", address_)); diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.h b/vendor_libs/test_vendor_lib/model/devices/device_properties.h index 5f4fe6a94..fed710a32 100644 --- a/vendor_libs/test_vendor_lib/model/devices/device_properties.h +++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.h @@ -282,6 +282,9 @@ class DeviceProperties { return le_supported_states_; } + // Specification Version 4.2, Volume 2, Part E, Section 7.8.41 + uint8_t GetLeResolvingListSize() const { return le_resolving_list_size_; } + // Vendor-specific commands const std::vector<uint8_t>& GetLeVendorCap() const { return le_vendor_cap_; @@ -318,6 +321,7 @@ class DeviceProperties { uint16_t le_data_packet_length_; uint8_t num_le_data_packets_; uint8_t le_white_list_size_; + uint8_t le_resolving_list_size_; uint64_t le_supported_features_{0x075b3fd8fe8ffeff}; uint64_t le_supported_states_; std::vector<uint8_t> le_vendor_cap_; diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc index 1244d3ede..1daa05d0a 100644 --- a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc +++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc @@ -80,7 +80,7 @@ void Keyboard::TimerTick() { } } -void Keyboard::IncomingPacket(model::packets::LinkLayerPacketView packet) { +void Keyboard::IncomingPacket(packets::LinkLayerPacketView packet) { if (!connected_) { Beacon::IncomingPacket(packet); } diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.h b/vendor_libs/test_vendor_lib/model/devices/keyboard.h index cf00dfeff..871fa529f 100644 --- a/vendor_libs/test_vendor_lib/model/devices/keyboard.h +++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.h @@ -40,8 +40,7 @@ class Keyboard : public Beacon { // Initialize the device based on the values of |args|. virtual void Initialize(const std::vector<std::string>& args) override; - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc index ab2c5f1dc..99f0c9def 100644 --- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc +++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc @@ -18,6 +18,8 @@ #include <unistd.h> +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "packets/packet_view.h" #include "packets/view.h" @@ -30,18 +32,16 @@ LinkLayerSocketDevice::LinkLayerSocketDevice(int socket_fd, Phy::Type phy_type) void LinkLayerSocketDevice::TimerTick() { if (bytes_left_ == 0) { - size_t size_bytes = sizeof(uint32_t); - received_ = std::make_shared<std::vector<uint8_t>>(size_bytes); - size_t bytes_received = socket_.TryReceive(size_bytes, received_->data()); + received_ = std::make_shared<std::vector<uint8_t>>(Link::kSizeBytes); + size_t bytes_received = socket_.TryReceive(Link::kSizeBytes, received_->data()); if (bytes_received == 0) { return; } - ASSERT_LOG(bytes_received == size_bytes, "bytes_received == %d", - static_cast<int>(bytes_received)); - packets::PacketView<true> size({packets::View(received_, 0, size_bytes)}); + ASSERT_LOG(bytes_received == Link::kSizeBytes, "bytes_received == %d", static_cast<int>(bytes_received)); + packets::PacketView<true> size({packets::View(received_, 0, Link::kSizeBytes)}); bytes_left_ = size.begin().extract<uint32_t>(); - received_->resize(size_bytes + bytes_left_); - offset_ = size_bytes; + received_->resize(Link::kSizeBytes + bytes_left_); + offset_ = Link::kSizeBytes; } size_t bytes_received = socket_.TryReceive(bytes_left_, received_->data() + offset_); if (bytes_received == 0) { @@ -50,23 +50,14 @@ void LinkLayerSocketDevice::TimerTick() { bytes_left_ -= bytes_received; offset_ += bytes_received; if (bytes_left_ == 0) { - bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet_view( - received_); - auto packet = model::packets::LinkLayerPacketView::Create(packet_view); - ASSERT(packet.IsValid()); - SendLinkLayerPacket(packet, phy_type_); + SendLinkLayerPacket(packets::LinkLayerPacketBuilder::ReWrap(received_), phy_type_); offset_ = 0; received_.reset(); } } -void LinkLayerSocketDevice::IncomingPacket( - model::packets::LinkLayerPacketView packet) { - std::shared_ptr<std::vector<uint8_t>> payload_bytes = - std::make_shared<std::vector<uint8_t>>(packet.begin(), packet.end()); - packets::PacketView<true> packet_view(payload_bytes); - - socket_.TrySend(packet_view); +void LinkLayerSocketDevice::IncomingPacket(packets::LinkLayerPacketView packet) { + socket_.TrySend(packet); } } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h index 2b662d184..d3bbb2e54 100644 --- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h +++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h @@ -20,8 +20,9 @@ #include <vector> #include "device.h" +#include "include/link.h" #include "include/phy.h" -#include "packets/link_layer_packets.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "polled_socket.h" namespace test_vendor_lib { @@ -42,8 +43,7 @@ class LinkLayerSocketDevice : public Device { virtual void Initialize(const std::vector<std::string>&) override {} - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; @@ -53,7 +53,7 @@ class LinkLayerSocketDevice : public Device { size_t bytes_left_{0}; size_t offset_; std::shared_ptr<std::vector<uint8_t>> received_; - std::vector<model::packets::LinkLayerPacketView> packet_queue_; + std::vector<packets::LinkLayerPacketView> packet_queue_; }; } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.cc b/vendor_libs/test_vendor_lib/model/devices/loopback.cc index e0b9f35b0..18af1c10e 100644 --- a/vendor_libs/test_vendor_lib/model/devices/loopback.cc +++ b/vendor_libs/test_vendor_lib/model/devices/loopback.cc @@ -66,20 +66,15 @@ void Loopback::Initialize(const vector<std::string>& args) { void Loopback::TimerTick() {} -void Loopback::IncomingPacket(model::packets::LinkLayerPacketView packet) { +void Loopback::IncomingPacket(packets::LinkLayerPacketView packet) { LOG_INFO("Got a packet of type %d", static_cast<int>(packet.GetType())); - if (packet.GetDestinationAddress() == properties_.GetLeAddress() && - packet.GetType() == model::packets::PacketType::LE_SCAN) { + if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) { LOG_INFO("Got a scan"); - - auto scan_response = model::packets::LeAdvertisementBuilder::Create( - properties_.GetLeAddress(), packet.GetSourceAddress(), - model::packets::AddressType::PUBLIC, - model::packets::AdvertisementType::SCAN_RESPONSE, + std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create( + LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE, properties_.GetLeScanResponse()); - std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send = - std::move(scan_response); - + std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse( + std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress()); std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY]; for (auto phy : le_phys) { LOG_INFO("Sending a Scan Response on a Phy"); diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.h b/vendor_libs/test_vendor_lib/model/devices/loopback.h index dd5c06945..31dd1cdeb 100644 --- a/vendor_libs/test_vendor_lib/model/devices/loopback.h +++ b/vendor_libs/test_vendor_lib/model/devices/loopback.h @@ -42,8 +42,7 @@ class Loopback : public Device { // Set the address and advertising interval from string args. virtual void Initialize(const std::vector<std::string>& args) override; - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc index db87028e3..82cf04fdd 100644 --- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc +++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc @@ -18,14 +18,16 @@ #include "model/setup/device_boutique.h" #include "os/log.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" using std::vector; namespace test_vendor_lib { -using model::packets::LinkLayerPacketBuilder; -using model::packets::LinkLayerPacketView; -using model::packets::PageResponseBuilder; +using packets::LinkLayerPacketBuilder; +using packets::LinkLayerPacketView; +using packets::PageResponseBuilder; bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register("remote_loopback", &RemoteLoopbackDevice::Create); @@ -42,23 +44,27 @@ void RemoteLoopbackDevice::Initialize(const std::vector<std::string>& args) { if (Address::FromString(args[1], addr)) properties_.SetAddress(addr); } -void RemoteLoopbackDevice::IncomingPacket( - model::packets::LinkLayerPacketView packet) { +void RemoteLoopbackDevice::IncomingPacket(LinkLayerPacketView packet) { // TODO: Check sender? // TODO: Handle other packet types Phy::Type phy_type = Phy::Type::BR_EDR; - model::packets::PacketType type = packet.GetType(); + Link::PacketType type = packet.GetType(); switch (type) { - case model::packets::PacketType::PAGE: - SendLinkLayerPacket( - PageResponseBuilder::Create(packet.GetSourceAddress(), - packet.GetSourceAddress(), true), - Phy::Type::BR_EDR); + case Link::PacketType::PAGE: + SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPageResponse( + PageResponseBuilder::Create(true), packet.GetSourceAddress(), packet.GetSourceAddress()), + Phy::Type::BR_EDR); break; default: { LOG_WARN("Resend = %d", static_cast<int>(packet.size())); - SendLinkLayerPacket(packet, phy_type); + std::shared_ptr<std::vector<uint8_t>> extracted_packet = std::make_shared<std::vector<uint8_t>>(); + extracted_packet->reserve(packet.size()); + for (const auto byte : packet) { + extracted_packet->push_back(byte); + } + + SendLinkLayerPacket(LinkLayerPacketBuilder::ReWrap(extracted_packet), phy_type); } } } diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h index 98c9a835b..55136779c 100644 --- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h +++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h @@ -20,6 +20,7 @@ #include <vector> #include "device.h" +#include "packets/link_layer/link_layer_packet_view.h" namespace test_vendor_lib { @@ -40,8 +41,7 @@ class RemoteLoopbackDevice : public Device { virtual void Initialize(const std::vector<std::string>& args) override; - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; private: static bool registered_; diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc index c4586d19d..ba4789304 100644 --- a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc +++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc @@ -39,7 +39,7 @@ void Sniffer::Initialize(const vector<std::string>& args) { void Sniffer::TimerTick() {} -void Sniffer::IncomingPacket(model::packets::LinkLayerPacketView packet) { +void Sniffer::IncomingPacket(packets::LinkLayerPacketView packet) { Address source = packet.GetSourceAddress(); Address dest = packet.GetDestinationAddress(); bool match_source = device_to_sniff_ == source; diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.h b/vendor_libs/test_vendor_lib/model/devices/sniffer.h index 162a401cb..3e0cfef48 100644 --- a/vendor_libs/test_vendor_lib/model/devices/sniffer.h +++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.h @@ -20,7 +20,7 @@ #include <vector> #include "device.h" -#include "packets/link_layer_packets.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "types/address.h" namespace test_vendor_lib { @@ -42,8 +42,7 @@ class Sniffer : public Device { return "sniffer"; } - virtual void IncomingPacket( - model::packets::LinkLayerPacketView packet) override; + virtual void IncomingPacket(packets::LinkLayerPacketView packet) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h index 9f2bc7a38..e49c412b7 100644 --- a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h +++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h @@ -17,22 +17,19 @@ #pragma once #include "include/phy.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" -#include "packets/link_layer_packets.h" namespace test_vendor_lib { class PhyLayer { public: - PhyLayer(Phy::Type phy_type, uint32_t id, - const std::function<void(model::packets::LinkLayerPacketView)>& - device_receive) + PhyLayer(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive) : phy_type_(phy_type), id_(id), transmit_to_device_(device_receive) {} - virtual void Send( - const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) = 0; - virtual void Send(model::packets::LinkLayerPacketView packet) = 0; + virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) = 0; - virtual void Receive(model::packets::LinkLayerPacketView packet) = 0; + virtual void Receive(packets::LinkLayerPacketView packet) = 0; virtual void TimerTick() = 0; @@ -55,8 +52,7 @@ class PhyLayer { uint32_t id_; protected: - const std::function<void(model::packets::LinkLayerPacketView)> - transmit_to_device_; + const std::function<void(packets::LinkLayerPacketView)> transmit_to_device_; }; } // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc index e1da9f377..654962eda 100644 --- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc +++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc @@ -30,11 +30,9 @@ uint32_t PhyLayerFactory::GetFactoryId() { } std::shared_ptr<PhyLayer> PhyLayerFactory::GetPhyLayer( - const std::function<void(model::packets::LinkLayerPacketView)>& - device_receive) { + const std::function<void(packets::LinkLayerPacketView)>& device_receive) { std::shared_ptr<PhyLayer> new_phy = - std::make_shared<PhyLayerImpl>(phy_type_, next_id_++, device_receive, - std::shared_ptr<PhyLayerFactory>(this)); + std::make_shared<PhyLayerImpl>(phy_type_, next_id_++, device_receive, std::shared_ptr<PhyLayerFactory>(this)); phy_layers_.push_back(new_phy); return new_phy; } @@ -49,32 +47,18 @@ void PhyLayerFactory::UnregisterPhyLayer(uint32_t id) { } } -void PhyLayerFactory::Send( - const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, - uint32_t id) { +void PhyLayerFactory::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id) { // Convert from a Builder to a View - auto bytes = std::make_shared<std::vector<uint8_t>>(); - bluetooth::packet::BitInserter i(*bytes); - bytes->reserve(packet->size()); - packet->Serialize(i); - auto packet_view = - bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>(bytes); - auto link_layer_packet_view = - model::packets::LinkLayerPacketView::Create(packet_view); - ASSERT(link_layer_packet_view.IsValid()); + std::shared_ptr<std::vector<uint8_t>> serialized_packet = + std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>()); + std::back_insert_iterator<std::vector<uint8_t>> itr(*serialized_packet); + serialized_packet->reserve(packet->size()); + packet->Serialize(itr); + packets::LinkLayerPacketView packet_view = packets::LinkLayerPacketView::Create(serialized_packet); for (const auto phy : phy_layers_) { if (id != phy->GetId()) { - phy->Receive(link_layer_packet_view); - } - } -} - -void PhyLayerFactory::Send(model::packets::LinkLayerPacketView packet, - uint32_t id) { - for (const auto phy : phy_layers_) { - if (id != phy->GetId()) { - phy->Receive(packet); + phy->Receive(packet_view); } } } @@ -98,23 +82,16 @@ std::string PhyLayerFactory::ToString() const { } } -PhyLayerImpl::PhyLayerImpl( - Phy::Type phy_type, uint32_t id, - const std::function<void(model::packets::LinkLayerPacketView)>& - device_receive, - const std::shared_ptr<PhyLayerFactory>& factory) +PhyLayerImpl::PhyLayerImpl(Phy::Type phy_type, uint32_t id, + const std::function<void(packets::LinkLayerPacketView)>& device_receive, + const std::shared_ptr<PhyLayerFactory>& factory) : PhyLayer(phy_type, id, device_receive), factory_(factory) {} PhyLayerImpl::~PhyLayerImpl() { Unregister(); } -void PhyLayerImpl::Send( - const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) { - factory_->Send(packet, GetId()); -} - -void PhyLayerImpl::Send(model::packets::LinkLayerPacketView packet) { +void PhyLayerImpl::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) { factory_->Send(packet, GetId()); } @@ -126,7 +103,7 @@ bool PhyLayerImpl::IsFactoryId(uint32_t id) { return factory_->GetFactoryId() == id; } -void PhyLayerImpl::Receive(model::packets::LinkLayerPacketView packet) { +void PhyLayerImpl::Receive(packets::LinkLayerPacketView packet) { transmit_to_device_(packet); } diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h index 003236a8c..aaf14f832 100644 --- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h +++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h @@ -20,7 +20,8 @@ #include <vector> #include "include/phy.h" -#include "packets/link_layer_packets.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" #include "phy_layer.h" namespace test_vendor_lib { @@ -37,9 +38,7 @@ class PhyLayerFactory { uint32_t GetFactoryId(); - std::shared_ptr<PhyLayer> GetPhyLayer( - const std::function<void(model::packets::LinkLayerPacketView)>& - device_receive); + std::shared_ptr<PhyLayer> GetPhyLayer(const std::function<void(packets::LinkLayerPacketView)>& device_receive); void UnregisterPhyLayer(uint32_t id); @@ -48,10 +47,7 @@ class PhyLayerFactory { virtual std::string ToString() const; protected: - virtual void Send( - const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, - uint32_t id); - virtual void Send(model::packets::LinkLayerPacketView packet, uint32_t id); + virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id); private: Phy::Type phy_type_; @@ -62,17 +58,12 @@ class PhyLayerFactory { class PhyLayerImpl : public PhyLayer { public: - PhyLayerImpl(Phy::Type phy_type, uint32_t id, - const std::function<void(model::packets::LinkLayerPacketView)>& - device_receive, + PhyLayerImpl(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive, const std::shared_ptr<PhyLayerFactory>& factory); virtual ~PhyLayerImpl() override; - virtual void Send( - const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) - override; - virtual void Send(model::packets::LinkLayerPacketView packet) override; - virtual void Receive(model::packets::LinkLayerPacketView packet) override; + virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) override; + virtual void Receive(packets::LinkLayerPacketView packet) override; virtual void Unregister() override; virtual bool IsFactoryId(uint32_t factory_id) override; virtual void TimerTick() override; diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.cc b/vendor_libs/test_vendor_lib/model/setup/test_model.cc index ebd5fb94a..05500a11a 100644 --- a/vendor_libs/test_vendor_lib/model/setup/test_model.cc +++ b/vendor_libs/test_vendor_lib/model/setup/test_model.cc @@ -131,10 +131,8 @@ void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) { return; } auto dev = device->second; - dev->RegisterPhyLayer(phy->second->GetPhyLayer( - [dev](model::packets::LinkLayerPacketView packet) { - dev->IncomingPacket(packet); - })); + dev->RegisterPhyLayer( + phy->second->GetPhyLayer([dev](packets::LinkLayerPacketView packet) { dev->IncomingPacket(packet); })); } void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) { diff --git a/vendor_libs/test_vendor_lib/packets/Android.bp b/vendor_libs/test_vendor_lib/packets/Android.bp index 69a7b00a0..937849273 100644 --- a/vendor_libs/test_vendor_lib/packets/Android.bp +++ b/vendor_libs/test_vendor_lib/packets/Android.bp @@ -24,6 +24,8 @@ cc_library_static { "hci/le_meta_event_builder.cc", "hci/sco_packet_builder.cc", "hci/sco_packet_view.cc", + "link_layer/link_layer_packet_builder.cc", + "link_layer/link_layer_packet_view.cc", ], cflags: [ "-fvisibility=hidden", @@ -54,6 +56,7 @@ cc_test_host { "clang_coverage_bin", ], srcs: [ + "test/link_layer_packet_builder_test.cc", "test/packet_builder_test.cc", "test/packet_view_test.cc", "hci/test/acl_builder_test.cc", diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h new file mode 100644 index 000000000..ea3a1a2a1 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class CommandBuilder : public PacketBuilder<true> { + public: + virtual ~CommandBuilder() = default; + + static std::unique_ptr<CommandBuilder> Create(uint16_t opcode, PacketView<true> args) { + return std::unique_ptr<CommandBuilder>(new CommandBuilder(opcode, args)); + } + + virtual size_t size() const override { + return sizeof(opcode_) + args_.size(); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(opcode_, it); + for (const auto&& byte : args_) { + insert(byte, it); + } + } + + private: + explicit CommandBuilder(uint16_t opcode, PacketView<true> args) : opcode_(opcode), args_(args) {} + uint16_t opcode_; + PacketView<true> args_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h new file mode 100644 index 000000000..6e83051eb --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h @@ -0,0 +1,52 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "os/log.h" +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class CommandView : public PacketView<true> { + public: + CommandView(const CommandView&) = default; + virtual ~CommandView() = default; + + static CommandView GetCommand(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::COMMAND); + return CommandView(view.GetPayload()); + } + + uint16_t GetOpcode() { + return begin().extract<uint16_t>(); + } + + Iterator<true> GetData() { + return begin() + sizeof(uint16_t); + } + + private: + CommandView() = delete; + CommandView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h new file mode 100644 index 000000000..8083c8587 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class DisconnectBuilder : public PacketBuilder<true> { + public: + virtual ~DisconnectBuilder() = default; + + static std::unique_ptr<DisconnectBuilder> Create(uint8_t reason) { + return std::unique_ptr<DisconnectBuilder>(new DisconnectBuilder(reason)); + } + + virtual size_t size() const override { + return sizeof(reason_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + *it++ = reason_; + } + + private: + explicit DisconnectBuilder(uint8_t reason) : reason_(reason) {} + uint8_t reason_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h new file mode 100644 index 000000000..3e7251398 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class DisconnectView : public PacketView<true> { + public: + DisconnectView(const DisconnectView&) = default; + virtual ~DisconnectView() = default; + + static DisconnectView GetDisconnect(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::DISCONNECT); + return DisconnectView(view.GetPayload()); + } + + uint8_t GetReason() { + return at(0); + } + + private: + DisconnectView() = delete; + DisconnectView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h new file mode 100644 index 000000000..702d2b4b1 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class EncryptConnectionBuilder : public PacketBuilder<true> { + public: + virtual ~EncryptConnectionBuilder() = default; + + static std::unique_ptr<EncryptConnectionBuilder> Create(const std::vector<uint8_t>& key) { + return std::unique_ptr<EncryptConnectionBuilder>(new EncryptConnectionBuilder(key)); + } + + virtual size_t size() const override { + return key_.size(); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert_vector(key_, it); + } + + private: + explicit EncryptConnectionBuilder(const std::vector<uint8_t>& key) : key_(key.begin(), key.begin() + 16) {} + std::vector<uint8_t> key_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h new file mode 100644 index 000000000..22006d05f --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h @@ -0,0 +1,48 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class EncryptConnectionView : public PacketView<true> { + public: + EncryptConnectionView(const EncryptConnectionView&) = default; + virtual ~EncryptConnectionView() = default; + + static EncryptConnectionView GetEncryptConnection(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::ENCRYPT_CONNECTION || + view.GetType() == Link::PacketType::ENCRYPT_CONNECTION_RESPONSE); + return EncryptConnectionView(view.GetPayload()); + } + + Iterator<true> GetKey() { + return begin(); + } + + private: + EncryptConnectionView() = delete; + EncryptConnectionView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h new file mode 100644 index 000000000..4c60ce066 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "inquiry.h" +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class InquiryBuilder : public PacketBuilder<true> { + public: + virtual ~InquiryBuilder() = default; + + static std::unique_ptr<InquiryBuilder> Create(Inquiry::InquiryType inquiry_type) { + return std::unique_ptr<InquiryBuilder>(new InquiryBuilder(inquiry_type)); + } + + virtual size_t size() const override { + return sizeof(uint8_t); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(static_cast<uint8_t>(inquiry_type_), it); + } + + private: + explicit InquiryBuilder(Inquiry::InquiryType inquiry_type) : inquiry_type_(inquiry_type) {} + Inquiry::InquiryType inquiry_type_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h new file mode 100644 index 000000000..5db0be5fd --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h @@ -0,0 +1,106 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "include/inquiry.h" +#include "packets/packet_builder.h" +#include "types/class_of_device.h" + +namespace test_vendor_lib { +namespace packets { + +class InquiryResponseBuilder : public PacketBuilder<true> { + public: + virtual ~InquiryResponseBuilder() = default; + + static std::unique_ptr<InquiryResponseBuilder> CreateStandard(uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, + uint16_t clock_offset) { + return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder( + Inquiry::InquiryType::STANDARD, page_scan_repetition_mode, class_of_device, clock_offset)); + } + static std::unique_ptr<InquiryResponseBuilder> CreateRssi(uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, uint16_t clock_offset, + uint8_t rssi) { + return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder( + Inquiry::InquiryType::RSSI, page_scan_repetition_mode, class_of_device, clock_offset, rssi)); + } + static std::unique_ptr<InquiryResponseBuilder> CreateExtended(uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, + uint16_t clock_offset, uint8_t rssi, + const std::vector<uint8_t>& extended_data) { + return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder( + Inquiry::InquiryType::EXTENDED, page_scan_repetition_mode, class_of_device, clock_offset, rssi, extended_data)); + } + + virtual size_t size() const override { + size_t inquiry_size = + sizeof(inquiry_type_) + sizeof(page_scan_repetition_mode_) + sizeof(class_of_device_) + sizeof(clock_offset_); + if (inquiry_type_ == Inquiry::InquiryType::STANDARD) { + return inquiry_size; + } + inquiry_size += sizeof(rssi_); + if (inquiry_type_ == Inquiry::InquiryType::RSSI) { + return inquiry_size; + } + + return inquiry_size + extended_data_.size(); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(static_cast<uint8_t>(inquiry_type_), it); + insert(page_scan_repetition_mode_, it); + insert_class_of_device(class_of_device_, it); + insert(clock_offset_, it); + if (inquiry_type_ == Inquiry::InquiryType::STANDARD) { + return; + } + insert(rssi_, it); + if (inquiry_type_ == Inquiry::InquiryType::RSSI) { + return; + } + insert_vector(extended_data_, it); + } + + private: + Inquiry::InquiryType inquiry_type_; + uint8_t page_scan_repetition_mode_; + ClassOfDevice class_of_device_; + uint16_t clock_offset_; + uint8_t rssi_{0xff}; + std::vector<uint8_t> extended_data_; + explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, uint16_t clock_offset) + : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode), + class_of_device_(class_of_device), clock_offset_(clock_offset) {} + explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi) + : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode), + class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi) {} + explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode, + const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi, + const std::vector<uint8_t>& extended_data) + : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode), + class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi), extended_data_(extended_data) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h new file mode 100644 index 000000000..f963134eb --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h @@ -0,0 +1,72 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "include/inquiry.h" +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class InquiryResponseView : public PacketView<true> { + public: + InquiryResponseView(const InquiryResponseView&) = default; + virtual ~InquiryResponseView() = default; + + static InquiryResponseView GetInquiryResponse(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::INQUIRY_RESPONSE); + return InquiryResponseView(view.GetPayload()); + } + + Inquiry::InquiryType GetType() { + return static_cast<Inquiry::InquiryType>(at(0)); + } + + uint8_t GetPageScanRepetitionMode() { + return at(1); + } + + ClassOfDevice GetClassOfDevice() { + size_t offset = 2 * sizeof(uint8_t); + return (begin() + offset).extract<ClassOfDevice>(); + } + + uint16_t GetClockOffset() { + size_t offset = 2 * sizeof(uint8_t) + 3; + return (begin() + offset).extract<uint16_t>(); + } + + uint8_t GetRssi() { + size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t); + return at(offset); + } + + Iterator<true> GetExtendedData() { + size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t) + sizeof(uint8_t); + return begin() + offset; + } + + private: + InquiryResponseView() = delete; + InquiryResponseView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h new file mode 100644 index 000000000..ea8fac968 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h @@ -0,0 +1,48 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "inquiry.h" +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class InquiryView : public PacketView<true> { + public: + InquiryView(const InquiryView&) = default; + virtual ~InquiryView() = default; + + static InquiryView GetInquiry(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::INQUIRY); + return InquiryView(view.GetPayload()); + } + + Inquiry::InquiryType GetType() { + return static_cast<Inquiry::InquiryType>(at(0)); + } + + private: + InquiryView() = delete; + InquiryView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h new file mode 100644 index 000000000..16843d127 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class IoCapabilityBuilder : public PacketBuilder<true> { + public: + virtual ~IoCapabilityBuilder() = default; + + static std::unique_ptr<IoCapabilityBuilder> Create(uint8_t io_capability, uint8_t oob_data_present, + uint8_t authentication_requirements) { + return std::unique_ptr<IoCapabilityBuilder>( + new IoCapabilityBuilder(io_capability, oob_data_present, authentication_requirements)); + } + + virtual size_t size() const override { + return sizeof(io_capability_) + sizeof(oob_data_present_) + sizeof(authentication_requirements_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(io_capability_, it); + insert(oob_data_present_, it); + insert(authentication_requirements_, it); + } + + private: + explicit IoCapabilityBuilder(uint8_t io_capability, uint8_t oob_data_present, uint8_t authentication_requirements) + : io_capability_(io_capability), oob_data_present_(oob_data_present), + authentication_requirements_(authentication_requirements) {} + uint8_t io_capability_; + uint8_t oob_data_present_; + uint8_t authentication_requirements_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h new file mode 100644 index 000000000..cd8631426 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class IoCapabilityNegativeResponseBuilder : public PacketBuilder<true> { + public: + virtual ~IoCapabilityNegativeResponseBuilder() = default; + + static std::unique_ptr<IoCapabilityNegativeResponseBuilder> Create(uint8_t reason) { + return std::unique_ptr<IoCapabilityNegativeResponseBuilder>(new IoCapabilityNegativeResponseBuilder(reason)); + } + + virtual size_t size() const override { + return sizeof(reason_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(reason_, it); + } + + private: + explicit IoCapabilityNegativeResponseBuilder(uint8_t reason) : reason_(reason) {} + uint8_t reason_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h new file mode 100644 index 000000000..59978141b --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class IoCapabilityNegativeResponseView : public PacketView<true> { + public: + IoCapabilityNegativeResponseView(const IoCapabilityNegativeResponseView&) = default; + virtual ~IoCapabilityNegativeResponseView() = default; + + static IoCapabilityNegativeResponseView GetIoCapabilityNegativeResponse(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE); + return IoCapabilityNegativeResponseView(view.GetPayload()); + } + + uint8_t GetReason() { + return at(0); + } + + private: + IoCapabilityNegativeResponseView() = delete; + IoCapabilityNegativeResponseView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h new file mode 100644 index 000000000..90a162c0a --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h @@ -0,0 +1,54 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class IoCapabilityView : public PacketView<true> { + public: + IoCapabilityView(const IoCapabilityView&) = default; + virtual ~IoCapabilityView() = default; + + static IoCapabilityView GetIoCapability(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::IO_CAPABILITY_RESPONSE || + view.GetType() == Link::PacketType::IO_CAPABILITY_REQUEST); + return IoCapabilityView(view.GetPayload()); + } + + uint8_t GetIoCapability() { + return at(0); + } + uint8_t GetOobDataPresent() { + return at(1); + } + uint8_t GetAuthenticationRequirements() { + return at(2); + } + + private: + IoCapabilityView() = delete; + IoCapabilityView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h new file mode 100644 index 000000000..8c0e71bad --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h @@ -0,0 +1,60 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "include/le_advertisement.h" +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class LeAdvertisementBuilder : public PacketBuilder<true>, public LeAdvertisement { + public: + virtual ~LeAdvertisementBuilder() = default; + + static std::unique_ptr<LeAdvertisementBuilder> Create(AddressType address_type, AdvertisementType advertisement_type, + const std::vector<uint8_t>& advertisement) { + return std::unique_ptr<LeAdvertisementBuilder>( + new LeAdvertisementBuilder(address_type, advertisement_type, advertisement)); + } + + virtual size_t size() const override { + return sizeof(address_type_) + sizeof(advertisement_type_) + advertisement_.size(); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(static_cast<uint8_t>(address_type_), it); + insert(static_cast<uint8_t>(advertisement_type_), it); + insert_vector(advertisement_, it); + } + + private: + LeAdvertisementBuilder() = delete; + explicit LeAdvertisementBuilder(AddressType address_type, AdvertisementType advertisement_type, + const std::vector<uint8_t>& advertisement) + : address_type_(address_type), advertisement_type_(advertisement_type), advertisement_(advertisement) {} + AddressType address_type_; + AdvertisementType advertisement_type_; + std::vector<uint8_t> advertisement_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h new file mode 100644 index 000000000..574af2839 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "include/link.h" +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class LeAdvertisementView : public PacketView<true>, public LeAdvertisement { + public: + LeAdvertisementView(const LeAdvertisementView&) = default; + virtual ~LeAdvertisementView() = default; + + static LeAdvertisementView GetLeAdvertisementView(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::LE_ADVERTISEMENT || + view.GetType() == Link::PacketType::LE_SCAN_RESPONSE); + return LeAdvertisementView(view.GetPayload()); + } + + AddressType GetAddressType() { + return static_cast<AddressType>(at(0)); + } + AdvertisementType GetAdvertisementType() { + return static_cast<AdvertisementType>(at(1)); + } + Iterator<true> GetData() { + return begin() + 2 * sizeof(uint8_t); + } + + private: + LeAdvertisementView() = delete; + LeAdvertisementView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_builder.h new file mode 100644 index 000000000..f33fc4264 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_builder.h @@ -0,0 +1,71 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class LeConnectBuilder : public PacketBuilder<true> { + public: + virtual ~LeConnectBuilder() = default; + + static std::unique_ptr<LeConnectBuilder> Create(uint16_t le_connection_interval_min, + uint16_t le_connection_interval_max, uint16_t le_connection_latency, + uint16_t le_connection_supervision_timeout, + uint8_t peer_address_type) { + return std::unique_ptr<LeConnectBuilder>( + new LeConnectBuilder(le_connection_interval_min, le_connection_interval_max, le_connection_latency, + le_connection_supervision_timeout, peer_address_type)); + } + + virtual size_t size() const override { + return sizeof(le_connection_interval_min_) + sizeof(le_connection_interval_max_) + sizeof(le_connection_latency_) + + sizeof(le_connection_supervision_timeout_) + sizeof(peer_address_type_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(le_connection_interval_min_, it); + insert(le_connection_interval_max_, it); + insert(le_connection_latency_, it); + insert(le_connection_supervision_timeout_, it); + insert(peer_address_type_, it); + } + + private: + explicit LeConnectBuilder(uint16_t le_connection_interval_min, uint16_t le_connection_interval_max, + uint16_t le_connection_latency, uint16_t le_connection_supervision_timeout, + uint8_t peer_address_type) + : le_connection_interval_min_(le_connection_interval_min), + le_connection_interval_max_(le_connection_interval_max), le_connection_latency_(le_connection_latency), + le_connection_supervision_timeout_(le_connection_supervision_timeout), peer_address_type_(peer_address_type) + + {} + uint16_t le_connection_interval_min_; + uint16_t le_connection_interval_max_; + uint16_t le_connection_latency_; + uint16_t le_connection_supervision_timeout_; + uint8_t peer_address_type_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_builder.h new file mode 100644 index 000000000..379c3d444 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_builder.h @@ -0,0 +1,66 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class LeConnectCompleteBuilder : public PacketBuilder<true> { + public: + virtual ~LeConnectCompleteBuilder() = default; + + static std::unique_ptr<LeConnectCompleteBuilder> Create(uint16_t le_connection_interval, + uint16_t le_connection_latency, + uint16_t le_connection_supervision_timeout, + uint8_t peer_address_type) { + return std::unique_ptr<LeConnectCompleteBuilder>(new LeConnectCompleteBuilder( + le_connection_interval, le_connection_latency, le_connection_supervision_timeout, peer_address_type)); + } + + virtual size_t size() const override { + return sizeof(le_connection_interval_) + sizeof(le_connection_latency_) + + sizeof(le_connection_supervision_timeout_) + sizeof(peer_address_type_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(le_connection_interval_, it); + insert(le_connection_latency_, it); + insert(le_connection_supervision_timeout_, it); + insert(peer_address_type_, it); + } + + private: + explicit LeConnectCompleteBuilder(uint16_t le_connection_interval, uint16_t le_connection_latency, + uint16_t le_connection_supervision_timeout, uint8_t peer_address_type) + : le_connection_interval_(le_connection_interval), le_connection_latency_(le_connection_latency), + le_connection_supervision_timeout_(le_connection_supervision_timeout), peer_address_type_(peer_address_type) + + {} + uint16_t le_connection_interval_; + uint16_t le_connection_latency_; + uint16_t le_connection_supervision_timeout_; + uint8_t peer_address_type_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_view.h new file mode 100644 index 000000000..88f5075cc --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_complete_view.h @@ -0,0 +1,59 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class LeConnectCompleteView : public PacketView<true> { + public: + LeConnectCompleteView(const LeConnectCompleteView&) = default; + virtual ~LeConnectCompleteView() = default; + + static LeConnectCompleteView GetLeConnectComplete(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::LE_CONNECT_COMPLETE); + return LeConnectCompleteView(view.GetPayload()); + } + + uint16_t GetLeConnectionInterval() { + return begin().extract<uint16_t>(); + } + + uint16_t GetLeConnectionLatency() { + return (begin() + 2).extract<uint16_t>(); + } + + uint16_t GetLeConnectionSupervisionTimeout() { + return (begin() + 4).extract<uint16_t>(); + } + + uint8_t GetAddressType() { + return (begin() + 6).extract<uint8_t>(); + } + + private: + LeConnectCompleteView() = delete; + LeConnectCompleteView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_view.h new file mode 100644 index 000000000..3fca36e99 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/le_connect_view.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class LeConnectView : public PacketView<true> { + public: + LeConnectView(const LeConnectView&) = default; + virtual ~LeConnectView() = default; + + static LeConnectView GetLeConnect(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::LE_CONNECT); + return LeConnectView(view.GetPayload()); + } + + uint16_t GetLeConnectionIntervalMin() { + return begin().extract<uint16_t>(); + } + + uint16_t GetLeConnectionIntervalMax() { + return (begin() + 2).extract<uint16_t>(); + } + + uint16_t GetLeConnectionLatency() { + return (begin() + 4).extract<uint16_t>(); + } + + uint16_t GetLeConnectionSupervisionTimeout() { + return (begin() + 6).extract<uint16_t>(); + } + + uint8_t GetAddressType() { + return (begin() + 8).extract<uint8_t>(); + } + + private: + LeConnectView() = delete; + LeConnectView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc new file mode 100644 index 000000000..816e44411 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc @@ -0,0 +1,187 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "link_layer_packet_builder.h" +#include "link_layer_packet_view.h" + +using std::vector; + +namespace test_vendor_lib { + +namespace packets { + +LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest) + : type_(type), source_addr_(source), dest_addr_(dest) {} + +LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet, + const Address& source) + : type_(type), source_addr_(source), dest_addr_(Address::kEmpty), builder_(std::move(packet)) {} + +LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet, + const Address& source, const Address& dest) + : type_(type), source_addr_(source), dest_addr_(dest), builder_(std::move(packet)) {} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl, + const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::ACL, std::move(acl), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapCommand(std::unique_ptr<CommandBuilder> command, + const Address& source, + const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::COMMAND, std::move(command), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapDisconnect( + std::unique_ptr<DisconnectBuilder> disconnect, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::DISCONNECT, std::move(disconnect), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnection( + std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::ENCRYPT_CONNECTION, std::move(encrypt_connection), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnectionResponse( + std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder( + Link::PacketType::ENCRYPT_CONNECTION_RESPONSE, std::move(encrypt_connection), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry, + const Address& source) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::INQUIRY, std::move(inquiry), source)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiryResponse( + std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::INQUIRY_RESPONSE, std::move(inquiry_response), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityRequest( + std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_REQUEST, std::move(io_capability), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityResponse( + std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_RESPONSE, std::move(io_capability), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse( + std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source, + const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder( + Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE, std::move(io_capability_negative_response), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeAdvertisement( + std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::LE_ADVERTISEMENT, std::move(advertisement), source)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeConnect(std::unique_ptr<LeConnectBuilder> connect, + const Address& source, + const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::LE_CONNECT, std::move(connect), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeConnectComplete( + std::unique_ptr<LeConnectCompleteBuilder> connect_complete, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::LE_CONNECT_COMPLETE, std::move(connect_complete), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScan(const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN, source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScanResponse( + std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN_RESPONSE, std ::move(scan_response), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPage(std::unique_ptr<PageBuilder> page, + const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::PAGE, std::move(page), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageReject( + std::unique_ptr<PageRejectBuilder> page_reject, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::PAGE_REJECT, std::move(page_reject), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageResponse( + std::unique_ptr<PageResponseBuilder> page_response, const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::PAGE_RESPONSE, std::move(page_response), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapResponse(std::unique_ptr<ResponseBuilder> response, + const Address& source, + const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::RESPONSE, std::move(response), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapSco(std::unique_ptr<ViewForwarderBuilder> sco, + const Address& source, const Address& dest) { + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(Link::PacketType::SCO, std::move(sco), source, dest)); +} + +std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::ReWrap( + const std::shared_ptr<std::vector<uint8_t>> raw_packet) { + LinkLayerPacketView received = LinkLayerPacketView::Create(raw_packet); + Link::PacketType packet_type = received.GetType(); + Address source = received.GetSourceAddress(); + Address dest = received.GetDestinationAddress(); + PacketView<true> payload = received.GetPayload(); + std::unique_ptr<PacketBuilder> builder = ViewForwarderBuilder::Create(payload); + return std::shared_ptr<LinkLayerPacketBuilder>( + new LinkLayerPacketBuilder(packet_type, std::move(builder), source, dest)); +} + +size_t LinkLayerPacketBuilder::size() const { + size_t builder_size = (builder_ ? builder_->size() : 0); + return Link::kTypeBytes + Link::kSizeBytes + 2 * Address::kLength + builder_size; +} + +void LinkLayerPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const { + insert(static_cast<uint32_t>(size() - Link::kSizeBytes), it); + insert(static_cast<uint8_t>(type_), it); + insert_address(source_addr_.address, it); + insert_address(dest_addr_.address, it); + if (builder_) { + builder_->Serialize(it); + } +} + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h new file mode 100644 index 000000000..310115512 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h @@ -0,0 +1,110 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <string> +#include <vector> + +#include "link.h" +#include "packets/link_layer/command_builder.h" +#include "packets/link_layer/disconnect_builder.h" +#include "packets/link_layer/encrypt_connection_builder.h" +#include "packets/link_layer/inquiry_builder.h" +#include "packets/link_layer/inquiry_response_builder.h" +#include "packets/link_layer/io_capability_builder.h" +#include "packets/link_layer/io_capability_negative_response_builder.h" +#include "packets/link_layer/le_advertisement_builder.h" +#include "packets/link_layer/le_connect_builder.h" +#include "packets/link_layer/le_connect_complete_builder.h" +#include "packets/link_layer/page_builder.h" +#include "packets/link_layer/page_reject_builder.h" +#include "packets/link_layer/page_response_builder.h" +#include "packets/link_layer/response_builder.h" +#include "packets/link_layer/view_forwarder_builder.h" +#include "packets/packet_builder.h" +#include "types/address.h" + +namespace test_vendor_lib { +namespace packets { + +// Link-layer packets are an abstraction of LMP PDUs. +class LinkLayerPacketBuilder : PacketBuilder<true> { + public: + virtual ~LinkLayerPacketBuilder() = default; + + static std::shared_ptr<LinkLayerPacketBuilder> WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapCommand(std::unique_ptr<CommandBuilder> command, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapDisconnect(std::unique_ptr<DisconnectBuilder> disconnect, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnection( + std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnectionResponse( + std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry, + const Address& source); + static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiryResponse( + std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityRequest( + std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityResponse( + std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityNegativeResponse( + std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source, + const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapLeAdvertisement( + std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source); + static std::shared_ptr<LinkLayerPacketBuilder> WrapLeConnect(std::unique_ptr<LeConnectBuilder> connect, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapLeConnectComplete( + std::unique_ptr<LeConnectCompleteBuilder> connect_complete, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScan(const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScanResponse( + std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapPage(std::unique_ptr<PageBuilder> page, const Address& source, + const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapPageReject(std::unique_ptr<PageRejectBuilder> page_response, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapPageResponse(std::unique_ptr<PageResponseBuilder> page_response, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapResponse(const std::unique_ptr<ResponseBuilder> response, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> WrapSco(std::unique_ptr<ViewForwarderBuilder> sco, + const Address& source, const Address& dest); + static std::shared_ptr<LinkLayerPacketBuilder> ReWrap(const std::shared_ptr<std::vector<uint8_t>> raw_packet); + + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override; + + virtual size_t size() const override; + + private: + LinkLayerPacketBuilder(const LinkLayerPacketBuilder&) = delete; + LinkLayerPacketBuilder() = delete; + LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest); + LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source, + const Address& dest); + LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source); + Link::PacketType type_; + Address source_addr_; + Address dest_addr_; + std::unique_ptr<PacketBuilder> builder_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc new file mode 100644 index 000000000..31cbdbfc7 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc @@ -0,0 +1,52 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "link_layer_packet_view.h" + +#include "os/log.h" + +namespace test_vendor_lib { +constexpr size_t Link::kSizeBytes; +constexpr size_t Link::kTypeBytes; + +namespace packets { +LinkLayerPacketView::LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw) : PacketView<true>(raw) {} + +LinkLayerPacketView LinkLayerPacketView::Create(std::shared_ptr<std::vector<uint8_t>> raw) { + ASSERT(raw->size() >= Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength); + return LinkLayerPacketView(raw); +} + +Link::PacketType LinkLayerPacketView::GetType() const { + return static_cast<Link::PacketType>(at(Link::kSizeBytes)); +} + +Address LinkLayerPacketView::GetSourceAddress() const { + size_t offset = Link::kSizeBytes + Link::kTypeBytes; + return (begin() + offset).extract<Address>(); +} + +Address LinkLayerPacketView::GetDestinationAddress() const { + size_t offset = Link::kSizeBytes + Link::kTypeBytes + Address::kLength; + return (begin() + offset).extract<Address>(); +} + +PacketView<true> LinkLayerPacketView::GetPayload() const { + return SubViewLittleEndian(Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength, size()); +} + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h new file mode 100644 index 000000000..bdbfaa705 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <string> +#include <vector> + +#include "include/link.h" +#include "packets/packet_view.h" +#include "types/address.h" + +namespace test_vendor_lib { +namespace packets { + +// Link-layer packets are an abstraction of LMP PDUs. +class LinkLayerPacketView : public PacketView<true> { + public: + LinkLayerPacketView(const LinkLayerPacketView&) = default; + virtual ~LinkLayerPacketView() = default; + + static LinkLayerPacketView Create(std::shared_ptr<std::vector<uint8_t>> raw); + + Link::PacketType GetType() const; + Address GetSourceAddress() const; + Address GetDestinationAddress() const; + PacketView<true> GetPayload() const; + + private: + LinkLayerPacketView() = delete; + LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw); +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h new file mode 100644 index 000000000..9b219d702 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h @@ -0,0 +1,54 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" +#include "types/class_of_device.h" + +namespace test_vendor_lib { +namespace packets { + +class PageBuilder : public PacketBuilder<true> { + public: + virtual ~PageBuilder() = default; + + static std::unique_ptr<PageBuilder> Create(const ClassOfDevice& class_of_device, uint8_t allow_role_switch) { + return std::unique_ptr<PageBuilder>(new PageBuilder(class_of_device, allow_role_switch)); + } + + virtual size_t size() const override { + return sizeof(class_of_device_) + sizeof(allow_role_switch_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert_class_of_device(class_of_device_, it); + insert(allow_role_switch_, it); + } + + private: + explicit PageBuilder(const ClassOfDevice& class_of_device, uint8_t allow_role_switch) + : class_of_device_(class_of_device), allow_role_switch_(allow_role_switch) {} + ClassOfDevice class_of_device_; + uint8_t allow_role_switch_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h new file mode 100644 index 000000000..ebf84d248 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class PageRejectBuilder : public PacketBuilder<true> { + public: + virtual ~PageRejectBuilder() = default; + + static std::unique_ptr<PageRejectBuilder> Create(uint8_t reason) { + return std::unique_ptr<PageRejectBuilder>(new PageRejectBuilder(reason)); + } + + virtual size_t size() const override { + return sizeof(reason_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(reason_, it); + } + + private: + explicit PageRejectBuilder(uint8_t reason) : reason_(reason) {} + uint8_t reason_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h new file mode 100644 index 000000000..0c7611cfa --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class PageRejectView : public PacketView<true> { + public: + PageRejectView(const PageRejectView&) = default; + virtual ~PageRejectView() = default; + + static PageRejectView GetPageReject(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::PAGE_REJECT); + return PageRejectView(view.GetPayload()); + } + + uint8_t GetReason() { + return at(0); + } + + private: + PageRejectView() = delete; + PageRejectView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h new file mode 100644 index 000000000..da7c85374 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class PageResponseBuilder : public PacketBuilder<true> { + public: + virtual ~PageResponseBuilder() = default; + + static std::unique_ptr<PageResponseBuilder> Create(uint8_t try_role_switch) { + return std::unique_ptr<PageResponseBuilder>(new PageResponseBuilder(try_role_switch)); + } + + virtual size_t size() const override { + return sizeof(try_role_switch_); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(try_role_switch_, it); + } + + private: + explicit PageResponseBuilder(uint8_t try_role_switch) : try_role_switch_(try_role_switch) {} + uint8_t try_role_switch_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h new file mode 100644 index 000000000..151052815 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class PageResponseView : public PacketView<true> { + public: + PageResponseView(const PageResponseView&) = default; + virtual ~PageResponseView() = default; + + static PageResponseView GetPageResponse(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::PAGE_RESPONSE); + return PageResponseView(view.GetPayload()); + } + + uint8_t GetTryRoleSwitch() { + return at(0); + } + + private: + PageResponseView() = delete; + PageResponseView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h new file mode 100644 index 000000000..7f54b8904 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class PageView : public PacketView<true> { + public: + PageView(const PageView&) = default; + virtual ~PageView() = default; + + static PageView GetPage(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::PAGE); + return PageView(view.GetPayload()); + } + + ClassOfDevice GetClassOfDevice() { + return begin().extract<ClassOfDevice>(); + } + + uint8_t GetAllowRoleSwitch() { + return at(3); + } + + private: + PageView() = delete; + PageView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h new file mode 100644 index 000000000..18f765dfc --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h @@ -0,0 +1,53 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> +#include <vector> + +#include "packets/packet_builder.h" + +namespace test_vendor_lib { +namespace packets { + +class ResponseBuilder : public PacketBuilder<true> { + public: + virtual ~ResponseBuilder() = default; + + static std::unique_ptr<ResponseBuilder> Create(uint16_t opcode, const std::vector<uint64_t>& data) { + return std::unique_ptr<ResponseBuilder>(new ResponseBuilder(opcode, data)); + } + + virtual size_t size() const override { + return sizeof(opcode_) + data_.size() * sizeof(uint64_t); + } + + protected: + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + insert(opcode_, it); + insert_vector(data_, it); + } + + private: + explicit ResponseBuilder(uint16_t opcode, const std::vector<uint64_t> data) : opcode_(opcode), data_(data) {} + uint16_t opcode_; + std::vector<uint64_t> data_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h new file mode 100644 index 000000000..60316a80b --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> + +#include "packets/link_layer/link_layer_packet_view.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class ResponseView : public PacketView<true> { + public: + ResponseView(const ResponseView&) = default; + virtual ~ResponseView() = default; + + static ResponseView GetResponse(const LinkLayerPacketView& view) { + ASSERT(view.GetType() == Link::PacketType::RESPONSE); + return ResponseView(view.GetPayload()); + } + + uint16_t GetOpcode() { + return begin().extract<uint16_t>(); + } + + Iterator<true> GetResponseData() { + return begin() + sizeof(uint16_t); + } + + private: + ResponseView() = delete; + ResponseView(const PacketView<true>& view) : PacketView(view) {} +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h new file mode 100644 index 000000000..81f7b5b82 --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h @@ -0,0 +1,52 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstdint> +#include <memory> + +#include "packets/packet_builder.h" +#include "packets/packet_view.h" + +namespace test_vendor_lib { +namespace packets { + +class ViewForwarderBuilder : public PacketBuilder<true> { + public: + virtual ~ViewForwarderBuilder() = default; + + static std::unique_ptr<ViewForwarderBuilder> Create(PacketView<true> view) { + return std::unique_ptr<ViewForwarderBuilder>(new ViewForwarderBuilder(view)); + } + + virtual size_t size() const override { + return view_.size(); + } + + virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override { + for (size_t i = 0; i < view_.size(); i++) { + insert(view_[i], it); + } + } + + private: + explicit ViewForwarderBuilder(PacketView<true> view) : view_(view) {} + PacketView<true> view_; +}; + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl deleted file mode 100644 index 0194ab3e3..000000000 --- a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl +++ /dev/null @@ -1,171 +0,0 @@ -little_endian_packets - -custom_field Address : 48 "types/" -custom_field ClassOfDevice : 24 "types/" - -enum PacketType : 8 { - UNKNOWN = 0x00, - ACL = 0x01, - COMMAND = 0x02, - DISCONNECT = 0x03, - ENCRYPT_CONNECTION = 0x04, - ENCRYPT_CONNECTION_RESPONSE = 0x05, - EVENT = 0x06, - INQUIRY = 0x07, - INQUIRY_RESPONSE = 0x08, - IO_CAPABILITY_REQUEST = 0x09, - IO_CAPABILITY_RESPONSE = 0x0A, - IO_CAPABILITY_NEGATIVE_RESPONSE = 0x0B, - LE_ADVERTISEMENT = 0x0C, - LE_CONNECT = 0x0D, - LE_CONNECT_COMPLETE = 0x0E, - LE_SCAN = 0x0F, - LE_SCAN_RESPONSE = 0x10, - PAGE = 0x11, - PAGE_RESPONSE = 0x12, - PAGE_REJECT = 0x13, - RESPONSE = 0x14, - SCO = 0x15, -} - -packet LinkLayerPacket { - type : PacketType, - source_address : Address, - destination_address : Address, - _body_, -} - -packet AclPacket : LinkLayerPacket (type = ACL) { - _payload_, -} - -packet Command : LinkLayerPacket (type = COMMAND) { - _payload_, -} - -packet Disconnect : LinkLayerPacket (type = DISCONNECT) { - reason : 8, -} - -packet EncryptConnection : LinkLayerPacket (type = ENCRYPT_CONNECTION) { - key : 8[], -} - -packet EncryptConnectionResponse : LinkLayerPacket (type = ENCRYPT_CONNECTION_RESPONSE) { - key : 8[], -} - -enum InquiryState : 8 { - STANDBY = 0x00, - INQUIRY = 0x01, -} - -enum InquiryType : 8 { - STANDARD = 0x00, - RSSI = 0x01, - EXTENDED = 0x02, -} - -packet Inquiry : LinkLayerPacket (type = INQUIRY) { - inquiry_type : InquiryType, -} - -packet BasicInquiryResponse : LinkLayerPacket(type = INQUIRY_RESPONSE) { - inquiry_type : InquiryType, - page_scan_repetition_mode : 8, - class_of_device : ClassOfDevice, - clock_offset : 15, - _reserved_ : 1, - _body_, -} - -packet InquiryResponse : BasicInquiryResponse (inquiry_type = STANDARD) { -} - -packet InquiryResponseWithRssi : BasicInquiryResponse (inquiry_type = RSSI) { - rssi: 8, -} - -packet ExtendedInquiryResponse : BasicInquiryResponse (inquiry_type = EXTENDED) { - rssi: 8, - extended_data : 8[], -} - -packet IoCapabilityRequest : LinkLayerPacket (type = IO_CAPABILITY_REQUEST) { - io_capability : 8, - oob_data_present : 8, - authentication_requirements : 8, -} - -packet IoCapabilityResponse : LinkLayerPacket (type = IO_CAPABILITY_RESPONSE) { - io_capability : 8, - oob_data_present : 8, - authentication_requirements : 8, -} - -packet IoCapabilityNegativeResponse : LinkLayerPacket (type = IO_CAPABILITY_NEGATIVE_RESPONSE) { - reason : 8, -} - -enum AddressType : 8 { - PUBLIC = 0, - RANDOM = 1, - PUBLIC_IDENTITY = 2, - RANDOM_IDENTITY = 3, -} - -enum AdvertisementType : 8 { - ADV_IND = 0, // Connectable and scannable - ADV_DIRECT_IND = 1, // Connectable directed - ADV_SCAN_IND = 2, // Scannable undirected - ADV_NONCONN_IND = 3, // Non connectable undirected - SCAN_RESPONSE = 4, -} - -packet LeAdvertisement : LinkLayerPacket (type = LE_ADVERTISEMENT) { - address_type : AddressType, - advertisement_type : AdvertisementType, - data : 8[], -} - -packet LeConnect : LinkLayerPacket (type = LE_CONNECT) { - le_connection_interval_min : 16, - le_connection_interval_max : 16, - le_connection_latency : 16, - le_connection_supervision_timeout : 16, - address_type : 8, -} - -packet LeConnectComplete : LinkLayerPacket (type = LE_CONNECT_COMPLETE) { - le_connection_interval : 16, - le_connection_latency : 16, - le_connection_supervision_timeout : 16, - address_type : 8, -} - -packet LeScan : LinkLayerPacket (type = LE_SCAN) { -} - -packet LeScanResponse : LinkLayerPacket (type = LE_SCAN_RESPONSE) { - address_type : AddressType, - advertisement_type : AdvertisementType, - data : 8[], -} - -packet Page : LinkLayerPacket (type = PAGE) { - class_of_device : ClassOfDevice, - allow_role_switch : 8, -} - -packet PageResponse : LinkLayerPacket (type = PAGE_RESPONSE) { - try_role_switch : 8, -} - -packet PageReject : LinkLayerPacket (type = PAGE_REJECT) { - reason : 8, -} - -packet Response : LinkLayerPacket (type = RESPONSE) { - opcode : 16, - _payload_, -} diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.h b/vendor_libs/test_vendor_lib/packets/packet_view.h index 22c530ad6..16255faaa 100644 --- a/vendor_libs/test_vendor_lib/packets/packet_view.h +++ b/vendor_libs/test_vendor_lib/packets/packet_view.h @@ -32,7 +32,6 @@ template <bool little_endian> class PacketView { public: PacketView(const std::forward_list<class View> fragments); - PacketView(std::shared_ptr<std::vector<uint8_t>> packet); PacketView(const PacketView& PacketView) = default; virtual ~PacketView() = default; @@ -50,6 +49,9 @@ class PacketView { PacketView<false> SubViewBigEndian(size_t begin, size_t end) const; + protected: + PacketView(std::shared_ptr<std::vector<uint8_t>> packet); + private: std::forward_list<View> fragments_; size_t length_; diff --git a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc new file mode 100644 index 000000000..3a141422c --- /dev/null +++ b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc @@ -0,0 +1,512 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "packets/link_layer/link_layer_packet_builder.h" + +#include <gtest/gtest.h> +#include <forward_list> +#include <memory> + +#include "link.h" +#include "packets/link_layer/command_view.h" +#include "packets/link_layer/disconnect_view.h" +#include "packets/link_layer/encrypt_connection_view.h" +#include "packets/link_layer/inquiry_response_view.h" +#include "packets/link_layer/inquiry_view.h" +#include "packets/link_layer/io_capability_negative_response_view.h" +#include "packets/link_layer/io_capability_view.h" +#include "packets/link_layer/le_advertisement_view.h" +#include "packets/link_layer/page_response_view.h" +#include "packets/link_layer/page_view.h" +#include "packets/link_layer/response_view.h" + +using std::vector; + +namespace { +vector<uint8_t> count = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, +}; + +} // namespace + +namespace test_vendor_lib { +namespace packets { + +class LinkLayerPacketBuilderTest : public ::testing::Test { + public: + LinkLayerPacketBuilderTest() = default; + ~LinkLayerPacketBuilderTest() override = default; + + Address source_{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}; + Address dest_{{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}}; +}; + +TEST_F(LinkLayerPacketBuilderTest, constructorTest) { + uint8_t reason = 0xf2; + auto disconnect = DisconnectBuilder::Create(reason); + ASSERT_EQ(disconnect->size(), sizeof(reason)); + auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect), source_, dest_); + + size_t wrapped_size = sizeof(uint8_t) + sizeof(uint32_t) + 2 * sizeof(Address) + sizeof(reason); + ASSERT_EQ(wrapped_disconnect->size(), wrapped_size); + std::vector<uint8_t> wrapped_vect; + std::back_insert_iterator<std::vector<uint8_t>> it(wrapped_vect); + wrapped_disconnect->Serialize(it); + ASSERT_EQ(wrapped_size, wrapped_vect.size()); + + std::vector<uint8_t> hand_wrapped_vect; + // Add the size + hand_wrapped_vect.push_back(sizeof(uint8_t) + 2 * sizeof(Address) + sizeof(reason)); + hand_wrapped_vect.push_back(0); + hand_wrapped_vect.push_back(0); + hand_wrapped_vect.push_back(0); + + hand_wrapped_vect.push_back(static_cast<uint8_t>(Link::PacketType::DISCONNECT)); + + for (auto byte : source_.address) { + hand_wrapped_vect.push_back(byte); + } + for (auto byte : dest_.address) { + hand_wrapped_vect.push_back(byte); + } + hand_wrapped_vect.push_back(reason); + ASSERT_EQ(wrapped_vect, hand_wrapped_vect); +} + +TEST_F(LinkLayerPacketBuilderTest, disconnectTest) { + uint8_t reason = 0x32; + auto disconnect_builder = DisconnectBuilder::Create(reason); + auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_disconnect->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_disconnect->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::DISCONNECT); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + DisconnectView disconnect = DisconnectView::GetDisconnect(view); + ASSERT_EQ(disconnect.GetReason(), reason); +} + +TEST_F(LinkLayerPacketBuilderTest, encryptConnectionTest) { + std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key); + auto wrapped_encrypt_connection = + LinkLayerPacketBuilder::WrapEncryptConnection(std::move(encrypt_connection_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_encrypt_connection->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_encrypt_connection->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view); + auto key_itr = encrypt_connection.GetKey(); + ASSERT_EQ(key_itr.NumBytesRemaining(), key.size()); + for (size_t i = 0; i < key.size(); i++) { + ASSERT_EQ(key[i], key_itr.extract<uint8_t>()); + } +} + +TEST_F(LinkLayerPacketBuilderTest, encryptConnectionResponseTest) { + std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key); + auto wrapped_encrypt_connection_response = + LinkLayerPacketBuilder::WrapEncryptConnectionResponse(std::move(encrypt_connection_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_encrypt_connection_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_encrypt_connection_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view); + auto key_itr = encrypt_connection.GetKey(); + ASSERT_EQ(key_itr.NumBytesRemaining(), key.size()); + for (size_t i = 0; i < key.size(); i++) { + ASSERT_EQ(key[i], key_itr.extract<uint8_t>()); + } +} + +TEST_F(LinkLayerPacketBuilderTest, inquiryTest) { + Inquiry::InquiryType inquiry_type = Inquiry::InquiryType::RSSI; + auto inquiry_builder = InquiryBuilder::Create(inquiry_type); + auto wrapped_inquiry = LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry_builder), source_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_inquiry->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_inquiry->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress()); + ASSERT_EQ(InquiryView::GetInquiry(view).GetType(), inquiry_type); +} + +TEST_F(LinkLayerPacketBuilderTest, standardInquiryResponseTest) { + uint8_t mode = 23; + ClassOfDevice class_of_device{{0x11, 0x22, 0x33}}; + uint16_t offset = 0x3456; + auto inquiry_response_builder = InquiryResponseBuilder::CreateStandard(mode, class_of_device, offset); + auto wrapped_inquiry = + LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_inquiry->Serialize(it); + ASSERT_EQ(packet_ptr->size(), 24u); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_inquiry->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + ASSERT_EQ(view.GetPayload().size(), 7u); + InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); + ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::STANDARD); + ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode); + ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); +} + +TEST_F(LinkLayerPacketBuilderTest, rssiInquiryResponseTest) { + uint8_t mode = 23; + ClassOfDevice class_of_device{{0x11, 0x22, 0x33}}; + uint16_t offset = 0x3456; + uint8_t rssi = 0x78; + auto inquiry_response_builder = InquiryResponseBuilder::CreateRssi(mode, class_of_device, offset, rssi); + auto wrapped_inquiry = + LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_inquiry->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_inquiry->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); + ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::RSSI); + ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode); + ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); + ASSERT_EQ(inquiry_response.GetRssi(), rssi); +} + +TEST_F(LinkLayerPacketBuilderTest, extendedInquiryResponseTest) { + uint8_t mode = 23; + ClassOfDevice class_of_device{{0x11, 0x22, 0x33}}; + uint16_t offset = 0x3456; + uint8_t rssi = 0x78; + auto inquiry_response_builder = InquiryResponseBuilder::CreateExtended(mode, class_of_device, offset, rssi, count); + auto wrapped_inquiry = + LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_inquiry->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_inquiry->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); + ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::EXTENDED); + ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode); + ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device); + ASSERT_EQ(inquiry_response.GetClockOffset(), offset); + ASSERT_EQ(inquiry_response.GetRssi(), rssi); + auto ext_it = inquiry_response.GetExtendedData(); + ASSERT_EQ(ext_it.NumBytesRemaining(), count.size()); + for (size_t i = 0; i < count.size(); i++) { + ASSERT_EQ(count[i], *(ext_it++)); + } +} + +TEST_F(LinkLayerPacketBuilderTest, ioCapabilityRequestTest) { + uint8_t io_cap = 0x2; + uint8_t oob_data_present = 0x1; + uint8_t authentication_requirements = 0x5; + auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements); + auto wrapped_io_capability_request = + LinkLayerPacketBuilder::WrapIoCapabilityRequest(std::move(io_capability_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_io_capability_request->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_io_capability_request->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_REQUEST); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view); + ASSERT_EQ(io_capability.GetIoCapability(), io_cap); + ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present); + ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements); +} + +TEST_F(LinkLayerPacketBuilderTest, ioCapabilityResponseTest) { + uint8_t io_cap = 0x2; + uint8_t oob_data_present = 0x1; + uint8_t authentication_requirements = 0x5; + auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements); + auto wrapped_io_capability_response = + LinkLayerPacketBuilder::WrapIoCapabilityResponse(std::move(io_capability_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_io_capability_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_io_capability_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view); + ASSERT_EQ(io_capability.GetIoCapability(), io_cap); + ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present); + ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements); +} + +TEST_F(LinkLayerPacketBuilderTest, ioCapabilityNegativeResponseTest) { + uint8_t reason = 23; + auto io_capability_negative_response_builder = IoCapabilityNegativeResponseBuilder::Create(reason); + auto wrapped_io_capability_negative_response = LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse( + std::move(io_capability_negative_response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_io_capability_negative_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_io_capability_negative_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + IoCapabilityNegativeResponseView io_capability_negative_response = + IoCapabilityNegativeResponseView::GetIoCapabilityNegativeResponse(view); + ASSERT_EQ(io_capability_negative_response.GetReason(), reason); +} + +TEST_F(LinkLayerPacketBuilderTest, pageTest) { + uint8_t allow_role_switch = 1; + ClassOfDevice class_of_device{{0x11, 0x22, 0x33}}; + auto page_builder = PageBuilder::Create(class_of_device, allow_role_switch); + auto wrapped_page = LinkLayerPacketBuilder::WrapPage(std::move(page_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_page->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_page->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::PAGE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + PageView page = PageView::GetPage(view); + ASSERT_EQ(page.GetAllowRoleSwitch(), allow_role_switch); + ASSERT_EQ(page.GetClassOfDevice(), class_of_device); +} + +TEST_F(LinkLayerPacketBuilderTest, pageResponseTest) { + uint8_t try_role_switch = 2; + auto page_response_builder = PageResponseBuilder::Create(try_role_switch); + auto wrapped_page_response = + LinkLayerPacketBuilder::WrapPageResponse(std::move(page_response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_page_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_page_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::PAGE_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + PageResponseView page_response = PageResponseView::GetPageResponse(view); + ASSERT_EQ(page_response.GetTryRoleSwitch(), try_role_switch); +} + +TEST_F(LinkLayerPacketBuilderTest, responseTest) { + uint16_t opcode = 0x1234; + std::vector<uint64_t> data{ + 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, + 0x7464544434241404, 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, + 0x7868584838281808, 0x7969594939291909, 0x7a6a5a4a3a2a1a0a, 0x7b6b5b4b3b2b1b0b, + 0x7c6c5c4c3c2c1c0c, 0x7d6d5d4d3d2d1d0d, 0x7e6e5e4e3e2e1e0e, 0x7f6f5f4f3f2f1f0f, + }; + auto response_builder = ResponseBuilder::Create(opcode, data); + auto wrapped_response = LinkLayerPacketBuilder::WrapResponse(std::move(response_builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + ResponseView response = ResponseView::GetResponse(view); + ASSERT_EQ(opcode, response.GetOpcode()); + auto data_it = response.GetResponseData(); + ASSERT_EQ(data.size(), data_it.NumBytesRemaining() / sizeof(uint64_t)); + ASSERT_EQ(0u, data_it.NumBytesRemaining() % sizeof(uint64_t)); + for (size_t i = 0; i < data.size(); i++) { + ASSERT_EQ(data[i], data_it.extract<uint64_t>()); + } +} + +TEST_F(LinkLayerPacketBuilderTest, wrapAclTest) { + std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count); + View count_view(count_shared, 0, count_shared->size()); + PacketView<true> count_packet_view({count_view}); + auto builder = ViewForwarderBuilder::Create(count_packet_view); + auto wrapped_acl = LinkLayerPacketBuilder::WrapAcl(std::move(builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_acl->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_acl->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::ACL); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + auto acl_view = view.GetPayload(); + ASSERT_EQ(acl_view.size(), count_view.size()); + for (size_t i = 0; i < count_view.size(); i++) { + ASSERT_EQ(acl_view[i], count_view[i]); + } +} + +TEST_F(LinkLayerPacketBuilderTest, wrapCommandTest) { + uint16_t opcode = 0x0102; + std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count); + View count_view(count_shared, 0, count_shared->size()); + PacketView<true> args({count_view}); + auto builder = CommandBuilder::Create(opcode, args); + auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_command->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_command->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::COMMAND); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + auto command_view = CommandView::GetCommand(view); + ASSERT_EQ(opcode, command_view.GetOpcode()); + auto args_itr = command_view.GetData(); + ASSERT_EQ(args_itr.NumBytesRemaining(), count.size()); + for (size_t i = 0; i < count.size(); i++) { + ASSERT_EQ(*args_itr++, count[i]); + } +} + +TEST_F(LinkLayerPacketBuilderTest, wrapLeAdvertisementTest) { + LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::RANDOM; + LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::ADV_NONCONN_IND; + auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count); + auto wrapped_le_advertisement = LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(builder), source_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_le_advertisement->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_le_advertisement->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::LE_ADVERTISEMENT); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress()); + LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view); + ASSERT_EQ(address_type, le_advertisement_view.GetAddressType()); + ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType()); + auto le_advertisement_itr = le_advertisement_view.GetData(); + ASSERT_EQ(le_advertisement_itr.NumBytesRemaining(), count.size()); + for (size_t i = 0; i < count.size(); i++) { + ASSERT_EQ(*(le_advertisement_itr++), count[i]); + } +} + +TEST_F(LinkLayerPacketBuilderTest, wrapLeScanTest) { + auto le_scan = LinkLayerPacketBuilder::WrapLeScan(source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + le_scan->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), le_scan->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + auto le_scan_view = view.GetPayload(); + ASSERT_EQ(0u, le_scan_view.size()); +} + +TEST_F(LinkLayerPacketBuilderTest, wrapLeScanResponseTest) { + LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::PUBLIC_IDENTITY; + LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::SCAN_RESPONSE; + auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count); + auto wrapped_scan_response = LinkLayerPacketBuilder::WrapLeScanResponse(std::move(builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_scan_response->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_scan_response->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN_RESPONSE); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view); + ASSERT_EQ(address_type, le_advertisement_view.GetAddressType()); + ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType()); + auto scan_response_itr = le_advertisement_view.GetData(); + ASSERT_EQ(scan_response_itr.NumBytesRemaining(), count.size()); + for (size_t i = 0; i < count.size(); i++) { + ASSERT_EQ((*scan_response_itr++), count[i]); + } +} + +TEST_F(LinkLayerPacketBuilderTest, wrapScoTest) { + std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count); + View count_view(count_shared, 0, count_shared->size()); + PacketView<true> count_packet_view({count_view}); + auto builder = ViewForwarderBuilder::Create(count_packet_view); + auto wrapped_sco = LinkLayerPacketBuilder::WrapSco(std::move(builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_sco->Serialize(it); + + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); + ASSERT_EQ(view.size(), wrapped_sco->size()); + ASSERT_EQ(view.GetType(), Link::PacketType::SCO); + ASSERT_EQ(source_, view.GetSourceAddress()); + ASSERT_EQ(dest_, view.GetDestinationAddress()); + auto sco_view = view.GetPayload(); + ASSERT_EQ(sco_view.size(), count.size()); + for (size_t i = 0; i < count.size(); i++) { + ASSERT_EQ(sco_view[i], count[i]); + } +} + +} // namespace packets +} // namespace test_vendor_lib diff --git a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc index 5b4ee49dc..0ddd2fc74 100644 --- a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc +++ b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc @@ -27,8 +27,11 @@ #include <sys/types.h> #include <unistd.h> +#include "include/link.h" #include "model/setup/async_manager.h" #include "packets/link_layer/command_view.h" +#include "packets/link_layer/link_layer_packet_builder.h" +#include "packets/link_layer/link_layer_packet_view.h" std::vector<uint8_t> count = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -182,7 +185,14 @@ class LinkLayerSocketDeviceTest : public ::testing::Test { LinkLayerPacketView NextPacket() { std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count); - LinkLayerPacketView view = LinkLayerPacketView::Create(count_shared); + View count_view(count_shared, 0, count_shared->size()); + PacketView<true> args({count_view}); + auto builder = CommandBuilder::Create(packet_id_++, args); + auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_); + std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>(); + std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr); + wrapped_command->Serialize(it); + LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr); return view; } diff --git a/vendor_libs/test_vendor_lib/types/address.h b/vendor_libs/test_vendor_lib/types/address.h index 12e2dbbb4..1aa8c97f6 100644 --- a/vendor_libs/test_vendor_lib/types/address.h +++ b/vendor_libs/test_vendor_lib/types/address.h @@ -20,9 +20,6 @@ #include <string> -namespace bluetooth { -namespace types { - /** Bluetooth Address */ class Address final { public: @@ -77,8 +74,3 @@ inline std::ostream& operator<<(std::ostream& os, const Address& a) { os << a.ToString(); return os; } - -} // namespace types -} // namespace bluetooth - -using ::bluetooth::types::Address; // TODO, remove diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.h b/vendor_libs/test_vendor_lib/types/class_of_device.h index 4c37ebf26..8c2ab37e8 100644 --- a/vendor_libs/test_vendor_lib/types/class_of_device.h +++ b/vendor_libs/test_vendor_lib/types/class_of_device.h @@ -20,9 +20,6 @@ #include <string> -namespace bluetooth { -namespace types { - /** Bluetooth Class of Device */ class ClassOfDevice final { public: @@ -55,8 +52,3 @@ inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) { os << c.ToString(); return os; } - -} // namespace types -} // namespace bluetooth - -using ::bluetooth::types::ClassOfDevice; // TODO, remove
\ No newline at end of file |