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/l2cap/channel.h" 17 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h" 18 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_channel.h" 19 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h" 20 21 namespace bt::l2cap::testing { 22 23 // This is a fake version of the ChannelManager class that can be injected into 24 // other layers for unit testing. 25 class FakeL2cap final : public ChannelManager { 26 public: FakeL2cap(pw::async::Dispatcher & pw_dispatcher)27 explicit FakeL2cap(pw::async::Dispatcher& pw_dispatcher) 28 : heap_dispatcher_(pw_dispatcher) {} 29 ~FakeL2cap() override; 30 AttachInspect(inspect::Node &,std::string)31 void AttachInspect(inspect::Node&, std::string) override {} 32 33 // Returns true if and only if a link identified by |handle| has been added 34 // and connected. 35 [[nodiscard]] bool IsLinkConnected(hci_spec::ConnectionHandle handle) const; 36 37 // Triggers a LE connection parameter update callback on the given link. 38 void TriggerLEConnectionParameterUpdate( 39 hci_spec::ConnectionHandle handle, 40 const hci_spec::LEPreferredConnectionParameters& params); 41 42 // Sets up the expectation that an outbound dynamic channel will be opened 43 // on the given link. Each call will expect one dyanmic channel to be 44 // created. If a call to OpenL2capChannel is made without expectation, it 45 // will assert. 46 // Multiple expectations for the same PSM should be queued in FIFO order. 47 void ExpectOutboundL2capChannel(hci_spec::ConnectionHandle handle, 48 Psm psm, 49 ChannelId id, 50 ChannelId remote_id, 51 ChannelParameters params); 52 53 // Triggers the creation of an inbound dynamic channel on the given link. The 54 // channels created will be provided to handlers passed to RegisterService. 55 // Returns false if unable to create the channel. 56 bool TriggerInboundL2capChannel(hci_spec::ConnectionHandle handle, 57 Psm psm, 58 ChannelId id, 59 ChannelId remote_id, 60 uint16_t tx_mtu = kDefaultMTU); 61 62 // Triggers a link error callback on the given link. 63 void TriggerLinkError(hci_spec::ConnectionHandle handle); 64 65 // L2cap overrides: 66 BrEdrFixedChannels AddACLConnection( 67 hci_spec::ConnectionHandle handle, 68 pw::bluetooth::emboss::ConnectionRole role, 69 LinkErrorCallback link_error_callback, 70 SecurityUpgradeCallback security_callback) override; 71 LEFixedChannels AddLEConnection( 72 hci_spec::ConnectionHandle handle, 73 pw::bluetooth::emboss::ConnectionRole role, 74 LinkErrorCallback link_error_callback, 75 LEConnectionParameterUpdateCallback conn_param_callback, 76 SecurityUpgradeCallback security_callback) override; 77 void RemoveConnection(hci_spec::ConnectionHandle handle) override; 78 void AssignLinkSecurityProperties(hci_spec::ConnectionHandle handle, 79 sm::SecurityProperties security) override; 80 81 // Immediately posts accept on |dispatcher|. 82 void RequestConnectionParameterUpdate( 83 hci_spec::ConnectionHandle handle, 84 hci_spec::LEPreferredConnectionParameters params, 85 ConnectionParameterUpdateRequestCallback request_cb) override; 86 OpenFixedChannel(hci_spec::ConnectionHandle,ChannelId)87 Channel::WeakPtr OpenFixedChannel(hci_spec::ConnectionHandle, 88 ChannelId) override { 89 return Channel::WeakPtr(); 90 } 91 void OpenL2capChannel(hci_spec::ConnectionHandle handle, 92 Psm psm, 93 ChannelParameters params, 94 ChannelCallback cb) override; 95 bool RegisterService(Psm psm, 96 ChannelParameters params, 97 ChannelCallback channel_callback) override; 98 void UnregisterService(Psm psm) override; 99 LogicalLinkForTesting(hci_spec::ConnectionHandle)100 WeakSelf<internal::LogicalLink>::WeakPtr LogicalLinkForTesting( 101 hci_spec::ConnectionHandle) override { 102 return WeakSelf<internal::LogicalLink>::WeakPtr(); 103 } 104 105 // Called when a new channel gets opened. Tests can use this to obtain a 106 // reference to all channels. 107 using FakeChannelCallback = 108 fit::function<void(testing::FakeChannel::WeakPtr)>; set_channel_callback(FakeChannelCallback callback)109 void set_channel_callback(FakeChannelCallback callback) { 110 chan_cb_ = std::move(callback); 111 } set_simulate_open_channel_failure(bool simulate_failure)112 void set_simulate_open_channel_failure(bool simulate_failure) { 113 simulate_open_channel_failure_ = simulate_failure; 114 } 115 116 // Called when RequestConnectionParameterUpdate is called. |request_cb| will 117 // be called with return value. Defaults to returning true if not set. 118 using ConnectionParameterUpdateRequestResponder = fit::function<bool( 119 hci_spec::ConnectionHandle, hci_spec::LEPreferredConnectionParameters)>; set_connection_parameter_update_request_responder(ConnectionParameterUpdateRequestResponder responder)120 void set_connection_parameter_update_request_responder( 121 ConnectionParameterUpdateRequestResponder responder) { 122 connection_parameter_update_request_responder_ = std::move(responder); 123 } 124 125 private: 126 // TODO(armansito): Consider moving the following logic into an internal fake 127 // that is L2CAP-specific. 128 struct ChannelData { 129 ChannelId local_id; 130 ChannelId remote_id; 131 ChannelParameters params; 132 }; 133 struct LinkData { 134 // Expectations on links can be created before they are connected. 135 bool connected; 136 hci_spec::ConnectionHandle handle; 137 pw::bluetooth::emboss::ConnectionRole role; 138 bt::LinkType type; 139 bool link_error_signaled = false; 140 141 // Dual-mode callbacks 142 LinkErrorCallback link_error_cb; 143 std::unordered_map<Psm, std::queue<ChannelData>> expected_outbound_conns; 144 145 // LE-only callbacks 146 LEConnectionParameterUpdateCallback le_conn_param_cb; 147 148 std::unordered_map<ChannelId, std::unique_ptr<FakeChannel>> channels_; 149 }; 150 151 LinkData* RegisterInternal(hci_spec::ConnectionHandle handle, 152 pw::bluetooth::emboss::ConnectionRole role, 153 bt::LinkType link_type, 154 LinkErrorCallback link_error_callback); 155 156 testing::FakeChannel::WeakPtr OpenFakeChannel( 157 LinkData* link, 158 ChannelId id, 159 ChannelId remote_id, 160 ChannelInfo info = ChannelInfo::MakeBasicMode(kDefaultMTU, kDefaultMTU)); 161 testing::FakeChannel::WeakPtr OpenFakeFixedChannel(LinkData* link, 162 ChannelId id); 163 164 // Gets the link data for |handle|, creating it if necessary. 165 LinkData& GetLinkData(hci_spec::ConnectionHandle handle); 166 // Gets the link data for |handle|. Asserts if the link is not connected yet. 167 LinkData& ConnectedLinkData(hci_spec::ConnectionHandle handle); 168 169 std::unordered_map<hci_spec::ConnectionHandle, LinkData> links_; 170 FakeChannelCallback chan_cb_; 171 bool simulate_open_channel_failure_ = false; 172 173 ConnectionParameterUpdateRequestResponder 174 connection_parameter_update_request_responder_; 175 176 std::unordered_map<Psm, ServiceInfo> registered_services_; 177 178 pw::async::HeapDispatcher heap_dispatcher_; 179 180 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeL2cap); 181 }; 182 183 } // namespace bt::l2cap::testing 184