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