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_manager.h"
17 #include "pw_bluetooth_sapphire/internal/host/l2cap/test_packets.h"
18 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
21 
22 namespace bt::l2cap {
23 
24 using TestingBase = bt::testing::ControllerTest<bt::testing::MockController>;
25 
26 // ChannelManager test fixture that uses a real AclDataChannel and uses
27 // MockController for HCI packet expectations.
28 class ChannelManagerMockControllerTest : public TestingBase {
29  public:
30   static constexpr size_t kMaxDataPacketLength = 64;
31   // High enough so that most tests don't need to worry about HCI flow control.
32   static constexpr size_t kBufferMaxNumPackets = 10;
33 
34   static constexpr l2cap::ChannelParameters kChannelParameters{
35       l2cap::RetransmissionAndFlowControlMode::kBasic,
36       l2cap::kMaxMTU,
37       std::nullopt};
38 
39   static constexpr l2cap::ExtendedFeatures kExtendedFeatures =
40       l2cap::kExtendedFeaturesBitEnhancedRetransmission;
41 
DoNothing()42   static void DoNothing() {}
NopRxCallback(ByteBufferPtr)43   static void NopRxCallback(ByteBufferPtr) {}
44 
ChannelManagerMockControllerTest(pw::async::Dispatcher & dispatcher)45   ChannelManagerMockControllerTest(pw::async::Dispatcher& dispatcher)
46       : TestingBase(dispatcher), dispatcher_(dispatcher) {}
47   ~ChannelManagerMockControllerTest() = default;
48 
49  protected:
Initialize()50   void Initialize() {
51     TestingBase::Initialize(pw::bluetooth::Controller::FeaturesBits::kHciSco);
52     const auto bredr_buffer_info =
53         hci::DataBufferInfo(kMaxDataPacketLength, kBufferMaxNumPackets);
54     InitializeACLDataChannel(bredr_buffer_info);
55 
56     // TODO(fxbug.dev/42141538): Remove assumptions about channel ordering so we
57     // can turn random ids on.
58     channel_manager_ = ChannelManager::Create(transport()->acl_data_channel(),
59                                               transport()->command_channel(),
60                                               /*random_channel_ids=*/false,
61                                               dispatcher_);
62 
63     next_command_id_ = 1;
64   }
65 
Initialize(size_t max_acl_payload_size,size_t max_le_payload_size,size_t max_acl_packets,size_t max_le_packets)66   void Initialize(size_t max_acl_payload_size,
67                   size_t max_le_payload_size,
68                   size_t max_acl_packets,
69                   size_t max_le_packets) {
70     TestingBase::Initialize(pw::bluetooth::Controller::FeaturesBits::kHciSco);
71 
72     InitializeACLDataChannel(
73         hci::DataBufferInfo(max_acl_payload_size, max_acl_packets),
74         hci::DataBufferInfo(max_le_payload_size, max_le_packets));
75 
76     channel_manager_ = ChannelManager::Create(transport()->acl_data_channel(),
77                                               transport()->command_channel(),
78                                               /*random_channel_ids=*/false,
79                                               dispatcher_);
80 
81     next_command_id_ = 1;
82   }
83 
DeleteChannelManager()84   void DeleteChannelManager() { channel_manager_ = nullptr; }
85 
NextCommandId()86   l2cap::CommandId NextCommandId() { return next_command_id_++; }
87 
QueueConfigNegotiation(hci_spec::ConnectionHandle handle,l2cap::ChannelParameters local_params,l2cap::ChannelParameters peer_params,l2cap::ChannelId local_cid,l2cap::ChannelId remote_cid,l2cap::CommandId local_config_req_id,l2cap::CommandId peer_config_req_id)88   void QueueConfigNegotiation(hci_spec::ConnectionHandle handle,
89                               l2cap::ChannelParameters local_params,
90                               l2cap::ChannelParameters peer_params,
91                               l2cap::ChannelId local_cid,
92                               l2cap::ChannelId remote_cid,
93                               l2cap::CommandId local_config_req_id,
94                               l2cap::CommandId peer_config_req_id) {
95     const auto kPeerConfigRsp = l2cap::testing::AclConfigRsp(
96         local_config_req_id, handle, local_cid, local_params);
97     const auto kPeerConfigReq = l2cap::testing::AclConfigReq(
98         peer_config_req_id, handle, local_cid, peer_params);
99     EXPECT_ACL_PACKET_OUT(
100         test_device(),
101         l2cap::testing::AclConfigReq(
102             local_config_req_id, handle, remote_cid, local_params),
103         &kPeerConfigRsp,
104         &kPeerConfigReq);
105     EXPECT_ACL_PACKET_OUT(
106         test_device(),
107         l2cap::testing::AclConfigRsp(
108             peer_config_req_id, handle, remote_cid, peer_params));
109   }
110 
111   void QueueInboundL2capConnection(
112       hci_spec::ConnectionHandle handle,
113       l2cap::Psm psm,
114       l2cap::ChannelId local_cid,
115       l2cap::ChannelId remote_cid,
116       l2cap::ChannelParameters local_params = kChannelParameters,
117       l2cap::ChannelParameters peer_params = kChannelParameters) {
118     const l2cap::CommandId kPeerConnReqId = 1;
119     const l2cap::CommandId kPeerConfigReqId = kPeerConnReqId + 1;
120     const auto kConfigReqId = NextCommandId();
121     EXPECT_ACL_PACKET_OUT(test_device(),
122                           l2cap::testing::AclConnectionRsp(
123                               kPeerConnReqId, handle, remote_cid, local_cid));
124     QueueConfigNegotiation(handle,
125                            local_params,
126                            peer_params,
127                            local_cid,
128                            remote_cid,
129                            kConfigReqId,
130                            kPeerConfigReqId);
131 
132     test_device()->SendACLDataChannelPacket(l2cap::testing::AclConnectionReq(
133         kPeerConnReqId, handle, remote_cid, psm));
134   }
135 
136   void QueueOutboundL2capConnection(
137       hci_spec::ConnectionHandle handle,
138       l2cap::Psm psm,
139       l2cap::ChannelId local_cid,
140       l2cap::ChannelId remote_cid,
141       ChannelCallback open_cb,
142       l2cap::ChannelParameters local_params = kChannelParameters,
143       l2cap::ChannelParameters peer_params = kChannelParameters) {
144     const l2cap::CommandId kPeerConfigReqId = 1;
145     const auto kConnReqId = NextCommandId();
146     const auto kConfigReqId = NextCommandId();
147     const auto kConnRsp = l2cap::testing::AclConnectionRsp(
148         kConnReqId, handle, local_cid, remote_cid);
149     EXPECT_ACL_PACKET_OUT(
150         test_device(),
151         l2cap::testing::AclConnectionReq(kConnReqId, handle, local_cid, psm),
152         &kConnRsp);
153     QueueConfigNegotiation(handle,
154                            local_params,
155                            peer_params,
156                            local_cid,
157                            remote_cid,
158                            kConfigReqId,
159                            kPeerConfigReqId);
160 
161     chanmgr()->OpenL2capChannel(handle, psm, local_params, std::move(open_cb));
162   }
163 
164   struct QueueAclConnectionRetVal {
165     l2cap::CommandId extended_features_id;
166     l2cap::CommandId fixed_channels_supported_id;
167     ChannelManager::BrEdrFixedChannels fixed_channels;
168   };
169 
170   QueueAclConnectionRetVal QueueAclConnection(
171       hci_spec::ConnectionHandle handle,
172       pw::bluetooth::emboss::ConnectionRole role =
173           pw::bluetooth::emboss::ConnectionRole::CENTRAL) {
174     QueueAclConnectionRetVal return_val;
175     return_val.extended_features_id = NextCommandId();
176     return_val.fixed_channels_supported_id = NextCommandId();
177 
178     const auto kExtFeaturesRsp = l2cap::testing::AclExtFeaturesInfoRsp(
179         return_val.extended_features_id, handle, kExtendedFeatures);
180     EXPECT_ACL_PACKET_OUT(test_device(),
181                           l2cap::testing::AclExtFeaturesInfoReq(
182                               return_val.extended_features_id, handle),
183                           &kExtFeaturesRsp);
184     EXPECT_ACL_PACKET_OUT(test_device(),
185                           l2cap::testing::AclFixedChannelsSupportedInfoReq(
186                               return_val.fixed_channels_supported_id, handle));
187 
188     return_val.fixed_channels = chanmgr()->AddACLConnection(
189         handle,
190         role,
191         /*link_error_callback=*/[]() {},
192         /*security_callback=*/[](auto, auto, auto) {});
193 
194     return return_val;
195   }
196 
QueueLEConnection(hci_spec::ConnectionHandle handle,pw::bluetooth::emboss::ConnectionRole role)197   ChannelManager::LEFixedChannels QueueLEConnection(
198       hci_spec::ConnectionHandle handle,
199       pw::bluetooth::emboss::ConnectionRole role) {
200     return chanmgr()->AddLEConnection(
201         handle,
202         role,
203         /*link_error_callback=*/[] {},
204         /*conn_param_callback=*/[](auto&) {},
205         /*security_callback=*/[](auto, auto, auto) {});
206   }
207 
208   Channel::WeakPtr ActivateNewFixedChannel(
209       ChannelId id,
210       hci_spec::ConnectionHandle conn_handle = 0x0001,
211       Channel::ClosedCallback closed_cb = DoNothing,
212       Channel::RxCallback rx_cb = NopRxCallback) {
213     auto chan = chanmgr()->OpenFixedChannel(conn_handle, id);
214     if (!chan.is_alive() ||
215         !chan->Activate(std::move(rx_cb), std::move(closed_cb))) {
216       return Channel::WeakPtr();
217     }
218 
219     return chan;
220   }
221 
chanmgr()222   ChannelManager* chanmgr() const { return channel_manager_.get(); }
223 
224  private:
225   std::unique_ptr<ChannelManager> channel_manager_;
226   l2cap::CommandId next_command_id_;
227   pw::async::Dispatcher& dispatcher_;
228 
229   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(ChannelManagerMockControllerTest);
230 };
231 
232 class FakeDispatcherChannelManagerMockControllerTest
233     : public pw::async::test::FakeDispatcherFixture,
234       public ChannelManagerMockControllerTest {
235  protected:
FakeDispatcherChannelManagerMockControllerTest()236   FakeDispatcherChannelManagerMockControllerTest()
237       : ChannelManagerMockControllerTest(dispatcher()) {}
238 
SetUp()239   void SetUp() override { Initialize(); }
240 
241   void SetUp(size_t max_acl_payload_size,
242              size_t max_le_payload_size,
243              size_t max_acl_packets = kBufferMaxNumPackets,
244              size_t max_le_packets = kBufferMaxNumPackets) {
245     Initialize(max_acl_payload_size,
246                max_le_payload_size,
247                max_acl_packets,
248                max_le_packets);
249   }
250 
TearDown()251   void TearDown() override {
252     DeleteChannelManager();
253     RunUntilIdle();
254     DeleteTransport();
255   }
256 };
257 
258 }  // namespace bt::l2cap
259