• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/l2cap/test_packets.h"
16 
17 #include <pw_assert/check.h>
18 
19 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/fcs.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/frame_headers.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
24 
25 namespace bt::l2cap::testing {
26 
AclExtFeaturesInfoReq(l2cap::CommandId id,hci_spec::ConnectionHandle handle)27 DynamicByteBuffer AclExtFeaturesInfoReq(l2cap::CommandId id,
28                                         hci_spec::ConnectionHandle handle) {
29   return DynamicByteBuffer(StaticByteBuffer(
30       // ACL data header (handle, length: 10)
31       LowerBits(handle),
32       UpperBits(handle),
33       0x0a,
34       0x00,
35 
36       // L2CAP B-frame header (length: 6, chanel-id: 0x0001 (ACL sig))
37       0x06,
38       0x00,
39       0x01,
40       0x00,
41 
42       // Extended Features Information Request
43       // (ID, length: 2, type)
44       0x0a,
45       id,
46       0x02,
47       0x00,
48       LowerBits(
49           static_cast<uint16_t>(InformationType::kExtendedFeaturesSupported)),
50       UpperBits(
51           static_cast<uint16_t>(InformationType::kExtendedFeaturesSupported))));
52 }
53 
AclCommandRejectNotUnderstoodRsp(l2cap::CommandId id,hci_spec::ConnectionHandle handle,ChannelId chan_id)54 DynamicByteBuffer AclCommandRejectNotUnderstoodRsp(
55     l2cap::CommandId id, hci_spec::ConnectionHandle handle, ChannelId chan_id) {
56   return DynamicByteBuffer(StaticByteBuffer(
57       // ACL data header (handle: |link_handle|, length: 10 bytes)
58       LowerBits(handle),
59       UpperBits(handle),
60       0x0a,
61       0x00,
62       // L2CAP B-frame header (length: 6 bytes, channel-id: 0x0001 (ACL sig))
63       0x06,
64       0x00,
65       LowerBits(chan_id),
66       UpperBits(chan_id),
67       // Information Response (type, ID, length: 2)
68       l2cap::kCommandRejectCode,
69       id,
70       0x02,
71       0x00,
72       // Reason = Not Understood
73       LowerBits(static_cast<uint16_t>(RejectReason::kNotUnderstood)),
74       UpperBits(static_cast<uint16_t>(RejectReason::kNotUnderstood))));
75 }
76 
AclExtFeaturesInfoRsp(l2cap::CommandId id,hci_spec::ConnectionHandle handle,l2cap::ExtendedFeatures features)77 DynamicByteBuffer AclExtFeaturesInfoRsp(l2cap::CommandId id,
78                                         hci_spec::ConnectionHandle handle,
79                                         l2cap::ExtendedFeatures features) {
80   const auto features_bytes = ToBytes(features);
81   return DynamicByteBuffer(StaticByteBuffer(
82       // ACL data header (handle: |link_handle|, length: 16 bytes)
83       LowerBits(handle),
84       UpperBits(handle),
85       0x10,
86       0x00,
87       // L2CAP B-frame header (length: 12 bytes, channel-id: 0x0001 (ACL sig))
88       0x0c,
89       0x00,
90       0x01,
91       0x00,
92       // Information Response (type, ID, length: 8)
93       l2cap::kInformationResponse,
94       id,
95       0x08,
96       0x00,
97       // Type = Features Mask
98       0x02,
99       0x00,
100       // Result = Success
101       0x00,
102       0x00,
103       // Data (Mask)
104       features_bytes[0],
105       features_bytes[1],
106       features_bytes[2],
107       features_bytes[3]));
108 }
109 
AclFixedChannelsSupportedInfoReq(l2cap::CommandId id,hci_spec::ConnectionHandle handle)110 DynamicByteBuffer AclFixedChannelsSupportedInfoReq(
111     l2cap::CommandId id, hci_spec::ConnectionHandle handle) {
112   return DynamicByteBuffer(StaticByteBuffer(
113       // ACL data header (handle, length: 10)
114       LowerBits(handle),
115       UpperBits(handle),
116       0x0a,
117       0x00,
118 
119       // L2CAP B-frame header (length: 6, chanel-id: 0x0001 (ACL sig))
120       0x06,
121       0x00,
122       0x01,
123       0x00,
124 
125       // Fixed Channels Supported Information Request
126       // (ID, length: 2, info type)
127       l2cap::kInformationRequest,
128       id,
129       0x02,
130       0x00,
131       LowerBits(
132           static_cast<uint16_t>(InformationType::kFixedChannelsSupported)),
133       UpperBits(
134           static_cast<uint16_t>(InformationType::kFixedChannelsSupported))));
135 }
136 
AclFixedChannelsSupportedInfoRsp(l2cap::CommandId id,hci_spec::ConnectionHandle handle,l2cap::FixedChannelsSupported chan_mask)137 DynamicByteBuffer AclFixedChannelsSupportedInfoRsp(
138     l2cap::CommandId id,
139     hci_spec::ConnectionHandle handle,
140     l2cap::FixedChannelsSupported chan_mask) {
141   const auto chan_bytes = ToBytes(chan_mask);
142   return DynamicByteBuffer(StaticByteBuffer(
143       // ACL data header (handle: |link_handle|, length: 20 bytes)
144       LowerBits(handle),
145       UpperBits(handle),
146       0x14,
147       0x00,
148       // L2CAP B-frame header (length: 16 bytes, channel-id: 0x0001 (ACL sig))
149       0x10,
150       0x00,
151       0x01,
152       0x00,
153       // Information Response (type, ID, length: 12)
154       l2cap::kInformationResponse,
155       id,
156       0x0c,
157       0x00,
158       // Type = Fixed Channels Supported
159       0x03,
160       0x00,
161       // Result = Success
162       0x00,
163       0x00,
164       // Data (Mask)
165       chan_bytes[0],
166       chan_bytes[1],
167       chan_bytes[2],
168       chan_bytes[3],
169       chan_bytes[4],
170       chan_bytes[5],
171       chan_bytes[6],
172       chan_bytes[7]));
173 }
174 
AclNotSupportedInformationResponse(l2cap::CommandId id,hci_spec::ConnectionHandle handle)175 DynamicByteBuffer AclNotSupportedInformationResponse(
176     l2cap::CommandId id, hci_spec::ConnectionHandle handle) {
177   return DynamicByteBuffer(StaticByteBuffer(
178       // ACL data header (handle: |link_handle|, length: 12 bytes)
179       LowerBits(handle),
180       UpperBits(handle),
181       0x0c,
182       0x00,
183       // L2CAP B-frame header (length: 8 bytes, channel-id: 0x0001 (ACL sig))
184       0x08,
185       0x00,
186       0x01,
187       0x00,
188       // Information Response (type, ID, length: 4)
189       l2cap::kInformationResponse,
190       id,
191       0x04,
192       0x00,
193       // Type = invalid type
194       0xFF,
195       0xFF,
196       // Result
197       LowerBits(static_cast<uint16_t>(l2cap::InformationResult::kNotSupported)),
198       UpperBits(
199           static_cast<uint16_t>(l2cap::InformationResult::kNotSupported))));
200 }
201 
AclConfigReq(l2cap::CommandId id,hci_spec::ConnectionHandle handle,l2cap::ChannelId dst_id,l2cap::ChannelParameters params)202 DynamicByteBuffer AclConfigReq(l2cap::CommandId id,
203                                hci_spec::ConnectionHandle handle,
204                                l2cap::ChannelId dst_id,
205                                l2cap::ChannelParameters params) {
206   const auto any_mode =
207       params.mode.value_or(l2cap::RetransmissionAndFlowControlMode::kBasic);
208   const auto mtu = params.max_rx_sdu_size.value_or(l2cap::kMaxMTU);
209 
210   PW_CHECK(
211       std::holds_alternative<l2cap::RetransmissionAndFlowControlMode>(any_mode),
212       "Channel mode is unsupported for configuration request.");
213   const auto mode = std::get<l2cap::RetransmissionAndFlowControlMode>(any_mode);
214   switch (mode) {
215     case l2cap::RetransmissionAndFlowControlMode::kBasic:
216       return DynamicByteBuffer(StaticByteBuffer(
217           // ACL data header (handle, length: 16 bytes)
218           LowerBits(handle),
219           UpperBits(handle),
220           0x10,
221           0x00,
222           // L2CAP B-frame header (length: 12, channel-id: 0x0001 (ACL sig))
223           0x0c,
224           0x00,
225           0x01,
226           0x00,
227           // Configuration Request (ID, length: 8, |dst_id|, flags: 0,
228           0x04,
229           id,
230           0x08,
231           0x00,
232           LowerBits(dst_id),
233           UpperBits(dst_id),
234           0x00,
235           0x00,
236           // MTU option: (ID: 1, length: 2, mtu)
237           0x01,
238           0x02,
239           LowerBits(mtu),
240           UpperBits(mtu)));
241     case l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission:
242       return DynamicByteBuffer(StaticByteBuffer(
243           // ACL data header (handle, length: 27 bytes)
244           LowerBits(handle),
245           UpperBits(handle),
246           0x1b,
247           0x00,
248           // L2CAP B-frame header (length: 23, channel-id: 0x0001 (ACL sig))
249           0x17,
250           0x00,
251           0x01,
252           0x00,
253           // Configuration Request (ID, length: 19, |dst_id|, flags: 0,
254           0x04,
255           id,
256           0x13,
257           0x00,
258           LowerBits(dst_id),
259           UpperBits(dst_id),
260           0x00,
261           0x00,
262           // MTU option: (ID: 1, length: 2, mtu)
263           0x01,
264           0x02,
265           LowerBits(mtu),
266           UpperBits(mtu),
267           // Retransmission & Flow Control option (Type, Length = 9, mode,
268           // fields)
269           0x04,
270           0x09,
271           static_cast<uint8_t>(mode),
272           l2cap::kErtmMaxUnackedInboundFrames,
273           l2cap::kErtmMaxInboundRetransmissions,
274           0x00,
275           0x00,
276           0x00,
277           0x00,
278           LowerBits(l2cap::kMaxInboundPduPayloadSize),
279           UpperBits(l2cap::kMaxInboundPduPayloadSize)));
280     case l2cap::RetransmissionAndFlowControlMode::kRetransmission:
281     case l2cap::RetransmissionAndFlowControlMode::kFlowControl:
282     case l2cap::RetransmissionAndFlowControlMode::kStreaming:
283       PW_CHECK(false, "unsupported mode");
284   }
285 }
286 
AclConfigRsp(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId src_id,l2cap::ChannelParameters params)287 DynamicByteBuffer AclConfigRsp(l2cap::CommandId id,
288                                hci_spec::ConnectionHandle link_handle,
289                                l2cap::ChannelId src_id,
290                                l2cap::ChannelParameters params) {
291   const auto any_mode =
292       params.mode.value_or(l2cap::RetransmissionAndFlowControlMode::kBasic);
293   const auto mtu = params.max_rx_sdu_size.value_or(l2cap::kMaxMTU);
294 
295   PW_CHECK(
296       std::holds_alternative<l2cap::RetransmissionAndFlowControlMode>(any_mode),
297       "Channel mode is unsupported for configuration response.");
298   const auto mode = std::get<l2cap::RetransmissionAndFlowControlMode>(any_mode);
299   switch (mode) {
300     case l2cap::RetransmissionAndFlowControlMode::kBasic:
301       return DynamicByteBuffer(StaticByteBuffer(
302           // ACL data header (handle: |link_handle|, length: 18 bytes)
303           LowerBits(link_handle),
304           UpperBits(link_handle),
305           0x12,
306           0x00,
307           // L2CAP B-frame header (length: 14 bytes, channel-id: 0x0001 (ACL
308           // sig))
309           0x0e,
310           0x00,
311           0x01,
312           0x00,
313           // Configuration Response (ID, length: 10, src cid, flags: 0,
314           // result: success)
315           0x05,
316           id,
317           0x0a,
318           0x00,
319           LowerBits(src_id),
320           UpperBits(src_id),
321           0x00,
322           0x00,
323           0x00,
324           0x00,
325           // MTU option: (ID: 1, length: 2, mtu)
326           0x01,
327           0x02,
328           LowerBits(mtu),
329           UpperBits(mtu)));
330     case l2cap::RetransmissionAndFlowControlMode::kEnhancedRetransmission: {
331       const auto rtx_timeout = kErtmReceiverReadyPollTimerMsecs;
332       const auto monitor_timeout = kErtmMonitorTimerMsecs;
333       return DynamicByteBuffer(StaticByteBuffer(
334           // ACL data header (handle: |link_handle|, length: 29 bytes)
335           LowerBits(link_handle),
336           UpperBits(link_handle),
337           0x1d,
338           0x00,
339           // L2CAP B-frame header (length: 25 bytes, channel-id: 0x0001 (ACL
340           // sig))
341           0x19,
342           0x00,
343           0x01,
344           0x00,
345           // Configuration Response (ID, length: 21, src cid, flags: 0,
346           // result: success)
347           0x05,
348           id,
349           0x15,
350           0x00,
351           LowerBits(src_id),
352           UpperBits(src_id),
353           0x00,
354           0x00,
355           0x00,
356           0x00,
357           // MTU option: (ID: 1, length: 2, mtu)
358           0x01,
359           0x02,
360           LowerBits(mtu),
361           UpperBits(mtu),
362           // Retransmission & Flow Control option (Type, Length = 9, mode,
363           // fields)
364           0x04,
365           0x09,
366           static_cast<uint8_t>(mode),
367           l2cap::kErtmMaxUnackedInboundFrames,
368           l2cap::kErtmMaxInboundRetransmissions,
369           LowerBits(rtx_timeout),
370           UpperBits(rtx_timeout),
371           LowerBits(monitor_timeout),
372           UpperBits(monitor_timeout),
373           LowerBits(l2cap::kMaxInboundPduPayloadSize),
374           UpperBits(l2cap::kMaxInboundPduPayloadSize)));
375     }
376     case l2cap::RetransmissionAndFlowControlMode::kRetransmission:
377     case l2cap::RetransmissionAndFlowControlMode::kFlowControl:
378     case l2cap::RetransmissionAndFlowControlMode::kStreaming:
379       PW_CHECK(false, "unsupported mode");
380   }
381 }
382 
AclConnectionReq(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId src_id,l2cap::Psm psm)383 DynamicByteBuffer AclConnectionReq(l2cap::CommandId id,
384                                    hci_spec::ConnectionHandle link_handle,
385                                    l2cap::ChannelId src_id,
386                                    l2cap::Psm psm) {
387   return DynamicByteBuffer(StaticByteBuffer(
388       // ACL data header (handle: |link_handle|, length: 12 bytes)
389       LowerBits(link_handle),
390       UpperBits(link_handle),
391       0x0c,
392       0x00,
393 
394       // L2CAP B-frame header (length: 8 bytes, channel-id: 0x0001 (ACL sig))
395       0x08,
396       0x00,
397       0x01,
398       0x00,
399 
400       // Connection Request (ID, length: 4, |psm|, |src_id|)
401       0x02,
402       id,
403       0x04,
404       0x00,
405       LowerBits(psm),
406       UpperBits(psm),
407       LowerBits(src_id),
408       UpperBits(src_id)));
409 }
410 
AclConnectionRsp(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId src_id,l2cap::ChannelId dst_id,l2cap::ConnectionResult result)411 DynamicByteBuffer AclConnectionRsp(l2cap::CommandId id,
412                                    hci_spec::ConnectionHandle link_handle,
413                                    l2cap::ChannelId src_id,
414                                    l2cap::ChannelId dst_id,
415                                    l2cap::ConnectionResult result) {
416   return DynamicByteBuffer(StaticByteBuffer(
417       // ACL data header (handle: |link handle|, length: 16 bytes)
418       LowerBits(link_handle),
419       UpperBits(link_handle),
420       0x10,
421       0x00,
422       // L2CAP B-frame header: length 12, channel-id 1 (signaling)
423       0x0c,
424       0x00,
425       0x01,
426       0x00,
427       // Connection Response (0x03), id, length 8
428       l2cap::kConnectionResponse,
429       id,
430       0x08,
431       0x00,
432       // destination cid
433       LowerBits(dst_id),
434       UpperBits(dst_id),
435       // source cid
436       LowerBits(src_id),
437       UpperBits(src_id),
438       // Result
439       LowerBits(static_cast<uint16_t>(result)),
440       UpperBits(static_cast<uint16_t>(result)),
441       // Status (no further information available)
442       0x00,
443       0x00));
444 }
445 
AclDisconnectionReq(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId src_id,l2cap::ChannelId dst_id)446 DynamicByteBuffer AclDisconnectionReq(l2cap::CommandId id,
447                                       hci_spec::ConnectionHandle link_handle,
448                                       l2cap::ChannelId src_id,
449                                       l2cap::ChannelId dst_id) {
450   return DynamicByteBuffer(StaticByteBuffer(
451       // ACL data header (handle: |link handle|, length: 12 bytes)
452       LowerBits(link_handle),
453       UpperBits(link_handle),
454       0x0c,
455       0x00,
456       // L2CAP B-frame header: length 8, channel-id 1 (signaling)
457       0x08,
458       0x00,
459       0x01,
460       0x00,
461       // Disconnection Request, id, length 4
462       l2cap::kDisconnectionRequest,
463       id,
464       0x04,
465       0x00,
466       // Destination CID
467       LowerBits(dst_id),
468       UpperBits(dst_id),
469       // Source CID
470       LowerBits(src_id),
471       UpperBits(src_id)));
472 }
473 
AclDisconnectionRsp(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId src_id,l2cap::ChannelId dst_id)474 DynamicByteBuffer AclDisconnectionRsp(l2cap::CommandId id,
475                                       hci_spec::ConnectionHandle link_handle,
476                                       l2cap::ChannelId src_id,
477                                       l2cap::ChannelId dst_id) {
478   return DynamicByteBuffer(StaticByteBuffer(
479       // ACL data header (handle: |link handle|, length: 12 bytes)
480       LowerBits(link_handle),
481       UpperBits(link_handle),
482       0x0c,
483       0x00,
484       // L2CAP B-frame header: length 8, channel-id 1 (signaling)
485       0x08,
486       0x00,
487       0x01,
488       0x00,
489       // Disconnection Response, id, length 4
490       l2cap::kDisconnectionResponse,
491       id,
492       0x04,
493       0x00,
494       // Destination CID
495       LowerBits(dst_id),
496       UpperBits(dst_id),
497       // Source CID
498       LowerBits(src_id),
499       UpperBits(src_id)));
500 }
501 
AclConnectionParameterUpdateReq(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,uint16_t interval_min,uint16_t interval_max,uint16_t peripheral_latency,uint16_t timeout_multiplier)502 DynamicByteBuffer AclConnectionParameterUpdateReq(
503     l2cap::CommandId id,
504     hci_spec::ConnectionHandle link_handle,
505     uint16_t interval_min,
506     uint16_t interval_max,
507     uint16_t peripheral_latency,
508     uint16_t timeout_multiplier) {
509   return DynamicByteBuffer(StaticByteBuffer(
510       // ACL data header (handle: |link handle|, length: 16 bytes)
511       LowerBits(link_handle),
512       UpperBits(link_handle),
513       0x10,
514       0x00,
515       // L2CAP B-frame header: length 12, channel-id 5 (LE signaling)
516       0x0c,
517       0x00,
518       0x05,
519       0x00,
520       // Connection Parameter Update Request (0x12), id, length 8
521       l2cap::kConnectionParameterUpdateRequest,
522       id,
523       0x08,
524       0x00,
525       // interval min
526       LowerBits(interval_min),
527       UpperBits(interval_min),
528       // interval max
529       LowerBits(interval_max),
530       UpperBits(interval_max),
531       // peripheral latency
532       LowerBits(peripheral_latency),
533       UpperBits(peripheral_latency),
534       // timeout multiplier
535       LowerBits(timeout_multiplier),
536       UpperBits(timeout_multiplier)));
537 }
538 
AclConnectionParameterUpdateRsp(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,ConnectionParameterUpdateResult result)539 DynamicByteBuffer AclConnectionParameterUpdateRsp(
540     l2cap::CommandId id,
541     hci_spec::ConnectionHandle link_handle,
542     ConnectionParameterUpdateResult result) {
543   return DynamicByteBuffer(StaticByteBuffer(
544       // ACL data header (handle: |link handle|, length: 10 bytes)
545       LowerBits(link_handle),
546       UpperBits(link_handle),
547       0x0a,
548       0x00,
549       // L2CAP B-frame header: length 6, channel-id 5 (LE signaling)
550       0x06,
551       0x00,
552       0x05,
553       0x00,
554       // Connection Parameter Update Response (0x13), id, length 2
555       l2cap::kConnectionParameterUpdateResponse,
556       id,
557       0x02,
558       0x00,
559       // Result
560       LowerBits(static_cast<uint16_t>(result)),
561       UpperBits(static_cast<uint16_t>(result))));
562 }
563 
AclLeCreditBasedConnectionReq(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::Psm psm,l2cap::ChannelId cid,uint16_t mtu,uint16_t mps,uint16_t credits)564 DynamicByteBuffer AclLeCreditBasedConnectionReq(
565     l2cap::CommandId id,
566     hci_spec::ConnectionHandle link_handle,
567     l2cap::Psm psm,
568     l2cap::ChannelId cid,
569     uint16_t mtu,
570     uint16_t mps,
571     uint16_t credits) {
572   return DynamicByteBuffer(StaticByteBuffer(
573       // ACL data header (link_handle, length: 18 bytes)
574       LowerBits(link_handle),
575       UpperBits(link_handle),
576       0x12,
577       0x00,
578       // L2CAP B-frame header: length 14, channel-id 5 (LE signaling)
579       0x0e,
580       0x00,
581       0x05,
582       0x00,
583       // LE credit based connection request, id 0x14, length 10
584       l2cap::kLECreditBasedConnectionRequest,
585       id,
586       0x0a,
587       0x00,
588       // SPSM
589       LowerBits(psm),
590       UpperBits(psm),
591       // Source CID
592       LowerBits(cid),
593       UpperBits(cid),
594       // MTU
595       LowerBits(mtu),
596       UpperBits(mtu),
597       // MPS
598       LowerBits(mps),
599       UpperBits(mps),
600       // Initial Credits
601       LowerBits(credits),
602       UpperBits(credits)));
603 }
604 
AclLeCreditBasedConnectionRsp(l2cap::CommandId id,hci_spec::ConnectionHandle link_handle,l2cap::ChannelId cid,uint16_t mtu,uint16_t mps,uint16_t credits,LECreditBasedConnectionResult result)605 DynamicByteBuffer AclLeCreditBasedConnectionRsp(
606     l2cap::CommandId id,
607     hci_spec::ConnectionHandle link_handle,
608     l2cap::ChannelId cid,
609     uint16_t mtu,
610     uint16_t mps,
611     uint16_t credits,
612     LECreditBasedConnectionResult result) {
613   return DynamicByteBuffer(StaticByteBuffer(
614       // ACL data header (link_handle, length: 18 bytes)
615       LowerBits(link_handle),
616       UpperBits(link_handle),
617       0x12,
618       0x00,
619       // L2CAP B-frame header: length 14, channel-id 5 (LE signaling)
620       0x0e,
621       0x00,
622       0x05,
623       0x00,
624       // LE credit based connection response, id 0x14, length 10
625       l2cap::kLECreditBasedConnectionResponse,
626       id,
627       0x0a,
628       0x00,
629       // Destination CID
630       LowerBits(cid),
631       UpperBits(cid),
632       // MTU
633       LowerBits(mtu),
634       UpperBits(mtu),
635       // MPS
636       LowerBits(mps),
637       UpperBits(mps),
638       // Initial Credits
639       LowerBits(credits),
640       UpperBits(credits),
641       // Result
642       LowerBits(static_cast<uint16_t>(result)),
643       UpperBits(static_cast<uint16_t>(result))));
644 }
645 
AclSFrame(hci_spec::ConnectionHandle link_handle,l2cap::ChannelId channel_id,l2cap::internal::SupervisoryFunction function,uint8_t receive_seq_num,bool is_poll_request,bool is_poll_response)646 DynamicByteBuffer AclSFrame(hci_spec::ConnectionHandle link_handle,
647                             l2cap::ChannelId channel_id,
648                             l2cap::internal::SupervisoryFunction function,
649                             uint8_t receive_seq_num,
650                             bool is_poll_request,
651                             bool is_poll_response) {
652   StaticByteBuffer acl_packet{
653       // ACL data header (handle: |link handle|, length: 8 bytes)
654       LowerBits(link_handle),
655       UpperBits(link_handle),
656       0x08,
657       0x00,
658 
659       // L2CAP B-frame header: length 4, channel-id
660       0x04,
661       0x00,
662       LowerBits(channel_id),
663       UpperBits(channel_id),
664 
665       // Enhanced Control Field: F is_poll_response, P is_poll_request,
666       // Supervisory function,
667       // Type S-Frame, ReqSeq receive_seq_num
668       (is_poll_response ? 0b1000'0000 : 0) | (is_poll_request ? 0b1'0000 : 0) |
669           (static_cast<uint8_t>(function) << 2) | 0b1,
670       receive_seq_num & 0b11'1111,
671 
672       // Frame Check Sequence
673       0x00,
674       0x00};
675   const FrameCheckSequence fcs = ComputeFcs(
676       acl_packet.view(sizeof(hci_spec::ACLDataHeader),
677                       acl_packet.size() - sizeof(hci_spec::ACLDataHeader) -
678                           sizeof(FrameCheckSequence)));
679   acl_packet[acl_packet.size() - 2] = LowerBits(fcs.fcs);
680   acl_packet[acl_packet.size() - 1] = UpperBits(fcs.fcs);
681   return DynamicByteBuffer(acl_packet);
682 }
683 
AclIFrame(hci_spec::ConnectionHandle link_handle,l2cap::ChannelId channel_id,uint8_t receive_seq_num,uint8_t tx_seq,bool is_poll_response,const ByteBuffer & payload)684 DynamicByteBuffer AclIFrame(hci_spec::ConnectionHandle link_handle,
685                             l2cap::ChannelId channel_id,
686                             uint8_t receive_seq_num,
687                             uint8_t tx_seq,
688                             bool is_poll_response,
689                             const ByteBuffer& payload) {
690   const uint16_t l2cap_size =
691       static_cast<uint16_t>(sizeof(internal::SimpleInformationFrameHeader) +
692                             payload.size() + sizeof(FrameCheckSequence));
693   const uint16_t acl_size = l2cap_size + sizeof(BasicHeader);
694   StaticByteBuffer headers(
695       // ACL data header (handle: |link handle|, length)
696       LowerBits(link_handle),
697       UpperBits(link_handle),
698       LowerBits(acl_size),
699       UpperBits(acl_size),
700 
701       // L2CAP B-frame header: length, channel-id
702       LowerBits(l2cap_size),
703       UpperBits(l2cap_size),
704       LowerBits(channel_id),
705       UpperBits(channel_id),
706 
707       // Enhanced Control Field: F is_poll_response, TxSeq tx_seq, Type I-Frame,
708       // ReqSeq receive_seq_num
709       (is_poll_response ? 0b1000'0000 : 0) | ((tx_seq << 1) & 0b111'1110),
710       receive_seq_num & 0b11'1111);
711 
712   FrameCheckSequence fcs =
713       ComputeFcs(headers.view(sizeof(hci_spec::ACLDataHeader), acl_size));
714   fcs = ComputeFcs(payload.view(), fcs);
715 
716   DynamicByteBuffer acl_packet(headers.size() + payload.size() + sizeof(fcs));
717   headers.Copy(&acl_packet);
718   auto payload_destination = acl_packet.mutable_view(headers.size());
719   payload.Copy(&payload_destination);
720   acl_packet[acl_packet.size() - 2] = LowerBits(fcs.fcs);
721   acl_packet[acl_packet.size() - 1] = UpperBits(fcs.fcs);
722   return acl_packet;
723 }
724 
725 }  // namespace bt::l2cap::testing
726