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 void AddACLConnection( 67 hci_spec::ConnectionHandle handle, 68 pw::bluetooth::emboss::ConnectionRole role, 69 l2cap::LinkErrorCallback link_error_callback, 70 l2cap::SecurityUpgradeCallback security_callback, 71 fit::callback<void(BrEdrFixedChannels)> fixed_channels_callback) override; 72 LEFixedChannels AddLEConnection( 73 hci_spec::ConnectionHandle handle, 74 pw::bluetooth::emboss::ConnectionRole role, 75 LinkErrorCallback link_error_callback, 76 LEConnectionParameterUpdateCallback conn_param_callback, 77 SecurityUpgradeCallback security_callback) override; 78 void RemoveConnection(hci_spec::ConnectionHandle handle) override; 79 void AssignLinkSecurityProperties(hci_spec::ConnectionHandle handle, 80 sm::SecurityProperties security) override; 81 82 // Immediately posts accept on |dispatcher|. 83 void RequestConnectionParameterUpdate( 84 hci_spec::ConnectionHandle handle, 85 hci_spec::LEPreferredConnectionParameters params, 86 ConnectionParameterUpdateRequestCallback request_cb) override; 87 OpenFixedChannel(hci_spec::ConnectionHandle,ChannelId)88 Channel::WeakPtr OpenFixedChannel(hci_spec::ConnectionHandle, 89 ChannelId) override { 90 return Channel::WeakPtr(); 91 } 92 void OpenL2capChannel(hci_spec::ConnectionHandle handle, 93 Psm psm, 94 ChannelParameters params, 95 ChannelCallback cb) override; 96 bool RegisterService(Psm psm, 97 ChannelParameters params, 98 ChannelCallback channel_callback) override; 99 void UnregisterService(Psm psm) override; 100 LogicalLinkForTesting(hci_spec::ConnectionHandle)101 WeakSelf<internal::LogicalLink>::WeakPtr LogicalLinkForTesting( 102 hci_spec::ConnectionHandle) override { 103 return WeakSelf<internal::LogicalLink>::WeakPtr(); 104 } 105 106 // Called when a new channel gets opened. Tests can use this to obtain a 107 // reference to all channels. 108 using FakeChannelCallback = 109 fit::function<void(testing::FakeChannel::WeakPtr)>; set_channel_callback(FakeChannelCallback callback)110 void set_channel_callback(FakeChannelCallback callback) { 111 chan_cb_ = std::move(callback); 112 } set_simulate_open_channel_failure(bool simulate_failure)113 void set_simulate_open_channel_failure(bool simulate_failure) { 114 simulate_open_channel_failure_ = simulate_failure; 115 } 116 117 // Called when RequestConnectionParameterUpdate is called. |request_cb| will 118 // be called with return value. Defaults to returning true if not set. 119 using ConnectionParameterUpdateRequestResponder = fit::function<bool( 120 hci_spec::ConnectionHandle, hci_spec::LEPreferredConnectionParameters)>; set_connection_parameter_update_request_responder(ConnectionParameterUpdateRequestResponder responder)121 void set_connection_parameter_update_request_responder( 122 ConnectionParameterUpdateRequestResponder responder) { 123 connection_parameter_update_request_responder_ = std::move(responder); 124 } 125 126 private: 127 // TODO(armansito): Consider moving the following logic into an internal fake 128 // that is L2CAP-specific. 129 struct ChannelData { 130 ChannelId local_id; 131 ChannelId remote_id; 132 ChannelParameters params; 133 }; 134 struct LinkData { 135 // Expectations on links can be created before they are connected. 136 bool connected; 137 hci_spec::ConnectionHandle handle; 138 pw::bluetooth::emboss::ConnectionRole role; 139 bt::LinkType type; 140 bool link_error_signaled = false; 141 142 // Dual-mode callbacks 143 LinkErrorCallback link_error_cb; 144 std::unordered_map<Psm, std::queue<ChannelData>> expected_outbound_conns; 145 146 // LE-only callbacks 147 LEConnectionParameterUpdateCallback le_conn_param_cb; 148 149 std::unordered_map<ChannelId, std::unique_ptr<FakeChannel>> channels_; 150 }; 151 152 LinkData* RegisterInternal(hci_spec::ConnectionHandle handle, 153 pw::bluetooth::emboss::ConnectionRole role, 154 bt::LinkType link_type, 155 LinkErrorCallback link_error_callback); 156 157 testing::FakeChannel::WeakPtr OpenFakeChannel( 158 LinkData* link, 159 ChannelId id, 160 ChannelId remote_id, 161 ChannelInfo info = ChannelInfo::MakeBasicMode(kDefaultMTU, kDefaultMTU)); 162 testing::FakeChannel::WeakPtr OpenFakeFixedChannel(LinkData* link, 163 ChannelId id); 164 165 // Gets the link data for |handle|, creating it if necessary. 166 LinkData& GetLinkData(hci_spec::ConnectionHandle handle); 167 // Gets the link data for |handle|. Asserts if the link is not connected yet. 168 LinkData& ConnectedLinkData(hci_spec::ConnectionHandle handle); 169 170 std::unordered_map<hci_spec::ConnectionHandle, LinkData> links_; 171 FakeChannelCallback chan_cb_; 172 bool simulate_open_channel_failure_ = false; 173 174 ConnectionParameterUpdateRequestResponder 175 connection_parameter_update_request_responder_; 176 177 std::unordered_map<Psm, ServiceInfo> registered_services_; 178 179 pw::async::HeapDispatcher heap_dispatcher_; 180 181 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeL2cap); 182 }; 183 184 } // namespace bt::l2cap::testing 185