• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cstdint>
16 
17 #include "pw_bluetooth/emboss_util.h"
18 #include "pw_bluetooth/hci_data.emb.h"
19 #include "pw_bluetooth/hci_h4.emb.h"
20 #include "pw_bluetooth/l2cap_frames.emb.h"
21 #include "pw_bluetooth/rfcomm_frames.emb.h"
22 #include "pw_bluetooth_proxy/h4_packet.h"
23 #include "pw_bluetooth_proxy/proxy_host.h"
24 #include "pw_bluetooth_proxy_private/test_utils.h"
25 #include "pw_containers/flat_map.h"
26 #include "pw_status/status.h"
27 #include "pw_status/try.h"
28 #include "pw_unit_test/framework.h"
29 
30 namespace pw::bluetooth::proxy {
31 namespace {
32 
33 using containers::FlatMap;
34 
35 // ########## RfcommWriteTest
36 
37 class RfcommWriteTest : public ProxyHostTest {};
38 
39 // Construct and send an RFCOMM frame from controller->host.
SendRfcommFromController(ProxyHost & proxy,RfcommParameters params,uint8_t fcs,std::optional<uint8_t> credits,pw::span<uint8_t> payload)40 Status SendRfcommFromController(ProxyHost& proxy,
41                                 RfcommParameters params,
42                                 uint8_t fcs,
43                                 std::optional<uint8_t> credits,
44                                 pw::span<uint8_t> payload) {
45   constexpr size_t kMaxShortLength = 0x7f;
46   const size_t credits_field_size = credits.has_value() ? 1 : 0;
47   const bool uses_extended_length = payload.size() > kMaxShortLength;
48   const size_t length_extended_size = uses_extended_length ? 1 : 0;
49   const size_t frame_size = emboss::RfcommFrame::MinSizeInBytes() +
50                             length_extended_size + credits_field_size +
51                             payload.size();
52 
53   PW_TRY_ASSIGN(BFrameWithStorage bframe,
54                 SetupBFrame(params.handle, params.rx_config.cid, frame_size));
55 
56   auto rfcomm = emboss::MakeRfcommFrameView(
57       bframe.writer.payload().BackingStorage().data(),
58       bframe.writer.payload().SizeInBytes());
59   rfcomm.extended_address().Write(true);
60   rfcomm.command_response_direction().Write(
61       emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
62   rfcomm.channel().Write(params.rfcomm_channel);
63 
64   if (!uses_extended_length) {
65     rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
66     rfcomm.length().Write(payload.size());
67   } else {
68     rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::EXTENDED);
69     rfcomm.length_extended().Write(payload.size());
70   }
71 
72   if (credits.has_value()) {
73     rfcomm.control().Write(
74         emboss::RfcommFrameType::
75             UNNUMBERED_INFORMATION_WITH_HEADER_CHECK_AND_POLL_FINAL);
76     rfcomm.credits().Write(*credits);
77   } else {
78     rfcomm.control().Write(
79         emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
80   }
81 
82   EXPECT_EQ(rfcomm.information().SizeInBytes(), payload.size());
83   EXPECT_TRUE(TryToCopyToEmbossStruct(/*emboss_dest=*/rfcomm.information(),
84                                       /*src=*/payload));
85   rfcomm.fcs().Write(fcs);
86   auto hci_span = bframe.acl.hci_span();
87   H4PacketWithHci packet{emboss::H4PacketType::ACL_DATA, hci_span};
88 
89   proxy.HandleH4HciFromController(std::move(packet));
90 
91   return OkStatus();
92 }
93 
TEST_F(RfcommWriteTest,BasicWrite)94 TEST_F(RfcommWriteTest, BasicWrite) {
95   struct {
96     int sends_called = 0;
97     // First four bits 0x0 encode PB & BC flags
98     uint16_t handle = 0x0ACB;
99     // Length of L2CAP PDU
100     uint16_t acl_data_total_length = 0x000C;
101     // L2CAP header PDU length field
102     uint16_t pdu_length = 0x0008;
103     // Random CID
104     uint16_t channel_id = 0x1234;
105     // RFCOMM header
106     std::array<uint8_t, 3> rfcomm_header = {0x19, 0xFF, 0x07};
107     uint8_t rfcomm_credits = 0;
108     // RFCOMM information payload
109     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
110     uint8_t rfcomm_fcs = 0x49;
111 
112     // Built from the preceding values in little endian order (except payload in
113     // big endian).
114     std::array<uint8_t, 16> expected_hci_packet = {0xCB,
115                                                    0x0A,
116                                                    0x0C,
117                                                    0x00,
118                                                    0x08,
119                                                    0x00,
120                                                    0x34,
121                                                    0x12,
122                                                    // RFCOMM header
123                                                    0x19,
124                                                    0xFF,
125                                                    0x07,
126                                                    0x00,
127                                                    0xAB,
128                                                    0xCD,
129                                                    0xEF,
130                                                    // FCS
131                                                    0x49};
132   } capture;
133 
134   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
135       []([[maybe_unused]] H4PacketWithHci&& packet) {});
136   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
137       [&capture](H4PacketWithH4&& packet) {
138         ++capture.sends_called;
139         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
140         EXPECT_EQ(packet.GetHciSpan().size(),
141                   capture.expected_hci_packet.size());
142         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
143                                packet.GetHciSpan().end(),
144                                capture.expected_hci_packet.begin(),
145                                capture.expected_hci_packet.end()));
146         PW_TEST_ASSERT_OK_AND_ASSIGN(
147             auto acl,
148             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
149         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
150         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
151                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
152         EXPECT_EQ(acl.header().broadcast_flag().Read(),
153                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
154         EXPECT_EQ(acl.data_total_length().Read(),
155                   capture.acl_data_total_length);
156         emboss::BFrameView bframe = emboss::BFrameView(
157             acl.payload().BackingStorage().data(), acl.SizeInBytes());
158         EXPECT_EQ(bframe.pdu_length().Read(), capture.pdu_length);
159         EXPECT_EQ(bframe.channel_id().Read(), capture.channel_id);
160         EXPECT_TRUE(std::equal(bframe.payload().BackingStorage().begin(),
161                                bframe.payload().BackingStorage().begin() +
162                                    capture.rfcomm_header.size(),
163                                capture.rfcomm_header.begin(),
164                                capture.rfcomm_header.end()));
165         auto rfcomm = emboss::MakeRfcommFrameView(
166             bframe.payload().BackingStorage().data(),
167             bframe.payload().SizeInBytes());
168         EXPECT_TRUE(rfcomm.Ok());
169         EXPECT_EQ(rfcomm.credits().Read(), capture.rfcomm_credits);
170 
171         for (size_t i = 0; i < 3; ++i) {
172           EXPECT_EQ(rfcomm.information()[i].Read(), capture.payload[i]);
173         }
174 
175         EXPECT_EQ(rfcomm.fcs().Read(), capture.rfcomm_fcs);
176       });
177 
178   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
179                               std::move(send_to_controller_fn),
180                               /*le_acl_credits_to_reserve=*/0,
181                               /*br_edr_acl_credits_to_reserve=*/1);
182   // Allow proxy to reserve 1 credit.
183   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
184 
185   RfcommParameters params = {.handle = capture.handle,
186                              .tx_config = {
187                                  .cid = capture.channel_id,
188                              }};
189   RfcommChannel channel = BuildRfcomm(proxy, params);
190   PW_TEST_EXPECT_OK(
191       channel.Write(MultiBufFromSpan(pw::span(capture.payload))).status);
192   EXPECT_EQ(capture.sends_called, 1);
193 }
194 
TEST_F(RfcommWriteTest,ExtendedWrite)195 TEST_F(RfcommWriteTest, ExtendedWrite) {
196   constexpr size_t kPayloadSize = 0x80;
197   struct {
198     int sends_called = 0;
199     // First four bits 0x0 encode PB & BC flags
200     uint16_t handle = 0x0ACB;
201     // Length of L2CAP PDU
202     uint16_t acl_data_total_length = 0x008A;
203     // L2CAP header PDU length field
204     uint16_t pdu_length = 0x0086;
205     // Random CID
206     uint16_t channel_id = 0x1234;
207     // RFCOMM header
208     std::array<uint8_t, 4> rfcomm_header = {0x19, 0xFF, 0x00, 0x01};
209     uint8_t rfcomm_credits = 0;
210     // RFCOMM information payload
211     std::array<uint8_t, kPayloadSize> payload = {
212         0xAB,
213         0xCD,
214         0xEF,
215     };
216     uint8_t rfcomm_fcs = 0x49;
217 
218     // Built from the preceding values in little endian order (except payload in
219     // big endian).
220     std::array<uint8_t, kPayloadSize + 14> expected_hci_packet = {
221         0xCB,
222         0x0A,
223         0x8A,
224         0x00,
225         0x86,
226         0x00,
227         0x34,
228         0x12,
229         // RFCOMM header
230         0x19,
231         0xFF,
232         0x00,
233         0x01,
234         0x00,
235         0xAB,
236         0xCD,
237         0xEF,
238     };
239   } capture;
240 
241   // FCS
242   capture.expected_hci_packet[capture.expected_hci_packet.size() - 1] =
243       capture.rfcomm_fcs;
244 
245   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
246       []([[maybe_unused]] H4PacketWithHci&& packet) {});
247   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
248       [&capture](H4PacketWithH4&& packet) {
249         ++capture.sends_called;
250         EXPECT_EQ(packet.GetH4Type(), emboss::H4PacketType::ACL_DATA);
251         EXPECT_EQ(packet.GetHciSpan().size(),
252                   capture.expected_hci_packet.size());
253         EXPECT_TRUE(std::equal(packet.GetHciSpan().begin(),
254                                packet.GetHciSpan().end(),
255                                capture.expected_hci_packet.begin(),
256                                capture.expected_hci_packet.end()));
257         PW_TEST_ASSERT_OK_AND_ASSIGN(
258             auto acl,
259             MakeEmbossView<emboss::AclDataFrameView>(packet.GetHciSpan()));
260         EXPECT_EQ(acl.header().handle().Read(), capture.handle);
261         EXPECT_EQ(acl.header().packet_boundary_flag().Read(),
262                   emboss::AclDataPacketBoundaryFlag::FIRST_NON_FLUSHABLE);
263         EXPECT_EQ(acl.header().broadcast_flag().Read(),
264                   emboss::AclDataPacketBroadcastFlag::POINT_TO_POINT);
265         EXPECT_EQ(acl.data_total_length().Read(),
266                   capture.acl_data_total_length);
267         emboss::BFrameView bframe = emboss::BFrameView(
268             acl.payload().BackingStorage().data(), acl.SizeInBytes());
269         EXPECT_EQ(bframe.pdu_length().Read(), capture.pdu_length);
270         EXPECT_EQ(bframe.channel_id().Read(), capture.channel_id);
271         EXPECT_TRUE(std::equal(bframe.payload().BackingStorage().begin(),
272                                bframe.payload().BackingStorage().begin() +
273                                    capture.rfcomm_header.size(),
274                                capture.rfcomm_header.begin(),
275                                capture.rfcomm_header.end()));
276         auto rfcomm = emboss::MakeRfcommFrameView(
277             bframe.payload().BackingStorage().data(),
278             bframe.payload().SizeInBytes());
279         EXPECT_TRUE(rfcomm.Ok());
280         EXPECT_EQ(rfcomm.credits().Read(), capture.rfcomm_credits);
281 
282         for (size_t i = 0; i < 3; ++i) {
283           EXPECT_EQ(rfcomm.information()[i].Read(), capture.payload[i]);
284         }
285 
286         EXPECT_EQ(rfcomm.fcs().Read(), capture.rfcomm_fcs);
287       });
288 
289   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
290                               std::move(send_to_controller_fn),
291                               /*le_acl_credits_to_reserve=*/0,
292                               /*br_edr_acl_credits_to_reserve=*/1);
293   // Allow proxy to reserve 1 credit.
294   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 1));
295 
296   RfcommParameters params = {.handle = capture.handle,
297                              .tx_config = {
298                                  .cid = capture.channel_id,
299                              }};
300   RfcommChannel channel = BuildRfcomm(proxy, params);
301   PW_TEST_EXPECT_OK(
302       channel.Write(MultiBufFromSpan(pw::span(capture.payload))).status);
303   EXPECT_EQ(capture.sends_called, 1);
304 }
305 
TEST_F(RfcommWriteTest,MixedLengthWrites)306 TEST_F(RfcommWriteTest, MixedLengthWrites) {
307   constexpr size_t kPayload1Size = 0x80;
308   constexpr size_t kPayload2Size = 0x3;
309   struct {
310     int sends_called = 0;
311     uint16_t handle = 0x0ACB;
312     // Random CID
313     uint16_t channel_id = 0x1234;
314     // RFCOMM information payload
315     std::array<uint8_t, kPayload1Size> payload = {
316         0xAB,
317         0xCD,
318         0xEF,
319     };
320   } capture;
321 
322   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
323       [](H4PacketWithHci&&) {});
324   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
325       [&capture](H4PacketWithH4&&) { ++capture.sends_called; });
326 
327   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
328                               std::move(send_to_controller_fn),
329                               /*le_acl_credits_to_reserve=*/0,
330                               /*br_edr_acl_credits_to_reserve=*/2);
331   // Allow proxy to reserve 2 credits.
332   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(proxy, 2));
333 
334   RfcommParameters params = {.handle = capture.handle,
335                              .tx_config = {
336                                  .cid = capture.channel_id,
337                              }};
338   RfcommChannel channel = BuildRfcomm(proxy, params);
339   PW_TEST_EXPECT_OK(
340       channel.Write(MultiBufFromSpan(pw::span(capture.payload))).status);
341   PW_TEST_EXPECT_OK(channel
342                         .Write(MultiBufFromSpan(
343                             pw::span(capture.payload).subspan(kPayload2Size)))
344                         .status);
345   EXPECT_EQ(capture.sends_called, 2);
346 }
347 
TEST_F(RfcommWriteTest,WriteFlowControl)348 TEST_F(RfcommWriteTest, WriteFlowControl) {
349   struct {
350     int sends_called = 0;
351     int queue_unblocked = 0;
352     // RFCOMM information payload
353     std::array<uint8_t, 3> payload = {0xAB, 0xCD, 0xEF};
354   } capture;
355 
356   pw::Function<void(H4PacketWithHci && packet)> send_to_host_fn(
357       [](H4PacketWithHci&&) {});
358   pw::Function<void(H4PacketWithH4 && packet)> send_to_controller_fn(
359       [&capture](H4PacketWithH4&&) { ++capture.sends_called; });
360   ChannelEventCallback event_fn([&capture](L2capChannelEvent event) {
361     if (event == L2capChannelEvent::kWriteAvailable) {
362       ++capture.queue_unblocked;
363     }
364   });
365 
366   ProxyHost proxy = ProxyHost(
367       std::move(send_to_host_fn),
368       std::move(send_to_controller_fn),
369       /*le_acl_credits_to_reserve=*/0,
370       /*br_edr_acl_credits_to_reserve=*/RfcommChannel::QueueCapacity() + 1);
371   // Start with plenty of ACL credits to test RFCOMM logic.
372   PW_TEST_EXPECT_OK(SendReadBufferResponseFromController(
373       proxy, RfcommChannel::QueueCapacity() + 1));
374 
375   RfcommParameters params = {.tx_config = {
376                                  .cid = 123,
377                                  .credits = 0,
378                              }};
379   RfcommChannel channel = BuildRfcomm(proxy,
380                                       params,
381                                       /*receive_fn=*/nullptr,
382                                       /*event_fn=*/std::move(event_fn));
383 
384   // Writes while queue has space will return Ok. No RFCOMM credits yet though
385   // so no sends complete.
386   PW_TEST_EXPECT_OK(
387       channel.Write(MultiBufFromSpan(pw::span(capture.payload))).status);
388   EXPECT_EQ(capture.sends_called, 0);
389   EXPECT_EQ(capture.queue_unblocked, 0);
390 
391   // Provide a credit
392   constexpr uint8_t kExpectedFcs = 0xE6;
393   PW_TEST_EXPECT_OK(SendRfcommFromController(
394       proxy, params, kExpectedFcs, /*credits=*/1, /*payload=*/{}));
395   EXPECT_EQ(capture.queue_unblocked, 0);
396   EXPECT_EQ(capture.sends_called, 1);
397 
398   // Now fill up queue
399   uint16_t queued = 0;
400   while (true) {
401     if (const auto status =
402             channel.Write(MultiBufFromSpan(pw::span(capture.payload))).status;
403         status == Status::Unavailable()) {
404       break;
405     }
406     ++queued;
407   }
408 
409   // Unblock queue with ACL and RFCOMM credits
410   PW_TEST_EXPECT_OK(SendNumberOfCompletedPackets(
411       proxy, FlatMap<uint16_t, uint16_t, 1>({{{params.handle, queued}}})));
412   PW_TEST_EXPECT_OK(SendRfcommFromController(
413       proxy, params, kExpectedFcs, /*credits=*/queued, /*payload=*/{}));
414 
415   EXPECT_EQ(capture.sends_called, queued + 1);
416   EXPECT_EQ(capture.queue_unblocked, 1);
417 }
418 
419 // ########## RfcommReadTest
420 
421 class RfcommReadTest : public ProxyHostTest {};
422 
TEST_F(RfcommReadTest,BasicRead)423 TEST_F(RfcommReadTest, BasicRead) {
424   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
425       []([[maybe_unused]] H4PacketWithHci&& packet) {});
426   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
427       []([[maybe_unused]] H4PacketWithH4&& packet) {});
428   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
429                               std::move(send_to_controller_fn),
430                               /*le_acl_credits_to_reserve=*/0,
431                               /*br_edr_acl_credits_to_reserve=*/0);
432 
433   struct {
434     int rx_called = 0;
435     std::array<uint8_t, 3> expected_payload = {0xAB, 0xCD, 0xEF};
436   } capture;
437 
438   constexpr uint8_t kExpectedFcs = 0xFA;
439 
440   RfcommParameters params = {};
441   RfcommChannel channel = BuildRfcomm(
442       proxy,
443       params,
444       /*receive_fn=*/[&capture](multibuf::MultiBuf&& buffer) {
445         ++capture.rx_called;
446         std::optional<pw::ByteSpan> payload = buffer.ContiguousSpan();
447         ConstByteSpan expected_bytes = as_bytes(span(
448             capture.expected_payload.data(), capture.expected_payload.size()));
449         ASSERT_TRUE(payload.has_value());
450         EXPECT_TRUE(std::equal(payload->begin(),
451                                payload->end(),
452                                expected_bytes.begin(),
453                                expected_bytes.end()));
454       });
455 
456   PW_TEST_EXPECT_OK(SendRfcommFromController(proxy,
457                                              params,
458                                              kExpectedFcs,
459                                              /*credits=*/std::nullopt,
460                                              capture.expected_payload));
461   EXPECT_EQ(capture.rx_called, 1);
462 }
463 
TEST_F(RfcommReadTest,ExtendedRead)464 TEST_F(RfcommReadTest, ExtendedRead) {
465   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
466       []([[maybe_unused]] H4PacketWithHci&& packet) {});
467   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
468       []([[maybe_unused]] H4PacketWithH4&& packet) {});
469   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
470                               std::move(send_to_controller_fn),
471                               /*le_acl_credits_to_reserve=*/0,
472                               /*br_edr_acl_credits_to_reserve=*/0);
473 
474   constexpr size_t kPayloadSize = 0x80;
475   struct {
476     int rx_called = 0;
477     std::array<uint8_t, kPayloadSize> expected_payload = {0xAB, 0xCD, 0xEF};
478   } capture;
479 
480   constexpr uint8_t kExpectedFcs = 0xFA;
481 
482   RfcommParameters params = {};
483   RfcommChannel channel = BuildRfcomm(
484       proxy,
485       params,
486       /*receive_fn=*/
487       [&capture](multibuf::MultiBuf&& buffer) {
488         ++capture.rx_called;
489         std::optional<pw::ByteSpan> payload = buffer.ContiguousSpan();
490         ConstByteSpan expected_bytes = as_bytes(span(
491             capture.expected_payload.data(), capture.expected_payload.size()));
492         ASSERT_TRUE(payload.has_value());
493         EXPECT_TRUE(std::equal(payload->begin(),
494                                payload->end(),
495                                expected_bytes.begin(),
496                                expected_bytes.end()));
497       });
498   PW_TEST_EXPECT_OK(SendRfcommFromController(proxy,
499                                              params,
500                                              kExpectedFcs,
501                                              /*credits=*/std::nullopt,
502                                              capture.expected_payload));
503 
504   EXPECT_EQ(capture.rx_called, 1);
505 }
506 
TEST_F(RfcommReadTest,InvalidReads)507 TEST_F(RfcommReadTest, InvalidReads) {
508   struct {
509     int rx_called = 0;
510     int host_called = 0;
511   } capture;
512 
513   pw::Function<void(H4PacketWithHci && packet)>&& send_to_host_fn(
514       [&capture]([[maybe_unused]] H4PacketWithHci&& packet) {
515         ++capture.host_called;
516       });
517   pw::Function<void(H4PacketWithH4 && packet)>&& send_to_controller_fn(
518       []([[maybe_unused]] H4PacketWithH4&& packet) {});
519   ProxyHost proxy = ProxyHost(std::move(send_to_host_fn),
520                               std::move(send_to_controller_fn),
521                               /*le_acl_credits_to_reserve=*/0,
522                               /*br_edr_acl_credits_to_reserve=*/0);
523 
524   constexpr uint8_t kExpectedFcs = 0xFA;
525   constexpr uint8_t kInvalidFcs = 0xFF;
526 
527   RfcommParameters params = {};
528   RfcommChannel channel = BuildRfcomm(
529       proxy,
530       params,
531       /*receive_fn=*/
532       [&capture](multibuf::MultiBuf&&) { ++capture.rx_called; },
533       /*event_fn=*/nullptr);
534 
535   // Construct valid packet but put invalid checksum on the end. Test that we
536   // don't get it sent on to us.
537   PW_TEST_EXPECT_OK(SendRfcommFromController(proxy,
538                                              params,
539                                              kInvalidFcs,
540                                              /*credits=*/std::nullopt,
541                                              /*payload=*/{}));
542   EXPECT_EQ(capture.rx_called, 0);
543   EXPECT_EQ(capture.host_called, 1);
544 
545   // Construct packet with everything valid but wrong length for actual data
546   // size. Ensure it doesn't end up being sent to our channel, but does get
547   // forwarded to host.
548   {
549     PW_TEST_ASSERT_OK_AND_ASSIGN(
550         BFrameWithStorage bframe,
551         SetupBFrame(params.handle,
552                     params.rx_config.cid,
553                     emboss::RfcommFrame::MinSizeInBytes()));
554 
555     auto rfcomm = emboss::MakeRfcommFrameView(
556         bframe.writer.payload().BackingStorage().data(),
557         bframe.writer.payload().SizeInBytes());
558     rfcomm.extended_address().Write(true);
559     rfcomm.command_response_direction().Write(
560         emboss::RfcommCommandResponseAndDirection::COMMAND_FROM_INITIATOR);
561     rfcomm.channel().Write(params.rfcomm_channel);
562 
563     rfcomm.control().Write(
564         emboss::RfcommFrameType::UNNUMBERED_INFORMATION_WITH_HEADER_CHECK);
565 
566     rfcomm.length_extended_flag().Write(emboss::RfcommLengthExtended::NORMAL);
567     // Invalid length.
568     rfcomm.length().Write(1);
569     // Can't Write FCS as emboss will assert because of invalid length. Place
570     // manually.
571     pw::span<uint8_t> hci_span = bframe.acl.hci_span();
572     hci_span[hci_span.size() - 1] = kExpectedFcs;
573 
574     H4PacketWithHci packet{emboss::H4PacketType::ACL_DATA, hci_span};
575     proxy.HandleH4HciFromController(std::move(packet));
576   }
577 
578   EXPECT_EQ(capture.rx_called, 0);
579   EXPECT_EQ(capture.host_called, 2);
580 }
581 
582 }  // namespace
583 }  // namespace pw::bluetooth::proxy
584