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