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