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