• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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