• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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