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