xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/proxy_host_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 #include "pw_bluetooth_proxy/proxy_host.h"
16 
17 #include <cstdint>
18 #include <numeric>
19 
20 #include "pw_bluetooth/att.emb.h"
21 #include "pw_bluetooth/emboss_util.h"
22 #include "pw_bluetooth/hci_commands.emb.h"
23 #include "pw_bluetooth/hci_common.emb.h"
24 #include "pw_bluetooth/hci_data.emb.h"
25 #include "pw_bluetooth/hci_events.emb.h"
26 #include "pw_bluetooth/hci_h4.emb.h"
27 #include "pw_bluetooth/l2cap_frames.emb.h"
28 #include "pw_bluetooth/rfcomm_frames.emb.h"
29 #include "pw_bluetooth_proxy/h4_packet.h"
30 #include "pw_bluetooth_proxy/internal/logical_transport.h"
31 #include "pw_containers/flat_map.h"
32 #include "pw_function/function.h"
33 #include "pw_status/status.h"
34 #include "pw_status/try.h"
35 #include "pw_unit_test/framework.h"  // IWYU pragma: keep
36 
37 namespace pw::bluetooth::proxy {
38 
39 namespace {
40 
41 using containers::FlatMap;
42 
43 // TODO: https://pwbug.dev/349700888 - Once size is configurable, switch to
44 // specifying directly. Until then this should match
45 // AclConnection::kMaxConnections.
46 static constexpr size_t kMaxProxyActiveConnections = 10;
47 
48 // ########## Util functions
49 
50 // Populate passed H4 command buffer and return Emboss view on it.
51 template <typename EmbossT>
CreateAndPopulateToControllerView(H4PacketWithH4 & h4_packet,emboss::OpCode opcode)52 Result<EmbossT> CreateAndPopulateToControllerView(H4PacketWithH4& h4_packet,
53                                                   emboss::OpCode opcode) {
54   std::iota(h4_packet.GetHciSpan().begin(), h4_packet.GetHciSpan().end(), 100);
55   h4_packet.SetH4Type(emboss::H4PacketType::COMMAND);
56   PW_TRY_ASSIGN(auto view, MakeEmbossWriter<EmbossT>(h4_packet.GetHciSpan()));
57   view.header().opcode_enum().Write(opcode);
58   return view;
59 }
60 
61 // Return a populated H4 command buffer of a type that proxy host doesn't
62 // interact with.
PopulateNoninteractingToControllerBuffer(H4PacketWithH4 & h4_packet)63 Status PopulateNoninteractingToControllerBuffer(H4PacketWithH4& h4_packet) {
64   return CreateAndPopulateToControllerView<emboss::InquiryCommandWriter>(
65              h4_packet, emboss::OpCode::LINK_KEY_REQUEST_REPLY)
66       .status();
67 }
68 
69 // Populate passed H4 event buffer and return Emboss view on it.
70 template <typename EmbossT>
CreateAndPopulateToHostEventView(H4PacketWithHci & h4_packet,emboss::EventCode event_code)71 Result<EmbossT> CreateAndPopulateToHostEventView(H4PacketWithHci& h4_packet,
72                                                  emboss::EventCode event_code) {
73   std::iota(h4_packet.GetHciSpan().begin(), h4_packet.GetHciSpan().end(), 0x10);
74   h4_packet.SetH4Type(emboss::H4PacketType::EVENT);
75 
76   PW_TRY_ASSIGN(auto view, MakeEmbossWriter<EmbossT>(h4_packet.GetHciSpan()));
77   view.header().event_code_enum().Write(event_code);
78   view.status().Write(emboss::StatusCode::SUCCESS);
79   EXPECT_TRUE(view.Ok());
80   return view;
81 }
82 
83 // Send an LE_Read_Buffer_Size (V2) CommandComplete event to `proxy` to request
84 // the reservation of a number of LE ACL send credits.
SendLeReadBufferResponseFromController(ProxyHost & proxy,uint8_t num_credits_to_reserve)85 Status SendLeReadBufferResponseFromController(ProxyHost& proxy,
86                                               uint8_t num_credits_to_reserve) {
87   std::array<
88       uint8_t,
89       emboss::LEReadBufferSizeV2CommandCompleteEventWriter::SizeInBytes()>
90       hci_arr;
91   hci_arr.fill(0);
92   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
93   PW_TRY_ASSIGN(auto view,
94                 CreateAndPopulateToHostEventView<
95                     emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(
96                     h4_packet, emboss::EventCode::COMMAND_COMPLETE));
97   view.command_complete().command_opcode_enum().Write(
98       emboss::OpCode::LE_READ_BUFFER_SIZE_V2);
99   view.total_num_le_acl_data_packets().Write(num_credits_to_reserve);
100 
101   proxy.HandleH4HciFromController(std::move(h4_packet));
102   return OkStatus();
103 }
104 
SendReadBufferResponseFromController(ProxyHost & proxy,uint8_t num_credits_to_reserve)105 Status SendReadBufferResponseFromController(ProxyHost& proxy,
106                                             uint8_t num_credits_to_reserve) {
107   std::array<uint8_t,
108              emboss::ReadBufferSizeCommandCompleteEventWriter::SizeInBytes()>
109       hci_arr{};
110   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
111   PW_TRY_ASSIGN(auto view,
112                 CreateAndPopulateToHostEventView<
113                     emboss::ReadBufferSizeCommandCompleteEventWriter>(
114                     h4_packet, emboss::EventCode::COMMAND_COMPLETE));
115   view.command_complete().command_opcode_enum().Write(
116       emboss::OpCode::READ_BUFFER_SIZE);
117   view.total_num_acl_data_packets().Write(num_credits_to_reserve);
118   EXPECT_TRUE(view.Ok());
119 
120   proxy.HandleH4HciFromController(std::move(h4_packet));
121   return OkStatus();
122 }
123 
124 // Send a Number_of_Completed_Packets event to `proxy` that reports each
125 // {connection handle, number of completed packets} entry provided.
126 template <size_t kNumConnections>
SendNumberOfCompletedPackets(ProxyHost & proxy,FlatMap<uint16_t,uint16_t,kNumConnections> packets_per_connection)127 Status SendNumberOfCompletedPackets(
128     ProxyHost& proxy,
129     FlatMap<uint16_t, uint16_t, kNumConnections> packets_per_connection) {
130   std::array<
131       uint8_t,
132       emboss::NumberOfCompletedPacketsEvent::MinSizeInBytes() +
133           kNumConnections *
134               emboss::NumberOfCompletedPacketsEventData::IntrinsicSizeInBytes()>
135       hci_arr;
136   hci_arr.fill(0);
137   H4PacketWithHci nocp_event{emboss::H4PacketType::EVENT, hci_arr};
138   PW_TRY_ASSIGN(auto view,
139                 MakeEmbossWriter<emboss::NumberOfCompletedPacketsEventWriter>(
140                     nocp_event.GetHciSpan()));
141   view.header().event_code_enum().Write(
142       emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
143   view.num_handles().Write(kNumConnections);
144 
145   size_t i = 0;
146   for (const auto& [handle, num_packets] : packets_per_connection) {
147     view.nocp_data()[i].connection_handle().Write(handle);
148     view.nocp_data()[i].num_completed_packets().Write(num_packets);
149     ++i;
150   }
151 
152   proxy.HandleH4HciFromController(std::move(nocp_event));
153   return OkStatus();
154 }
155 
156 // Send a Connection_Complete event to `proxy` indicating the provided
157 // `handle` has disconnected.
SendConnectionCompleteEvent(ProxyHost & proxy,uint16_t handle,emboss::StatusCode status)158 Status SendConnectionCompleteEvent(ProxyHost& proxy,
159                                    uint16_t handle,
160                                    emboss::StatusCode status) {
161   std::array<uint8_t, emboss::ConnectionCompleteEvent::IntrinsicSizeInBytes()>
162       hci_arr_dc{};
163   H4PacketWithHci dc_event{emboss::H4PacketType::EVENT, hci_arr_dc};
164   PW_TRY_ASSIGN(auto view,
165                 MakeEmbossWriter<emboss::ConnectionCompleteEventWriter>(
166                     dc_event.GetHciSpan()));
167   view.header().event_code_enum().Write(emboss::EventCode::CONNECTION_COMPLETE);
168   view.status().Write(status);
169   view.connection_handle().Write(handle);
170   proxy.HandleH4HciFromController(std::move(dc_event));
171   return OkStatus();
172 }
173 
174 // Send a LE_Connection_Complete event to `proxy` indicating the provided
175 // `handle` has disconnected.
SendLeConnectionCompleteEvent(ProxyHost & proxy,uint16_t handle,emboss::StatusCode status)176 Status SendLeConnectionCompleteEvent(ProxyHost& proxy,
177                                      uint16_t handle,
178                                      emboss::StatusCode status) {
179   std::array<uint8_t,
180              emboss::LEConnectionCompleteSubevent::IntrinsicSizeInBytes()>
181       hci_arr_dc{};
182   H4PacketWithHci dc_event{emboss::H4PacketType::EVENT, hci_arr_dc};
183   PW_TRY_ASSIGN(auto view,
184                 MakeEmbossWriter<emboss::LEConnectionCompleteSubeventWriter>(
185                     dc_event.GetHciSpan()));
186   view.le_meta_event().header().event_code_enum().Write(
187       emboss::EventCode::LE_META_EVENT);
188   view.le_meta_event().subevent_code_enum().Write(
189       emboss::LeSubEventCode::CONNECTION_COMPLETE);
190   view.status().Write(status);
191   view.connection_handle().Write(handle);
192   proxy.HandleH4HciFromController(std::move(dc_event));
193   return OkStatus();
194 }
195 
196 // Send a Disconnection_Complete event to `proxy` indicating the provided
197 // `handle` has disconnected.
SendDisconnectionCompleteEvent(ProxyHost & proxy,uint16_t handle,bool successful=true)198 Status SendDisconnectionCompleteEvent(ProxyHost& proxy,
199                                       uint16_t handle,
200                                       bool successful = true) {
201   std::array<uint8_t,
202              emboss::DisconnectionCompleteEvent::IntrinsicSizeInBytes()>
203       hci_arr_dc;
204   hci_arr_dc.fill(0);
205   H4PacketWithHci dc_event{emboss::H4PacketType::EVENT, hci_arr_dc};
206   PW_TRY_ASSIGN(auto view,
207                 MakeEmbossWriter<emboss::DisconnectionCompleteEventWriter>(
208                     dc_event.GetHciSpan()));
209   view.header().event_code_enum().Write(
210       emboss::EventCode::DISCONNECTION_COMPLETE);
211   view.status().Write(successful ? emboss::StatusCode::SUCCESS
212                                  : emboss::StatusCode::HARDWARE_FAILURE);
213   view.connection_handle().Write(handle);
214   proxy.HandleH4HciFromController(std::move(dc_event));
215   return OkStatus();
216 }
217 
218 // Return a populated H4 event buffer of a type that proxy host doesn't interact
219 // with.
CreateNonInteractingToHostBuffer(H4PacketWithHci & h4_packet)220 Status CreateNonInteractingToHostBuffer(H4PacketWithHci& h4_packet) {
221   return CreateAndPopulateToHostEventView<emboss::InquiryCompleteEventWriter>(
222              h4_packet, emboss::EventCode::INQUIRY_COMPLETE)
223       .status();
224 }
225 
226 struct CocParameters {
227   uint16_t handle = 123;
228   uint16_t local_cid = 234;
229   uint16_t remote_cid = 456;
230   uint16_t rx_mtu = 100;
231   uint16_t rx_mps = 100;
232   uint16_t rx_credits = 1;
233   uint16_t tx_mtu = 100;
234   uint16_t tx_mps = 100;
235   uint16_t tx_credits = 1;
236   pw::Function<void(pw::span<uint8_t> payload)>&& receive_fn = nullptr;
237   pw::Function<void(L2capCoc::Event event)>&& event_fn = nullptr;
238   uint16_t rx_additional_credits = 0;
239 };
240 
241 // Open and return an L2CAP connection-oriented channel managed by `proxy`.
BuildCoc(ProxyHost & proxy,CocParameters params)242 L2capCoc BuildCoc(ProxyHost& proxy, CocParameters params) {
243   pw::Result<L2capCoc> channel =
244       proxy.AcquireL2capCoc(params.handle,
245                             {.cid = params.local_cid,
246                              .mtu = params.rx_mtu,
247                              .mps = params.rx_mps,
248                              .credits = params.rx_credits},
249                             {.cid = params.remote_cid,
250                              .mtu = params.tx_mtu,
251                              .mps = params.tx_mps,
252                              .credits = params.tx_credits},
253                             std::move(params.receive_fn),
254                             std::move(params.event_fn),
255                             params.rx_additional_credits);
256   return std::move(channel.value());
257 }
258 
259 struct RfcommParameters {
260   uint16_t handle = 123;
261   RfcommChannel::Config rx_config = {
262       .cid = 234, .max_information_length = 900, .credits = 10};
263   RfcommChannel::Config tx_config = {
264       .cid = 456, .max_information_length = 900, .credits = 10};
265   uint8_t rfcomm_channel = 3;
266 };
267 
BuildRfcomm(ProxyHost & proxy,RfcommParameters params)268 RfcommChannel BuildRfcomm(ProxyHost& proxy, RfcommParameters params) {
269   pw::Result<RfcommChannel> channel =
270       proxy.AcquireRfcommChannel(params.handle,
271                                  params.rx_config,
272                                  params.tx_config,
273                                  params.rfcomm_channel,
274                                  nullptr);
275   PW_TEST_EXPECT_OK(channel);
276   return std::move((channel.value()));
277 }
278 
279 // ########## Examples
280 
281 // Example for docs.rst.
TEST(Example,ExampleUsage)282 TEST(Example, ExampleUsage) {
283   // Populate H4 buffer to send towards controller.
284   std::array<uint8_t, emboss::InquiryCommandView::SizeInBytes() + 1>
285       h4_array_from_host{};
286   H4PacketWithH4 h4_packet_from_host{emboss::H4PacketType::UNKNOWN,
287                                      h4_array_from_host};
288   PW_TEST_EXPECT_OK(
289       PopulateNoninteractingToControllerBuffer(h4_packet_from_host));
290 
291   // Populate H4 buffer to send towards host.
292   std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes() + 1>
293       hci_array_from_controller{};
294   H4PacketWithHci h4_packet_from_controller{emboss::H4PacketType::UNKNOWN,
295                                             hci_array_from_controller};
296 
297   PW_TEST_EXPECT_OK(
298       CreateNonInteractingToHostBuffer(h4_packet_from_controller));
299 
300   pw::Function<void(H4PacketWithHci && packet)> container_send_to_host_fn(
301       []([[maybe_unused]] H4PacketWithHci&& packet) {});
302 
303   pw::Function<void(H4PacketWithH4 && packet)> container_send_to_controller_fn(
304       ([]([[maybe_unused]] H4PacketWithH4&& packet) {}));
305 
306   // DOCSTAG: [pw_bluetooth_proxy-examples-basic]
307 
308 #include "pw_bluetooth_proxy/proxy_host.h"
309 
310   // Container creates ProxyHost .
311   ProxyHost proxy = ProxyHost(std::move(container_send_to_host_fn),
312                               std::move(container_send_to_controller_fn),
313                               2);
314 
315   // Container passes H4 packets from host through proxy. Proxy will in turn
316   // call the container-provided `container_send_to_controller_fn` to pass them
317   // on to the controller. Some packets may be modified, added, or removed.
318   proxy.HandleH4HciFromHost(std::move(h4_packet_from_host));
319 
320   // Container passes H4 packets from controller through proxy. Proxy will in
321   // turn call the container-provided `container_send_to_host_fn` to pass them
322   // on to the controller. Some packets may be modified, added, or removed.
323   proxy.HandleH4HciFromController(std::move(h4_packet_from_controller));
324 
325   // DOCSTAG: [pw_bluetooth_proxy-examples-basic]
326 }
327 
328 // ########## PassthroughTest
329 
330 // Verify buffer is properly passed (contents unaltered and zero-copy).
TEST(PassthroughTest,ToControllerPassesEqualBuffer)331 TEST(PassthroughTest, ToControllerPassesEqualBuffer) {
332   std::array<uint8_t, emboss::InquiryCommandView::SizeInBytes() + 1> h4_arr{};
333   H4PacketWithH4 h4_packet{emboss::H4PacketType::UNKNOWN, h4_arr};
334   PW_TEST_EXPECT_OK(PopulateNoninteractingToControllerBuffer(h4_packet));
335 
336   // Struct for capturing because `pw::Function` can't fit multiple captures.
337   struct {
338     // Use a copy for comparison to catch if proxy incorrectly changes the
339     // passed buffer.
340     std::array<uint8_t, emboss::InquiryCommandView::SizeInBytes() + 1> h4_arr;
341     H4PacketWithH4* h4_packet;
342     uint8_t sends_called;
343   } send_capture = {h4_arr, &h4_packet, 0};
344 
345   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
346       [&send_capture](H4PacketWithH4&& packet) {
347         send_capture.sends_called++;
348         EXPECT_EQ(packet.GetH4Type(),
349                   emboss::H4PacketType(send_capture.h4_arr[0]));
350         EXPECT_TRUE(std::equal(send_capture.h4_packet->GetHciSpan().begin(),
351                                send_capture.h4_packet->GetHciSpan().end(),
352                                send_capture.h4_arr.begin() + 1,
353                                send_capture.h4_arr.end()));
354         // Verify no copy by verifying buffer is at the same memory location.
355         EXPECT_EQ(packet.GetHciSpan().data(),
356                   send_capture.h4_packet->GetHciSpan().data());
357       });
358 
359   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
360       []([[maybe_unused]] H4PacketWithHci&& packet) {});
361 
362   ProxyHost proxy = ProxyHost(
363       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
364 
365   proxy.HandleH4HciFromHost(std::move(h4_packet));
366 
367   // Verify to controller callback was called.
368   EXPECT_EQ(send_capture.sends_called, 1);
369 }
370 
371 // Verify buffer is properly passed (contents unaltered and zero-copy).
TEST(PassthroughTest,ToHostPassesEqualBuffer)372 TEST(PassthroughTest, ToHostPassesEqualBuffer) {
373   std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes()>
374       hci_arr{};
375   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
376   PW_TEST_EXPECT_OK(CreateNonInteractingToHostBuffer(h4_packet));
377 
378   // Struct for capturing because `pw::Function` can't fit multiple captures.
379   struct {
380     // Use a copy for comparison to catch if proxy incorrectly changes the
381     // passed buffer.
382     std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes()>
383         hci_arr;
384     H4PacketWithHci* h4_packet;
385     uint8_t sends_called;
386   } send_capture = {hci_arr, &h4_packet, 0};
387 
388   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
389       [&send_capture](H4PacketWithHci&& packet) {
390         send_capture.sends_called++;
391         EXPECT_EQ(packet.GetH4Type(), send_capture.h4_packet->GetH4Type());
392         EXPECT_TRUE(std::equal(send_capture.h4_packet->GetHciSpan().begin(),
393                                send_capture.h4_packet->GetHciSpan().end(),
394                                send_capture.h4_packet->GetHciSpan().begin(),
395                                send_capture.h4_packet->GetHciSpan().end()));
396         // Verify no copy by verifying buffer is at the same memory location.
397         EXPECT_EQ(packet.GetHciSpan().data(),
398                   send_capture.h4_packet->GetHciSpan().data());
399       });
400 
401   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
402       []([[maybe_unused]] H4PacketWithH4&& packet) {});
403 
404   ProxyHost proxy = ProxyHost(
405       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
406 
407   proxy.HandleH4HciFromController(std::move(h4_packet));
408 
409   // Verify to controller callback was called.
410   EXPECT_EQ(send_capture.sends_called, 1);
411 }
412 
413 // Verify a command complete event (of a type that proxy doesn't act on) is
414 // properly passed (contents unaltered and zero-copy).
TEST(PassthroughTest,ToHostPassesEqualCommandComplete)415 TEST(PassthroughTest, ToHostPassesEqualCommandComplete) {
416   std::array<
417       uint8_t,
418       emboss::ReadLocalVersionInfoCommandCompleteEventWriter::SizeInBytes()>
419       hci_arr{};
420   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
421   PW_TEST_ASSERT_OK_AND_ASSIGN(
422       auto view,
423       CreateAndPopulateToHostEventView<
424           emboss::ReadLocalVersionInfoCommandCompleteEventWriter>(
425           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
426   view.command_complete().command_opcode_enum().Write(
427       emboss::OpCode::READ_LOCAL_VERSION_INFO);
428 
429   // Struct for capturing because `pw::Function` can't fit multiple captures.
430   struct {
431     std::array<
432         uint8_t,
433         emboss::ReadLocalVersionInfoCommandCompleteEventWriter::SizeInBytes()>
434         hci_arr;
435     H4PacketWithHci* h4_packet;
436     uint8_t sends_called;
437   } send_capture = {hci_arr, &h4_packet, 0};
438 
439   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
440       [&send_capture](H4PacketWithHci&& packet) {
441         send_capture.sends_called++;
442         EXPECT_EQ(packet.GetH4Type(), send_capture.h4_packet->GetH4Type());
443         EXPECT_TRUE(std::equal(send_capture.h4_packet->GetHciSpan().begin(),
444                                send_capture.h4_packet->GetHciSpan().end(),
445                                send_capture.h4_packet->GetHciSpan().begin(),
446                                send_capture.h4_packet->GetHciSpan().end()));
447         // Verify no copy by verifying buffer is at the same memory location.
448         EXPECT_EQ(packet.GetHciSpan().data(),
449                   send_capture.h4_packet->GetHciSpan().data());
450       });
451 
452   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
453       []([[maybe_unused]] H4PacketWithH4&& packet) {});
454 
455   ProxyHost proxy = ProxyHost(
456       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
457 
458   proxy.HandleH4HciFromController(std::move(h4_packet));
459 
460   // Verify to controller callback was called.
461   EXPECT_EQ(send_capture.sends_called, 1);
462 }
463 
464 // ########## BadPacketTest
465 // The proxy should not affect buffers it can't process (it should just pass
466 // them on).
467 
TEST(BadPacketTest,BadH4TypeToControllerIsPassedOn)468 TEST(BadPacketTest, BadH4TypeToControllerIsPassedOn) {
469   std::array<uint8_t, emboss::InquiryCommandView::SizeInBytes() + 1> h4_arr{};
470   H4PacketWithH4 h4_packet{emboss::H4PacketType::UNKNOWN, h4_arr};
471   PW_TEST_EXPECT_OK(PopulateNoninteractingToControllerBuffer(h4_packet));
472   // Set back to an invalid type (after
473   // PopulateNoninteractingToControllerBuffer).
474   h4_packet.SetH4Type(emboss::H4PacketType::UNKNOWN);
475 
476   // Struct for capturing because `pw::Function` can't fit multiple captures.
477   struct {
478     // Use a copy for comparison to catch if proxy incorrectly changes the
479     // passed buffer.
480     std::array<uint8_t, emboss::InquiryCommandView::SizeInBytes() + 1> h4_arr;
481     H4PacketWithH4* h4_packet;
482     uint8_t sends_called;
483   } send_capture = {h4_arr, &h4_packet, 0};
484 
485   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
486       [&send_capture](H4PacketWithH4&& packet) {
487         send_capture.sends_called++;
488         EXPECT_EQ(packet.GetH4Type(),
489                   emboss::H4PacketType(send_capture.h4_arr[0]));
490         EXPECT_TRUE(std::equal(send_capture.h4_packet->GetHciSpan().begin(),
491                                send_capture.h4_packet->GetHciSpan().end(),
492                                send_capture.h4_arr.begin() + 1,
493                                send_capture.h4_arr.end()));
494         // Verify no copy by verifying buffer is at the same memory location.
495         EXPECT_EQ(packet.GetHciSpan().data(),
496                   send_capture.h4_packet->GetHciSpan().data());
497       });
498 
499   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
500       []([[maybe_unused]] H4PacketWithHci&& packet) {});
501 
502   ProxyHost proxy = ProxyHost(
503       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
504 
505   proxy.HandleH4HciFromHost(std::move(h4_packet));
506 
507   // Verify to controller callback was called.
508   EXPECT_EQ(send_capture.sends_called, 1);
509 }
510 
TEST(BadPacketTest,BadH4TypeToHostIsPassedOn)511 TEST(BadPacketTest, BadH4TypeToHostIsPassedOn) {
512   std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes()>
513       hci_arr{};
514   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
515   PW_TEST_EXPECT_OK(CreateNonInteractingToHostBuffer(h4_packet));
516 
517   // Set back to an invalid type.
518   h4_packet.SetH4Type(emboss::H4PacketType::UNKNOWN);
519 
520   // Struct for capturing because `pw::Function` can't fit multiple captures.
521   struct {
522     // Use a copy for comparison to catch if proxy incorrectly changes the
523     // passed buffer.
524     std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes()>
525         hci_arr;
526     H4PacketWithHci* h4_packet;
527     uint8_t sends_called = 0;
528   } send_capture = {hci_arr, &h4_packet, 0};
529 
530   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
531       [&send_capture](H4PacketWithHci&& packet) {
532         send_capture.sends_called++;
533         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
534         EXPECT_TRUE(std::equal(send_capture.h4_packet->GetHciSpan().begin(),
535                                send_capture.h4_packet->GetHciSpan().end(),
536                                send_capture.h4_packet->GetHciSpan().begin(),
537                                send_capture.h4_packet->GetHciSpan().end()));
538         // Verify no copy by verifying buffer is at the same memory location.
539         EXPECT_EQ(packet.GetHciSpan().data(),
540                   send_capture.h4_packet->GetHciSpan().data());
541       });
542 
543   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
544       []([[maybe_unused]] H4PacketWithH4&& packet) {});
545 
546   ProxyHost proxy = ProxyHost(
547       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
548 
549   proxy.HandleH4HciFromController(std::move(h4_packet));
550 
551   // Verify to controller callback was called.
552   EXPECT_EQ(send_capture.sends_called, 1);
553 }
554 
TEST(BadPacketTest,EmptyBufferToControllerIsPassedOn)555 TEST(BadPacketTest, EmptyBufferToControllerIsPassedOn) {
556   std::array<uint8_t, 0> h4_arr;
557   H4PacketWithH4 h4_packet{emboss::H4PacketType::COMMAND, h4_arr};
558   // H4PacketWithH4 use the underlying h4 buffer to store type. Since its length
559   // is zero, it can't store it and will always return UNKNOWN.
560   EXPECT_EQ(h4_packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
561 
562   uint8_t sends_called = 0;
563   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
564       [&sends_called](H4PacketWithH4&& packet) {
565         sends_called++;
566         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::UNKNOWN);
567         EXPECT_TRUE(packet.GetHciSpan().empty());
568       });
569 
570   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
571       []([[maybe_unused]] H4PacketWithHci&& packet) {});
572 
573   ProxyHost proxy = ProxyHost(
574       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
575 
576   proxy.HandleH4HciFromHost(std::move(h4_packet));
577 
578   // Verify callback was called.
579   EXPECT_EQ(sends_called, 1);
580 }
581 
TEST(BadPacketTest,EmptyBufferToHostIsPassedOn)582 TEST(BadPacketTest, EmptyBufferToHostIsPassedOn) {
583   std::array<uint8_t, 0> hci_arr;
584   H4PacketWithHci h4_packet{emboss::H4PacketType::EVENT, hci_arr};
585 
586   uint8_t sends_called = 0;
587   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
588       [&sends_called](H4PacketWithHci&& packet) {
589         sends_called++;
590         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::EVENT);
591         EXPECT_TRUE(packet.GetHciSpan().empty());
592       });
593 
594   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
595       []([[maybe_unused]] H4PacketWithH4&& packet) {});
596 
597   ProxyHost proxy = ProxyHost(
598       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
599 
600   proxy.HandleH4HciFromController(std::move(h4_packet));
601 
602   // Verify callback was called.
603   EXPECT_EQ(sends_called, 1);
604 }
605 
TEST(BadPacketTest,TooShortEventToHostIsPassOn)606 TEST(BadPacketTest, TooShortEventToHostIsPassOn) {
607   std::array<uint8_t, emboss::InquiryCompleteEventView::SizeInBytes()>
608       valid_hci_arr{};
609   H4PacketWithHci valid_packet{emboss::H4PacketType::UNKNOWN, valid_hci_arr};
610   PW_TEST_EXPECT_OK(CreateNonInteractingToHostBuffer(valid_packet));
611 
612   // Create packet for sending whose span size is one less than a valid command
613   // complete event.
614   H4PacketWithHci h4_packet{valid_packet.GetH4Type(),
615                             valid_packet.GetHciSpan().subspan(
616                                 0, emboss::EventHeaderView::SizeInBytes() - 1)};
617 
618   // Struct for capturing because `pw::Function` can't fit multiple captures.
619   struct {
620     std::array<uint8_t, emboss::EventHeaderView::SizeInBytes() - 1> hci_arr;
621     uint8_t sends_called = 0;
622   } send_capture;
623   // Copy valid event into a short_array whose size is one less than a valid
624   // EventHeader.
625   std::copy(h4_packet.GetHciSpan().begin(),
626             h4_packet.GetHciSpan().end(),
627             send_capture.hci_arr.begin());
628   send_capture.sends_called = 0;
629 
630   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
631       [&send_capture](H4PacketWithHci&& packet) {
632         send_capture.sends_called++;
633         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
634                                packet.GetHciSpan().end(),
635                                send_capture.hci_arr.begin(),
636                                send_capture.hci_arr.end()));
637       });
638 
639   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
640       []([[maybe_unused]] H4PacketWithH4&& packet) {});
641 
642   ProxyHost proxy = ProxyHost(
643       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
644 
645   proxy.HandleH4HciFromController(std::move(h4_packet));
646 
647   // Verify callback was called.
648   EXPECT_EQ(send_capture.sends_called, 1);
649 }
650 
TEST(BadPacketTest,TooShortCommandCompleteEventToHost)651 TEST(BadPacketTest, TooShortCommandCompleteEventToHost) {
652   std::array<
653       uint8_t,
654       emboss::ReadLocalVersionInfoCommandCompleteEventWriter::SizeInBytes()>
655       valid_hci_arr{};
656   H4PacketWithHci valid_packet{emboss::H4PacketType::UNKNOWN, valid_hci_arr};
657   PW_TEST_ASSERT_OK_AND_ASSIGN(
658       auto view,
659       CreateAndPopulateToHostEventView<
660           emboss::ReadLocalVersionInfoCommandCompleteEventWriter>(
661           valid_packet, emboss::EventCode::COMMAND_COMPLETE));
662   view.command_complete().command_opcode_enum().Write(
663       emboss::OpCode::READ_LOCAL_VERSION_INFO);
664 
665   // Create packet for sending whose span size is one less than a valid command
666   // complete event.
667   H4PacketWithHci h4_packet{
668       valid_packet.GetH4Type(),
669       valid_packet.GetHciSpan().subspan(
670           0,
671           emboss::ReadLocalVersionInfoCommandCompleteEventWriter::
672                   SizeInBytes() -
673               1)};
674 
675   // Struct for capturing because `pw::Function` capture can't fit multiple
676   // fields .
677   struct {
678     std::array<
679         uint8_t,
680         emboss::ReadLocalVersionInfoCommandCompleteEventWriter::SizeInBytes() -
681             1>
682         hci_arr;
683     uint8_t sends_called = 0;
684   } send_capture;
685   std::copy(h4_packet.GetHciSpan().begin(),
686             h4_packet.GetHciSpan().end(),
687             send_capture.hci_arr.begin());
688   send_capture.sends_called = 0;
689 
690   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
691       [&send_capture](H4PacketWithHci&& packet) {
692         send_capture.sends_called++;
693         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
694                                packet.GetHciSpan().end(),
695                                send_capture.hci_arr.begin(),
696                                send_capture.hci_arr.end()));
697       });
698 
699   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
700       []([[maybe_unused]] H4PacketWithH4&& packet) {});
701 
702   ProxyHost proxy = ProxyHost(
703       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
704 
705   proxy.HandleH4HciFromController(std::move(h4_packet));
706 
707   // Verify callback was called.
708   EXPECT_EQ(send_capture.sends_called, 1);
709 }
710 
711 // ########## ReserveLeAclCredits Tests
712 
713 // Proxy Host should reserve requested ACL credits from controller's ACL credits
714 // when using ReadBufferSize command.
TEST(ReserveBrEdrAclCredits,ProxyCreditsReserveCreditsWithReadBufferSize)715 TEST(ReserveBrEdrAclCredits, ProxyCreditsReserveCreditsWithReadBufferSize) {
716   std::array<uint8_t,
717              emboss::ReadBufferSizeCommandCompleteEventWriter::SizeInBytes()>
718       hci_arr;
719   hci_arr.fill(0);
720   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
721   PW_TEST_ASSERT_OK_AND_ASSIGN(
722       auto view,
723       CreateAndPopulateToHostEventView<
724           emboss::ReadBufferSizeCommandCompleteEventWriter>(
725           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
726   view.command_complete().command_opcode_enum().Write(
727       emboss::OpCode::READ_BUFFER_SIZE);
728   view.total_num_acl_data_packets().Write(10);
729 
730   uint8_t sends_called = 0;
731   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
732       [&sends_called](H4PacketWithHci&& received_packet) {
733         sends_called++;
734         PW_TEST_ASSERT_OK_AND_ASSIGN(
735             auto event_view,
736             MakeEmbossWriter<emboss::ReadBufferSizeCommandCompleteEventWriter>(
737                 received_packet.GetHciSpan()));
738         // Should reserve 2 credits from original total of 10 (so 8 left for
739         // host).
740         EXPECT_EQ(event_view.total_num_acl_data_packets().Read(), 8);
741       });
742 
743   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
744       []([[maybe_unused]] H4PacketWithH4&& packet) {});
745 
746   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
747                               std::move(send_to_controller_fn),
748                               /*le_acl_credits_to_reserve=*/0,
749                               /*br_edr_acl_credits_to_reserve=*/2);
750 
751   proxy.HandleH4HciFromController(std::move(h4_packet));
752 
753   EXPECT_EQ(proxy.GetNumFreeBrEdrAclPackets(), 2);
754 
755   EXPECT_TRUE(proxy.HasSendBrEdrAclCapability());
756 
757   // Verify to controller callback was called.
758   EXPECT_EQ(sends_called, 1);
759 }
760 
761 // Proxy Host should reserve requested ACL LE credits from controller's ACL LE
762 // credits when using LEReadBufferSizeV1 command.
TEST(ReserveLeAclCredits,ProxyCreditsReserveCreditsWithLEReadBufferSizeV1)763 TEST(ReserveLeAclCredits, ProxyCreditsReserveCreditsWithLEReadBufferSizeV1) {
764   std::array<
765       uint8_t,
766       emboss::LEReadBufferSizeV1CommandCompleteEventWriter::SizeInBytes()>
767       hci_arr{};
768   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
769   PW_TEST_ASSERT_OK_AND_ASSIGN(
770       auto view,
771       CreateAndPopulateToHostEventView<
772           emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
773           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
774   view.command_complete().command_opcode_enum().Write(
775       emboss::OpCode::LE_READ_BUFFER_SIZE_V1);
776   view.total_num_le_acl_data_packets().Write(10);
777 
778   uint8_t sends_called = 0;
779   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
780       [&sends_called](H4PacketWithHci&& received_packet) {
781         sends_called++;
782         PW_TEST_ASSERT_OK_AND_ASSIGN(
783             auto event_view,
784             MakeEmbossView<
785                 emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
786                 received_packet.GetHciSpan()));
787 
788         // Should reserve 2 credits from original total of 10 (so 8 left for
789         // host).
790         EXPECT_EQ(event_view.total_num_le_acl_data_packets().Read(), 8);
791       });
792 
793   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
794       []([[maybe_unused]] H4PacketWithH4&& packet) {});
795 
796   ProxyHost proxy = ProxyHost(
797       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
798 
799   proxy.HandleH4HciFromController(std::move(h4_packet));
800 
801   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
802 
803   EXPECT_TRUE(proxy.HasSendLeAclCapability());
804 
805   // Verify to controller callback was called.
806   EXPECT_EQ(sends_called, 1);
807 }
808 
809 // Proxy Host should reserve requested ACL LE credits from controller's ACL LE
810 // credits when using LEReadBufferSizeV2 command.
TEST(ReserveLeAclCredits,ProxyCreditsReserveCreditsWithLEReadBufferSizeV2)811 TEST(ReserveLeAclCredits, ProxyCreditsReserveCreditsWithLEReadBufferSizeV2) {
812   std::array<
813       uint8_t,
814       emboss::LEReadBufferSizeV2CommandCompleteEventWriter::SizeInBytes()>
815       hci_arr{};
816   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
817   PW_TEST_ASSERT_OK_AND_ASSIGN(
818       auto view,
819       CreateAndPopulateToHostEventView<
820           emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(
821           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
822   view.command_complete().command_opcode_enum().Write(
823       emboss::OpCode::LE_READ_BUFFER_SIZE_V2);
824   view.total_num_le_acl_data_packets().Write(10);
825 
826   uint8_t sends_called = 0;
827   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
828       [&sends_called](H4PacketWithHci&& received_packet) {
829         sends_called++;
830         PW_TEST_ASSERT_OK_AND_ASSIGN(
831             auto event_view,
832             MakeEmbossView<
833                 emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(
834                 received_packet.GetHciSpan()));
835         // Should reserve 2 credits from original total of 10 (so 8 left for
836         // host).
837         EXPECT_EQ(event_view.total_num_le_acl_data_packets().Read(), 8);
838       });
839 
840   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
841       []([[maybe_unused]] H4PacketWithH4&& packet) {});
842 
843   ProxyHost proxy = ProxyHost(
844       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
845 
846   proxy.HandleH4HciFromController(std::move(h4_packet));
847 
848   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
849 
850   EXPECT_TRUE(proxy.HasSendLeAclCapability());
851 
852   // Verify to controller callback was called.
853   EXPECT_EQ(sends_called, 1);
854 }
855 
856 // If controller provides less than wanted credits, we should reserve that
857 // smaller amount.
TEST(ReserveLeAclCredits,ProxyCreditsCappedByControllerCredits)858 TEST(ReserveLeAclCredits, ProxyCreditsCappedByControllerCredits) {
859   std::array<
860       uint8_t,
861       emboss::LEReadBufferSizeV1CommandCompleteEventWriter::SizeInBytes()>
862       hci_arr{};
863   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
864   PW_TEST_ASSERT_OK_AND_ASSIGN(
865       auto view,
866       CreateAndPopulateToHostEventView<
867           emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
868           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
869   view.command_complete().command_opcode_enum().Write(
870       emboss::OpCode::LE_READ_BUFFER_SIZE_V1);
871   view.total_num_le_acl_data_packets().Write(5);
872 
873   uint8_t sends_called = 0;
874   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
875       [&sends_called](H4PacketWithHci&& received_packet) {
876         sends_called++;
877         // We want 7, but can reserve only 5 from original 5 (so 0 left for
878         // host).
879         PW_TEST_ASSERT_OK_AND_ASSIGN(
880             auto event_view,
881             MakeEmbossView<
882                 emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
883                 received_packet.GetHciSpan()));
884         EXPECT_EQ(event_view.total_num_le_acl_data_packets().Read(), 0);
885       });
886 
887   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
888       []([[maybe_unused]] H4PacketWithH4&& packet) {});
889 
890   ProxyHost proxy = ProxyHost(
891       std::move(send_to_host_fn), std::move(send_to_controller_fn), 7);
892 
893   proxy.HandleH4HciFromController(std::move(h4_packet));
894 
895   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 5);
896 
897   // Verify to controller callback was called.
898   EXPECT_EQ(sends_called, 1);
899 }
900 
901 // Proxy Host can reserve zero credits from controller's ACL LE credits.
TEST(ReserveLeAclCredits,ProxyCreditsReserveZeroCredits)902 TEST(ReserveLeAclCredits, ProxyCreditsReserveZeroCredits) {
903   std::array<
904       uint8_t,
905       emboss::LEReadBufferSizeV1CommandCompleteEventWriter::SizeInBytes()>
906       hci_arr{};
907   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
908   PW_TEST_ASSERT_OK_AND_ASSIGN(
909       auto view,
910       CreateAndPopulateToHostEventView<
911           emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
912           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
913   view.command_complete().command_opcode_enum().Write(
914       emboss::OpCode::LE_READ_BUFFER_SIZE_V1);
915   view.total_num_le_acl_data_packets().Write(10);
916 
917   uint8_t sends_called = 0;
918   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
919       [&sends_called](H4PacketWithHci&& received_packet) {
920         sends_called++;
921         PW_TEST_ASSERT_OK_AND_ASSIGN(
922             auto event_view,
923             MakeEmbossView<
924                 emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
925                 received_packet.GetHciSpan()));
926         // Should reserve 0 credits from original total of 10 (so 10 left for
927         // host).
928         EXPECT_EQ(event_view.total_num_le_acl_data_packets().Read(), 10);
929       });
930 
931   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
932       []([[maybe_unused]] H4PacketWithH4&& packet) {});
933 
934   ProxyHost proxy = ProxyHost(
935       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
936 
937   proxy.HandleH4HciFromController(std::move(h4_packet));
938 
939   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
940 
941   EXPECT_FALSE(proxy.HasSendLeAclCapability());
942 
943   // Verify to controller callback was called.
944   EXPECT_EQ(sends_called, 1);
945 }
946 
947 // If controller has no credits, proxy should reserve none.
TEST(ReserveLeAclPackets,ProxyCreditsZeroWhenHostCreditsZero)948 TEST(ReserveLeAclPackets, ProxyCreditsZeroWhenHostCreditsZero) {
949   std::array<
950       uint8_t,
951       emboss::LEReadBufferSizeV1CommandCompleteEventWriter::SizeInBytes()>
952       hci_arr;
953   hci_arr.fill(0);
954   H4PacketWithHci h4_packet{emboss::H4PacketType::UNKNOWN, hci_arr};
955   PW_TEST_ASSERT_OK_AND_ASSIGN(
956       auto view,
957       CreateAndPopulateToHostEventView<
958           emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
959           h4_packet, emboss::EventCode::COMMAND_COMPLETE));
960   view.command_complete().command_opcode_enum().Write(
961       emboss::OpCode::LE_READ_BUFFER_SIZE_V1);
962   view.total_num_le_acl_data_packets().Write(0);
963 
964   uint8_t sends_called = 0;
965   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
966       [&sends_called](H4PacketWithHci&& received_packet) {
967         sends_called++;
968         PW_TEST_ASSERT_OK_AND_ASSIGN(
969             auto event_view,
970             MakeEmbossView<
971                 emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
972                 received_packet.GetHciSpan()));
973         // Should reserve 0 credit from original total of 0 (so 0 left for
974         // host).
975         EXPECT_EQ(event_view.total_num_le_acl_data_packets().Read(), 0);
976       });
977 
978   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
979       []([[maybe_unused]] H4PacketWithH4&& packet) {});
980 
981   ProxyHost proxy = ProxyHost(
982       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
983 
984   proxy.HandleH4HciFromController(std::move(h4_packet));
985 
986   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
987 
988   EXPECT_TRUE(proxy.HasSendLeAclCapability());
989 
990   // Verify to controller callback was called.
991   EXPECT_EQ(sends_called, 1);
992 }
993 
TEST(ReserveLeAclPackets,ProxyCreditsZeroWhenNotInitialized)994 TEST(ReserveLeAclPackets, ProxyCreditsZeroWhenNotInitialized) {
995   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
996       []([[maybe_unused]] H4PacketWithHci&& packet) {});
997 
998   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
999       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1000 
1001   ProxyHost proxy = ProxyHost(
1002       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
1003 
1004   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1005 
1006   EXPECT_TRUE(proxy.HasSendLeAclCapability());
1007 }
1008 
1009 // ########## GattNotifyTest
1010 
TEST(GattNotifyTest,Send1ByteAttribute)1011 TEST(GattNotifyTest, Send1ByteAttribute) {
1012   struct {
1013     int sends_called = 0;
1014     // First four bits 0x0 encode PB & BC flags
1015     uint16_t handle = 0x0ACB;
1016     // Length of L2CAP PDU
1017     uint16_t acl_data_total_length = 0x0008;
1018     // Length of ATT PDU
1019     uint16_t pdu_length = 0x0004;
1020     // Attribute protocol channel ID (0x0004)
1021     uint16_t channel_id = 0x0004;
1022     // ATT_HANDLE_VALUE_NTF opcode 0x1B
1023     uint8_t attribute_opcode = 0x1B;
1024     uint16_t attribute_handle = 0x4321;
1025     std::array<uint8_t, 1> attribute_value = {0xFA};
1026 
1027     // Built from the preceding values in little endian order.
1028     std::array<uint8_t, 12> expected_gatt_notify_packet = {
1029         0xCB, 0x0A, 0x08, 0x00, 0x04, 0x00, 0x04, 0x00, 0x1B, 0x21, 0x43, 0xFA};
1030   } capture;
1031 
1032   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
1033       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1034 
1035   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
1036       [&capture](H4PacketWithH4&& packet) {
1037         capture.sends_called++;
1038         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
1039         EXPECT_EQ(packet.GetHciSpan().size(),
1040                   capture.expected_gatt_notify_packet.size());
1041         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
1042                                packet.GetHciSpan().end(),
1043                                capture.expected_gatt_notify_packet.begin(),
1044                                capture.expected_gatt_notify_packet.end()));
1045         PW_TEST_ASSERT_OK_AND_ASSIGN(
1046             auto acl,
1047             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
1048         emboss::BFrameView l2cap =
1049             emboss::MakeBFrameView(acl.payload().BackingStorage().data(),
1050                                    acl.data_total_length().Read());
1051         emboss::AttHandleValueNtfView gatt_notify =
1052             emboss::MakeAttHandleValueNtfView(
1053                 capture.attribute_value.size(),
1054                 l2cap.payload().BackingStorage().data(),
1055                 l2cap.pdu_length().Read());
1056         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
1057         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
1058                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
1059         EXPECT_EQ(acl.header().broadcast_flag().Read(),
1060                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
1061         EXPECT_EQ(acl.data_total_length().Read(),
1062                   capture.acl_data_total_length);
1063         EXPECT_EQ(l2cap.pdu_length().Read(), capture.pdu_length);
1064         EXPECT_EQ(l2cap.channel_id().Read(), capture.channel_id);
1065         EXPECT_EQ(gatt_notify.attribute_opcode().Read(),
1066                   static_cast<emboss::AttOpcode>(capture.attribute_opcode));
1067         EXPECT_EQ(gatt_notify.attribute_handle().Read(),
1068                   capture.attribute_handle);
1069         EXPECT_EQ(gatt_notify.attribute_value()[0].Read(),
1070                   capture.attribute_value[0]);
1071       });
1072 
1073   ProxyHost proxy = ProxyHost(
1074       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1075   // Allow proxy to reserve 1 credit.
1076   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1077 
1078   PW_TEST_EXPECT_OK(proxy.SendGattNotify(capture.handle,
1079                                          capture.attribute_handle,
1080                                          pw::span(capture.attribute_value)));
1081   EXPECT_EQ(capture.sends_called, 1);
1082 }
1083 
TEST(GattNotifyTest,Send2ByteAttribute)1084 TEST(GattNotifyTest, Send2ByteAttribute) {
1085   struct {
1086     int sends_called = 0;
1087     // Max connection_handle value; first four bits 0x0 encode PB & BC flags
1088     const uint16_t handle = 0x0EFF;
1089     // Length of L2CAP PDU
1090     const uint16_t acl_data_total_length = 0x0009;
1091     // Length of ATT PDU
1092     const uint16_t pdu_length = 0x0005;
1093     // Attribute protocol channel ID (0x0004)
1094     const uint16_t channel_id = 0x0004;
1095     // ATT_HANDLE_VALUE_NTF opcode 0x1B
1096     const uint8_t attribute_opcode = 0x1B;
1097     const uint16_t attribute_handle = 0x1234;
1098     const std::array<uint8_t, 2> attribute_value = {0xAB, 0xCD};
1099 
1100     // Built from the preceding values in little endian order.
1101     const std::array<uint8_t, 13> expected_gatt_notify_packet = {0xFF,
1102                                                                  0x0E,
1103                                                                  0x09,
1104                                                                  0x00,
1105                                                                  0x05,
1106                                                                  0x00,
1107                                                                  0x04,
1108                                                                  0x00,
1109                                                                  0x1B,
1110                                                                  0x34,
1111                                                                  0x12,
1112                                                                  0xAB,
1113                                                                  0XCD};
1114   } capture;
1115 
1116   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
1117       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1118 
1119   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
1120       [&capture](H4PacketWithH4&& packet) {
1121         ++capture.sends_called;
1122         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
1123         EXPECT_EQ(packet.GetHciSpan().size(),
1124                   capture.expected_gatt_notify_packet.size());
1125         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
1126                                packet.GetHciSpan().end(),
1127                                capture.expected_gatt_notify_packet.begin(),
1128                                capture.expected_gatt_notify_packet.end()));
1129         PW_TEST_ASSERT_OK_AND_ASSIGN(
1130             auto acl,
1131             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
1132         emboss::BFrameView l2cap = emboss::MakeBFrameView(
1133             acl.payload().BackingStorage().data(), acl.SizeInBytes());
1134         emboss::AttHandleValueNtfView gatt_notify =
1135             emboss::MakeAttHandleValueNtfView(
1136                 capture.attribute_value.size(),
1137                 l2cap.payload().BackingStorage().data(),
1138                 l2cap.pdu_length().Read());
1139         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
1140         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
1141                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
1142         EXPECT_EQ(acl.header().broadcast_flag().Read(),
1143                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
1144         EXPECT_EQ(acl.data_total_length().Read(),
1145                   capture.acl_data_total_length);
1146         EXPECT_EQ(l2cap.pdu_length().Read(), capture.pdu_length);
1147         EXPECT_EQ(l2cap.channel_id().Read(), capture.channel_id);
1148         EXPECT_EQ(gatt_notify.attribute_opcode().Read(),
1149                   static_cast<emboss::AttOpcode>(capture.attribute_opcode));
1150         EXPECT_EQ(gatt_notify.attribute_handle().Read(),
1151                   capture.attribute_handle);
1152         EXPECT_EQ(gatt_notify.attribute_value()[0].Read(),
1153                   capture.attribute_value[0]);
1154         EXPECT_EQ(gatt_notify.attribute_value()[1].Read(),
1155                   capture.attribute_value[1]);
1156       });
1157 
1158   ProxyHost proxy = ProxyHost(
1159       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1160   // Allow proxy to reserve 1 credit.
1161   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1162 
1163   PW_TEST_EXPECT_OK(proxy.SendGattNotify(capture.handle,
1164                                          capture.attribute_handle,
1165                                          pw::span(capture.attribute_value)));
1166   EXPECT_EQ(capture.sends_called, 1);
1167 }
1168 
TEST(GattNotifyTest,ReturnsErrorIfAttributeTooLarge)1169 TEST(GattNotifyTest, ReturnsErrorIfAttributeTooLarge) {
1170   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
1171       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1172   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1173       []([[maybe_unused]] H4PacketWithH4 packet) { FAIL(); });
1174 
1175   ProxyHost proxy = ProxyHost(
1176       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
1177 
1178   // attribute_value 1 byte too large
1179   std::array<uint8_t,
1180              proxy.GetMaxAclSendSize() -
1181                  emboss::AclDataFrameHeader::IntrinsicSizeInBytes() -
1182                  emboss::BasicL2capHeader::IntrinsicSizeInBytes() -
1183                  emboss::AttHandleValueNtf::MinSizeInBytes() + 1>
1184       attribute_value_too_large;
1185   EXPECT_EQ(proxy.SendGattNotify(123, 456, attribute_value_too_large),
1186             PW_STATUS_INVALID_ARGUMENT);
1187 }
1188 
TEST(GattNotifyTest,ChannelIsNotConstructedIfParametersInvalid)1189 TEST(GattNotifyTest, ChannelIsNotConstructedIfParametersInvalid) {
1190   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
1191       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1192   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1193       []([[maybe_unused]] H4PacketWithH4 packet) { FAIL(); });
1194 
1195   ProxyHost proxy = ProxyHost(
1196       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
1197 
1198   EXPECT_EQ(proxy.SendGattNotify(123, 0, {}), PW_STATUS_INVALID_ARGUMENT);
1199   // connection_handle too large
1200   EXPECT_EQ(proxy.SendGattNotify(0x0FFF, 345, {}), PW_STATUS_INVALID_ARGUMENT);
1201 }
1202 
1203 // ########## NumberOfCompletedPacketsTest
1204 
TEST(NumberOfCompletedPacketsTest,TwoOfThreeSentPacketsComplete)1205 TEST(NumberOfCompletedPacketsTest, TwoOfThreeSentPacketsComplete) {
1206   constexpr size_t kNumConnections = 3;
1207   struct {
1208     int sends_called = 0;
1209     const std::array<uint16_t, kNumConnections> connection_handles = {
1210         0x123, 0x456, 0x789};
1211   } capture;
1212 
1213   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1214       [&capture](H4PacketWithHci&& packet) {
1215         PW_TEST_ASSERT_OK_AND_ASSIGN(
1216             auto event_header,
1217             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1218                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1219         capture.sends_called++;
1220         if (event_header.event_code_enum().Read() !=
1221             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1222           return;
1223         }
1224 
1225         PW_TEST_ASSERT_OK_AND_ASSIGN(
1226             auto view,
1227             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1228                 packet.GetHciSpan()));
1229         EXPECT_EQ(packet.GetHciSpan().size(), 15ul);
1230         EXPECT_EQ(view.num_handles().Read(), capture.connection_handles.size());
1231         EXPECT_EQ(view.header().event_code_enum().Read(),
1232                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1233 
1234         // Proxy should have reclaimed 1 credit from Connection 0 (leaving 0
1235         // credits in packet), no credits from Connection 1 (meaning 0 will be
1236         // unchanged), and 1 credit from Connection 2 (leaving 0).
1237         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1238                   capture.connection_handles[0]);
1239         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 0);
1240 
1241         EXPECT_EQ(view.nocp_data()[1].connection_handle().Read(),
1242                   capture.connection_handles[1]);
1243         EXPECT_EQ(view.nocp_data()[1].num_completed_packets().Read(), 0);
1244 
1245         EXPECT_EQ(view.nocp_data()[2].connection_handle().Read(),
1246                   capture.connection_handles[2]);
1247         EXPECT_EQ(view.nocp_data()[2].num_completed_packets().Read(), 0);
1248       });
1249   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1250       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1251 
1252   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
1253                               std::move(send_to_controller_fn),
1254                               kNumConnections);
1255   PW_TEST_EXPECT_OK(
1256       SendLeReadBufferResponseFromController(proxy, kNumConnections));
1257   EXPECT_EQ(capture.sends_called, 1);
1258 
1259   std::array<uint8_t, 1> attribute_value = {0};
1260 
1261   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 3);
1262 
1263   // Send packet; num free packets should decrement.
1264   EXPECT_TRUE(proxy
1265                   .SendGattNotify(capture.connection_handles[0],
1266                                   1,
1267                                   pw::span(attribute_value))
1268                   .ok());
1269   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
1270   // Proxy host took all credits so will not pass NOCP on to host.
1271   EXPECT_EQ(capture.sends_called, 1);
1272 
1273   // Send packet over Connection 1, which will not have a packet completed in
1274   // the Number_of_Completed_Packets event.
1275   EXPECT_TRUE(proxy
1276                   .SendGattNotify(capture.connection_handles[1],
1277                                   1,
1278                                   pw::span(attribute_value))
1279                   .ok());
1280   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 1);
1281 
1282   // Send third packet; num free packets should decrement again.
1283   EXPECT_TRUE(proxy
1284                   .SendGattNotify(capture.connection_handles[2],
1285                                   1,
1286                                   pw::span(attribute_value))
1287                   .ok());
1288   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1289 
1290   // Send Number_of_Completed_Packets event that reports 1 packet on Connection
1291   // 0, 0 packets on Connection 1, and 1 packet on Connection 2. Checks in
1292   // send_to_host_fn will ensure we have reclaimed 2 of 3 credits.
1293   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1294       proxy,
1295       FlatMap<uint16_t, uint16_t, 3>({{{capture.connection_handles[0], 1},
1296                                        {capture.connection_handles[1], 0},
1297                                        {capture.connection_handles[2], 1}}})));
1298   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
1299   // Proxy host took all credits so will not pass NOCP event on to host.
1300   EXPECT_EQ(capture.sends_called, 1);
1301 }
1302 
TEST(NumberOfCompletedPacketsTest,ManyMorePacketsCompletedThanPacketsPending)1303 TEST(NumberOfCompletedPacketsTest, ManyMorePacketsCompletedThanPacketsPending) {
1304   constexpr size_t kNumConnections = 2;
1305   struct {
1306     int sends_called = 0;
1307     const std::array<uint16_t, kNumConnections> connection_handles = {0x123,
1308                                                                       0x456};
1309   } capture;
1310 
1311   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1312       [&capture](H4PacketWithHci&& packet) {
1313         PW_TEST_ASSERT_OK_AND_ASSIGN(
1314             auto event_header,
1315             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1316                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1317         capture.sends_called++;
1318         if (event_header.event_code_enum().Read() !=
1319             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1320           return;
1321         }
1322 
1323         PW_TEST_ASSERT_OK_AND_ASSIGN(
1324             auto view,
1325             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1326                 packet.GetHciSpan()));
1327         EXPECT_EQ(packet.GetHciSpan().size(), 11ul);
1328         EXPECT_EQ(view.num_handles().Read(), capture.connection_handles.size());
1329         EXPECT_EQ(view.header().event_code_enum().Read(),
1330                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1331 
1332         // Proxy should have reclaimed 1 credit from Connection 0 (leaving
1333         // 9 credits in packet) and 1 credit from Connection 2 (leaving 14).
1334         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1335                   capture.connection_handles[0]);
1336         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 9);
1337 
1338         EXPECT_EQ(view.nocp_data()[1].connection_handle().Read(),
1339                   capture.connection_handles[1]);
1340         EXPECT_EQ(view.nocp_data()[1].num_completed_packets().Read(), 14);
1341       });
1342   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1343       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1344 
1345   ProxyHost proxy = ProxyHost(
1346       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
1347   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 2));
1348   EXPECT_EQ(capture.sends_called, 1);
1349 
1350   std::array<uint8_t, 1> attribute_value = {0};
1351 
1352   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
1353 
1354   // Send packet over Connection 0; num free packets should decrement.
1355   EXPECT_TRUE(proxy
1356                   .SendGattNotify(capture.connection_handles[0],
1357                                   1,
1358                                   pw::span(attribute_value))
1359                   .ok());
1360   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 1);
1361 
1362   // Send packet over Connection 1; num free packets should decrement again.
1363   EXPECT_TRUE(proxy
1364                   .SendGattNotify(capture.connection_handles[1],
1365                                   1,
1366                                   pw::span(attribute_value))
1367                   .ok());
1368   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1369 
1370   // Send Number_of_Completed_Packets event that reports 10 packets on
1371   // Connection 0 and 15 packets on Connection 1. Checks in send_to_host_fn
1372   // will ensure we have reclaimed exactly 2 credits, 1 from each Connection.
1373   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1374       proxy,
1375       FlatMap<uint16_t, uint16_t, 2>({{{capture.connection_handles[0], 10},
1376                                        {capture.connection_handles[1], 15}}})));
1377   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
1378   EXPECT_EQ(capture.sends_called, 2);
1379 }
1380 
TEST(NumberOfCompletedPacketsTest,ProxyReclaimsOnlyItsUsedCredits)1381 TEST(NumberOfCompletedPacketsTest, ProxyReclaimsOnlyItsUsedCredits) {
1382   constexpr size_t kNumConnections = 2;
1383   struct {
1384     int sends_called = 0;
1385     const std::array<uint16_t, kNumConnections> connection_handles = {0x123,
1386                                                                       0x456};
1387   } capture;
1388 
1389   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1390       [&capture](H4PacketWithHci&& packet) {
1391         PW_TEST_ASSERT_OK_AND_ASSIGN(
1392             auto event_header,
1393             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1394                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1395         capture.sends_called++;
1396         if (event_header.event_code_enum().Read() !=
1397             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1398           return;
1399         }
1400 
1401         PW_TEST_ASSERT_OK_AND_ASSIGN(
1402             auto view,
1403             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1404                 packet.GetHciSpan()));
1405         EXPECT_EQ(packet.GetHciSpan().size(), 11ul);
1406         EXPECT_EQ(view.num_handles().Read(), 2);
1407         EXPECT_EQ(view.header().event_code_enum().Read(),
1408                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1409 
1410         // Proxy has 4 credits it wants to reclaim, but it should have only
1411         // reclaimed the 2 credits it used on Connection 0.
1412         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1413                   capture.connection_handles[0]);
1414         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 8);
1415         EXPECT_EQ(view.nocp_data()[1].connection_handle().Read(),
1416                   capture.connection_handles[1]);
1417         EXPECT_EQ(view.nocp_data()[1].num_completed_packets().Read(), 15);
1418       });
1419   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1420       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1421 
1422   ProxyHost proxy = ProxyHost(
1423       std::move(send_to_host_fn), std::move(send_to_controller_fn), 4);
1424   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 4));
1425   EXPECT_EQ(capture.sends_called, 1);
1426 
1427   std::array<uint8_t, 1> attribute_value = {0};
1428 
1429   // Use 2 credits on Connection 0 and 2 credits on random connections that will
1430   // not be included in the NOCP event.
1431   EXPECT_TRUE(proxy
1432                   .SendGattNotify(capture.connection_handles[0],
1433                                   1,
1434                                   pw::span(attribute_value))
1435                   .ok());
1436   EXPECT_TRUE(proxy
1437                   .SendGattNotify(capture.connection_handles[0],
1438                                   1,
1439                                   pw::span(attribute_value))
1440                   .ok());
1441   EXPECT_TRUE(proxy.SendGattNotify(0xABC, 1, pw::span(attribute_value)).ok());
1442   EXPECT_TRUE(proxy.SendGattNotify(0xBCD, 1, pw::span(attribute_value)).ok());
1443   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1444 
1445   // Send Number_of_Completed_Packets event that reports 10 packets on
1446   // Connection 0 and 15 packets on Connection 1. Checks in send_to_host_fn
1447   // will ensure we have reclaimed only 2 credits.
1448   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1449       proxy,
1450       FlatMap<uint16_t, uint16_t, 2>({{{capture.connection_handles[0], 10},
1451                                        {capture.connection_handles[1], 15}}})));
1452   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 2);
1453   // NOCP has credits remaining so will be passed on to host.
1454   EXPECT_EQ(capture.sends_called, 2);
1455 }
1456 
TEST(NumberOfCompletedPacketsTest,EventUnmodifiedIfNoCreditsInUse)1457 TEST(NumberOfCompletedPacketsTest, EventUnmodifiedIfNoCreditsInUse) {
1458   constexpr size_t kNumConnections = 2;
1459   struct {
1460     int sends_called = 0;
1461     const std::array<uint16_t, kNumConnections> connection_handles = {0x123,
1462                                                                       0x456};
1463   } capture;
1464 
1465   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1466       [&capture](H4PacketWithHci&& packet) {
1467         PW_TEST_ASSERT_OK_AND_ASSIGN(
1468             auto event_header,
1469             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1470                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1471         capture.sends_called++;
1472         if (event_header.event_code_enum().Read() !=
1473             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1474           return;
1475         }
1476 
1477         PW_TEST_ASSERT_OK_AND_ASSIGN(
1478             auto view,
1479             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1480                 packet.GetHciSpan()));
1481         EXPECT_EQ(packet.GetHciSpan().size(), 11ul);
1482         EXPECT_EQ(view.num_handles().Read(), 2);
1483         EXPECT_EQ(view.header().event_code_enum().Read(),
1484                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1485 
1486         // Event should be unmodified.
1487         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1488                   capture.connection_handles[0]);
1489         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 10);
1490         EXPECT_EQ(view.nocp_data()[1].connection_handle().Read(),
1491                   capture.connection_handles[1]);
1492         EXPECT_EQ(view.nocp_data()[1].num_completed_packets().Read(), 15);
1493       });
1494   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1495       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1496 
1497   ProxyHost proxy = ProxyHost(
1498       std::move(send_to_host_fn), std::move(send_to_controller_fn), 10);
1499   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 10));
1500   EXPECT_EQ(capture.sends_called, 1);
1501 
1502   // Send Number_of_Completed_Packets event that reports 10 packets on
1503   // Connection 0 and 15 packets on Connection 1. Checks in send_to_host_fn
1504   // will ensure we have not modified the NOCP event.
1505   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1506       proxy,
1507       FlatMap<uint16_t, uint16_t, 2>({{{capture.connection_handles[0], 10},
1508                                        {capture.connection_handles[1], 15}}})));
1509   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 10);
1510   // NOCP has credits remaining so will be passed on to host.
1511   EXPECT_EQ(capture.sends_called, 2);
1512 }
1513 
TEST(NumberOfCompletedPacketsTest,HandlesUnusualEvents)1514 TEST(NumberOfCompletedPacketsTest, HandlesUnusualEvents) {
1515   constexpr size_t kNumConnections = 5;
1516   struct {
1517     int sends_called = 0;
1518     const std::array<uint16_t, kNumConnections> connection_handles = {
1519         0x123, 0x234, 0x345, 0x456, 0x567};
1520   } capture;
1521 
1522   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1523       [&capture](H4PacketWithHci&& packet) {
1524         PW_TEST_ASSERT_OK_AND_ASSIGN(
1525             auto event_header,
1526             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1527                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1528         capture.sends_called++;
1529         if (event_header.event_code_enum().Read() !=
1530             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1531           return;
1532         }
1533 
1534         PW_TEST_ASSERT_OK_AND_ASSIGN(
1535             auto view,
1536             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1537                 packet.GetHciSpan()));
1538         if (view.num_handles().Read() == 0) {
1539           return;
1540         }
1541 
1542         EXPECT_EQ(packet.GetHciSpan().size(), 23ul);
1543         EXPECT_EQ(view.num_handles().Read(), 5);
1544         EXPECT_EQ(view.header().event_code_enum().Read(),
1545                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1546 
1547         // Event should be unmodified.
1548         for (int i = 0; i < 5; ++i) {
1549           EXPECT_EQ(view.nocp_data()[i].connection_handle().Read(),
1550                     capture.connection_handles[i]);
1551           EXPECT_EQ(view.nocp_data()[i].num_completed_packets().Read(), 0);
1552         }
1553       });
1554   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1555       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1556 
1557   ProxyHost proxy = ProxyHost(
1558       std::move(send_to_host_fn), std::move(send_to_controller_fn), 10);
1559   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 10));
1560   EXPECT_EQ(capture.sends_called, 1);
1561 
1562   // Send Number_of_Completed_Packets event with no entries.
1563   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1564       proxy, FlatMap<uint16_t, uint16_t, 0>({{}})));
1565   // NOCP has no entries, so will not be passed on to host.
1566   EXPECT_EQ(capture.sends_called, 1);
1567 
1568   // Send Number_of_Completed_Packets event that reports 0 packets for various
1569   // connections.
1570   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1571       proxy,
1572       FlatMap<uint16_t, uint16_t, 5>({{{capture.connection_handles[0], 0},
1573                                        {capture.connection_handles[1], 0},
1574                                        {capture.connection_handles[2], 0},
1575                                        {capture.connection_handles[3], 0},
1576                                        {capture.connection_handles[4], 0}}})));
1577   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 10);
1578   // Proxy host will not pass on a NOCP with no credits.
1579   EXPECT_EQ(capture.sends_called, 1);
1580 }
1581 
TEST(NumberOfCompletedPacketsTest,MultipleChannelsDifferentTransports)1582 TEST(NumberOfCompletedPacketsTest, MultipleChannelsDifferentTransports) {
1583   static constexpr size_t kPayloadSize = 3;
1584   struct {
1585     int sends_called = 0;
1586     std::array<uint8_t, kPayloadSize> payload = {
1587         0xAB,
1588         0xCD,
1589         0xEF,
1590     };
1591   } capture;
1592 
1593   pw::Function<void(H4PacketWithHci&&)>&& send_to_host_fn(
1594       [](H4PacketWithHci&&) {});
1595   pw::Function<void(H4PacketWithH4&&)>&& send_to_controller_fn(
1596       [&capture](H4PacketWithH4&&) { ++capture.sends_called; });
1597 
1598   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
1599                               std::move(send_to_controller_fn),
1600                               /*le_acl_credits_to_reserve=*/1,
1601                               /*br_edr_acl_credits_to_reserve=*/1);
1602   // Allow proxy to reserve BR/EDR 1 credit.
1603   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
1604   // Allow proxy to reserve LE 1 credit.
1605   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1606 
1607   // Test that sending on one type of transport doesn't get blocked if the other
1608   // type of transport is out of credits.
1609 
1610   L2capCoc le_channel =
1611       BuildCoc(proxy, CocParameters{.handle = 0x123, .tx_credits = 2});
1612   EXPECT_EQ(le_channel.Write(capture.payload), PW_STATUS_OK);
1613   EXPECT_EQ(capture.sends_called, 1);
1614 
1615   RfcommChannel bredr_channel =
1616       BuildRfcomm(proxy, RfcommParameters{.handle = 0x456});
1617   EXPECT_EQ(bredr_channel.Write(capture.payload), PW_STATUS_OK);
1618   // Send should succeed even though no LE credits available
1619   EXPECT_EQ(capture.sends_called, 2);
1620 
1621   // Queue an LE write
1622   EXPECT_EQ(le_channel.Write(capture.payload), PW_STATUS_OK);
1623   EXPECT_EQ(capture.sends_called, 2);
1624 
1625   // Complete previous LE write
1626   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1627       proxy, FlatMap<uint16_t, uint16_t, 1>({{{0x123, 1}}})));
1628   EXPECT_EQ(capture.sends_called, 3);
1629 
1630   // Complete BR/EDR write
1631   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1632       proxy, FlatMap<uint16_t, uint16_t, 1>({{{0x456, 1}}})));
1633 
1634   // Write again
1635   EXPECT_EQ(bredr_channel.Write(capture.payload), PW_STATUS_OK);
1636   EXPECT_EQ(capture.sends_called, 4);
1637 }
1638 
1639 // ########## DisconnectionCompleteTest
1640 
TEST(DisconnectionCompleteTest,DisconnectionReclaimsCredits)1641 TEST(DisconnectionCompleteTest, DisconnectionReclaimsCredits) {
1642   struct {
1643     int sends_called = 0;
1644     uint16_t connection_handle = 0x123;
1645   } capture;
1646 
1647   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1648       [&capture](H4PacketWithHci&& packet) {
1649         PW_TEST_ASSERT_OK_AND_ASSIGN(
1650             auto event_header,
1651             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1652                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1653         capture.sends_called++;
1654         if (event_header.event_code_enum().Read() !=
1655             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1656           return;
1657         }
1658 
1659         PW_TEST_ASSERT_OK_AND_ASSIGN(
1660             auto view,
1661             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1662                 packet.GetHciSpan()));
1663         EXPECT_EQ(packet.GetHciSpan().size(), 7ul);
1664         EXPECT_EQ(view.num_handles().Read(), 1);
1665         EXPECT_EQ(view.header().event_code_enum().Read(),
1666                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1667 
1668         // Event should be unmodified.
1669         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1670                   capture.connection_handle);
1671         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 10);
1672       });
1673   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1674       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1675 
1676   ProxyHost proxy = ProxyHost(
1677       std::move(send_to_host_fn), std::move(send_to_controller_fn), 10);
1678   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 10));
1679   EXPECT_EQ(capture.sends_called, 1);
1680 
1681   std::array<uint8_t, 1> attribute_value = {0};
1682 
1683   // Use up 3 of the 10 credits on the Connection that will be disconnected.
1684   for (int i = 0; i < 3; ++i) {
1685     EXPECT_TRUE(proxy
1686                     .SendGattNotify(
1687                         capture.connection_handle, 1, pw::span(attribute_value))
1688                     .ok());
1689   }
1690   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 7);
1691   // Use up 2 credits on a random Connection.
1692   for (int i = 0; i < 2; ++i) {
1693     EXPECT_TRUE(proxy.SendGattNotify(0x456, 1, pw::span(attribute_value)).ok());
1694   }
1695   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 5);
1696 
1697   // Send Disconnection_Complete event, which should reclaim 3 credits.
1698   PW_TEST_EXPECT_OK(
1699       SendDisconnectionCompleteEvent(proxy, capture.connection_handle));
1700   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 8);
1701 
1702   // Use 1 credit and reclaim it on a bunch of random channels. Then send
1703   // disconnect and ensure it was cleaned up in connections list. The send will
1704   // fail if disconnect doesn't cleanup properly.
1705   //
1706   // We already have an active connection at this point in the test, so loop
1707   // over the remaining slots + 1 which would otherwise fail if cleanup wasn't
1708   // working right.
1709   for (uint16_t i = 0; i < kMaxProxyActiveConnections; ++i) {
1710     uint16_t handle = 0x234 + i;
1711     EXPECT_TRUE(
1712         proxy.SendGattNotify(handle, 1, pw::span(attribute_value)).ok());
1713     PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1714         proxy, FlatMap<uint16_t, uint16_t, 1>({{{handle, 1}}})));
1715     EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 8);
1716     PW_TEST_EXPECT_OK(SendDisconnectionCompleteEvent(proxy, handle));
1717   }
1718 
1719   // Send Number_of_Completed_Packets event that reports 10 packets, none of
1720   // which should be reclaimed because this Connection has disconnected. Checks
1721   // in send_to_host_fn will ensure we have not modified the NOCP event.
1722   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1723       proxy,
1724       FlatMap<uint16_t, uint16_t, 1>({{{capture.connection_handle, 10}}})));
1725   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 8);
1726   // NOCP has credits remaining so will be passed on to host.
1727   EXPECT_EQ(capture.sends_called, 13);
1728 }
1729 
TEST(DisconnectionCompleteTest,FailedDisconnectionHasNoEffect)1730 TEST(DisconnectionCompleteTest, FailedDisconnectionHasNoEffect) {
1731   uint16_t connection_handle = 0x123;
1732 
1733   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1734       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1735   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1736       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1737 
1738   ProxyHost proxy = ProxyHost(
1739       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1740   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1741 
1742   std::array<uint8_t, 1> attribute_value = {0};
1743 
1744   // Use sole credit.
1745   EXPECT_TRUE(
1746       proxy.SendGattNotify(connection_handle, 1, pw::span(attribute_value))
1747           .ok());
1748   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1749 
1750   // Send failed Disconnection_Complete event, should not reclaim credit.
1751   PW_TEST_EXPECT_OK(
1752       SendDisconnectionCompleteEvent(proxy,
1753                                      connection_handle, /*successful=*/
1754                                      false));
1755   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1756 }
1757 
TEST(DisconnectionCompleteTest,DisconnectionOfUnusedConnectionHasNoEffect)1758 TEST(DisconnectionCompleteTest, DisconnectionOfUnusedConnectionHasNoEffect) {
1759   uint16_t connection_handle = 0x123;
1760 
1761   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1762       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1763   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1764       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1765 
1766   ProxyHost proxy = ProxyHost(
1767       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1768   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1769 
1770   std::array<uint8_t, 1> attribute_value = {0};
1771 
1772   // Use sole credit.
1773   EXPECT_TRUE(
1774       proxy.SendGattNotify(connection_handle, 1, pw::span(attribute_value))
1775           .ok());
1776   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1777 
1778   // Send Disconnection_Complete event to random Connection, should have no
1779   // effect.
1780   PW_TEST_EXPECT_OK(SendDisconnectionCompleteEvent(proxy, 0x456));
1781   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1782 }
1783 
TEST(DisconnectionCompleteTest,CanReuseConnectionHandleAfterDisconnection)1784 TEST(DisconnectionCompleteTest, CanReuseConnectionHandleAfterDisconnection) {
1785   struct {
1786     int sends_called = 0;
1787     uint16_t connection_handle = 0x123;
1788   } capture;
1789 
1790   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1791       [&capture](H4PacketWithHci&& packet) {
1792         PW_TEST_ASSERT_OK_AND_ASSIGN(
1793             auto event_header,
1794             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1795                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1796         capture.sends_called++;
1797         if (event_header.event_code_enum().Read() !=
1798             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1799           return;
1800         }
1801 
1802         PW_TEST_ASSERT_OK_AND_ASSIGN(
1803             auto view,
1804             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1805                 packet.GetHciSpan()));
1806         EXPECT_EQ(packet.GetHciSpan().size(), 7ul);
1807         EXPECT_EQ(view.num_handles().Read(), 1);
1808         EXPECT_EQ(view.header().event_code_enum().Read(),
1809                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1810 
1811         // Should have reclaimed the 1 packet.
1812         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1813                   capture.connection_handle);
1814         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 0);
1815       });
1816   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1817       []([[maybe_unused]] H4PacketWithH4&& packet) {});
1818 
1819   ProxyHost proxy = ProxyHost(
1820       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1821   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1822   EXPECT_EQ(capture.sends_called, 1);
1823 
1824   std::array<uint8_t, 1> attribute_value = {0};
1825 
1826   // Establish connection over `connection_handle`.
1827   EXPECT_TRUE(proxy
1828                   .SendGattNotify(
1829                       capture.connection_handle, 1, pw::span(attribute_value))
1830                   .ok());
1831   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1832 
1833   // Disconnect `connection_handle`.
1834   PW_TEST_EXPECT_OK(
1835       SendDisconnectionCompleteEvent(proxy, capture.connection_handle));
1836   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 1);
1837   EXPECT_EQ(capture.sends_called, 2);
1838 
1839   // Re-establish connection over `connection_handle`.
1840   EXPECT_TRUE(proxy
1841                   .SendGattNotify(
1842                       capture.connection_handle, 1, pw::span(attribute_value))
1843                   .ok());
1844   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1845 
1846   // Send Number_of_Completed_Packets event that reports 1 packet. Checks in
1847   // send_to_host_fn will ensure packet has been reclaimed.
1848   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1849       proxy,
1850       FlatMap<uint16_t, uint16_t, 1>({{{capture.connection_handle, 1}}})));
1851   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 1);
1852   // Since proxy reclaimed the one credit, it does not pass event on to host.
1853   EXPECT_EQ(capture.sends_called, 2);
1854 }
1855 
1856 // ########## ResetTest
1857 
TEST(ResetTest,ResetClearsActiveConnections)1858 TEST(ResetTest, ResetClearsActiveConnections) {
1859   struct {
1860     int sends_called = 0;
1861     const uint16_t connection_handle = 0x123;
1862   } host_capture;
1863   struct {
1864     int sends_called = 0;
1865     const uint16_t connection_handle = 0x123;
1866   } controller_capture;
1867 
1868   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1869       [&host_capture](H4PacketWithHci&& packet) {
1870         PW_TEST_ASSERT_OK_AND_ASSIGN(
1871             auto event_header,
1872             MakeEmbossView<emboss::EventHeaderView>(packet.GetHciSpan().subspan(
1873                 0, emboss::EventHeader::IntrinsicSizeInBytes())));
1874         host_capture.sends_called++;
1875         if (event_header.event_code_enum().Read() !=
1876             emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS) {
1877           return;
1878         }
1879 
1880         PW_TEST_ASSERT_OK_AND_ASSIGN(
1881             auto view,
1882             MakeEmbossView<emboss::NumberOfCompletedPacketsEventView>(
1883                 packet.GetHciSpan()));
1884         EXPECT_EQ(packet.GetHciSpan().size(), 7ul);
1885         EXPECT_EQ(view.num_handles().Read(), 1);
1886         EXPECT_EQ(view.header().event_code_enum().Read(),
1887                   emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
1888 
1889         // Should be unchanged.
1890         EXPECT_EQ(view.nocp_data()[0].connection_handle().Read(),
1891                   host_capture.connection_handle);
1892         EXPECT_EQ(view.nocp_data()[0].num_completed_packets().Read(), 1);
1893       });
1894   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1895       [&controller_capture]([[maybe_unused]] H4PacketWithH4&& packet) {
1896         ++controller_capture.sends_called;
1897       });
1898 
1899   ProxyHost proxy = ProxyHost(
1900       std::move(send_to_host_fn), std::move(send_to_controller_fn), 2);
1901   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 2));
1902   EXPECT_EQ(host_capture.sends_called, 1);
1903 
1904   std::array<uint8_t, 1> attribute_value = {0};
1905   EXPECT_TRUE(proxy
1906                   .SendGattNotify(controller_capture.connection_handle,
1907                                   1,
1908                                   pw::span(attribute_value))
1909                   .ok());
1910   EXPECT_EQ(controller_capture.sends_called, 1);
1911 
1912   proxy.Reset();
1913 
1914   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1915   // Reset should not have cleared `le_acl_credits_to_reserve`, so proxy should
1916   // still indicate the capability.
1917   EXPECT_TRUE(proxy.HasSendLeAclCapability());
1918 
1919   // Re-initialize AclDataChannel with 2 credits.
1920   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 2));
1921   EXPECT_EQ(host_capture.sends_called, 2);
1922 
1923   // Send ACL on random handle to expend one credit.
1924   EXPECT_TRUE(proxy.SendGattNotify(1, 1, pw::span(attribute_value)).ok());
1925   EXPECT_EQ(controller_capture.sends_called, 2);
1926   // This should have no effect, as the reset has cleared our active connection
1927   // on this handle.
1928   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
1929       proxy,
1930       FlatMap<uint16_t, uint16_t, 1>({{{host_capture.connection_handle, 1}}})));
1931   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 1);
1932   // NOCP has credits remaining so will be passed on to host.
1933   EXPECT_EQ(host_capture.sends_called, 3);
1934 }
1935 
TEST(ResetTest,ProxyHandlesMultipleResets)1936 TEST(ResetTest, ProxyHandlesMultipleResets) {
1937   int sends_called = 0;
1938 
1939   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
1940       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1941   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1942       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
1943         ++sends_called;
1944       });
1945 
1946   ProxyHost proxy = ProxyHost(
1947       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
1948   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1949 
1950   proxy.Reset();
1951   proxy.Reset();
1952 
1953   std::array<uint8_t, 1> attribute_value = {0};
1954   // Validate state after double reset.
1955   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1956   EXPECT_TRUE(proxy.HasSendAclCapability());
1957   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1958   EXPECT_EQ(proxy.SendGattNotify(1, 1, pw::span(attribute_value)),
1959             PW_STATUS_OK);
1960   EXPECT_EQ(sends_called, 1);
1961 
1962   proxy.Reset();
1963 
1964   // Validate state after third reset.
1965   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
1966   EXPECT_TRUE(proxy.HasSendAclCapability());
1967   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
1968   EXPECT_EQ(proxy.SendGattNotify(1, 1, pw::span(attribute_value)),
1969             PW_STATUS_OK);
1970   EXPECT_EQ(sends_called, 2);
1971 }
1972 
1973 // ########## MultiSendTest
1974 
TEST(MultiSendTest,CanOccupyAllThenReuseEachBuffer)1975 TEST(MultiSendTest, CanOccupyAllThenReuseEachBuffer) {
1976   constexpr size_t kMaxSends = ProxyHost::GetNumSimultaneousAclSendsSupported();
1977   struct {
1978     size_t sends_called = 0;
1979     std::array<H4PacketWithH4, 2 * kMaxSends> released_packets;
1980   } capture;
1981 
1982   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
1983       []([[maybe_unused]] H4PacketWithHci&& packet) {});
1984   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
1985       [&capture](H4PacketWithH4&& packet) {
1986         // Capture all packets to prevent their destruction.
1987         capture.released_packets[capture.sends_called++] = std::move(packet);
1988       });
1989 
1990   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
1991                               std::move(send_to_controller_fn),
1992                               2 * kMaxSends);
1993   // Allow proxy to reserve enough credits to send twice the number of
1994   // simultaneous sends supported by proxy.
1995   PW_TEST_EXPECT_OK(
1996       SendLeReadBufferResponseFromController(proxy, 2 * kMaxSends));
1997 
1998   std::array<uint8_t, 1> attribute_value = {0xF};
1999   // Occupy all send buffers.
2000   for (size_t i = 0; i < kMaxSends; ++i) {
2001     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2002   }
2003   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), kMaxSends);
2004   EXPECT_EQ(proxy.SendGattNotify(123, 345, pw::span(attribute_value)),
2005             PW_STATUS_UNAVAILABLE);
2006 
2007   // Confirm we can release and reoccupy each buffer slot.
2008   for (size_t i = 0; i < kMaxSends; ++i) {
2009     capture.released_packets[i].~H4PacketWithH4();
2010     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2011     EXPECT_EQ(proxy.SendGattNotify(123, 345, pw::span(attribute_value)),
2012               PW_STATUS_UNAVAILABLE);
2013   }
2014   EXPECT_EQ(capture.sends_called, 2 * kMaxSends);
2015 
2016   // If captured packets are not reset here, they may destruct after the proxy
2017   // and lead to a crash when trying to lock the proxy's destructed mutex.
2018   for (auto& packet : capture.released_packets) {
2019     packet.ResetAndReturnReleaseFn();
2020   }
2021 }
2022 
TEST(MultiSendTest,CanRepeatedlyReuseOneBuffer)2023 TEST(MultiSendTest, CanRepeatedlyReuseOneBuffer) {
2024   constexpr size_t kMaxSends = ProxyHost::GetNumSimultaneousAclSendsSupported();
2025   struct {
2026     size_t sends_called = 0;
2027     std::array<H4PacketWithH4, kMaxSends> released_packets;
2028   } capture;
2029 
2030   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2031       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2032   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2033       [&capture](H4PacketWithH4&& packet) {
2034         // Capture first kMaxSends packets linearly.
2035         if (capture.sends_called < capture.released_packets.size()) {
2036           capture.released_packets[capture.sends_called] = std::move(packet);
2037         } else {
2038           // Reuse only first packet slot after kMaxSends.
2039           capture.released_packets[0] = std::move(packet);
2040         }
2041         ++capture.sends_called;
2042       });
2043 
2044   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
2045                               std::move(send_to_controller_fn),
2046                               2 * kMaxSends);
2047   PW_TEST_EXPECT_OK(
2048       SendLeReadBufferResponseFromController(proxy, 2 * kMaxSends));
2049 
2050   std::array<uint8_t, 1> attribute_value = {0xF};
2051   // Occupy all send buffers.
2052   for (size_t i = 0; i < kMaxSends; ++i) {
2053     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2054   }
2055 
2056   // Repeatedly free and reoccupy first buffer.
2057   for (size_t i = 0; i < kMaxSends; ++i) {
2058     capture.released_packets[0].~H4PacketWithH4();
2059     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2060     EXPECT_EQ(proxy.SendGattNotify(123, 345, pw::span(attribute_value)),
2061               PW_STATUS_UNAVAILABLE);
2062   }
2063   EXPECT_EQ(capture.sends_called, 2 * kMaxSends);
2064 
2065   // If captured packets are not reset here, they may destruct after the proxy
2066   // and lead to a crash when trying to lock the proxy's destructed mutex.
2067   for (auto& packet : capture.released_packets) {
2068     packet.ResetAndReturnReleaseFn();
2069   }
2070 }
2071 
TEST(MultiSendTest,CanSendOverManyDifferentConnections)2072 TEST(MultiSendTest, CanSendOverManyDifferentConnections) {
2073   std::array<uint8_t, 1> attribute_value = {0xF};
2074   struct {
2075     uint16_t sends_called = 0;
2076   } capture;
2077 
2078   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2079       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2080   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2081       [&capture]([[maybe_unused]] H4PacketWithH4&& packet) {
2082         ++capture.sends_called;
2083       });
2084 
2085   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
2086                               std::move(send_to_controller_fn),
2087                               ProxyHost::GetMaxNumLeAclConnections());
2088   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(
2089       proxy, ProxyHost::GetMaxNumLeAclConnections()));
2090 
2091   for (uint16_t send = 1; send <= ProxyHost::GetMaxNumLeAclConnections();
2092        send++) {
2093     // Use current send count as the connection handle.
2094     uint16_t conn_handle = send;
2095     EXPECT_TRUE(
2096         proxy.SendGattNotify(conn_handle, 345, pw::span(attribute_value)).ok());
2097     EXPECT_EQ(capture.sends_called, send);
2098   }
2099 }
2100 
TEST(MultiSendTest,AttemptToSendOverMaxConnectionsFails)2101 TEST(MultiSendTest, AttemptToSendOverMaxConnectionsFails) {
2102   constexpr uint16_t kSends = kMaxProxyActiveConnections + 1;
2103   std::array<uint8_t, 1> attribute_value = {0xF};
2104   struct {
2105     uint16_t sends_called = 0;
2106   } capture;
2107 
2108   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2109       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2110   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2111       [&capture]([[maybe_unused]] H4PacketWithH4&& packet) {
2112         ++capture.sends_called;
2113       });
2114 
2115   ProxyHost proxy = ProxyHost(
2116       std::move(send_to_host_fn), std::move(send_to_controller_fn), kSends);
2117   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, kSends));
2118 
2119   for (uint16_t send = 1; send <= kMaxProxyActiveConnections; send++) {
2120     // Use current send count as the connection handle.
2121     uint16_t conn_handle = send;
2122     EXPECT_TRUE(
2123         proxy.SendGattNotify(conn_handle, 345, pw::span(attribute_value)).ok());
2124     EXPECT_EQ(capture.sends_called, send);
2125   }
2126 
2127   // Last one should fail
2128   uint16_t conn_handle = kSends;
2129   EXPECT_FALSE(
2130       proxy.SendGattNotify(conn_handle, 345, pw::span(attribute_value)).ok());
2131   EXPECT_EQ(capture.sends_called, kMaxProxyActiveConnections);
2132 }
2133 
TEST(MultiSendTest,ResetClearsBuffOccupiedFlags)2134 TEST(MultiSendTest, ResetClearsBuffOccupiedFlags) {
2135   constexpr size_t kMaxSends = ProxyHost::GetNumSimultaneousAclSendsSupported();
2136   struct {
2137     size_t sends_called = 0;
2138     std::array<H4PacketWithH4, 2 * kMaxSends> released_packets;
2139   } capture;
2140 
2141   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2142       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2143   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2144       [&capture](H4PacketWithH4&& packet) {
2145         // Capture all packets to prevent their destruction.
2146         capture.released_packets[capture.sends_called++] = std::move(packet);
2147       });
2148 
2149   ProxyHost proxy = ProxyHost(
2150       std::move(send_to_host_fn), std::move(send_to_controller_fn), kMaxSends);
2151   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, kMaxSends));
2152 
2153   std::array<uint8_t, 1> attribute_value = {0xF};
2154   // Occupy all send buffers.
2155   for (size_t i = 0; i < kMaxSends; ++i) {
2156     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2157   }
2158 
2159   proxy.Reset();
2160   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, kMaxSends));
2161 
2162   // Although sent packets have not been released, proxy.Reset() should have
2163   // marked all buffers as unoccupied.
2164   for (size_t i = 0; i < kMaxSends; ++i) {
2165     EXPECT_TRUE(proxy.SendGattNotify(123, 345, pw::span(attribute_value)).ok());
2166   }
2167   EXPECT_EQ(capture.sends_called, 2 * kMaxSends);
2168 
2169   // If captured packets are not reset here, they may destruct after the proxy
2170   // and lead to a crash when trying to lock the proxy's destructed mutex.
2171   for (auto& packet : capture.released_packets) {
2172     packet.ResetAndReturnReleaseFn();
2173   }
2174 }
2175 
2176 // ########## BasicL2capChannelTest
2177 
TEST(BasicL2capChannelTest,BasicWrite)2178 TEST(BasicL2capChannelTest, BasicWrite) {
2179   struct {
2180     int sends_called = 0;
2181     // First four bits 0x0 encode PB & BC flags
2182     uint16_t handle = 0x0ACB;
2183     // Length of L2CAP PDU
2184     uint16_t acl_data_total_length = 0x0007;
2185     // L2CAP header PDU length field
2186     uint16_t pdu_length = 0x0003;
2187     // Random CID
2188     uint16_t channel_id = 0x1234;
2189     // L2CAP information payload
2190     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
2191 
2192     // Built from the preceding values in little endian order (except payload in
2193     // big endian).
2194     std::array<uint8_t, 11> expected_hci_packet = {
2195         0xCB, 0x0A, 0x07, 0x00, 0x03, 0x00, 0x34, 0x12, 0xAB, 0xCD, 0xEF};
2196   } capture;
2197 
2198   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2199       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2200   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2201       [&capture](H4PacketWithH4&& packet) {
2202         ++capture.sends_called;
2203         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
2204         EXPECT_EQ(packet.GetHciSpan().size(),
2205                   capture.expected_hci_packet.size());
2206         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
2207                                packet.GetHciSpan().end(),
2208                                capture.expected_hci_packet.begin(),
2209                                capture.expected_hci_packet.end()));
2210         PW_TEST_ASSERT_OK_AND_ASSIGN(
2211             auto acl,
2212             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
2213         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
2214         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
2215                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
2216         EXPECT_EQ(acl.header().broadcast_flag().Read(),
2217                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
2218         EXPECT_EQ(acl.data_total_length().Read(),
2219                   capture.acl_data_total_length);
2220         emboss::BFrameView bframe = emboss::MakeBFrameView(
2221             acl.payload().BackingStorage().data(), acl.SizeInBytes());
2222         EXPECT_EQ(bframe.pdu_length().Read(), capture.pdu_length);
2223         EXPECT_EQ(bframe.channel_id().Read(), capture.channel_id);
2224         for (size_t i = 0; i < 3; ++i) {
2225           EXPECT_EQ(bframe.payload()[i].Read(), capture.payload[i]);
2226         }
2227       });
2228 
2229   ProxyHost proxy = ProxyHost(
2230       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
2231   // Allow proxy to reserve 1 LE credit.
2232   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
2233 
2234   PW_TEST_ASSERT_OK_AND_ASSIGN(
2235       BasicL2capChannel channel,
2236       proxy.AcquireBasicL2capChannel(/*connection_handle=*/capture.handle,
2237                                      /*local_cid=*/0x123,
2238                                      /*remote_cid=*/capture.channel_id,
2239                                      /*transport=*/AclTransportType::kLe,
2240                                      /*payload_from_controller_fn=*/nullptr));
2241 
2242   EXPECT_EQ(channel.Write(capture.payload), PW_STATUS_OK);
2243   EXPECT_EQ(capture.sends_called, 1);
2244 }
2245 
TEST(BasicL2capChannelTest,ErrorOnWriteTooLarge)2246 TEST(BasicL2capChannelTest, ErrorOnWriteTooLarge) {
2247   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2248       [](H4PacketWithHci&&) {});
2249   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2250       [](H4PacketWithH4&&) { FAIL(); });
2251 
2252   ProxyHost proxy = ProxyHost(
2253       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
2254   // Allow proxy to reserve 1 credit.
2255   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
2256 
2257   std::array<uint8_t,
2258              ProxyHost::GetMaxAclSendSize() -
2259                  emboss::AclDataFrameHeader::IntrinsicSizeInBytes() -
2260                  emboss::BasicL2capHeader::IntrinsicSizeInBytes() + 1>
2261       hci_arr;
2262   PW_TEST_ASSERT_OK_AND_ASSIGN(
2263       BasicL2capChannel channel,
2264       proxy.AcquireBasicL2capChannel(/*connection_handle=*/0x123,
2265                                      /*local_cid=*/0x123,
2266                                      /*remote_cid=*/0x123,
2267                                      /*transport=*/AclTransportType::kLe,
2268                                      /*payload_from_controller_fn=*/nullptr));
2269 
2270   EXPECT_EQ(channel.Write(span(hci_arr)), PW_STATUS_INVALID_ARGUMENT);
2271 }
2272 
TEST(BasicL2capChannelTest,CannotCreateChannelWithInvalidArgs)2273 TEST(BasicL2capChannelTest, CannotCreateChannelWithInvalidArgs) {
2274   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2275       [](H4PacketWithHci&&) {});
2276   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2277       [](H4PacketWithH4&&) {});
2278 
2279   ProxyHost proxy = ProxyHost(
2280       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2281 
2282   // Connection handle too large by 1.
2283   EXPECT_EQ(
2284       proxy
2285           .AcquireBasicL2capChannel(/*connection_handle=*/0x0FFF,
2286                                     /*local_cid=*/0x123,
2287                                     /*remote_cid=*/0x123,
2288                                     /*transport=*/AclTransportType::kLe,
2289                                     /*payload_from_controller_fn=*/nullptr)
2290           .status(),
2291       PW_STATUS_INVALID_ARGUMENT);
2292 
2293   // Local CID invalid (0).
2294   EXPECT_EQ(
2295       proxy
2296           .AcquireBasicL2capChannel(/*connection_handle=*/0x123,
2297                                     /*local_cid=*/0,
2298                                     /*remote_cid=*/0x123,
2299                                     /*transport=*/AclTransportType::kLe,
2300                                     /*payload_from_controller_fn=*/nullptr)
2301           .status(),
2302       PW_STATUS_INVALID_ARGUMENT);
2303 }
2304 
TEST(BasicL2capChannelTest,BasicRead)2305 TEST(BasicL2capChannelTest, BasicRead) {
2306   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2307       [](H4PacketWithHci&&) {});
2308   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2309       [](H4PacketWithH4&&) {});
2310   ProxyHost proxy = ProxyHost(
2311       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2312 
2313   struct {
2314     int sends_called = 0;
2315     std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
2316   } capture;
2317 
2318   uint16_t handle = 334;
2319   uint16_t local_cid = 443;
2320   PW_TEST_ASSERT_OK_AND_ASSIGN(
2321       BasicL2capChannel channel,
2322       proxy.AcquireBasicL2capChannel(
2323           /*connection_handle=*/handle,
2324           /*local_cid=*/local_cid,
2325           /*remote_cid=*/0x123,
2326           /*transport=*/AclTransportType::kLe,
2327           /*payload_from_controller_fn=*/
2328           [&capture](pw::span<uint8_t> payload) {
2329             ++capture.sends_called;
2330             EXPECT_TRUE(std::equal(payload.begin(),
2331                                    payload.end(),
2332                                    capture.expected_payload.begin(),
2333                                    capture.expected_payload.end()));
2334           }));
2335 
2336   std::array<uint8_t,
2337              emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
2338                  emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
2339                  capture.expected_payload.size()>
2340       hci_arr;
2341   hci_arr.fill(0);
2342   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2343 
2344   Result<emboss::AclDataFrameWriter> acl =
2345       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2346   acl->header().handle().Write(handle);
2347   acl->data_total_length().Write(
2348       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
2349       capture.expected_payload.size());
2350 
2351   emboss::BFrameWriter bframe = emboss::MakeBFrameView(
2352       acl->payload().BackingStorage().data(), acl->payload().SizeInBytes());
2353   bframe.pdu_length().Write(capture.expected_payload.size());
2354   bframe.channel_id().Write(local_cid);
2355   std::copy(capture.expected_payload.begin(),
2356             capture.expected_payload.end(),
2357             hci_arr.begin() +
2358                 emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
2359                 emboss::BasicL2capHeader::IntrinsicSizeInBytes());
2360 
2361   // Send ACL data packet destined for the CoC we registered.
2362   proxy.HandleH4HciFromController(std::move(h4_packet));
2363 
2364   EXPECT_EQ(capture.sends_called, 1);
2365 }
2366 
2367 // ########## L2capCocTest
2368 
TEST(L2capCocTest,CannotCreateChannelWithInvalidArgs)2369 TEST(L2capCocTest, CannotCreateChannelWithInvalidArgs) {
2370   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2371       [](H4PacketWithHci&&) {});
2372   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2373       [](H4PacketWithH4&&) {});
2374 
2375   ProxyHost proxy = ProxyHost(
2376       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2377 
2378   // Connection handle too large by 1.
2379   EXPECT_EQ(
2380       proxy
2381           .AcquireL2capCoc(
2382               /*connection_handle=*/0x0FFF,
2383               /*rx_config=*/
2384               {.cid = 0x123, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2385               /*tx_config=*/
2386               {.cid = 0x123, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2387               /*receive_fn=*/nullptr,
2388               /*event_fn=*/nullptr)
2389           .status(),
2390       PW_STATUS_INVALID_ARGUMENT);
2391 
2392   // Local CID invalid (0).
2393   EXPECT_EQ(
2394       proxy
2395           .AcquireL2capCoc(
2396               /*connection_handle=*/0x123,
2397               /*rx_config=*/
2398               {.cid = 0, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2399               /*tx_config=*/
2400               {.cid = 0x123, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2401               /*receive_fn=*/nullptr,
2402               /*event_fn=*/nullptr)
2403           .status(),
2404       PW_STATUS_INVALID_ARGUMENT);
2405 
2406   // Remote CID invalid (0).
2407   EXPECT_EQ(
2408       proxy
2409           .AcquireL2capCoc(
2410               /*connection_handle=*/0x123,
2411               /*rx_config=*/
2412               {.cid = 0x123, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2413               /*tx_config=*/
2414               {.cid = 0, .mtu = 0x123, .mps = 0x123, .credits = 0x123},
2415               /*receive_fn=*/nullptr,
2416               /*event_fn=*/nullptr)
2417           .status(),
2418       PW_STATUS_INVALID_ARGUMENT);
2419 }
2420 
2421 // ########## L2capCocWriteTest
2422 
2423 // Size of sdu_length field in first K-frames.
2424 constexpr uint8_t kSduLengthFieldSize = 2;
2425 // Size of a K-Frame over Acl packet with no payload.
2426 constexpr uint8_t kFirstKFrameOverAclMinSize =
2427     emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
2428     emboss::FirstKFrame::MinSizeInBytes();
2429 
TEST(L2capCocWriteTest,BasicWrite)2430 TEST(L2capCocWriteTest, BasicWrite) {
2431   struct {
2432     int sends_called = 0;
2433     // First four bits 0x0 encode PB & BC flags
2434     uint16_t handle = 0x0ACB;
2435     // Length of L2CAP PDU
2436     uint16_t acl_data_total_length = 0x0009;
2437     // L2CAP header PDU length field
2438     uint16_t pdu_length = 0x0005;
2439     // Random CID
2440     uint16_t channel_id = 0x1234;
2441     // Length of L2CAP SDU
2442     uint16_t sdu_length = 0x0003;
2443     // L2CAP information payload
2444     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
2445 
2446     // Built from the preceding values in little endian order (except payload in
2447     // big endian).
2448     std::array<uint8_t, 13> expected_hci_packet = {0xCB,
2449                                                    0x0A,
2450                                                    0x09,
2451                                                    0x00,
2452                                                    0x05,
2453                                                    0x00,
2454                                                    0x34,
2455                                                    0x12,
2456                                                    0x03,
2457                                                    0x00,
2458                                                    0xAB,
2459                                                    0xCD,
2460                                                    0xEF};
2461   } capture;
2462 
2463   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2464       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2465   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2466       [&capture](H4PacketWithH4&& packet) {
2467         ++capture.sends_called;
2468         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
2469         EXPECT_EQ(packet.GetHciSpan().size(),
2470                   capture.expected_hci_packet.size());
2471         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
2472                                packet.GetHciSpan().end(),
2473                                capture.expected_hci_packet.begin(),
2474                                capture.expected_hci_packet.end()));
2475         PW_TEST_ASSERT_OK_AND_ASSIGN(
2476             auto acl,
2477             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
2478         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
2479         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
2480                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
2481         EXPECT_EQ(acl.header().broadcast_flag().Read(),
2482                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
2483         EXPECT_EQ(acl.data_total_length().Read(),
2484                   capture.acl_data_total_length);
2485         emboss::FirstKFrameView kframe = emboss::MakeFirstKFrameView(
2486             acl.payload().BackingStorage().data(), acl.SizeInBytes());
2487         EXPECT_EQ(kframe.pdu_length().Read(), capture.pdu_length);
2488         EXPECT_EQ(kframe.channel_id().Read(), capture.channel_id);
2489         EXPECT_EQ(kframe.sdu_length().Read(), capture.sdu_length);
2490         for (size_t i = 0; i < 3; ++i) {
2491           EXPECT_EQ(kframe.payload()[i].Read(), capture.payload[i]);
2492         }
2493       });
2494 
2495   ProxyHost proxy = ProxyHost(
2496       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
2497   // Allow proxy to reserve 1 credit.
2498   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
2499 
2500   L2capCoc channel = BuildCoc(proxy,
2501                               CocParameters{.handle = capture.handle,
2502                                             .remote_cid = capture.channel_id});
2503   EXPECT_EQ(channel.Write(capture.payload), PW_STATUS_OK);
2504   EXPECT_EQ(capture.sends_called, 1);
2505 }
2506 
TEST(L2capCocWriteTest,ErrorOnWriteToStoppedChannel)2507 TEST(L2capCocWriteTest, ErrorOnWriteToStoppedChannel) {
2508   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2509       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2510   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2511       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2512   ProxyHost proxy = ProxyHost(
2513       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
2514   // Allow proxy to reserve 1 credit.
2515   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
2516 
2517   L2capCoc channel = BuildCoc(
2518       proxy,
2519       CocParameters{
2520           .handle = 123,
2521           .tx_credits = 1,
2522           .event_fn = []([[maybe_unused]] L2capCoc::Event event) { FAIL(); }});
2523 
2524   EXPECT_EQ(channel.Stop(), PW_STATUS_OK);
2525   EXPECT_EQ(channel.Write({}), PW_STATUS_FAILED_PRECONDITION);
2526 }
2527 
TEST(L2capCocWriteTest,TooLargeWritesFail)2528 TEST(L2capCocWriteTest, TooLargeWritesFail) {
2529   int sends_called = 0;
2530 
2531   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2532       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2533   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2534       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
2535         ++sends_called;
2536       });
2537 
2538   ProxyHost proxy = ProxyHost(
2539       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
2540   // Allow proxy to reserve 1 credit.
2541   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
2542 
2543   // Payload size exceeds MTU.
2544   L2capCoc small_mtu_channel = BuildCoc(proxy, CocParameters{.tx_mtu = 1});
2545   std::array<uint8_t, 24> payload;
2546   EXPECT_EQ(small_mtu_channel.Write(payload), PW_STATUS_INVALID_ARGUMENT);
2547 
2548   // Payload size exceeds MPS.
2549   L2capCoc small_mps_channel = BuildCoc(proxy, CocParameters{.tx_mps = 23});
2550   EXPECT_EQ(small_mps_channel.Write(payload), PW_STATUS_INVALID_ARGUMENT);
2551 
2552   // Payload size exceeds max allowable based on H4 buffer size.
2553   std::array<uint8_t,
2554              proxy.GetMaxAclSendSize() - kFirstKFrameOverAclMinSize + 1>
2555       payload_one_byte_too_large;
2556   L2capCoc channel = BuildCoc(proxy, {});
2557   EXPECT_EQ(channel.Write(payload_one_byte_too_large),
2558             PW_STATUS_INVALID_ARGUMENT);
2559 
2560   EXPECT_EQ(sends_called, 0);
2561 }
2562 
TEST(L2capCocWriteTest,MultipleWritesSameChannel)2563 TEST(L2capCocWriteTest, MultipleWritesSameChannel) {
2564   struct {
2565     int sends_called = 0;
2566     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
2567   } capture;
2568 
2569   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2570       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2571   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2572       [&capture](H4PacketWithH4&& packet) {
2573         ++capture.sends_called;
2574         PW_TEST_ASSERT_OK_AND_ASSIGN(
2575             auto acl,
2576             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
2577         emboss::FirstKFrameView kframe = emboss::MakeFirstKFrameView(
2578             acl.payload().BackingStorage().data(), acl.SizeInBytes());
2579         for (size_t i = 0; i < 3; ++i) {
2580           EXPECT_EQ(kframe.payload()[i].Read(), capture.payload[i]);
2581         }
2582       });
2583 
2584   uint16_t num_writes = 5;
2585   ProxyHost proxy = ProxyHost(
2586       std::move(send_to_host_fn), std::move(send_to_controller_fn), num_writes);
2587   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(
2588       proxy,
2589       /*num_credits_to_reserve=*/num_writes));
2590 
2591   L2capCoc channel = BuildCoc(proxy, CocParameters{.tx_credits = num_writes});
2592   for (int i = 0; i < num_writes; ++i) {
2593     EXPECT_EQ(channel.Write(capture.payload), PW_STATUS_OK);
2594     std::for_each(capture.payload.begin(),
2595                   capture.payload.end(),
2596                   [](uint8_t& byte) { ++byte; });
2597   }
2598 
2599   EXPECT_EQ(capture.sends_called, num_writes);
2600 }
2601 
TEST(L2capCocWriteTest,MultipleWritesMultipleChannels)2602 TEST(L2capCocWriteTest, MultipleWritesMultipleChannels) {
2603   struct {
2604     int sends_called = 0;
2605     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
2606   } capture;
2607 
2608   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2609       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2610   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2611       [&capture](H4PacketWithH4&& packet) {
2612         ++capture.sends_called;
2613         PW_TEST_ASSERT_OK_AND_ASSIGN(
2614             auto acl,
2615             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
2616         emboss::FirstKFrameView kframe = emboss::MakeFirstKFrameView(
2617             acl.payload().BackingStorage().data(), acl.SizeInBytes());
2618         for (size_t i = 0; i < 3; ++i) {
2619           EXPECT_EQ(kframe.payload()[i].Read(), capture.payload[i]);
2620         }
2621       });
2622 
2623   constexpr uint16_t kNumChannels = 5;
2624   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
2625                               std::move(send_to_controller_fn),
2626                               kNumChannels);
2627   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(
2628       proxy,
2629       /*num_credits_to_reserve=*/kNumChannels));
2630 
2631   uint16_t remote_cid = 123;
2632   std::array<L2capCoc, kNumChannels> channels{
2633       BuildCoc(proxy, CocParameters{.remote_cid = remote_cid}),
2634       BuildCoc(
2635           proxy,
2636           CocParameters{.remote_cid = static_cast<uint16_t>(remote_cid + 1)}),
2637       BuildCoc(
2638           proxy,
2639           CocParameters{.remote_cid = static_cast<uint16_t>(remote_cid + 2)}),
2640       BuildCoc(
2641           proxy,
2642           CocParameters{.remote_cid = static_cast<uint16_t>(remote_cid + 3)}),
2643       BuildCoc(
2644           proxy,
2645           CocParameters{.remote_cid = static_cast<uint16_t>(remote_cid + 4)}),
2646   };
2647 
2648   for (int i = 0; i < kNumChannels; ++i) {
2649     EXPECT_EQ(channels[i].Write(capture.payload), PW_STATUS_OK);
2650     std::for_each(capture.payload.begin(),
2651                   capture.payload.end(),
2652                   [](uint8_t& byte) { ++byte; });
2653   }
2654 
2655   EXPECT_EQ(capture.sends_called, kNumChannels);
2656 }
2657 
2658 // ########## L2capCocReadTest
2659 
TEST(L2capCocReadTest,BasicRead)2660 TEST(L2capCocReadTest, BasicRead) {
2661   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2662       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2663   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2664       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2665   ProxyHost proxy = ProxyHost(
2666       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2667 
2668   struct {
2669     int sends_called = 0;
2670     std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
2671   } capture;
2672 
2673   uint16_t handle = 123;
2674   uint16_t local_cid = 234;
2675   L2capCoc channel = BuildCoc(
2676       proxy,
2677       CocParameters{.handle = handle,
2678                     .local_cid = local_cid,
2679                     .receive_fn = [&capture](pw::span<uint8_t> payload) {
2680                       ++capture.sends_called;
2681                       EXPECT_TRUE(std::equal(payload.begin(),
2682                                              payload.end(),
2683                                              capture.expected_payload.begin(),
2684                                              capture.expected_payload.end()));
2685                     }});
2686 
2687   std::array<uint8_t,
2688              kFirstKFrameOverAclMinSize + capture.expected_payload.size()>
2689       hci_arr;
2690   hci_arr.fill(0);
2691   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2692 
2693   Result<emboss::AclDataFrameWriter> acl =
2694       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2695   acl->header().handle().Write(handle);
2696   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
2697                                  capture.expected_payload.size());
2698 
2699   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2700       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
2701   kframe.pdu_length().Write(kSduLengthFieldSize +
2702                             capture.expected_payload.size());
2703   kframe.channel_id().Write(local_cid);
2704   kframe.sdu_length().Write(capture.expected_payload.size());
2705   std::copy(capture.expected_payload.begin(),
2706             capture.expected_payload.end(),
2707             hci_arr.begin() + kFirstKFrameOverAclMinSize);
2708 
2709   // Send ACL data packet destined for the CoC we registered.
2710   proxy.HandleH4HciFromController(std::move(h4_packet));
2711 
2712   EXPECT_EQ(capture.sends_called, 1);
2713 }
2714 
TEST(L2capCocReadTest,ChannelHandlesReadWithNullReceiveFn)2715 TEST(L2capCocReadTest, ChannelHandlesReadWithNullReceiveFn) {
2716   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2717       []([[maybe_unused]] H4PacketWithHci&& packet) { FAIL(); });
2718   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2719       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2720   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
2721                               std::move(send_to_controller_fn),
2722                               /*le_acl_credits_to_reserve=*/0,
2723                               /*br_edr_acl_credits_to_reserve=*/0);
2724 
2725   uint16_t handle = 123;
2726   uint16_t local_cid = 234;
2727   L2capCoc channel = BuildCoc(
2728       proxy,
2729       CocParameters{
2730           .handle = handle,
2731           .local_cid = local_cid,
2732           .rx_credits = 1,
2733           .event_fn = []([[maybe_unused]] L2capCoc::Event event) { FAIL(); }});
2734 
2735   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
2736   hci_arr.fill(0);
2737   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2738 
2739   Result<emboss::AclDataFrameWriter> acl =
2740       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2741   acl->header().handle().Write(handle);
2742   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
2743 
2744   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2745       acl->payload().BackingStorage().data(), acl->payload().SizeInBytes());
2746   kframe.pdu_length().Write(kSduLengthFieldSize);
2747   kframe.channel_id().Write(local_cid);
2748   kframe.sdu_length().Write(0);
2749 
2750   proxy.HandleH4HciFromController(std::move(h4_packet));
2751 }
2752 
TEST(L2capCocReadTest,ErrorOnRxToStoppedChannel)2753 TEST(L2capCocReadTest, ErrorOnRxToStoppedChannel) {
2754   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2755       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2756   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
2757       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2758   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
2759                               std::move(send_to_controller_fn),
2760                               /*le_acl_credits_to_reserve=*/0,
2761                               /*br_edr_acl_credits_to_reserve*/ 0);
2762 
2763   int events_received = 0;
2764   uint16_t num_invalid_rx = 3;
2765   uint16_t handle = 123;
2766   uint16_t local_cid = 234;
2767   L2capCoc channel = BuildCoc(
2768       proxy,
2769       CocParameters{
2770           .handle = handle,
2771           .local_cid = local_cid,
2772           .rx_credits = num_invalid_rx,
2773           .receive_fn =
2774               []([[maybe_unused]] pw::span<uint8_t> payload) { FAIL(); },
2775           .event_fn =
2776               [&events_received](L2capCoc::Event event) {
2777                 ++events_received;
2778                 EXPECT_EQ(event, L2capCoc::Event::kRxWhileStopped);
2779               }});
2780 
2781   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
2782   hci_arr.fill(0);
2783 
2784   Result<emboss::AclDataFrameWriter> acl =
2785       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2786   acl->header().handle().Write(handle);
2787   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
2788 
2789   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2790       acl->payload().BackingStorage().data(), acl->payload().SizeInBytes());
2791   kframe.pdu_length().Write(kSduLengthFieldSize);
2792   kframe.channel_id().Write(local_cid);
2793   kframe.sdu_length().Write(0);
2794 
2795   EXPECT_EQ(channel.Stop(), PW_STATUS_OK);
2796   for (int i = 0; i < num_invalid_rx; ++i) {
2797     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2798     proxy.HandleH4HciFromController(std::move(h4_packet));
2799   }
2800   EXPECT_EQ(events_received, num_invalid_rx);
2801 }
2802 
TEST(L2capCocReadTest,TooShortAclPassedToHost)2803 TEST(L2capCocReadTest, TooShortAclPassedToHost) {
2804   int sends_called = 0;
2805   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2806       [&sends_called]([[maybe_unused]] H4PacketWithHci&& packet) {
2807         ++sends_called;
2808       });
2809   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2810       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2811   ProxyHost proxy = ProxyHost(
2812       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2813 
2814   uint16_t handle = 123;
2815   uint16_t local_cid = 234;
2816   L2capCoc channel = BuildCoc(
2817       proxy,
2818       CocParameters{
2819           .handle = handle,
2820           .local_cid = local_cid,
2821           .receive_fn = []([[maybe_unused]] pw::span<uint8_t> payload) {
2822             FAIL();
2823           }});
2824 
2825   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
2826   hci_arr.fill(0);
2827   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2828 
2829   Result<emboss::AclDataFrameWriter> acl =
2830       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2831   acl->header().handle().Write(handle);
2832   // Write size larger than buffer size.
2833   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() + 5);
2834 
2835   proxy.HandleH4HciFromController(std::move(h4_packet));
2836 
2837   EXPECT_EQ(sends_called, 1);
2838 }
2839 
TEST(L2capCocReadTest,ChannelClosedWithErrorIfMtuExceeded)2840 TEST(L2capCocReadTest, ChannelClosedWithErrorIfMtuExceeded) {
2841   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2842       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2843   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2844       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2845   ProxyHost proxy = ProxyHost(
2846       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2847 
2848   uint16_t handle = 123;
2849   uint16_t local_cid = 234;
2850   constexpr uint16_t kRxMtu = 5;
2851   int events_received = 0;
2852   L2capCoc channel = BuildCoc(
2853       proxy,
2854       CocParameters{
2855           .handle = handle,
2856           .local_cid = local_cid,
2857           .rx_mtu = kRxMtu,
2858           .receive_fn =
2859               []([[maybe_unused]] pw::span<uint8_t> payload) { FAIL(); },
2860           .event_fn =
2861               [&events_received](L2capCoc::Event event) {
2862                 ++events_received;
2863                 EXPECT_EQ(event, L2capCoc::Event::kRxInvalid);
2864               }});
2865 
2866   constexpr uint16_t kPayloadSize = kRxMtu + 1;
2867   std::array<uint8_t, kFirstKFrameOverAclMinSize + kPayloadSize> hci_arr;
2868   hci_arr.fill(0);
2869   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2870 
2871   Result<emboss::AclDataFrameWriter> acl =
2872       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2873   acl->header().handle().Write(handle);
2874   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
2875                                  kPayloadSize);
2876 
2877   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2878       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
2879   kframe.pdu_length().Write(kSduLengthFieldSize + kPayloadSize);
2880   kframe.channel_id().Write(local_cid);
2881   kframe.sdu_length().Write(kPayloadSize);
2882 
2883   proxy.HandleH4HciFromController(std::move(h4_packet));
2884 
2885   EXPECT_EQ(events_received, 1);
2886 }
2887 
TEST(L2capCocReadTest,ChannelClosedWithErrorIfMpsExceeded)2888 TEST(L2capCocReadTest, ChannelClosedWithErrorIfMpsExceeded) {
2889   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2890       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2891   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2892       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2893   ProxyHost proxy = ProxyHost(
2894       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2895 
2896   uint16_t handle = 123;
2897   uint16_t local_cid = 234;
2898   constexpr uint16_t kRxMps = 5;
2899   int events_received = 0;
2900   L2capCoc channel = BuildCoc(
2901       proxy,
2902       CocParameters{
2903           .handle = handle,
2904           .local_cid = local_cid,
2905           .rx_mps = kRxMps,
2906           .receive_fn =
2907               []([[maybe_unused]] pw::span<uint8_t> payload) { FAIL(); },
2908           .event_fn =
2909               [&events_received](L2capCoc::Event event) {
2910                 ++events_received;
2911                 EXPECT_EQ(event, L2capCoc::Event::kRxInvalid);
2912               }});
2913 
2914   constexpr uint16_t kPayloadSize = kRxMps + 1;
2915   std::array<uint8_t, kFirstKFrameOverAclMinSize + kPayloadSize> hci_arr;
2916   hci_arr.fill(0);
2917   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
2918 
2919   Result<emboss::AclDataFrameWriter> acl =
2920       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2921   acl->header().handle().Write(handle);
2922   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
2923                                  kPayloadSize);
2924 
2925   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2926       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
2927   kframe.pdu_length().Write(kSduLengthFieldSize + kPayloadSize);
2928   kframe.channel_id().Write(local_cid);
2929   kframe.sdu_length().Write(kPayloadSize);
2930 
2931   proxy.HandleH4HciFromController(std::move(h4_packet));
2932 
2933   EXPECT_EQ(events_received, 1);
2934 }
2935 
TEST(L2capCocReadTest,ChannelClosedWithErrorIfPayloadsExceedSduLength)2936 TEST(L2capCocReadTest, ChannelClosedWithErrorIfPayloadsExceedSduLength) {
2937   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
2938       []([[maybe_unused]] H4PacketWithHci&& packet) {});
2939   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
2940       []([[maybe_unused]] H4PacketWithH4&& packet) {});
2941   ProxyHost proxy = ProxyHost(
2942       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
2943 
2944   uint16_t handle = 123;
2945   uint16_t local_cid = 234;
2946   int events_received = 0;
2947   L2capCoc channel = BuildCoc(
2948       proxy,
2949       CocParameters{
2950           .handle = handle,
2951           .local_cid = local_cid,
2952           .receive_fn =
2953               []([[maybe_unused]] pw::span<uint8_t> payload) { FAIL(); },
2954           .event_fn =
2955               [&events_received](L2capCoc::Event event) {
2956                 ++events_received;
2957                 EXPECT_EQ(event, L2capCoc::Event::kRxInvalid);
2958               }});
2959 
2960   constexpr uint16_t k1stPayloadSize = 1;
2961   constexpr uint16_t k2ndPayloadSize = 3;
2962   ASSERT_GT(k2ndPayloadSize, k1stPayloadSize + 1);
2963   // Indicate SDU length that does not account for the 2nd payload size.
2964   constexpr uint16_t kSduLength = k1stPayloadSize + 1;
2965 
2966   std::array<uint8_t,
2967              kFirstKFrameOverAclMinSize +
2968                  std::max(k1stPayloadSize, k2ndPayloadSize)>
2969       hci_arr;
2970   hci_arr.fill(0);
2971   H4PacketWithHci h4_1st_segment{
2972       emboss::H4PacketType::ACL_DATA,
2973       pw::span<uint8_t>(hci_arr.data(),
2974                         kFirstKFrameOverAclMinSize + k1stPayloadSize)};
2975 
2976   Result<emboss::AclDataFrameWriter> acl =
2977       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
2978   acl->header().handle().Write(handle);
2979   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
2980                                  k1stPayloadSize);
2981 
2982   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
2983       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
2984   kframe.pdu_length().Write(kSduLengthFieldSize + k1stPayloadSize);
2985   kframe.channel_id().Write(local_cid);
2986   kframe.sdu_length().Write(kSduLength);
2987 
2988   proxy.HandleH4HciFromController(std::move(h4_1st_segment));
2989 
2990   // Send 2nd segment.
2991   acl->data_total_length().Write(emboss::SubsequentKFrame::MinSizeInBytes() +
2992                                  k2ndPayloadSize);
2993   kframe.pdu_length().Write(k2ndPayloadSize);
2994   H4PacketWithHci h4_2nd_segment{
2995       emboss::H4PacketType::ACL_DATA,
2996       pw::span<uint8_t>(hci_arr.data(),
2997                         emboss::AclDataFrame::MinSizeInBytes() +
2998                             emboss::SubsequentKFrame::MinSizeInBytes() +
2999                             k2ndPayloadSize)};
3000 
3001   proxy.HandleH4HciFromController(std::move(h4_2nd_segment));
3002 
3003   EXPECT_EQ(events_received, 1);
3004 }
3005 
TEST(L2capCocReadTest,NoReadOnStoppedChannel)3006 TEST(L2capCocReadTest, NoReadOnStoppedChannel) {
3007   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3008       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3009   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3010       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3011   ProxyHost proxy = ProxyHost(
3012       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3013 
3014   uint16_t handle = 123;
3015   uint16_t local_cid = 234;
3016   L2capCoc channel = BuildCoc(
3017       proxy,
3018       CocParameters{
3019           .handle = handle,
3020           .local_cid = local_cid,
3021           .receive_fn = []([[maybe_unused]] pw::span<uint8_t> payload) {
3022             FAIL();
3023           }});
3024 
3025   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
3026   hci_arr.fill(0);
3027   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3028 
3029   Result<emboss::AclDataFrameWriter> acl =
3030       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3031   acl->header().handle().Write(handle);
3032   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3033 
3034   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3035       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3036   kframe.pdu_length().Write(kSduLengthFieldSize);
3037   kframe.channel_id().Write(local_cid);
3038 
3039   EXPECT_EQ(channel.Stop(), PW_STATUS_OK);
3040   proxy.HandleH4HciFromController(std::move(h4_packet));
3041 }
3042 
TEST(L2capCocReadTest,NoReadOnSameCidDifferentConnectionHandle)3043 TEST(L2capCocReadTest, NoReadOnSameCidDifferentConnectionHandle) {
3044   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3045       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3046   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3047       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3048   ProxyHost proxy = ProxyHost(
3049       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3050 
3051   uint16_t local_cid = 234;
3052   L2capCoc channel = BuildCoc(
3053       proxy,
3054       CocParameters{
3055           .local_cid = local_cid,
3056           .receive_fn = []([[maybe_unused]] pw::span<uint8_t> payload) {
3057             FAIL();
3058           }});
3059 
3060   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
3061   hci_arr.fill(0);
3062   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3063 
3064   Result<emboss::AclDataFrameWriter> acl =
3065       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3066   acl->header().handle().Write(444);
3067   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3068 
3069   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3070       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3071   kframe.pdu_length().Write(kSduLengthFieldSize);
3072   kframe.channel_id().Write(local_cid);
3073 
3074   proxy.HandleH4HciFromController(std::move(h4_packet));
3075 }
3076 
TEST(L2capCocReadTest,MultipleReadsSameChannel)3077 TEST(L2capCocReadTest, MultipleReadsSameChannel) {
3078   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3079       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3080   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3081       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3082   ProxyHost proxy = ProxyHost(
3083       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3084 
3085   struct {
3086     int sends_called = 0;
3087     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
3088   } capture;
3089 
3090   uint16_t handle = 123;
3091   uint16_t local_cid = 234;
3092   L2capCoc channel = BuildCoc(
3093       proxy,
3094       CocParameters{.handle = handle,
3095                     .local_cid = local_cid,
3096                     .receive_fn = [&capture](pw::span<uint8_t> payload) {
3097                       ++capture.sends_called;
3098                       EXPECT_TRUE(std::equal(payload.begin(),
3099                                              payload.end(),
3100                                              capture.payload.begin(),
3101                                              capture.payload.end()));
3102                     }});
3103 
3104   std::array<uint8_t, kFirstKFrameOverAclMinSize + capture.payload.size()>
3105       hci_arr;
3106   hci_arr.fill(0);
3107 
3108   Result<emboss::AclDataFrameWriter> acl =
3109       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3110   acl->header().handle().Write(handle);
3111   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
3112                                  capture.payload.size());
3113 
3114   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3115       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3116   kframe.pdu_length().Write(capture.payload.size() + kSduLengthFieldSize);
3117   kframe.channel_id().Write(local_cid);
3118   kframe.sdu_length().Write(capture.payload.size());
3119 
3120   int num_reads = 10;
3121   for (int i = 0; i < num_reads; ++i) {
3122     std::copy(capture.payload.begin(),
3123               capture.payload.end(),
3124               hci_arr.begin() + kFirstKFrameOverAclMinSize);
3125 
3126     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3127     proxy.HandleH4HciFromController(std::move(h4_packet));
3128 
3129     std::for_each(capture.payload.begin(),
3130                   capture.payload.end(),
3131                   [](uint8_t& byte) { ++byte; });
3132   }
3133 
3134   EXPECT_EQ(capture.sends_called, num_reads);
3135 }
3136 
TEST(L2capCocReadTest,MultipleReadsMultipleChannels)3137 TEST(L2capCocReadTest, MultipleReadsMultipleChannels) {
3138   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3139       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3140   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3141       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3142   ProxyHost proxy = ProxyHost(
3143       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3144 
3145   struct {
3146     int sends_called = 0;
3147     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
3148   } capture;
3149 
3150   constexpr int kNumChannels = 5;
3151   uint16_t local_cid = 123;
3152   uint16_t handle = 456;
3153   auto receive_fn = [&capture](pw::span<uint8_t> payload) {
3154     ++capture.sends_called;
3155     EXPECT_TRUE(std::equal(payload.begin(),
3156                            payload.end(),
3157                            capture.payload.begin(),
3158                            capture.payload.end()));
3159   };
3160   std::array<L2capCoc, kNumChannels> channels{
3161       BuildCoc(proxy,
3162                CocParameters{.handle = handle,
3163                              .local_cid = local_cid,
3164                              .receive_fn = receive_fn}),
3165       BuildCoc(proxy,
3166                CocParameters{.handle = handle,
3167                              .local_cid = static_cast<uint16_t>(local_cid + 1),
3168                              .receive_fn = receive_fn}),
3169       BuildCoc(proxy,
3170                CocParameters{.handle = handle,
3171                              .local_cid = static_cast<uint16_t>(local_cid + 2),
3172                              .receive_fn = receive_fn}),
3173       BuildCoc(proxy,
3174                CocParameters{.handle = handle,
3175                              .local_cid = static_cast<uint16_t>(local_cid + 3),
3176                              .receive_fn = receive_fn}),
3177       BuildCoc(proxy,
3178                CocParameters{.handle = handle,
3179                              .local_cid = static_cast<uint16_t>(local_cid + 4),
3180                              .receive_fn = receive_fn}),
3181   };
3182 
3183   std::array<uint8_t, kFirstKFrameOverAclMinSize + capture.payload.size()>
3184       hci_arr;
3185   hci_arr.fill(0);
3186 
3187   Result<emboss::AclDataFrameWriter> acl =
3188       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3189   acl->header().handle().Write(handle);
3190   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
3191                                  capture.payload.size());
3192 
3193   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3194       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3195   kframe.pdu_length().Write(capture.payload.size() + kSduLengthFieldSize);
3196   kframe.sdu_length().Write(capture.payload.size());
3197 
3198   for (int i = 0; i < kNumChannels; ++i) {
3199     kframe.channel_id().Write(local_cid + i);
3200 
3201     std::copy(capture.payload.begin(),
3202               capture.payload.end(),
3203               hci_arr.begin() + kFirstKFrameOverAclMinSize);
3204 
3205     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3206     proxy.HandleH4HciFromController(std::move(h4_packet));
3207 
3208     std::for_each(capture.payload.begin(),
3209                   capture.payload.end(),
3210                   [](uint8_t& byte) { ++byte; });
3211   }
3212 
3213   EXPECT_EQ(capture.sends_called, kNumChannels);
3214 }
3215 
TEST(L2capCocReadTest,ChannelStoppageDoNotAffectOtherChannels)3216 TEST(L2capCocReadTest, ChannelStoppageDoNotAffectOtherChannels) {
3217   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3218       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3219   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3220       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3221   ProxyHost proxy = ProxyHost(
3222       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3223 
3224   struct {
3225     int sends_called = 0;
3226     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
3227   } capture;
3228 
3229   constexpr int kNumChannels = 5;
3230   uint16_t local_cid = 123;
3231   uint16_t handle = 456;
3232   auto receive_fn = [&capture](pw::span<uint8_t> payload) {
3233     ++capture.sends_called;
3234     EXPECT_TRUE(std::equal(payload.begin(),
3235                            payload.end(),
3236                            capture.payload.begin(),
3237                            capture.payload.end()));
3238   };
3239   std::array<L2capCoc, kNumChannels> channels{
3240       BuildCoc(proxy,
3241                CocParameters{.handle = handle,
3242                              .local_cid = local_cid,
3243                              .receive_fn = receive_fn}),
3244       BuildCoc(proxy,
3245                CocParameters{.handle = handle,
3246                              .local_cid = static_cast<uint16_t>(local_cid + 1),
3247                              .receive_fn = receive_fn}),
3248       BuildCoc(proxy,
3249                CocParameters{.handle = handle,
3250                              .local_cid = static_cast<uint16_t>(local_cid + 2),
3251                              .receive_fn = receive_fn}),
3252       BuildCoc(proxy,
3253                CocParameters{.handle = handle,
3254                              .local_cid = static_cast<uint16_t>(local_cid + 3),
3255                              .receive_fn = receive_fn}),
3256       BuildCoc(proxy,
3257                CocParameters{.handle = handle,
3258                              .local_cid = static_cast<uint16_t>(local_cid + 4),
3259                              .receive_fn = receive_fn}),
3260   };
3261 
3262   // Stop the 2nd and 4th of the 5 channels.
3263   EXPECT_EQ(channels[1].Stop(), PW_STATUS_OK);
3264   EXPECT_EQ(channels[3].Stop(), PW_STATUS_OK);
3265 
3266   std::array<uint8_t, kFirstKFrameOverAclMinSize + capture.payload.size()>
3267       hci_arr;
3268   hci_arr.fill(0);
3269 
3270   Result<emboss::AclDataFrameWriter> acl =
3271       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3272   acl->header().handle().Write(handle);
3273   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
3274                                  capture.payload.size());
3275 
3276   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3277       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3278   kframe.pdu_length().Write(capture.payload.size() + kSduLengthFieldSize);
3279   kframe.sdu_length().Write(capture.payload.size());
3280 
3281   for (int i = 0; i < kNumChannels; ++i) {
3282     // Still send packets to the stopped channels, so we can validate that it
3283     // does not cause issues.
3284     kframe.channel_id().Write(local_cid + i);
3285 
3286     std::copy(capture.payload.begin(),
3287               capture.payload.end(),
3288               hci_arr.begin() + kFirstKFrameOverAclMinSize);
3289 
3290     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3291     proxy.HandleH4HciFromController(std::move(h4_packet));
3292 
3293     std::for_each(capture.payload.begin(),
3294                   capture.payload.end(),
3295                   [](uint8_t& byte) { ++byte; });
3296   }
3297 
3298   EXPECT_EQ(capture.sends_called, kNumChannels - 2);
3299 }
3300 
TEST(L2capCocReadTest,ReadDropsSduSentOver2Segments)3301 TEST(L2capCocReadTest, ReadDropsSduSentOver2Segments) {
3302   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3303       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3304   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3305       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3306   ProxyHost proxy = ProxyHost(
3307       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3308 
3309   int sends_called = 0;
3310   uint16_t local_cid = 234;
3311   uint16_t handle = 123;
3312   L2capCoc channel = BuildCoc(
3313       proxy,
3314       CocParameters{.handle = handle,
3315                     .local_cid = local_cid,
3316                     .receive_fn = [&sends_called](pw::span<uint8_t> payload) {
3317                       EXPECT_EQ(payload.size(), 0ul);
3318                       ++sends_called;
3319                     }});
3320 
3321   // Send L2CAP SDU segmented over 2 frames.
3322   constexpr uint16_t k1stPayloadSize = 13;
3323   constexpr uint16_t k2ndPayloadSize = 19;
3324   constexpr uint16_t kSduLength = k1stPayloadSize + k2ndPayloadSize;
3325 
3326   std::array<uint8_t,
3327              kFirstKFrameOverAclMinSize +
3328                  std::max(k1stPayloadSize, k2ndPayloadSize)>
3329       hci_arr;
3330   hci_arr.fill(0);
3331   H4PacketWithHci h4_1st_segment{
3332       emboss::H4PacketType::ACL_DATA,
3333       pw::span<uint8_t>(hci_arr.data(),
3334                         kFirstKFrameOverAclMinSize + k1stPayloadSize)};
3335 
3336   Result<emboss::AclDataFrameWriter> acl =
3337       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3338   acl->header().handle().Write(handle);
3339   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes() +
3340                                  k1stPayloadSize);
3341 
3342   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3343       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3344   kframe.pdu_length().Write(kSduLengthFieldSize + k1stPayloadSize);
3345   kframe.channel_id().Write(local_cid);
3346   kframe.sdu_length().Write(kSduLength);
3347 
3348   proxy.HandleH4HciFromController(std::move(h4_1st_segment));
3349 
3350   // Send 2nd segment.
3351   acl->data_total_length().Write(emboss::SubsequentKFrame::MinSizeInBytes() +
3352                                  k2ndPayloadSize);
3353   kframe.pdu_length().Write(k2ndPayloadSize);
3354   H4PacketWithHci h4_2nd_segment{
3355       emboss::H4PacketType::ACL_DATA,
3356       pw::span<uint8_t>(hci_arr.data(),
3357                         emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
3358                             emboss::SubsequentKFrame::MinSizeInBytes() +
3359                             k2ndPayloadSize)};
3360 
3361   proxy.HandleH4HciFromController(std::move(h4_2nd_segment));
3362 
3363   // Now ensure a non-segmented packet with size 0 payload is read.
3364   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3365   kframe.pdu_length().Write(kSduLengthFieldSize);
3366   kframe.sdu_length().Write(0);
3367   H4PacketWithHci h4_packet{
3368       emboss::H4PacketType::ACL_DATA,
3369       pw::span<uint8_t>(hci_arr.data(), kFirstKFrameOverAclMinSize)};
3370 
3371   proxy.HandleH4HciFromController(std::move(h4_packet));
3372 
3373   EXPECT_EQ(sends_called, 1);
3374 }
3375 
TEST(L2capCocReadTest,ReadDropsSduSentOver4Segments)3376 TEST(L2capCocReadTest, ReadDropsSduSentOver4Segments) {
3377   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3378       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3379   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3380       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3381   ProxyHost proxy = ProxyHost(
3382       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3383 
3384   int sends_called = 0;
3385   uint16_t handle = 123;
3386   uint16_t local_cid = 234;
3387   L2capCoc channel = BuildCoc(
3388       proxy,
3389       CocParameters{
3390           .handle = handle,
3391           .local_cid = local_cid,
3392           .receive_fn =
3393               [&sends_called]([[maybe_unused]] pw::span<uint8_t> payload) {
3394                 EXPECT_EQ(payload.size(), 0ul);
3395                 ++sends_called;
3396               }});
3397 
3398   // Send L2CAP SDU segmented over 4 frames with equal PDU length.
3399   constexpr uint16_t kPduLength = 13;
3400   ASSERT_GE(kPduLength, kSduLengthFieldSize);
3401   constexpr uint16_t kSduLength = 4 * kPduLength - kSduLengthFieldSize;
3402 
3403   std::array<uint8_t,
3404              emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
3405                  emboss::BasicL2capHeader::IntrinsicSizeInBytes() + kPduLength>
3406       hci_arr;
3407   hci_arr.fill(0);
3408   H4PacketWithHci h4_1st_segment{emboss::H4PacketType::ACL_DATA, hci_arr};
3409 
3410   Result<emboss::AclDataFrameWriter> acl =
3411       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3412   acl->header().handle().Write(handle);
3413   acl->data_total_length().Write(
3414       emboss::BasicL2capHeader::IntrinsicSizeInBytes() + kPduLength);
3415 
3416   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3417       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3418   kframe.pdu_length().Write(kPduLength);
3419   kframe.channel_id().Write(local_cid);
3420   kframe.sdu_length().Write(kSduLength);
3421 
3422   proxy.HandleH4HciFromController(std::move(h4_1st_segment));
3423 
3424   H4PacketWithHci h4_2nd_segment{emboss::H4PacketType::ACL_DATA, hci_arr};
3425   proxy.HandleH4HciFromController(std::move(h4_2nd_segment));
3426 
3427   H4PacketWithHci h4_3rd_segment{emboss::H4PacketType::ACL_DATA, hci_arr};
3428   proxy.HandleH4HciFromController(std::move(h4_3rd_segment));
3429 
3430   H4PacketWithHci h4_4th_segment{emboss::H4PacketType::ACL_DATA, hci_arr};
3431   proxy.HandleH4HciFromController(std::move(h4_4th_segment));
3432 
3433   // Now ensure a non-segmented packet with size 0 payload is read.
3434   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3435   kframe.pdu_length().Write(kSduLengthFieldSize);
3436   kframe.sdu_length().Write(0);
3437   H4PacketWithHci h4_packet{
3438       emboss::H4PacketType::ACL_DATA,
3439       pw::span(hci_arr.data(), kFirstKFrameOverAclMinSize)};
3440 
3441   proxy.HandleH4HciFromController(std::move(h4_packet));
3442 
3443   EXPECT_EQ(sends_called, 1);
3444 }
3445 
TEST(L2capCocReadTest,NonCocAclPacketPassesThroughToHost)3446 TEST(L2capCocReadTest, NonCocAclPacketPassesThroughToHost) {
3447   struct {
3448     int sends_called = 0;
3449     uint16_t handle = 123;
3450     std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
3451   } capture;
3452 
3453   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3454       [&capture](H4PacketWithHci&& packet) {
3455         ++capture.sends_called;
3456         Result<emboss::AclDataFrameWriter> acl =
3457             MakeEmbossWriter<emboss::AclDataFrameWriter>(packet.GetHciSpan());
3458         EXPECT_EQ(acl->header().handle().Read(), capture.handle);
3459         emboss::BFrameView bframe =
3460             emboss::MakeBFrameView(acl->payload().BackingStorage().data(),
3461                                    acl->data_total_length().Read());
3462         for (size_t i = 0; i < capture.expected_payload.size(); ++i) {
3463           EXPECT_EQ(bframe.payload()[i].Read(), capture.expected_payload[i]);
3464         }
3465       });
3466   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3467       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3468   ProxyHost proxy = ProxyHost(
3469       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3470 
3471   // Acquire unused CoC to validate that doing so does not interfere.
3472   L2capCoc channel = BuildCoc(
3473       proxy,
3474       CocParameters{
3475           .handle = capture.handle,
3476           .receive_fn = []([[maybe_unused]] pw::span<uint8_t> payload) {
3477             FAIL();
3478           }});
3479 
3480   std::array<uint8_t,
3481              emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
3482                  emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
3483                  capture.expected_payload.size()>
3484       hci_arr;
3485   hci_arr.fill(0);
3486   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3487 
3488   Result<emboss::AclDataFrameWriter> acl =
3489       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3490   acl->header().handle().Write(capture.handle);
3491   acl->data_total_length().Write(
3492       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
3493       capture.expected_payload.size());
3494 
3495   emboss::BFrameWriter bframe = emboss::MakeBFrameView(
3496       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3497   bframe.pdu_length().Write(capture.expected_payload.size());
3498   bframe.channel_id().Write(111);
3499   std::copy(capture.expected_payload.begin(),
3500             capture.expected_payload.end(),
3501             hci_arr.begin() +
3502                 emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
3503                 emboss::BasicL2capHeader::IntrinsicSizeInBytes());
3504 
3505   // Send ACL packet that should be forwarded to host.
3506   proxy.HandleH4HciFromController(std::move(h4_packet));
3507 
3508   EXPECT_EQ(capture.sends_called, 1);
3509 }
3510 
TEST(L2capCocReadTest,FragmentedPduStopsChannelWithoutDisruptingOtherChannel)3511 TEST(L2capCocReadTest, FragmentedPduStopsChannelWithoutDisruptingOtherChannel) {
3512   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3513       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3514   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3515       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3516   ProxyHost proxy = ProxyHost(
3517       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3518 
3519   int events_called = 0;
3520   uint16_t handle = 123;
3521   uint16_t local_cid = 234;
3522   L2capCoc channel = BuildCoc(
3523       proxy,
3524       CocParameters{
3525           .handle = handle,
3526           .local_cid = local_cid,
3527           .receive_fn =
3528               []([[maybe_unused]] pw::span<uint8_t> payload) { FAIL(); },
3529           .event_fn =
3530               [&events_called](L2capCoc::Event event) {
3531                 EXPECT_EQ(event, L2capCoc::Event::kRxFragmented);
3532                 ++events_called;
3533               }});
3534 
3535   constexpr uint8_t kPduLength = 19;
3536   ASSERT_GT(kPduLength, kSduLengthFieldSize);
3537   constexpr uint8_t kSduLength = kPduLength - kSduLengthFieldSize;
3538 
3539   // Send first ACL fragment. Should stop channel with error.
3540   std::array<uint8_t, emboss::AclDataFrame::MinSizeInBytes() + kSduLength>
3541       hci_arr;
3542   hci_arr.fill(0);
3543   H4PacketWithHci h4_1st_fragment{
3544       emboss::H4PacketType::ACL_DATA,
3545       pw::span(hci_arr.data(), kFirstKFrameOverAclMinSize)};
3546 
3547   Result<emboss::AclDataFrameWriter> acl =
3548       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3549   acl->header().handle().Write(handle);
3550   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3551 
3552   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3553       acl->payload().BackingStorage().data(), acl->data_total_length().Read());
3554   kframe.pdu_length().Write(kPduLength);
3555   kframe.channel_id().Write(local_cid);
3556   kframe.sdu_length().Write(kSduLength);
3557 
3558   proxy.HandleH4HciFromController(std::move(h4_1st_fragment));
3559 
3560   // Ensure 2nd fragment is silently discarded.
3561   acl->header().packet_boundary_flag().Write(
3562       emboss::AclDataPacketBoundaryFlag::CONTINUING_FRAGMENT);
3563   acl->data_total_length().Write(kSduLength / 2);
3564   H4PacketWithHci h4_2nd_fragment{
3565       emboss::H4PacketType::ACL_DATA,
3566       pw::span<uint8_t>(
3567           hci_arr.data(),
3568           emboss::AclDataFrame::MinSizeInBytes() + kSduLength / 2)};
3569   proxy.HandleH4HciFromController(std::move(h4_2nd_fragment));
3570 
3571   // Ensure 3rd fragment is silently discarded.
3572   if (kSduLength % 2 == 1) {
3573     acl->data_total_length().Write(kSduLength / 2 + 1);
3574   }
3575   H4PacketWithHci h4_3rd_fragment{
3576       emboss::H4PacketType::ACL_DATA,
3577       pw::span<uint8_t>(hci_arr.data(),
3578                         emboss::AclDataFrame::MinSizeInBytes() +
3579                             kSduLength / 2 + (kSduLength % 2))};
3580   proxy.HandleH4HciFromController(std::move(h4_3rd_fragment));
3581 
3582   EXPECT_EQ(events_called, 1);
3583 
3584   int reads_called = 0;
3585   uint16_t different_local_cid = 432;
3586   L2capCoc different_channel = BuildCoc(
3587       proxy,
3588       CocParameters{
3589           .handle = handle,
3590           .local_cid = different_local_cid,
3591           .receive_fn =
3592               [&reads_called]([[maybe_unused]] pw::span<uint8_t> payload) {
3593                 ++reads_called;
3594               },
3595           .event_fn = []([[maybe_unused]] L2capCoc::Event event) { FAIL(); }});
3596 
3597   // Ensure different channel can still receive valid payload.
3598   std::array<uint8_t, kFirstKFrameOverAclMinSize> other_hci_arr;
3599   other_hci_arr.fill(0);
3600   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, other_hci_arr};
3601 
3602   Result<emboss::AclDataFrameWriter> other_acl =
3603       MakeEmbossWriter<emboss::AclDataFrameWriter>(other_hci_arr);
3604   other_acl->header().handle().Write(handle);
3605   other_acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3606 
3607   emboss::FirstKFrameWriter other_kframe =
3608       emboss::MakeFirstKFrameView(other_acl->payload().BackingStorage().data(),
3609                                   other_acl->data_total_length().Read());
3610   other_kframe.pdu_length().Write(kSduLengthFieldSize);
3611   other_kframe.channel_id().Write(different_local_cid);
3612 
3613   proxy.HandleH4HciFromController(std::move(h4_packet));
3614 
3615   EXPECT_EQ(reads_called, 1);
3616 }
3617 
TEST(L2capCocReadTest,UnexpectedContinuingFragmentStopsChannel)3618 TEST(L2capCocReadTest, UnexpectedContinuingFragmentStopsChannel) {
3619   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3620       [](H4PacketWithHci&&) {});
3621   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3622       [](H4PacketWithH4&&) {});
3623   ProxyHost proxy = ProxyHost(
3624       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3625 
3626   int events_received = 0;
3627   uint16_t handle = 123;
3628   uint16_t local_cid = 234;
3629   L2capCoc channel = BuildCoc(
3630       proxy,
3631       CocParameters{.handle = handle,
3632                     .local_cid = local_cid,
3633                     .receive_fn = [](span<uint8_t>) { FAIL(); },
3634                     .event_fn =
3635                         [&events_received](L2capCoc::Event event) {
3636                           ++events_received;
3637                           EXPECT_EQ(event, L2capCoc::Event::kRxFragmented);
3638                         }});
3639 
3640   std::array<uint8_t, kFirstKFrameOverAclMinSize> hci_arr;
3641   hci_arr.fill(0);
3642   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3643 
3644   Result<emboss::AclDataFrameWriter> acl =
3645       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3646   acl->header().handle().Write(handle);
3647   acl->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3648   acl->header().packet_boundary_flag().Write(
3649       emboss::AclDataPacketBoundaryFlag::CONTINUING_FRAGMENT);
3650 
3651   emboss::FirstKFrameWriter kframe = emboss::MakeFirstKFrameView(
3652       acl->payload().BackingStorage().data(), acl->payload().SizeInBytes());
3653   kframe.pdu_length().Write(kSduLengthFieldSize);
3654   kframe.channel_id().Write(local_cid);
3655 
3656   proxy.HandleH4HciFromController(std::move(h4_packet));
3657 
3658   EXPECT_EQ(events_received, 1);
3659 }
3660 
TEST(L2capCocReadTest,AclFrameWithIncompleteL2capHeaderForwardedToHost)3661 TEST(L2capCocReadTest, AclFrameWithIncompleteL2capHeaderForwardedToHost) {
3662   int sends_to_host_called = 0;
3663   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3664       [&sends_to_host_called]([[maybe_unused]] H4PacketWithHci&& packet) {
3665         ++sends_to_host_called;
3666       });
3667   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3668       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3669   ProxyHost proxy = ProxyHost(
3670       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3671 
3672   uint16_t handle = 123;
3673   L2capCoc channel = BuildCoc(proxy, CocParameters{.handle = handle});
3674 
3675   std::array<uint8_t, emboss::AclDataFrameHeader::IntrinsicSizeInBytes()>
3676       hci_arr;
3677   hci_arr.fill(0);
3678   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
3679 
3680   Result<emboss::AclDataFrameWriter> acl =
3681       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3682   acl->header().handle().Write(handle);
3683   acl->data_total_length().Write(0);
3684 
3685   proxy.HandleH4HciFromController(std::move(h4_packet));
3686 
3687   EXPECT_EQ(sends_to_host_called, 1);
3688 }
3689 
TEST(L2capCocReadTest,FragmentedPduDoesNotInterfereWithOtherChannels)3690 TEST(L2capCocReadTest, FragmentedPduDoesNotInterfereWithOtherChannels) {
3691   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3692       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3693   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3694       []([[maybe_unused]] H4PacketWithH4&& packet) {});
3695   ProxyHost proxy = ProxyHost(
3696       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
3697 
3698   uint16_t handle_frag = 0x123, handle_fine = 0x234;
3699   uint16_t cid_frag = 0x345, cid_fine = 0x456;
3700   int packets_received = 0;
3701   auto receive_fn =
3702       [&packets_received]([[maybe_unused]] pw::span<uint8_t> payload) {
3703         ++packets_received;
3704       };
3705   L2capCoc frag_channel = BuildCoc(proxy,
3706                                    CocParameters{
3707                                        .handle = handle_frag,
3708                                        .local_cid = cid_frag,
3709                                        .receive_fn = receive_fn,
3710                                    });
3711   L2capCoc fine_channel = BuildCoc(proxy,
3712                                    CocParameters{
3713                                        .handle = handle_fine,
3714                                        .local_cid = cid_fine,
3715                                        .receive_fn = receive_fn,
3716                                    });
3717 
3718   // Order of receptions:
3719   // 1. 1st of 3 fragments to frag_channel.
3720   // 2. Non-fragmented PDU to fine_channel.
3721   // 3. 2nd of 3 fragments to frag_channel.
3722   // 4. Non-fragmented PDU to fine_channel.
3723   // 5. 3rd of 3 fragments to frag_channel.
3724   // 6. Non-fragmented PDU to fine_channel.
3725 
3726   constexpr uint8_t kPduLength = 14;
3727   ASSERT_GT(kPduLength, kSduLengthFieldSize);
3728   constexpr uint8_t kSduLength = kPduLength - kSduLengthFieldSize;
3729 
3730   // 1. 1st of 3 fragments to frag_channel.
3731   std::array<uint8_t, emboss::AclDataFrame::MinSizeInBytes() + kSduLength>
3732       frag_hci_arr;
3733   frag_hci_arr.fill(0);
3734   H4PacketWithHci h4_1st_fragment{
3735       emboss::H4PacketType::ACL_DATA,
3736       pw::span(frag_hci_arr.data(), kFirstKFrameOverAclMinSize)};
3737 
3738   Result<emboss::AclDataFrameWriter> acl_frag =
3739       MakeEmbossWriter<emboss::AclDataFrameWriter>(frag_hci_arr);
3740   acl_frag->header().handle().Write(handle_frag);
3741   acl_frag->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3742 
3743   emboss::FirstKFrameWriter kframe_frag =
3744       emboss::MakeFirstKFrameView(acl_frag->payload().BackingStorage().data(),
3745                                   acl_frag->data_total_length().Read());
3746   kframe_frag.pdu_length().Write(kPduLength);
3747   kframe_frag.channel_id().Write(cid_frag);
3748   kframe_frag.sdu_length().Write(kSduLength);
3749 
3750   proxy.HandleH4HciFromController(std::move(h4_1st_fragment));
3751 
3752   // 2. Non-fragmented PDU to fine_channel.
3753   std::array<uint8_t, kFirstKFrameOverAclMinSize> fine_hci_arr;
3754   fine_hci_arr.fill(0);
3755   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA,
3756                             pw::span(fine_hci_arr)};
3757 
3758   Result<emboss::AclDataFrameWriter> acl_fine =
3759       MakeEmbossWriter<emboss::AclDataFrameWriter>(fine_hci_arr);
3760   acl_fine->header().handle().Write(handle_fine);
3761   acl_fine->data_total_length().Write(emboss::FirstKFrame::MinSizeInBytes());
3762 
3763   emboss::FirstKFrameWriter kframe_fine =
3764       emboss::MakeFirstKFrameView(acl_fine->payload().BackingStorage().data(),
3765                                   acl_fine->data_total_length().Read());
3766   kframe_fine.pdu_length().Write(kSduLengthFieldSize);
3767   kframe_fine.channel_id().Write(cid_fine);
3768   kframe_fine.sdu_length().Write(0);
3769 
3770   proxy.HandleH4HciFromController(std::move(h4_packet));
3771 
3772   // 3. 2nd of 3 fragments to frag_channel.
3773   acl_frag->header().packet_boundary_flag().Write(
3774       emboss::AclDataPacketBoundaryFlag::CONTINUING_FRAGMENT);
3775   acl_frag->data_total_length().Write(kSduLength / 2);
3776   H4PacketWithHci h4_2nd_fragment{
3777       emboss::H4PacketType::ACL_DATA,
3778       pw::span<uint8_t>(
3779           frag_hci_arr.data(),
3780           emboss::AclDataFrame::MinSizeInBytes() + kSduLength / 2)};
3781   proxy.HandleH4HciFromController(std::move(h4_2nd_fragment));
3782 
3783   // 4. Non-fragmented PDU to fine_channel.
3784   H4PacketWithHci h4_packet_2{emboss::H4PacketType::ACL_DATA,
3785                               pw::span(fine_hci_arr)};
3786   proxy.HandleH4HciFromController(std::move(h4_packet_2));
3787 
3788   // 5. 3rd of 3 fragments to frag_channel.
3789   if (kSduLength % 2 == 1) {
3790     acl_frag->data_total_length().Write(kSduLength / 2 + 1);
3791   }
3792   H4PacketWithHci h4_3rd_fragment{
3793       emboss::H4PacketType::ACL_DATA,
3794       pw::span<uint8_t>(frag_hci_arr.data(),
3795                         emboss::AclDataFrame::MinSizeInBytes() +
3796                             kSduLength / 2 + (kSduLength % 2))};
3797   proxy.HandleH4HciFromController(std::move(h4_3rd_fragment));
3798 
3799   // 6. Non-fragmented PDU to fine_channel.
3800   H4PacketWithHci h4_packet_3{emboss::H4PacketType::ACL_DATA,
3801                               pw::span(fine_hci_arr)};
3802   proxy.HandleH4HciFromController(std::move(h4_packet_3));
3803 
3804   EXPECT_EQ(packets_received, 3);
3805 }
3806 // ########## L2capCocQueueTest
3807 
TEST(L2capCocQueueTest,ReadBufferResponseDrainsQueue)3808 TEST(L2capCocQueueTest, ReadBufferResponseDrainsQueue) {
3809   size_t sends_called = 0;
3810 
3811   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3812       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3813   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3814       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
3815         ++sends_called;
3816       });
3817   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
3818                               std::move(send_to_controller_fn),
3819                               L2capCoc::QueueCapacity());
3820 
3821   L2capCoc channel =
3822       BuildCoc(proxy, CocParameters{.tx_credits = L2capCoc::QueueCapacity()});
3823 
3824   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
3825   for (size_t i = 0; i < L2capCoc::QueueCapacity(); ++i) {
3826     EXPECT_EQ(channel.Write({}), PW_STATUS_OK);
3827   }
3828   EXPECT_EQ(channel.Write({}), PW_STATUS_UNAVAILABLE);
3829   EXPECT_EQ(sends_called, 0u);
3830 
3831   PW_TEST_EXPECT_OK(
3832       SendLeReadBufferResponseFromController(proxy, L2capCoc::QueueCapacity()));
3833 
3834   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity());
3835 }
3836 
TEST(L2capCocQueueTest,NocpEventDrainsQueue)3837 TEST(L2capCocQueueTest, NocpEventDrainsQueue) {
3838   size_t sends_called = 0;
3839 
3840   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3841       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3842   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3843       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
3844         ++sends_called;
3845       });
3846   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
3847                               std::move(send_to_controller_fn),
3848                               L2capCoc::QueueCapacity());
3849   PW_TEST_EXPECT_OK(
3850       SendLeReadBufferResponseFromController(proxy, L2capCoc::QueueCapacity()));
3851 
3852   uint16_t handle = 123;
3853   L2capCoc channel =
3854       BuildCoc(proxy,
3855                CocParameters{.handle = handle,
3856                              .tx_credits = 2 * L2capCoc::QueueCapacity()});
3857 
3858   for (size_t i = 0; i < L2capCoc::QueueCapacity(); ++i) {
3859     EXPECT_EQ(channel.Write({}), PW_STATUS_OK);
3860   }
3861 
3862   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), 0);
3863   for (size_t i = 0; i < L2capCoc::QueueCapacity(); ++i) {
3864     EXPECT_EQ(channel.Write({}), PW_STATUS_OK);
3865   }
3866   EXPECT_EQ(channel.Write({}), PW_STATUS_UNAVAILABLE);
3867   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity());
3868 
3869   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
3870       proxy,
3871       FlatMap<uint16_t, uint16_t, 1>({{{handle, L2capCoc::QueueCapacity()}}})));
3872 
3873   EXPECT_EQ(sends_called, 2 * L2capCoc::QueueCapacity());
3874 }
3875 
TEST(L2capCocQueueTest,RemovingLrdWriteChannelDoesNotInvalidateRoundRobin)3876 TEST(L2capCocQueueTest, RemovingLrdWriteChannelDoesNotInvalidateRoundRobin) {
3877   size_t sends_called = 0;
3878   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3879       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3880   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3881       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
3882         ++sends_called;
3883       });
3884   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
3885                               std::move(send_to_controller_fn),
3886                               L2capCoc::QueueCapacity());
3887   PW_TEST_EXPECT_OK(
3888       SendLeReadBufferResponseFromController(proxy, L2capCoc::QueueCapacity()));
3889   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), L2capCoc::QueueCapacity());
3890 
3891   uint16_t handle = 123;
3892   std::array<uint16_t, 3> remote_cids = {1, 2, 3};
3893   L2capCoc chan_left = BuildCoc(
3894       proxy,
3895       CocParameters{
3896           .handle = handle, .remote_cid = remote_cids[0], .tx_credits = 1});
3897   std::optional<L2capCoc> chan_middle =
3898       BuildCoc(proxy,
3899                CocParameters{.handle = handle,
3900                              .remote_cid = remote_cids[1],
3901                              .tx_credits = L2capCoc::QueueCapacity() + 1});
3902   L2capCoc chan_right = BuildCoc(
3903       proxy,
3904       CocParameters{
3905           .handle = handle, .remote_cid = remote_cids[2], .tx_credits = 1});
3906 
3907   // We have 3 channels. Make it so LRD write channel iterator is on the
3908   // middle channel, then release that channel and ensure the other two are
3909   // still reached in the round robin.
3910 
3911   // Queue a packet in middle channel.
3912   for (size_t i = 0; i < L2capCoc::QueueCapacity() + 1; ++i) {
3913     EXPECT_EQ(chan_middle->Write({}), PW_STATUS_OK);
3914   }
3915   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity());
3916 
3917   // Make middle channel the LRD write channel.
3918   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
3919       proxy, FlatMap<uint16_t, uint16_t, 1>({{{handle, 1}}})));
3920   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity() + 1);
3921 
3922   // Queue a packet each in left and right channels.
3923   EXPECT_EQ(chan_left.Write({}), PW_STATUS_OK);
3924   EXPECT_EQ(chan_right.Write({}), PW_STATUS_OK);
3925   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity() + 1);
3926 
3927   // Drop middle channel. LRD write channel iterator should still be valid.
3928   chan_middle.reset();
3929 
3930   // Confirm packets in remaining two channels are sent in round robin.
3931   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
3932       proxy, FlatMap<uint16_t, uint16_t, 1>({{{handle, 2}}})));
3933   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity() + 3);
3934 }
3935 
3936 // ########## L2capSignalingTest
3937 
TEST(L2capSignalingTest,FlowControlCreditIndDrainsQueue)3938 TEST(L2capSignalingTest, FlowControlCreditIndDrainsQueue) {
3939   size_t sends_called = 0;
3940 
3941   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
3942       []([[maybe_unused]] H4PacketWithHci&& packet) {});
3943   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
3944       [&sends_called]([[maybe_unused]] H4PacketWithH4&& packet) {
3945         ++sends_called;
3946       });
3947   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
3948                               std::move(send_to_controller_fn),
3949                               L2capCoc::QueueCapacity());
3950   PW_TEST_EXPECT_OK(
3951       SendLeReadBufferResponseFromController(proxy, L2capCoc::QueueCapacity()));
3952   EXPECT_EQ(proxy.GetNumFreeLeAclPackets(), L2capCoc::QueueCapacity());
3953 
3954   uint16_t handle = 123;
3955   uint16_t remote_cid = 456;
3956   L2capCoc channel = BuildCoc(
3957       proxy,
3958       CocParameters{
3959           .handle = handle, .remote_cid = remote_cid, .tx_credits = 0});
3960 
3961   for (size_t i = 0; i < L2capCoc::QueueCapacity(); ++i) {
3962     EXPECT_EQ(channel.Write({}), PW_STATUS_OK);
3963   }
3964   EXPECT_EQ(channel.Write({}), PW_STATUS_UNAVAILABLE);
3965   EXPECT_EQ(sends_called, 0u);
3966 
3967   constexpr size_t kL2capLength =
3968       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
3969       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes();
3970   constexpr size_t kHciLength =
3971       emboss::AclDataFrame::MinSizeInBytes() + kL2capLength;
3972   std::array<uint8_t, kHciLength> hci_arr;
3973   hci_arr.fill(0);
3974   H4PacketWithHci flow_control_credit_ind{emboss::H4PacketType::ACL_DATA,
3975                                           pw::span(hci_arr.data(), kHciLength)};
3976 
3977   Result<emboss::AclDataFrameWriter> acl =
3978       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
3979   acl->header().handle().Write(handle);
3980   acl->data_total_length().Write(kL2capLength);
3981 
3982   emboss::CFrameWriter l2cap = emboss::MakeCFrameView(
3983       acl->payload().BackingStorage().data(), kL2capLength);
3984   l2cap.pdu_length().Write(
3985       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
3986   // 0x0005 = LE-U fixed signaling channel ID.
3987   l2cap.channel_id().Write(0x0005);
3988 
3989   emboss::L2capFlowControlCreditIndWriter ind =
3990       emboss::MakeL2capFlowControlCreditIndView(
3991           l2cap.payload().BackingStorage().data(),
3992           emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
3993   ind.command_header().code().Write(
3994       emboss::L2capSignalingPacketCode::FLOW_CONTROL_CREDIT_IND);
3995   ind.command_header().data_length().Write(
3996       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes() -
3997       emboss::L2capSignalingCommandHeader::IntrinsicSizeInBytes());
3998   ind.cid().Write(remote_cid);
3999   ind.credits().Write(L2capCoc::QueueCapacity());
4000 
4001   proxy.HandleH4HciFromController(std::move(flow_control_credit_ind));
4002 
4003   EXPECT_EQ(sends_called, L2capCoc::QueueCapacity());
4004 }
4005 
TEST(L2capSignalingTest,ChannelClosedWithErrorIfCreditsExceeded)4006 TEST(L2capSignalingTest, ChannelClosedWithErrorIfCreditsExceeded) {
4007   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4008       []([[maybe_unused]] H4PacketWithHci&& packet) {});
4009   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4010       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4011 
4012   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4013                               std::move(send_to_controller_fn),
4014                               L2capCoc::QueueCapacity());
4015 
4016   uint16_t handle = 123;
4017   uint16_t remote_cid = 456;
4018   int events_received = 0;
4019   L2capCoc channel = BuildCoc(
4020       proxy,
4021       CocParameters{
4022           .handle = handle,
4023           .remote_cid = remote_cid,
4024           // Initialize with max credit count.
4025           .tx_credits =
4026               emboss::L2capLeCreditBasedConnectionReq::max_credit_value(),
4027           .event_fn = [&events_received](L2capCoc::Event event) {
4028             EXPECT_EQ(event, L2capCoc::Event::kRxInvalid);
4029             ++events_received;
4030           }});
4031 
4032   constexpr size_t kL2capLength =
4033       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
4034       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes();
4035   constexpr size_t kHciLength =
4036       emboss::AclDataFrame::MinSizeInBytes() + kL2capLength;
4037   std::array<uint8_t, kHciLength> hci_arr;
4038   hci_arr.fill(0);
4039   H4PacketWithHci flow_control_credit_ind{emboss::H4PacketType::ACL_DATA,
4040                                           pw::span(hci_arr.data(), kHciLength)};
4041 
4042   Result<emboss::AclDataFrameWriter> acl =
4043       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
4044   acl->header().handle().Write(handle);
4045   acl->data_total_length().Write(kL2capLength);
4046 
4047   emboss::CFrameWriter l2cap =
4048       emboss::MakeCFrameView(acl->payload().BackingStorage().data(),
4049                              emboss::BasicL2capHeader::IntrinsicSizeInBytes());
4050   l2cap.pdu_length().Write(
4051       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4052   // 0x0005 = LE-U fixed signaling channel ID.
4053   l2cap.channel_id().Write(0x0005);
4054 
4055   emboss::L2capFlowControlCreditIndWriter ind =
4056       emboss::MakeL2capFlowControlCreditIndView(
4057           l2cap.payload().BackingStorage().data(),
4058           emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4059   ind.command_header().code().Write(
4060       emboss::L2capSignalingPacketCode::FLOW_CONTROL_CREDIT_IND);
4061   ind.command_header().data_length().Write(
4062       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes() -
4063       emboss::L2capSignalingCommandHeader::IntrinsicSizeInBytes());
4064   ind.cid().Write(remote_cid);
4065   // Exceed max credit count by 1.
4066   ind.credits().Write(1);
4067 
4068   proxy.HandleH4HciFromController(std::move(flow_control_credit_ind));
4069 
4070   EXPECT_EQ(events_received, 1);
4071 }
4072 
TEST(L2capSignalingTest,CreditIndAddressedToNonManagedChannelForwardedToHost)4073 TEST(L2capSignalingTest, CreditIndAddressedToNonManagedChannelForwardedToHost) {
4074   int forwards_to_host = 0;
4075   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4076       [&forwards_to_host](H4PacketWithHci&&) { ++forwards_to_host; });
4077   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4078       [](H4PacketWithH4&&) {});
4079 
4080   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4081                               std::move(send_to_controller_fn),
4082                               L2capCoc::QueueCapacity());
4083 
4084   uint16_t handle = 123;
4085   uint16_t remote_cid = 456;
4086   L2capCoc channel = BuildCoc(
4087       proxy, CocParameters{.handle = handle, .remote_cid = remote_cid});
4088 
4089   constexpr size_t kL2capLength =
4090       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
4091       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes();
4092   constexpr size_t kHciLength =
4093       emboss::AclDataFrame::MinSizeInBytes() + kL2capLength;
4094   std::array<uint8_t, kHciLength> hci_arr;
4095   hci_arr.fill(0);
4096   H4PacketWithHci flow_control_credit_ind{emboss::H4PacketType::ACL_DATA,
4097                                           pw::span(hci_arr.data(), kHciLength)};
4098 
4099   Result<emboss::AclDataFrameWriter> acl =
4100       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr);
4101   acl->header().handle().Write(handle);
4102   acl->data_total_length().Write(kL2capLength);
4103 
4104   emboss::CFrameWriter l2cap =
4105       emboss::MakeCFrameView(acl->payload().BackingStorage().data(),
4106                              emboss::BasicL2capHeader::IntrinsicSizeInBytes());
4107   l2cap.pdu_length().Write(
4108       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4109   // 0x0005 = LE-U fixed signaling channel ID.
4110   l2cap.channel_id().Write(0x0005);
4111 
4112   emboss::L2capFlowControlCreditIndWriter ind =
4113       emboss::MakeL2capFlowControlCreditIndView(
4114           l2cap.payload().BackingStorage().data(),
4115           emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4116   ind.command_header().code().Write(
4117       emboss::L2capSignalingPacketCode::FLOW_CONTROL_CREDIT_IND);
4118   ind.command_header().data_length().Write(
4119       emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes() -
4120       emboss::L2capSignalingCommandHeader::IntrinsicSizeInBytes());
4121   // Address packet to different CID on same connection.
4122   ind.cid().Write(remote_cid + 1);
4123 
4124   proxy.HandleH4HciFromController(std::move(flow_control_credit_ind));
4125 
4126   EXPECT_EQ(forwards_to_host, 1);
4127 }
4128 
TEST(L2capSignalingTest,RxAdditionalCreditsSentOnL2capCocAcquisition)4129 TEST(L2capSignalingTest, RxAdditionalCreditsSentOnL2capCocAcquisition) {
4130   struct {
4131     uint16_t handle = 123;
4132     uint16_t local_cid = 456;
4133     uint16_t credits = 3;
4134     int sends_called = 0;
4135   } capture;
4136 
4137   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4138       [](H4PacketWithHci&&) {});
4139   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4140       [&capture](H4PacketWithH4&& packet) {
4141         ++capture.sends_called;
4142         PW_TEST_ASSERT_OK_AND_ASSIGN(
4143             auto acl,
4144             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
4145         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
4146         EXPECT_EQ(
4147             acl.data_total_length().Read(),
4148             emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
4149                 emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4150         emboss::CFrameView cframe = emboss::MakeCFrameView(
4151             acl.payload().BackingStorage().data(), acl.payload().SizeInBytes());
4152         EXPECT_EQ(cframe.pdu_length().Read(),
4153                   emboss::L2capFlowControlCreditInd::IntrinsicSizeInBytes());
4154         // 0x0005 = LE-U fixed signaling channel ID.
4155         EXPECT_EQ(cframe.channel_id().Read(), 0x0005);
4156         emboss::L2capFlowControlCreditIndView ind =
4157             emboss::MakeL2capFlowControlCreditIndView(
4158                 cframe.payload().BackingStorage().data(),
4159                 cframe.payload().SizeInBytes());
4160         EXPECT_EQ(ind.cid().Read(), capture.local_cid);
4161         EXPECT_EQ(ind.credits().Read(), capture.credits);
4162       });
4163 
4164   ProxyHost proxy = ProxyHost(
4165       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
4166   // Allow proxy to reserve 1 LE credit.
4167   PW_TEST_EXPECT_OK(SendLeReadBufferResponseFromController(proxy, 1));
4168 
4169   L2capCoc channel =
4170       BuildCoc(proxy,
4171                CocParameters{.handle = capture.handle,
4172                              .local_cid = capture.local_cid,
4173                              .rx_additional_credits = capture.credits});
4174 
4175   EXPECT_EQ(capture.sends_called, 1);
4176 }
4177 
4178 // ########## AcluSignalingChannelTest
4179 
TEST(AcluSignalingChannelTest,HandlesMultipleCommands)4180 TEST(AcluSignalingChannelTest, HandlesMultipleCommands) {
4181   std::optional<H4PacketWithHci> host_packet;
4182   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4183       [&host_packet](H4PacketWithHci&& packet) {
4184         host_packet = std::move(packet);
4185       });
4186   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
4187       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4188 
4189   ProxyHost proxy = ProxyHost(
4190       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
4191 
4192   constexpr uint16_t kHandle = 123;
4193 
4194   // Test that the proxy can parse a CFrame containing multiple commands and
4195   // pass it through. We pack 3 CONNECTION_REQ commands into one CFrame.
4196   constexpr size_t kNumCommands = 3;
4197   constexpr size_t kCmdLen = emboss::L2capConnectionReq::IntrinsicSizeInBytes();
4198   constexpr size_t kL2capLength =
4199       emboss::BasicL2capHeader::IntrinsicSizeInBytes() + kCmdLen * kNumCommands;
4200   constexpr size_t kHciLength =
4201       emboss::AclDataFrame::MinSizeInBytes() + kL2capLength;
4202   std::array<uint8_t, kHciLength> hci_arr{};
4203   H4PacketWithHci l2cap_cframe_packet{emboss::H4PacketType::ACL_DATA,
4204                                       pw::span(hci_arr.data(), kHciLength)};
4205 
4206   // ACL header
4207   PW_TEST_ASSERT_OK_AND_ASSIGN(
4208       auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4209   acl.header().handle().Write(kHandle);
4210   acl.data_total_length().Write(kL2capLength);
4211   EXPECT_EQ(kL2capLength, acl.payload().BackingStorage().SizeInBytes());
4212 
4213   // L2CAP header
4214   auto l2cap =
4215       emboss::MakeCFrameView(acl.payload().BackingStorage().data(),
4216                              acl.payload().BackingStorage().SizeInBytes());
4217   l2cap.pdu_length().Write(kNumCommands * kCmdLen);
4218   l2cap.channel_id().Write(
4219       cpp23::to_underlying(emboss::L2capFixedCid::ACL_U_SIGNALING));
4220   EXPECT_TRUE(l2cap.Ok());
4221 
4222   auto command_buffer =
4223       pw::span(l2cap.payload().BackingStorage().data(),
4224                l2cap.payload().BackingStorage().SizeInBytes());
4225   EXPECT_EQ(l2cap.payload().BackingStorage().SizeInBytes(),
4226             kCmdLen * kNumCommands);
4227 
4228   do {
4229     // CONNECTION_REQ
4230     auto cmd_writer = emboss::MakeL2capConnectionReqView(command_buffer.data(),
4231                                                          command_buffer.size());
4232     cmd_writer.command_header().code().Write(
4233         emboss::L2capSignalingPacketCode::CONNECTION_REQ);
4234     // Note data_length doesn't include command header.
4235     cmd_writer.command_header().data_length().Write(
4236         kCmdLen - emboss::L2capSignalingCommandHeader::IntrinsicSizeInBytes());
4237     cmd_writer.psm().Write(1);
4238     cmd_writer.source_cid().Write(1);
4239     EXPECT_TRUE(cmd_writer.Ok());
4240     EXPECT_EQ(cmd_writer.SizeInBytes(), kCmdLen);
4241     command_buffer = command_buffer.subspan(cmd_writer.SizeInBytes());
4242   } while (!command_buffer.empty());
4243 
4244   proxy.HandleH4HciFromController(std::move(l2cap_cframe_packet));
4245   // We should get back what we sent, since the proxy doesn't consume
4246   // CONNECTION_REQ commands. It would be nice to also verify the individual
4247   // commands were parsed out but hooks don't exist for that at the time of
4248   // writing.
4249   EXPECT_TRUE(host_packet.has_value());
4250   EXPECT_EQ(host_packet->GetHciSpan().size(), kHciLength);
4251 }
4252 
TEST(AcluSignalingChannelTest,InvalidPacketForwarded)4253 TEST(AcluSignalingChannelTest, InvalidPacketForwarded) {
4254   std::optional<H4PacketWithHci> host_packet;
4255   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4256       [&host_packet](H4PacketWithHci&& packet) {
4257         host_packet = std::move(packet);
4258       });
4259   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
4260       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4261 
4262   ProxyHost proxy = ProxyHost(
4263       std::move(send_to_host_fn), std::move(send_to_controller_fn), 1);
4264 
4265   constexpr uint16_t kHandle = 123;
4266 
4267   // Test that the proxy forwards on invalid L2cap B-frames destined for
4268   // signaling channel.
4269 
4270   constexpr size_t kL2capLength =
4271       emboss::BasicL2capHeader::IntrinsicSizeInBytes();
4272   constexpr size_t kHciLength =
4273       emboss::AclDataFrame::MinSizeInBytes() + kL2capLength;
4274   std::array<uint8_t, kHciLength> hci_arr{};
4275   H4PacketWithHci l2cap_cframe_packet{emboss::H4PacketType::ACL_DATA,
4276                                       pw::span(hci_arr.data(), kHciLength)};
4277 
4278   // ACL header
4279   PW_TEST_ASSERT_OK_AND_ASSIGN(
4280       auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4281   acl.header().handle().Write(kHandle);
4282   acl.data_total_length().Write(kL2capLength);
4283   EXPECT_EQ(kL2capLength, acl.payload().BackingStorage().SizeInBytes());
4284 
4285   // L2CAP header
4286   auto l2cap =
4287       emboss::MakeCFrameView(acl.payload().BackingStorage().data(),
4288                              acl.payload().BackingStorage().SizeInBytes());
4289   // Invalid length, since we aren't encoding a payload.
4290   l2cap.pdu_length().Write(1);
4291   l2cap.channel_id().Write(
4292       cpp23::to_underlying(emboss::L2capFixedCid::ACL_U_SIGNALING));
4293   EXPECT_FALSE(l2cap.Ok());
4294 
4295   proxy.HandleH4HciFromController(std::move(l2cap_cframe_packet));
4296   // We should get back what we sent.
4297   EXPECT_TRUE(host_packet.has_value());
4298   EXPECT_EQ(host_packet->GetHciSpan().size(), kHciLength);
4299 }
4300 
4301 // ########## RfcommWriteTest
4302 
4303 constexpr uint8_t kBFrameOverAclMinSize =
4304     emboss::AclDataFrameHeader::IntrinsicSizeInBytes() +
4305     emboss::BFrame::MinSizeInBytes();
4306 
TEST(RfcommWriteTest,BasicWrite)4307 TEST(RfcommWriteTest, BasicWrite) {
4308   struct {
4309     int sends_called = 0;
4310     // First four bits 0x0 encode PB & BC flags
4311     uint16_t handle = 0x0ACB;
4312     // Length of L2CAP PDU
4313     uint16_t acl_data_total_length = 0x000C;
4314     // L2CAP header PDU length field
4315     uint16_t pdu_length = 0x0008;
4316     // Random CID
4317     uint16_t channel_id = 0x1234;
4318     // RFCOMM header
4319     std::array<uint8_t, 3> rfcomm_header = {0x19, 0xFF, 0x07};
4320     uint8_t rfcomm_credits = 0;
4321     // RFCOMM information payload
4322     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
4323     uint8_t rfcomm_fcs = 0x49;
4324 
4325     // Built from the preceding values in little endian order (except payload in
4326     // big endian).
4327     std::array<uint8_t, 16> expected_hci_packet = {0xCB,
4328                                                    0x0A,
4329                                                    0x0C,
4330                                                    0x00,
4331                                                    0x08,
4332                                                    0x00,
4333                                                    0x34,
4334                                                    0x12,
4335                                                    // RFCOMM header
4336                                                    0x19,
4337                                                    0xFF,
4338                                                    0x07,
4339                                                    0x00,
4340                                                    0xAB,
4341                                                    0xCD,
4342                                                    0xEF,
4343                                                    // FCS
4344                                                    0x49};
4345   } capture;
4346 
4347   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4348       []([[maybe_unused]] H4PacketWithHci&& packet) {});
4349   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4350       [&capture](H4PacketWithH4&& packet) {
4351         ++capture.sends_called;
4352         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
4353         EXPECT_EQ(packet.GetHciSpan().size(),
4354                   capture.expected_hci_packet.size());
4355         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
4356                                packet.GetHciSpan().end(),
4357                                capture.expected_hci_packet.begin(),
4358                                capture.expected_hci_packet.end()));
4359         PW_TEST_ASSERT_OK_AND_ASSIGN(
4360             auto acl,
4361             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
4362         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
4363         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
4364                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
4365         EXPECT_EQ(acl.header().broadcast_flag().Read(),
4366                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
4367         EXPECT_EQ(acl.data_total_length().Read(),
4368                   capture.acl_data_total_length);
4369         emboss::BFrameView bframe = emboss::BFrameView(
4370             acl.payload().BackingStorage().data(), acl.SizeInBytes());
4371         EXPECT_EQ(bframe.pdu_length().Read(), capture.pdu_length);
4372         EXPECT_EQ(bframe.channel_id().Read(), capture.channel_id);
4373         EXPECT_TRUE(std::equal(bframe.payload().BackingStorage().begin(),
4374                                bframe.payload().BackingStorage().begin() +
4375                                    capture.rfcomm_header.size(),
4376                                capture.rfcomm_header.begin(),
4377                                capture.rfcomm_header.end()));
4378         auto rfcomm = emboss::MakeRfcommFrameView(
4379             bframe.payload().BackingStorage().data(),
4380             bframe.payload().SizeInBytes());
4381         EXPECT_TRUE(rfcomm.Ok());
4382         EXPECT_EQ(rfcomm.credits().Read(), capture.rfcomm_credits);
4383 
4384         for (size_t i = 0; i < 3; ++i) {
4385           EXPECT_EQ(rfcomm.information()[i].Read(), capture.payload[i]);
4386         }
4387 
4388         EXPECT_EQ(rfcomm.fcs().Read(), capture.rfcomm_fcs);
4389       });
4390 
4391   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4392                               std::move(send_to_controller_fn),
4393                               /*le_acl_credits_to_reserve=*/0,
4394                               /*br_edr_acl_credits_to_reserve=*/1);
4395   // Allow proxy to reserve 1 credit.
4396   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
4397 
4398   constexpr uint8_t kMaxCredits = 10;
4399   constexpr uint16_t kMaxFrameSize = 900;
4400   constexpr uint8_t kRfcommChannel = 0x03;
4401 
4402   PW_TEST_ASSERT_OK_AND_ASSIGN(
4403       auto channel,
4404       proxy.AcquireRfcommChannel(
4405           capture.handle,
4406           /*rx_config=*/
4407           RfcommChannel::Config{.cid = capture.channel_id,
4408                                 .max_information_length = kMaxFrameSize,
4409                                 .credits = kMaxCredits},
4410           /*tx_config*/
4411           RfcommChannel::Config{.cid = capture.channel_id,
4412                                 .max_information_length = kMaxFrameSize,
4413                                 .credits = kMaxCredits},
4414           kRfcommChannel,
4415           nullptr));
4416   EXPECT_EQ(channel.Write(capture.payload), PW_STATUS_OK);
4417   EXPECT_EQ(capture.sends_called, 1);
4418 }
4419 
TEST(RfcommWriteTest,ExtendedWrite)4420 TEST(RfcommWriteTest, ExtendedWrite) {
4421   constexpr size_t kPayloadSize = 0x80;
4422   struct {
4423     int sends_called = 0;
4424     // First four bits 0x0 encode PB & BC flags
4425     uint16_t handle = 0x0ACB;
4426     // Length of L2CAP PDU
4427     uint16_t acl_data_total_length = 0x008A;
4428     // L2CAP header PDU length field
4429     uint16_t pdu_length = 0x0086;
4430     // Random CID
4431     uint16_t channel_id = 0x1234;
4432     // RFCOMM header
4433     std::array<uint8_t, 4> rfcomm_header = {0x19, 0xFF, 0x00, 0x01};
4434     uint8_t rfcomm_credits = 0;
4435     // RFCOMM information payload
4436     std::array<uint8_t, kPayloadSize> payload = {
4437         0xAB,
4438         0xCD,
4439         0xEF,
4440     };
4441     uint8_t rfcomm_fcs = 0x49;
4442 
4443     // Built from the preceding values in little endian order (except payload in
4444     // big endian).
4445     std::array<uint8_t, kPayloadSize + 14> expected_hci_packet = {
4446         0xCB,
4447         0x0A,
4448         0x8A,
4449         0x00,
4450         0x86,
4451         0x00,
4452         0x34,
4453         0x12,
4454         // RFCOMM header
4455         0x19,
4456         0xFF,
4457         0x00,
4458         0x01,
4459         0x00,
4460         0xAB,
4461         0xCD,
4462         0xEF,
4463     };
4464   } capture;
4465 
4466   // FCS
4467   capture.expected_hci_packet[capture.expected_hci_packet.size() - 1] =
4468       capture.rfcomm_fcs;
4469 
4470   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4471       []([[maybe_unused]] H4PacketWithHci&& packet) {});
4472   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4473       [&capture](H4PacketWithH4&& packet) {
4474         ++capture.sends_called;
4475         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
4476         EXPECT_EQ(packet.GetHciSpan().size(),
4477                   capture.expected_hci_packet.size());
4478         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
4479                                packet.GetHciSpan().end(),
4480                                capture.expected_hci_packet.begin(),
4481                                capture.expected_hci_packet.end()));
4482         PW_TEST_ASSERT_OK_AND_ASSIGN(
4483             auto acl,
4484             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
4485         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
4486         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
4487                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
4488         EXPECT_EQ(acl.header().broadcast_flag().Read(),
4489                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
4490         EXPECT_EQ(acl.data_total_length().Read(),
4491                   capture.acl_data_total_length);
4492         emboss::BFrameView bframe = emboss::BFrameView(
4493             acl.payload().BackingStorage().data(), acl.SizeInBytes());
4494         EXPECT_EQ(bframe.pdu_length().Read(), capture.pdu_length);
4495         EXPECT_EQ(bframe.channel_id().Read(), capture.channel_id);
4496         EXPECT_TRUE(std::equal(bframe.payload().BackingStorage().begin(),
4497                                bframe.payload().BackingStorage().begin() +
4498                                    capture.rfcomm_header.size(),
4499                                capture.rfcomm_header.begin(),
4500                                capture.rfcomm_header.end()));
4501         auto rfcomm = emboss::MakeRfcommFrameView(
4502             bframe.payload().BackingStorage().data(),
4503             bframe.payload().SizeInBytes());
4504         EXPECT_TRUE(rfcomm.Ok());
4505         EXPECT_EQ(rfcomm.credits().Read(), capture.rfcomm_credits);
4506 
4507         for (size_t i = 0; i < 3; ++i) {
4508           EXPECT_EQ(rfcomm.information()[i].Read(), capture.payload[i]);
4509         }
4510 
4511         EXPECT_EQ(rfcomm.fcs().Read(), capture.rfcomm_fcs);
4512       });
4513 
4514   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4515                               std::move(send_to_controller_fn),
4516                               /*le_acl_credits_to_reserve=*/0,
4517                               /*br_edr_acl_credits_to_reserve=*/1);
4518   // Allow proxy to reserve 1 credit.
4519   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
4520 
4521   constexpr uint8_t kMaxCredits = 10;
4522   constexpr uint16_t kMaxFrameSize = 900;
4523   constexpr uint8_t kRfcommChannel = 0x03;
4524 
4525   PW_TEST_ASSERT_OK_AND_ASSIGN(
4526       auto channel,
4527       proxy.AcquireRfcommChannel(
4528           capture.handle,
4529           /*rx_config=*/
4530           RfcommChannel::Config{.cid = capture.channel_id,
4531                                 .max_information_length = kMaxFrameSize,
4532                                 .credits = kMaxCredits},
4533           /*tx_config*/
4534           RfcommChannel::Config{.cid = capture.channel_id,
4535                                 .max_information_length = kMaxFrameSize,
4536                                 .credits = kMaxCredits},
4537           kRfcommChannel,
4538           nullptr));
4539   EXPECT_EQ(channel.Write(capture.payload), PW_STATUS_OK);
4540   EXPECT_EQ(capture.sends_called, 1);
4541 }
4542 
4543 // ########## RfcommReadTest
4544 
TEST(RfcommReadTest,BasicRead)4545 TEST(RfcommReadTest, BasicRead) {
4546   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4547       []([[maybe_unused]] H4PacketWithHci&& packet) {});
4548   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4549       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4550   ProxyHost proxy = ProxyHost(
4551       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
4552 
4553   struct {
4554     int rx_called = 0;
4555     std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
4556   } capture;
4557 
4558   constexpr uint8_t kExpectedFcs = 0xFA;
4559   constexpr uint16_t kHandle = 123;
4560   constexpr uint16_t kCid = 234;
4561   constexpr uint8_t kMaxCredits = 10;
4562   constexpr uint16_t kMaxFrameSize = 900;
4563   constexpr uint8_t kRfcommChannel = 0x03;
4564   const size_t frame_size = emboss::RfcommFrame::MinSizeInBytes() +
4565                             /*payload*/ capture.expected_payload.size();
4566   const size_t acl_data_length =
4567       emboss::BasicL2capHeader::IntrinsicSizeInBytes() + frame_size;
4568 
4569   PW_TEST_ASSERT_OK_AND_ASSIGN(
4570       auto channel,
4571       proxy.AcquireRfcommChannel(
4572           kHandle,
4573           /*rx_config=*/
4574           RfcommChannel::Config{.cid = kCid,
4575                                 .max_information_length = kMaxFrameSize,
4576                                 .credits = kMaxCredits},
4577           /*tx_config*/
4578           RfcommChannel::Config{.cid = kCid,
4579                                 .max_information_length = kMaxFrameSize,
4580                                 .credits = kMaxCredits},
4581           kRfcommChannel,
4582           [&capture](pw::span<uint8_t> payload) {
4583             ++capture.rx_called;
4584             EXPECT_TRUE(std::equal(payload.begin(),
4585                                    payload.end(),
4586                                    capture.expected_payload.begin(),
4587                                    capture.expected_payload.end()));
4588           }));
4589 
4590   std::array<uint8_t, kBFrameOverAclMinSize + frame_size> hci_arr{};
4591   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
4592 
4593   PW_TEST_ASSERT_OK_AND_ASSIGN(
4594       auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4595   acl.header().handle().Write(kHandle);
4596   acl.data_total_length().Write(acl_data_length);
4597 
4598   auto bframe = emboss::MakeBFrameView(acl.payload().BackingStorage().data(),
4599                                        acl.data_total_length().Read());
4600   bframe.pdu_length().Write(frame_size);
4601   bframe.channel_id().Write(kCid);
4602 
4603   auto rfcomm = emboss::MakeRfcommFrameView(
4604       bframe.payload().BackingStorage().data(), bframe.payload().SizeInBytes());
4605   rfcomm.extended_address().Write(true);
4606   rfcomm.command_response_direction().Write(
4607       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
4608   rfcomm.channel().Write(kRfcommChannel);
4609 
4610   rfcomm.control().Write(
4611       emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
4612 
4613   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
4614   rfcomm.length().Write(capture.expected_payload.size());
4615 
4616   std::memcpy(rfcomm.information().BackingStorage().data(),
4617               capture.expected_payload.data(),
4618               capture.expected_payload.size());
4619   rfcomm.fcs().Write(kExpectedFcs);
4620 
4621   // Send ACL data packet destined for the channel we registered.
4622   proxy.HandleH4HciFromController(std::move(h4_packet));
4623 
4624   EXPECT_EQ(capture.rx_called, 1);
4625 }
4626 
TEST(RfcommReadTest,ExtendedRead)4627 TEST(RfcommReadTest, ExtendedRead) {
4628   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4629       []([[maybe_unused]] H4PacketWithHci&& packet) {});
4630   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4631       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4632   ProxyHost proxy = ProxyHost(
4633       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
4634 
4635   constexpr size_t kPayloadSize = 0x80;
4636   struct {
4637     int rx_called = 0;
4638     std::array<uint8_t, kPayloadSize> expected_payload = {0xAB, 0xCD, 0xEF};
4639   } capture;
4640 
4641   constexpr uint8_t kExpectedFcs = 0xFA;
4642   constexpr uint16_t kHandle = 123;
4643   constexpr uint16_t kCid = 234;
4644   constexpr uint8_t kMaxCredits = 10;
4645   constexpr uint16_t kMaxFrameSize = 900;
4646   constexpr uint8_t kRfcommChannel = 0x03;
4647 
4648   const size_t frame_size = emboss::RfcommFrame::MinSizeInBytes() +
4649                             /*length_extended*/ 1 +
4650                             /*payload*/ capture.expected_payload.size();
4651   const size_t acl_data_length =
4652       emboss::BasicL2capHeader::IntrinsicSizeInBytes() + frame_size;
4653 
4654   PW_TEST_ASSERT_OK_AND_ASSIGN(
4655       auto channel,
4656       proxy.AcquireRfcommChannel(
4657           kHandle,
4658           /*rx_config=*/
4659           RfcommChannel::Config{.cid = kCid,
4660                                 .max_information_length = kMaxFrameSize,
4661                                 .credits = kMaxCredits},
4662           /*tx_config*/
4663           RfcommChannel::Config{.cid = kCid,
4664                                 .max_information_length = kMaxFrameSize,
4665                                 .credits = kMaxCredits},
4666           kRfcommChannel,
4667           [&capture](pw::span<uint8_t> payload) {
4668             ++capture.rx_called;
4669             EXPECT_TRUE(std::equal(payload.begin(),
4670                                    payload.end(),
4671                                    capture.expected_payload.begin(),
4672                                    capture.expected_payload.end()));
4673           }));
4674 
4675   std::array<uint8_t, kBFrameOverAclMinSize + frame_size> hci_arr{};
4676   H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
4677 
4678   PW_TEST_ASSERT_OK_AND_ASSIGN(
4679       auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4680   acl.header().handle().Write(kHandle);
4681   acl.data_total_length().Write(acl_data_length);
4682 
4683   auto bframe = emboss::MakeBFrameView(acl.payload().BackingStorage().data(),
4684                                        acl.data_total_length().Read());
4685   bframe.pdu_length().Write(frame_size);
4686   bframe.channel_id().Write(kCid);
4687 
4688   auto rfcomm = emboss::MakeRfcommFrameView(
4689       bframe.payload().BackingStorage().data(), bframe.payload().SizeInBytes());
4690   rfcomm.extended_address().Write(true);
4691   rfcomm.command_response_direction().Write(
4692       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
4693   rfcomm.channel().Write(kRfcommChannel);
4694 
4695   rfcomm.control().Write(
4696       emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
4697 
4698   rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::EXTENDED);
4699   rfcomm.length_extended().Write(capture.expected_payload.size());
4700 
4701   std::memcpy(rfcomm.information().BackingStorage().data(),
4702               capture.expected_payload.data(),
4703               capture.expected_payload.size());
4704   rfcomm.fcs().Write(kExpectedFcs);
4705 
4706   // Send ACL data packet destined for the channel we registered.
4707   proxy.HandleH4HciFromController(std::move(h4_packet));
4708 
4709   EXPECT_EQ(capture.rx_called, 1);
4710 }
4711 
TEST(RfcommReadTest,InvalidReads)4712 TEST(RfcommReadTest, InvalidReads) {
4713   struct {
4714     int rx_called = 0;
4715     int host_called = 0;
4716   } capture;
4717 
4718   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
4719       [&capture]([[maybe_unused]] H4PacketWithHci&& packet) {
4720         ++capture.host_called;
4721       });
4722   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
4723       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4724   ProxyHost proxy = ProxyHost(
4725       std::move(send_to_host_fn), std::move(send_to_controller_fn), 0);
4726 
4727   constexpr uint8_t kExpectedFcs = 0xFA;
4728   constexpr uint8_t kInvalidFcs = 0xFF;
4729   constexpr uint16_t kHandle = 123;
4730   constexpr uint16_t kCid = 234;
4731   constexpr uint8_t kMaxCredits = 10;
4732   constexpr uint16_t kMaxFrameSize = 900;
4733   constexpr uint8_t kRfcommChannel = 0x03;
4734   const size_t frame_size = emboss::RfcommFrame::MinSizeInBytes() +
4735                             /*payload*/ 0;
4736   const size_t acl_data_length =
4737       emboss::BasicL2capHeader::IntrinsicSizeInBytes() + frame_size;
4738 
4739   PW_TEST_ASSERT_OK_AND_ASSIGN(
4740       auto channel,
4741       proxy.AcquireRfcommChannel(
4742           kHandle,
4743           /*rx_config=*/
4744           RfcommChannel::Config{.cid = kCid,
4745                                 .max_information_length = kMaxFrameSize,
4746                                 .credits = kMaxCredits},
4747           /*tx_config*/
4748           RfcommChannel::Config{.cid = kCid,
4749                                 .max_information_length = kMaxFrameSize,
4750                                 .credits = kMaxCredits},
4751           kRfcommChannel,
4752           [&capture](pw::span<uint8_t>) { ++capture.rx_called; }));
4753 
4754   std::array<uint8_t, kBFrameOverAclMinSize + frame_size> hci_arr{};
4755 
4756   // Construct valid packet but put invalid checksum on the end. Test that we
4757   // don't get it sent on to us.
4758   {
4759     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
4760     PW_TEST_ASSERT_OK_AND_ASSIGN(
4761         auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4762     acl.header().handle().Write(kHandle);
4763     acl.data_total_length().Write(acl_data_length);
4764 
4765     auto bframe = emboss::MakeBFrameView(acl.payload().BackingStorage().data(),
4766                                          acl.data_total_length().Read());
4767     bframe.pdu_length().Write(frame_size);
4768     bframe.channel_id().Write(kCid);
4769 
4770     auto rfcomm =
4771         emboss::MakeRfcommFrameView(bframe.payload().BackingStorage().data(),
4772                                     bframe.payload().SizeInBytes());
4773     rfcomm.extended_address().Write(true);
4774     rfcomm.command_response_direction().Write(
4775         emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
4776     rfcomm.channel().Write(kRfcommChannel);
4777 
4778     rfcomm.control().Write(
4779         emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
4780 
4781     rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
4782     rfcomm.length().Write(0);
4783     rfcomm.fcs().Write(kInvalidFcs);
4784 
4785     proxy.HandleH4HciFromController(std::move(h4_packet));
4786   }
4787 
4788   EXPECT_EQ(capture.rx_called, 0);
4789   EXPECT_EQ(capture.host_called, 1);
4790 
4791   // Construct packet with everything valid but wrong length for actual data
4792   // size. Ensure it doesn't end up being sent to our channel, but does get
4793   // forwarded to host.
4794   {
4795     H4PacketWithHci h4_packet{emboss::H4PacketType::ACL_DATA, hci_arr};
4796 
4797     PW_TEST_ASSERT_OK_AND_ASSIGN(
4798         auto acl, MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_arr));
4799     acl.header().handle().Write(kHandle);
4800     acl.data_total_length().Write(acl_data_length);
4801 
4802     auto bframe = emboss::MakeBFrameView(acl.payload().BackingStorage().data(),
4803                                          acl.data_total_length().Read());
4804     bframe.pdu_length().Write(frame_size);
4805     bframe.channel_id().Write(kCid);
4806 
4807     auto rfcomm =
4808         emboss::MakeRfcommFrameView(bframe.payload().BackingStorage().data(),
4809                                     bframe.payload().SizeInBytes());
4810     rfcomm.extended_address().Write(true);
4811     rfcomm.command_response_direction().Write(
4812         emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
4813     rfcomm.channel().Write(kRfcommChannel);
4814 
4815     rfcomm.control().Write(
4816         emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
4817 
4818     rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
4819     // Invalid length.
4820     rfcomm.length().Write(1);
4821     // Can't Write FCS as emboss will assert because of invalid length. Place
4822     // manually.
4823     hci_arr[hci_arr.size() - 1] = kExpectedFcs;
4824 
4825     proxy.HandleH4HciFromController(std::move(h4_packet));
4826   }
4827 
4828   EXPECT_EQ(capture.rx_called, 0);
4829   EXPECT_EQ(capture.host_called, 2);
4830 }
4831 
4832 // ########## ProxyHostConnectionEventTest
4833 
TEST(ProxyHostConnectionEventTest,ConnectionCompletePassthroughOk)4834 TEST(ProxyHostConnectionEventTest, ConnectionCompletePassthroughOk) {
4835   size_t host_called = 0;
4836   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
4837       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4838 
4839   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
4840       [&host_called]([[maybe_unused]] H4PacketWithHci&& packet) {
4841         ++host_called;
4842       });
4843 
4844   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4845                               std::move(send_to_controller_fn),
4846                               /*le_acl_credits_to_reserve=*/0);
4847 
4848   PW_TEST_EXPECT_OK(
4849       SendConnectionCompleteEvent(proxy, 1, emboss::StatusCode::SUCCESS));
4850   EXPECT_EQ(host_called, 1U);
4851 
4852   PW_TEST_EXPECT_OK(SendDisconnectionCompleteEvent(proxy, 1));
4853   EXPECT_EQ(host_called, 2U);
4854 }
4855 
TEST(ProxyHostConnectionEventTest,ConnectionCompleteWithErrorStatusPassthroughOk)4856 TEST(ProxyHostConnectionEventTest,
4857      ConnectionCompleteWithErrorStatusPassthroughOk) {
4858   size_t host_called = 0;
4859   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
4860       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4861 
4862   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
4863       [&host_called]([[maybe_unused]] H4PacketWithHci&& packet) {
4864         ++host_called;
4865       });
4866 
4867   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4868                               std::move(send_to_controller_fn),
4869                               /*le_acl_credits_to_reserve=*/0);
4870 
4871   PW_TEST_EXPECT_OK(SendConnectionCompleteEvent(
4872       proxy, 1, emboss::StatusCode::CONNECTION_FAILED_TO_BE_ESTABLISHED));
4873   EXPECT_EQ(host_called, 1U);
4874 }
4875 
TEST(ProxyHostConnectionEventTest,LeConnectionCompletePassthroughOk)4876 TEST(ProxyHostConnectionEventTest, LeConnectionCompletePassthroughOk) {
4877   size_t host_called = 0;
4878   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
4879       []([[maybe_unused]] H4PacketWithH4&& packet) {});
4880 
4881   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
4882       [&host_called]([[maybe_unused]] H4PacketWithHci&& packet) {
4883         ++host_called;
4884       });
4885 
4886   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
4887                               std::move(send_to_controller_fn),
4888                               /*le_acl_credits_to_reserve=*/0);
4889 
4890   PW_TEST_EXPECT_OK(
4891       SendLeConnectionCompleteEvent(proxy, 1, emboss::StatusCode::SUCCESS));
4892   EXPECT_EQ(host_called, 1U);
4893 }
4894 
4895 // TODO: https://pwbug.dev/360929142 - Add many more tests exercising queueing
4896 // credit-based control flow.
4897 
4898 }  // namespace
4899 }  // namespace pw::bluetooth::proxy
4900