1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h" 17 #include "pw_bluetooth_sapphire/internal/host/gap/adapter.h" 18 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 19 #include "pw_bluetooth_sapphire/internal/host/hci/fake_local_address_delegate.h" 20 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel.h" 21 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h" 22 23 namespace bt::gap::testing { 24 25 // FakeAdapter is a fake implementation of Adapter that can be used in higher 26 // layer unit tests (e.g. FIDL tests). 27 class FakeAdapter final : public Adapter { 28 public: 29 explicit FakeAdapter(pw::async::Dispatcher& pw_dispatcher); 30 ~FakeAdapter() override = default; 31 mutable_state()32 AdapterState& mutable_state() { return state_; } 33 34 // Adapter overrides: 35 identifier()36 AdapterId identifier() const override { return AdapterId(0); } 37 38 bool Initialize(InitializeCallback callback, 39 fit::closure transport_closed_callback) override; 40 41 void ShutDown() override; 42 IsInitializing()43 bool IsInitializing() const override { 44 return init_state_ == InitState::kInitializing; 45 } 46 IsInitialized()47 bool IsInitialized() const override { 48 return init_state_ == InitState::kInitialized; 49 } 50 state()51 const AdapterState& state() const override { return state_; } 52 53 class FakeLowEnergy final : public LowEnergy { 54 public: 55 struct RegisteredAdvertisement { 56 AdvertisingData data; 57 AdvertisingData scan_response; 58 bool include_tx_power_level; 59 DeviceAddress::Type addr_type; 60 bool extended_pdu; 61 bool anonymous; 62 std::optional<ConnectableAdvertisingParameters> connectable; 63 }; 64 65 struct Connection { 66 PeerId peer_id; 67 LowEnergyConnectionOptions options; 68 LowEnergyConnectionHandle* handle; 69 }; 70 FakeLowEnergy(FakeAdapter * adapter)71 explicit FakeLowEnergy(FakeAdapter* adapter) 72 : adapter_(adapter), fake_address_delegate_(adapter->pw_dispatcher_) {} 73 ~FakeLowEnergy() override = default; 74 75 const std::unordered_map<AdvertisementId, RegisteredAdvertisement>& registered_advertisements()76 registered_advertisements() { 77 return advertisements_; 78 } 79 connections()80 const std::unordered_map<PeerId, Connection>& connections() const { 81 return connections_; 82 } 83 84 // Update the LE random address of the adapter. 85 void UpdateRandomAddress(DeviceAddress& address); 86 87 // Overrides the result returned to StartAdvertising() callback. 88 void set_advertising_result(hci::Result<> result); 89 90 // Notify all discovery sessions of a scan result. 91 // Make sure to set the advertising data in Peer first! 92 void NotifyScanResult(const Peer& peer); 93 94 // Add scan result that discovery result callbacks will be notified of when 95 // the result callback is set. AddCachedScanResult(bt::PeerId peer_id)96 void AddCachedScanResult(bt::PeerId peer_id) { 97 cached_scan_results_.insert(peer_id); 98 } 99 discovery_sessions()100 const std::unordered_set<LowEnergyDiscoverySession*>& discovery_sessions() 101 const { 102 return discovery_sessions_; 103 } 104 105 // LowEnergy overrides: 106 107 // If Connect is called multiple times, only the connection options of the 108 // last call will be reported in connections(). 109 void Connect(PeerId peer_id, 110 ConnectionResultCallback callback, 111 LowEnergyConnectionOptions connection_options) override; 112 113 bool Disconnect(PeerId peer_id) override; 114 115 void OpenL2capChannel(PeerId peer_id, 116 l2cap::Psm, 117 l2cap::ChannelParameters, 118 sm::SecurityLevel security_level, 119 l2cap::ChannelCallback) override; 120 Pair(PeerId,sm::SecurityLevel,sm::BondableMode,sm::ResultFunction<>)121 void Pair(PeerId, 122 sm::SecurityLevel, 123 sm::BondableMode, 124 sm::ResultFunction<>) override {} 125 SetLESecurityMode(LESecurityMode)126 void SetLESecurityMode(LESecurityMode) override {} 127 security_mode()128 LESecurityMode security_mode() const override { 129 return adapter_->le_security_mode_; 130 } 131 132 void StartAdvertising( 133 AdvertisingData data, 134 AdvertisingData scan_rsp, 135 AdvertisingInterval interval, 136 bool extended_pdu, 137 bool anonymous, 138 bool include_tx_power_level, 139 std::optional<ConnectableAdvertisingParameters> connectable, 140 std::optional<DeviceAddress::Type> address_type, 141 AdvertisingStatusCallback status_callback) override; 142 143 void StartDiscovery(bool active, 144 std::vector<hci::DiscoveryFilter> filters, 145 SessionCallback callback) override; 146 147 void EnablePrivacy(bool enabled) override; 148 149 // Returns true if the privacy feature is currently enabled. PrivacyEnabled()150 bool PrivacyEnabled() const override { 151 return fake_address_delegate_.privacy_enabled(); 152 } 153 // Returns the current LE address. CurrentAddress()154 const DeviceAddress CurrentAddress() const override { 155 return fake_address_delegate_.current_address(); 156 } 157 register_address_changed_callback(fit::closure callback)158 void register_address_changed_callback(fit::closure callback) override { 159 fake_address_delegate_.register_address_changed_callback( 160 std::move(callback)); 161 } 162 set_irk(const std::optional<UInt128> &)163 void set_irk(const std::optional<UInt128>&) override {} 164 irk()165 std::optional<UInt128> irk() const override { return std::nullopt; } 166 set_request_timeout_for_testing(pw::chrono::SystemClock::duration)167 void set_request_timeout_for_testing( 168 pw::chrono::SystemClock::duration) override {} 169 set_scan_period_for_testing(pw::chrono::SystemClock::duration)170 void set_scan_period_for_testing( 171 pw::chrono::SystemClock::duration) override {} 172 173 private: 174 uint16_t next_scan_id_ = 0; 175 FakeAdapter* adapter_; 176 AdvertisementId next_advertisement_id_ = AdvertisementId(1); 177 std::unordered_map<AdvertisementId, RegisteredAdvertisement> 178 advertisements_; 179 std::unordered_map<PeerId, Connection> connections_; 180 hci::FakeLocalAddressDelegate fake_address_delegate_; 181 l2cap::ChannelId next_channel_id_ = l2cap::kFirstDynamicChannelId; 182 std::unordered_map<l2cap::ChannelId, 183 std::unique_ptr<l2cap::testing::FakeChannel>> 184 channels_; 185 std::optional<hci::Result<>> advertising_result_override_; 186 std::unordered_set<LowEnergyDiscoverySession*> discovery_sessions_; 187 std::unordered_set<PeerId> cached_scan_results_; 188 }; 189 le()190 LowEnergy* le() const override { return fake_le_.get(); } fake_le()191 FakeLowEnergy* fake_le() const { return fake_le_.get(); } 192 193 class FakeBrEdr final : public BrEdr { 194 public: 195 struct RegisteredService { 196 std::vector<sdp::ServiceRecord> records; 197 l2cap::ChannelParameters channel_params; 198 ServiceConnectCallback connect_callback; 199 }; 200 201 struct RegisteredSearch { 202 UUID uuid; 203 std::unordered_set<sdp::AttributeId> attributes; 204 SearchCallback callback; 205 }; 206 207 FakeBrEdr() = default; 208 ~FakeBrEdr() override; 209 210 // Called with a reference to the l2cap::FakeChannel created when a channel 211 // is connected with Connect(). 212 using ChannelCallback = 213 fit::function<void(l2cap::testing::FakeChannel::WeakPtr)>; set_l2cap_channel_callback(ChannelCallback cb)214 void set_l2cap_channel_callback(ChannelCallback cb) { 215 channel_cb_ = std::move(cb); 216 } 217 218 // Destroys the channel, invaliding all weak pointers. Returns true if the 219 // channel was successfully destroyed. DestroyChannel(l2cap::ChannelId channel_id)220 bool DestroyChannel(l2cap::ChannelId channel_id) { 221 return channels_.erase(channel_id); 222 } 223 224 // Notifies all registered searches associated with the provided |uuid| with 225 // the peer's service |attributes|. 226 void TriggerServiceFound( 227 PeerId peer_id, 228 UUID uuid, 229 std::map<sdp::AttributeId, sdp::DataElement> attributes); 230 registered_services()231 const std::map<RegistrationHandle, RegisteredService>& registered_services() 232 const { 233 return registered_services_; 234 } 235 registered_searches()236 const std::map<RegistrationHandle, RegisteredSearch>& registered_searches() 237 const { 238 return registered_searches_; 239 } 240 241 // BrEdr overrides: Connect(PeerId,ConnectResultCallback)242 [[nodiscard]] bool Connect(PeerId, ConnectResultCallback) override { 243 return false; 244 } 245 Disconnect(PeerId,DisconnectReason)246 bool Disconnect(PeerId, DisconnectReason) override { return false; } 247 248 void OpenL2capChannel(PeerId peer_id, 249 l2cap::Psm psm, 250 BrEdrSecurityRequirements security_requirements, 251 l2cap::ChannelParameters params, 252 l2cap::ChannelCallback cb) override; 253 GetPeerId(hci_spec::ConnectionHandle)254 PeerId GetPeerId(hci_spec::ConnectionHandle) const override { 255 return PeerId(); 256 } 257 258 SearchId AddServiceSearch(const UUID& uuid, 259 std::unordered_set<sdp::AttributeId> attributes, 260 SearchCallback callback) override; 261 RemoveServiceSearch(SearchId)262 bool RemoveServiceSearch(SearchId) override { return false; } 263 Pair(PeerId,BrEdrSecurityRequirements,hci::ResultFunction<>)264 void Pair(PeerId, 265 BrEdrSecurityRequirements, 266 hci::ResultFunction<>) override {} 267 SetBrEdrSecurityMode(BrEdrSecurityMode)268 void SetBrEdrSecurityMode(BrEdrSecurityMode) override {} 269 security_mode()270 BrEdrSecurityMode security_mode() const override { 271 return BrEdrSecurityMode::Mode4; 272 } 273 SetConnectable(bool,hci::ResultFunction<>)274 void SetConnectable(bool, hci::ResultFunction<>) override {} 275 RequestDiscovery(DiscoveryCallback)276 void RequestDiscovery(DiscoveryCallback) override {} 277 RequestDiscoverable(DiscoverableCallback)278 void RequestDiscoverable(DiscoverableCallback) override {} 279 280 RegistrationHandle RegisterService(std::vector<sdp::ServiceRecord> records, 281 l2cap::ChannelParameters chan_params, 282 ServiceConnectCallback conn_cb) override; 283 284 bool UnregisterService(RegistrationHandle handle) override; 285 GetRegisteredServices(RegistrationHandle)286 std::vector<sdp::ServiceRecord> GetRegisteredServices( 287 RegistrationHandle) const override { 288 return {}; 289 } 290 OpenScoConnection(PeerId,const bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter> &,sco::ScoConnectionManager::OpenConnectionCallback)291 std::optional<ScoRequestHandle> OpenScoConnection( 292 PeerId, 293 const bt::StaticPacket< 294 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>&, 295 sco::ScoConnectionManager::OpenConnectionCallback) override { 296 return std::nullopt; 297 } 298 AcceptScoConnection(PeerId,std::vector<bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>,sco::ScoConnectionManager::AcceptConnectionCallback)299 std::optional<ScoRequestHandle> AcceptScoConnection( 300 PeerId, 301 std::vector<bt::StaticPacket< 302 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>, 303 sco::ScoConnectionManager::AcceptConnectionCallback) override { 304 return std::nullopt; 305 } 306 307 private: 308 // Callback used by tests to get new channel refs. 309 ChannelCallback channel_cb_; 310 RegistrationHandle next_service_handle_ = 1; 311 RegistrationHandle next_search_handle_ = 1; 312 std::map<RegistrationHandle, RegisteredService> registered_services_; 313 std::map<RegistrationHandle, RegisteredSearch> registered_searches_; 314 315 l2cap::ChannelId next_channel_id_ = l2cap::kFirstDynamicChannelId; 316 std::unordered_map<l2cap::ChannelId, 317 std::unique_ptr<l2cap::testing::FakeChannel>> 318 channels_; 319 }; 320 bredr()321 BrEdr* bredr() const override { return fake_bredr_.get(); } fake_bredr()322 FakeBrEdr* fake_bredr() const { return fake_bredr_.get(); } 323 peer_cache()324 PeerCache* peer_cache() override { return &peer_cache_; } 325 AddBondedPeer(BondingData)326 bool AddBondedPeer(BondingData) override { return true; } 327 SetPairingDelegate(PairingDelegate::WeakPtr)328 void SetPairingDelegate(PairingDelegate::WeakPtr) override {} 329 IsDiscoverable()330 bool IsDiscoverable() const override { return is_discoverable_; } 331 IsDiscovering()332 bool IsDiscovering() const override { return is_discovering_; } 333 334 void SetLocalName(std::string name, hci::ResultFunction<> callback) override; 335 local_name()336 std::string local_name() const override { return local_name_; } 337 338 void SetDeviceClass(DeviceClass dev_class, 339 hci::ResultFunction<> callback) override; 340 341 void GetSupportedDelayRange( 342 const bt::StaticPacket<pw::bluetooth::emboss::CodecIdWriter>& codec_id, 343 pw::bluetooth::emboss::LogicalTransportType logical_transport_type, 344 pw::bluetooth::emboss::DataPathDirection direction, 345 const std::optional<std::vector<uint8_t>>& codec_configuration, 346 GetSupportedDelayRangeCallback cb) override; 347 set_auto_connect_callback(AutoConnectCallback)348 void set_auto_connect_callback(AutoConnectCallback) override {} 349 AttachInspect(inspect::Node &,std::string)350 void AttachInspect(inspect::Node&, std::string) override {} 351 AsWeakPtr()352 Adapter::WeakPtr AsWeakPtr() override { return weak_self_.GetWeakPtr(); } 353 354 private: 355 enum InitState { 356 kNotInitialized = 0, 357 kInitializing, 358 kInitialized, 359 }; 360 361 InitState init_state_; 362 AdapterState state_; 363 std::unique_ptr<FakeLowEnergy> fake_le_; 364 std::unique_ptr<FakeBrEdr> fake_bredr_; 365 bool is_discoverable_ = true; 366 bool is_discovering_ = true; 367 std::string local_name_; 368 DeviceClass device_class_; 369 LESecurityMode le_security_mode_; 370 371 pw::async::Dispatcher& pw_dispatcher_; 372 pw::async::HeapDispatcher heap_dispatcher_; 373 PeerCache peer_cache_; 374 WeakSelf<Adapter> weak_self_; 375 }; 376 377 } // namespace bt::gap::testing 378