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