• 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 <unordered_set>
17 
18 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
21 #include "pw_bluetooth_sapphire/internal/host/hci-spec/le_connection_parameters.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/fake_gatt_server.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/fake_l2cap.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/fake_sdp_server.h"
26 #include "pw_bluetooth_sapphire/internal/host/testing/fake_signaling_server.h"
27 
28 namespace bt::testing {
29 
30 class FakeController;
31 
32 // FakePeer is used to emulate a remote Bluetooth device.
33 class FakePeer {
34  public:
35   // NOTE: Setting |connectable| to true will result in a "Connectable and
36   // Scannable Advertisement" (i.e. ADV_IND) even if |scannable| is set to
37   // false. This is OK since we use |scannable| to drive the receipt of Scan
38   // Response PDUs: we use this to test the condition in which the advertisement
39   // is scannable but the host never receives a scan response.
40   explicit FakePeer(const DeviceAddress& address,
41                     pw::async::Dispatcher& pw_dispatcher,
42                     bool connectable = true,
43                     bool scannable = true);
44 
advertising_data()45   const ByteBuffer& advertising_data() const { return adv_data_; }
set_advertising_data(const ByteBuffer & data)46   void set_advertising_data(const ByteBuffer& data) {
47     adv_data_ = DynamicByteBuffer(data);
48   }
49 
50   // |should_batch_reports| indicates to the FakeController that the SCAN_IND
51   // report should be included in the same HCI LE Advertising Report Event
52   // payload that includes the original advertising data (see comments for
53   // should_batch_reports()).
54   void set_scan_response(bool should_batch_reports, const ByteBuffer& data);
scan_response()55   const ByteBuffer& scan_response() const { return scan_rsp_; }
56 
advertising_enabled()57   bool advertising_enabled() const { return advertising_enabled_; }
set_advertising_enabled(bool enabled)58   void set_advertising_enabled(bool enabled) { advertising_enabled_ = enabled; }
59 
60   // Mark this device for directed advertising.
directed_advertising_enabled()61   bool directed_advertising_enabled() const { return directed_; }
set_directed_advertising_enabled(bool enable)62   void set_directed_advertising_enabled(bool enable) { directed_ = enable; }
63 
64   // Toggles whether the address of this device represents a resolved RPA.
address_resolved()65   bool address_resolved() const { return address_resolved_; }
set_address_resolved(bool value)66   void set_address_resolved(bool value) { address_resolved_ = value; }
67 
68   // Extended advertising PDUs are used when advertising but allow for a greater
69   // set of features and a larger payload versus legacy advertising PDUs.
use_extended_advertising_pdus()70   bool use_extended_advertising_pdus() const {
71     return use_extended_advertising_pdus_;
72   }
set_use_extended_advertising_pdus(bool value)73   void set_use_extended_advertising_pdus(bool value) {
74     use_extended_advertising_pdus_ = value;
75   }
76 
77   // TODO(armansito): Come up with a better scheme to determine supported
78   // transport type instead of relying on address type, which doesn't translate
79   // well to dual-mode.
supports_bredr()80   bool supports_bredr() const {
81     // All BR/EDR devices have inquiry responses.
82     return address().type() == DeviceAddress::Type::kBREDR;
83   }
84 
85   // TODO(armansito): Come up with a better scheme to determine supported
86   // transport type instead of relying on address type, which doesn't translate
87   // well to dual-mode.
supports_le()88   bool supports_le() const {
89     return address().type() != DeviceAddress::Type::kBREDR;
90   }
91 
92   // Generates a Inquiry Response Event payload containing a inquiry result
93   // response.
94   DynamicByteBuffer CreateInquiryResponseEvent(
95       pw::bluetooth::emboss::InquiryMode mode) const;
96 
address()97   const DeviceAddress& address() const { return address_; }
rssi()98   int8_t rssi() const { return -1; }
tx_power()99   int8_t tx_power() const { return -2; }
100 
101   // The local name of the device. Used in HCI Remote Name Request event.
name()102   std::string name() const { return name_; }
set_name(const std::string & name)103   void set_name(const std::string& name) { name_ = name; }
104 
105   // Indicates whether or not this device should include the scan response and
106   // the advertising data in the same HCI LE Advertising Report Event. This is
107   // used to test that the host stack can correctly consolidate advertising
108   // reports when the payloads are spread across events and when they are
109   // batched together in the same event.
110   //
111   // This isn't used by FakePeer directly to generated batched reports. Rather
112   // it is a hint to the corresponding FakeController which decides how the
113   // reports should be generated.
should_batch_reports()114   bool should_batch_reports() const { return should_batch_reports_; }
115 
116   // Returns true if this device is scannable. We use this to tell
117   // FakeController whether or not it should send scan response PDUs.
scannable()118   bool scannable() const { return scannable_; }
119 
connectable()120   bool connectable() const { return connectable_; }
121 
connected()122   bool connected() const { return connected_; }
set_connected(bool connected)123   void set_connected(bool connected) { connected_ = connected; }
124 
set_class_of_device(DeviceClass class_of_device)125   void set_class_of_device(DeviceClass class_of_device) {
126     class_of_device_ = class_of_device;
127   }
128 
le_params()129   const hci_spec::LEConnectionParameters& le_params() const {
130     return le_params_;
131   }
set_le_params(const hci_spec::LEConnectionParameters & value)132   void set_le_params(const hci_spec::LEConnectionParameters& value) {
133     le_params_ = value;
134   }
135 
supports_ll_conn_update_procedure()136   bool supports_ll_conn_update_procedure() const {
137     return supports_ll_conn_update_procedure_;
138   }
set_supports_ll_conn_update_procedure(bool supports)139   void set_supports_ll_conn_update_procedure(bool supports) {
140     supports_ll_conn_update_procedure_ = supports;
141   }
142 
le_features()143   hci_spec::LESupportedFeatures le_features() const { return le_features_; }
set_le_features(hci_spec::LESupportedFeatures le_features)144   void set_le_features(hci_spec::LESupportedFeatures le_features) {
145     le_features_ = le_features;
146   }
147 
148   // The response status that will be returned when this device receives a LE
149   // Create Connection command.
connect_response()150   pw::bluetooth::emboss::StatusCode connect_response() const {
151     return connect_response_;
152   }
set_connect_response(pw::bluetooth::emboss::StatusCode response)153   void set_connect_response(pw::bluetooth::emboss::StatusCode response) {
154     connect_response_ = response;
155   }
156 
157   // The status that will be returned in the Command Status event in response to
158   // a LE Create Connection command. If this is set to anything other than
159   // pw::bluetooth::emboss::StatusCode::SUCCESS, then connect_response() will
160   // have no effect.
connect_status()161   pw::bluetooth::emboss::StatusCode connect_status() const {
162     return connect_status_;
163   }
set_connect_status(pw::bluetooth::emboss::StatusCode status)164   void set_connect_status(pw::bluetooth::emboss::StatusCode status) {
165     connect_status_ = status;
166   }
167 
force_pending_connect()168   bool force_pending_connect() const { return force_pending_connect_; }
set_force_pending_connect(bool value)169   void set_force_pending_connect(bool value) { force_pending_connect_ = value; }
170 
171   const std::optional<pw::bluetooth::emboss::LinkType>&
last_connection_request_link_type()172   last_connection_request_link_type() const {
173     return last_connection_request_link_type_;
174   }
set_last_connection_request_link_type(std::optional<pw::bluetooth::emboss::LinkType> type)175   void set_last_connection_request_link_type(
176       std::optional<pw::bluetooth::emboss::LinkType> type) {
177     last_connection_request_link_type_ = type;
178   }
179 
180   void AddLink(hci_spec::ConnectionHandle handle);
181   void RemoveLink(hci_spec::ConnectionHandle handle);
182   bool HasLink(hci_spec::ConnectionHandle handle) const;
183 
184   using HandleSet = std::unordered_set<hci_spec::ConnectionHandle>;
logical_links()185   const HandleSet& logical_links() const { return logical_links_; }
186 
187   // Marks this device as disconnected. Clears and returns all logical link
188   // handles.
189   HandleSet Disconnect();
190 
191   // Returns the FakeController that has been assigned to this device.
controller()192   FakeController* controller() const { return controller_; }
193 
194   // Returns the FakeSdpServer associated with this device.
sdp_server()195   FakeSdpServer* sdp_server() { return &sdp_server_; }
196 
197  private:
198   friend class FakeController;
199 
200   // Called by a FakeController when a FakePeer is registered with it.
set_controller(FakeController * ctrl)201   void set_controller(FakeController* ctrl) { controller_ = ctrl; }
202 
203   void WriteScanResponseReport(hci_spec::LEAdvertisingReportData* report) const;
204 
205   // Validate received L2CAP packets and then route them to the FakeL2cap
206   // instance owned by the device. The FakeL2cap instance will process the
207   // packet and route it to the appropriate packet handler.
208   void OnRxL2CAP(hci_spec::ConnectionHandle conn, const ByteBuffer& pdu);
209 
210   // Sends packets over channel ID |cid| and handle |conn| using the
211   // FakeController's SendL2CapBFrame function. Assumes that input buffer
212   // |packet| has signaling packet header intact but does not have an L2CAP
213   //  packet header.
214   void SendPacket(hci_spec::ConnectionHandle conn,
215                   l2cap::ChannelId cid,
216                   const ByteBuffer& packet) const;
217 
218   // The FakeController that this FakePeer has been assigned to.
219   FakeController* controller_;  // weak
220 
221   DeviceAddress address_;
222   std::string name_;
223   bool connected_;
224   bool connectable_;
225   bool scannable_;
226   bool advertising_enabled_;
227   bool directed_;
228   bool address_resolved_;
229   bool use_extended_advertising_pdus_;
230 
231   pw::bluetooth::emboss::StatusCode connect_status_;
232   pw::bluetooth::emboss::StatusCode connect_response_;
233   bool force_pending_connect_;  // Causes connection requests to remain pending.
234   std::optional<pw::bluetooth::emboss::LinkType>
235       last_connection_request_link_type_;
236 
237   hci_spec::LEConnectionParameters le_params_;
238 
239   // If false, FakeController will send LE Connection Update complete events
240   // with status kRemoteFeatureNotSupported.
241   bool supports_ll_conn_update_procedure_;
242 
243   hci_spec::LESupportedFeatures le_features_;
244 
245   bool should_batch_reports_;
246   DynamicByteBuffer adv_data_;
247   DynamicByteBuffer scan_rsp_;
248 
249   // Open connection handles.
250   HandleSet logical_links_;
251 
252   // Class of device
253   DeviceClass class_of_device_;
254 
255   FakeL2cap l2cap_;
256   FakeGattServer gatt_server_;
257   FakeSignalingServer signaling_server_;
258   FakeSdpServer sdp_server_;
259   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakePeer);
260 };
261 
262 }  // namespace bt::testing
263