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                     bool send_advertising_report = true);
45 
advertising_data()46   const ByteBuffer& advertising_data() const { return advertising_data_; }
set_advertising_data(const ByteBuffer & data)47   void set_advertising_data(const ByteBuffer& data) {
48     advertising_data_ = DynamicByteBuffer(data);
49   }
50 
51   void set_scan_response(const ByteBuffer& data);
scan_response()52   const ByteBuffer& scan_response() const { return scan_response_; }
53 
advertising_enabled()54   bool advertising_enabled() const { return advertising_enabled_; }
set_advertising_enabled(bool enabled)55   void set_advertising_enabled(bool enabled) { advertising_enabled_ = enabled; }
56 
57   // Mark this device for directed advertising.
directed_advertising_enabled()58   bool directed_advertising_enabled() const { return directed_; }
set_directed_advertising_enabled(bool enable)59   void set_directed_advertising_enabled(bool enable) { directed_ = enable; }
60 
61   // Toggles whether the address of this device represents a resolved RPA.
address_resolved()62   bool address_resolved() const { return address_resolved_; }
set_address_resolved(bool value)63   void set_address_resolved(bool value) { address_resolved_ = value; }
64 
65   // Extended advertising PDUs are used when advertising but allow for a greater
66   // set of features and a larger payload versus legacy advertising PDUs.
use_extended_advertising_pdus()67   bool use_extended_advertising_pdus() const {
68     return use_extended_advertising_pdus_;
69   }
set_use_extended_advertising_pdus(bool value)70   void set_use_extended_advertising_pdus(bool value) {
71     use_extended_advertising_pdus_ = value;
72   }
73 
74   // TODO(armansito): Come up with a better scheme to determine supported
75   // transport type instead of relying on address type, which doesn't translate
76   // well to dual-mode.
supports_bredr()77   bool supports_bredr() const {
78     // All BR/EDR devices have inquiry responses.
79     return address().type() == DeviceAddress::Type::kBREDR;
80   }
81 
82   // TODO(armansito): Come up with a better scheme to determine supported
83   // transport type instead of relying on address type, which doesn't translate
84   // well to dual-mode.
supports_le()85   bool supports_le() const {
86     return address().type() != DeviceAddress::Type::kBREDR;
87   }
88 
89   // Generates a Inquiry Response Event payload containing a inquiry result
90   // response.
91   DynamicByteBuffer CreateInquiryResponseEvent(
92       pw::bluetooth::emboss::InquiryMode mode) const;
93 
address()94   const DeviceAddress& address() const { return address_; }
rssi()95   int8_t rssi() const { return -1; }
tx_power()96   int8_t tx_power() const { return -2; }
97 
98   // The local name of the device. Used in HCI Remote Name Request event.
name()99   std::string name() const { return name_; }
set_name(const std::string & name)100   void set_name(const std::string& name) { name_ = name; }
101 
102   // Returns true if this device is scannable. We use this to tell
103   // FakeController whether or not it should send scan response PDUs.
scannable()104   bool scannable() const { return scannable_; }
set_scannable(bool scannable)105   void set_scannable(bool scannable) { scannable_ = scannable; }
106 
connectable()107   bool connectable() const { return connectable_; }
108 
connected()109   bool connected() const { return connected_; }
set_connected(bool connected)110   void set_connected(bool connected) { connected_ = connected; }
111 
send_advertising_report()112   bool send_advertising_report() const { return send_advertising_report_; }
set_send_advertising_report(bool value)113   void set_send_advertising_report(bool value) {
114     send_advertising_report_ = value;
115   }
116 
set_class_of_device(DeviceClass class_of_device)117   void set_class_of_device(DeviceClass class_of_device) {
118     class_of_device_ = class_of_device;
119   }
120 
le_params()121   const hci_spec::LEConnectionParameters& le_params() const {
122     return le_params_;
123   }
set_le_params(const hci_spec::LEConnectionParameters & value)124   void set_le_params(const hci_spec::LEConnectionParameters& value) {
125     le_params_ = value;
126   }
127 
supports_ll_conn_update_procedure()128   bool supports_ll_conn_update_procedure() const {
129     return supports_ll_conn_update_procedure_;
130   }
set_supports_ll_conn_update_procedure(bool supports)131   void set_supports_ll_conn_update_procedure(bool supports) {
132     supports_ll_conn_update_procedure_ = supports;
133   }
134 
le_features()135   hci_spec::LESupportedFeatures le_features() const { return le_features_; }
set_le_features(hci_spec::LESupportedFeatures le_features)136   void set_le_features(hci_spec::LESupportedFeatures le_features) {
137     le_features_ = le_features;
138   }
139 
set_le_advertising_address(DeviceAddress address)140   void set_le_advertising_address(DeviceAddress address) {
141     le_advertising_address_ = address;
142   }
143 
144   // The response status that will be returned when this device receives a LE
145   // Create Connection command.
connect_response()146   pw::bluetooth::emboss::StatusCode connect_response() const {
147     return connect_response_;
148   }
set_connect_response(pw::bluetooth::emboss::StatusCode response)149   void set_connect_response(pw::bluetooth::emboss::StatusCode response) {
150     connect_response_ = response;
151   }
152 
153   // The status that will be returned in the Command Status event in response to
154   // a LE Create Connection command. If this is set to anything other than
155   // pw::bluetooth::emboss::StatusCode::SUCCESS, then connect_response() will
156   // have no effect.
connect_status()157   pw::bluetooth::emboss::StatusCode connect_status() const {
158     return connect_status_;
159   }
set_connect_status(pw::bluetooth::emboss::StatusCode status)160   void set_connect_status(pw::bluetooth::emboss::StatusCode status) {
161     connect_status_ = status;
162   }
163 
force_pending_connect()164   bool force_pending_connect() const { return force_pending_connect_; }
set_force_pending_connect(bool value)165   void set_force_pending_connect(bool value) { force_pending_connect_ = value; }
166 
167   const std::optional<pw::bluetooth::emboss::LinkType>&
last_connection_request_link_type()168   last_connection_request_link_type() const {
169     return last_connection_request_link_type_;
170   }
set_last_connection_request_link_type(std::optional<pw::bluetooth::emboss::LinkType> type)171   void set_last_connection_request_link_type(
172       std::optional<pw::bluetooth::emboss::LinkType> type) {
173     last_connection_request_link_type_ = type;
174   }
175 
176   void AddLink(hci_spec::ConnectionHandle handle);
177   void RemoveLink(hci_spec::ConnectionHandle handle);
178   bool HasLink(hci_spec::ConnectionHandle handle) const;
179 
180   using HandleSet = std::unordered_set<hci_spec::ConnectionHandle>;
logical_links()181   const HandleSet& logical_links() const { return logical_links_; }
182 
183   // Marks this device as disconnected. Clears and returns all logical link
184   // handles.
185   HandleSet Disconnect();
186 
187   // Returns the FakeController that has been assigned to this device.
controller()188   FakeController* controller() const { return controller_; }
189 
190   // Returns the FakeSdpServer associated with this device.
sdp_server()191   FakeSdpServer* sdp_server() { return &sdp_server_; }
192 
193   // Generates and returns a LE Advertising Report Event payload. If
194   // |include_scan_rsp| is true, then the returned PDU will contain two reports
195   // including the SCAN_IND report.
196   DynamicByteBuffer BuildLegacyAdvertisingReportEvent(
197       bool include_scan_rsp = false) const;
198 
199   // Generates a LE Advertising Report Event payload containing the scan
200   // response.
201   DynamicByteBuffer BuildLegacyScanResponseReportEvent() const;
202 
203   // Generates and returns an LE Extended Advertising Report Event payload.
204   DynamicByteBuffer BuildExtendedAdvertisingReportEvent() const;
205 
206   // Generates an LE Extended Advertising Report Event payload containing the
207   // scan response.
208   DynamicByteBuffer BuildExtendedScanResponseEvent() const;
209 
210   // Populate an LEExtendedAdvertisingReportData as though it was received from
211   // this fake peer
212   void FillExtendedAdvertisingReport(
213       pw::bluetooth::emboss::LEExtendedAdvertisingReportDataWriter report,
214       const ByteBuffer& data,
215       bool is_fragmented,
216       bool is_scan_response) const;
217 
218  private:
219   friend class FakeController;
220 
221   // Called by a FakeController when a FakePeer is registered with it.
set_controller(FakeController * ctrl)222   void set_controller(FakeController* ctrl) { controller_ = ctrl; }
223 
224   void WriteScanResponseReport(
225       pw::bluetooth::emboss::LEAdvertisingReportDataWriter report) const;
226 
227   // Validate received L2CAP packets and then route them to the FakeL2cap
228   // instance owned by the device. The FakeL2cap instance will process the
229   // packet and route it to the appropriate packet handler.
230   void OnRxL2CAP(hci_spec::ConnectionHandle conn, const ByteBuffer& pdu);
231 
232   // Sends packets over channel ID |cid| and handle |conn| using the
233   // FakeController's SendL2CapBFrame function. Assumes that input buffer
234   // |packet| has signaling packet header intact but does not have an L2CAP
235   //  packet header.
236   void SendPacket(hci_spec::ConnectionHandle conn,
237                   l2cap::ChannelId cid,
238                   const ByteBuffer& packet) const;
239 
240   DynamicByteBuffer BuildExtendedAdvertisingReports(
241       const ByteBuffer& data, bool is_scan_response) const;
242 
243   // The FakeController that this FakePeer has been assigned to.
244   FakeController* controller_;  // weak
245 
246   DeviceAddress address_;
247   std::string name_;
248   bool connected_;
249   bool connectable_;
250   bool scannable_;
251   bool advertising_enabled_;
252   bool directed_;
253   bool address_resolved_;
254   bool use_extended_advertising_pdus_ = false;
255   bool send_advertising_report_;
256 
257   pw::bluetooth::emboss::StatusCode connect_status_;
258   pw::bluetooth::emboss::StatusCode connect_response_;
259   bool force_pending_connect_;  // Causes connection requests to remain pending.
260   std::optional<pw::bluetooth::emboss::LinkType>
261       last_connection_request_link_type_;
262 
263   hci_spec::LEConnectionParameters le_params_;
264 
265   // If false, FakeController will send LE Connection Update complete events
266   // with status kRemoteFeatureNotSupported.
267   bool supports_ll_conn_update_procedure_;
268 
269   hci_spec::LESupportedFeatures le_features_;
270 
271   std::optional<DeviceAddress> le_advertising_address_;
272 
273   DynamicByteBuffer advertising_data_;
274   DynamicByteBuffer scan_response_;
275 
276   // Open connection handles.
277   HandleSet logical_links_;
278 
279   // Class of device
280   DeviceClass class_of_device_;
281 
282   FakeL2cap l2cap_;
283   FakeGattServer gatt_server_;
284   FakeSignalingServer signaling_server_;
285   FakeSdpServer sdp_server_;
286   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakePeer);
287 };
288 
289 }  // namespace bt::testing
290