| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_L2CAP_INTERNAL_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_L2CAP_INTERNAL_H_ |
| |
| #include <endian.h> |
| #include <zircon/assert.h> |
| #include <zircon/compiler.h> |
| |
| #include <cstdint> |
| #include <type_traits> |
| |
| namespace bt { |
| namespace l2cap { |
| namespace internal { |
| |
| // The definitions within this namespace don't directly map to full frame |
| // formats. Rather, they provide access to mode-specific headers beyond the |
| // L2CAP basic frame header. |
| // |
| // The structs can be used in two ways: to parse inbound data, or to format |
| // outbound data. When used to parse inbound data, the structs due not provide |
| // any validation. When used to format outbound data, the structs initialize |
| // bits to 0, or (if appropriate) a value appropriate for that struct. |
| |
| // For Retransmission and Flow Control Modes. (Vol 3, Part A, Sec 3.3.2) |
| using StandardControlField = uint16_t; |
| |
| // See Vol 3, Part A, Table 3.4. |
| enum class SegmentationStatus { |
| Unsegmented = 0b00, |
| FirstSegment = 0b01, // AKA "Start of L2CAP SDU" |
| LastSegment = 0b10, // AKA "End of L2CAP SDU" |
| MiddleSegment = 0b11 // AKA "Continuation of L2CAP SDU" |
| }; |
| |
| // For Enhanced Retransmission and Streaming Modes _without_ Extended Window |
| // Size. (Vol 3, Part A, Sec 3.3.2) |
| struct EnhancedControlField { |
| // See Core Spec v5, Vol 3, Part A, Sec 8.3. |
| static constexpr auto kMaxSeqNum{63}; |
| |
| EnhancedControlField() : raw_value(0) {} |
| |
| bool designates_information_frame() const { |
| return !(le16toh(raw_value) & 0b1); |
| } |
| bool designates_supervisory_frame() const { return le16toh(raw_value) & 0x1; } |
| bool designates_start_of_segmented_sdu() const { |
| return designates_information_frame() && |
| ((le16toh(raw_value) & (0b11 << 14)) == (0b01 << 14)); |
| } |
| // Returns true for all segmented frames, including the start-of-segment frame |
| // (even though the start-of-segment frame has a different header format). |
| bool designates_part_of_segmented_sdu() const { |
| return designates_information_frame() && |
| (le16toh(raw_value) & (0b11 << 14)); |
| } |
| |
| void set_supervisory_frame() { |
| // See Vol 3, Part A, Table 3.2. |
| raw_value = htole16(le16toh(raw_value) | 0x1); |
| } |
| |
| uint8_t request_seq_num() const { |
| // See Vol 3, Part A, Table 3.2. |
| return (le16toh(raw_value) >> 8) & 0b11'1111; |
| } |
| |
| void set_request_seq_num(uint8_t seq_num) { |
| ZX_DEBUG_ASSERT(seq_num <= kMaxSeqNum); |
| // See Vol 3, Part A, Table 3.2. |
| raw_value = htole16(le16toh(raw_value) | (seq_num << 8)); |
| } |
| |
| void set_segmentation_status(SegmentationStatus status) { |
| // See Vol 3, Part A, Table 3.2. |
| raw_value = htole16((le16toh(raw_value) & 0b0011'1111'1111'1111) | |
| (static_cast<uint8_t>(status) << 14)); |
| } |
| |
| protected: |
| uint16_t raw_value; // In protocol byte-order (little-endian). |
| } __PACKED; |
| |
| // For Enhanced Retransmission and Streaming Modes _with_ Extended Window |
| // Size. (Vol 3, Part A, Secs 3.3.2 and 5.7. Feature 2/39.) |
| using ExtendedControlField = uint32_t; |
| |
| // Represents an I-frame header for: |
| // * a channel operating in Enhanced Retransmission or |
| // Streaming Mode, where |
| // * the Extended Window Size and Frame Checksum options are |
| // disabled, and |
| // * the frame is _not_ a "Start of L2CAP SDU" frame. |
| // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. |
| struct SimpleInformationFrameHeader : public EnhancedControlField { |
| explicit SimpleInformationFrameHeader(uint8_t tx_seq) { |
| ZX_DEBUG_ASSERT(tx_seq <= kMaxSeqNum); |
| raw_value = htole16(le16toh(raw_value) | (tx_seq << 1)); |
| } |
| |
| uint8_t tx_seq() const { |
| ZX_DEBUG_ASSERT(!designates_supervisory_frame()); |
| return (le16toh(raw_value) & (0b0111'1110)) >> 1; |
| } |
| } __PACKED; |
| |
| // Represents an I-frame header for: |
| // * a channel operating in Enhanced Retransmission or |
| // Streaming Mode, where |
| // * the Extended Window Size and Frame Checksum options are |
| // disabled, and |
| // * the frame _is_ a "Start of L2CAP SDU" frame. |
| // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. |
| struct SimpleStartOfSduFrameHeader : public SimpleInformationFrameHeader { |
| explicit SimpleStartOfSduFrameHeader(uint8_t tx_seq) |
| : SimpleInformationFrameHeader(tx_seq), sdu_len(0) { |
| set_segmentation_status(SegmentationStatus::FirstSegment); |
| } |
| uint16_t sdu_len; |
| } __PACKED; |
| |
| // See Vol 3, Part A, Table 3.5. |
| enum class SupervisoryFunction { |
| ReceiverReady = 0, |
| Reject = 1, |
| ReceiverNotReady = 2, |
| SelectiveReject = 3 |
| }; |
| |
| // Represents an S-frame for: |
| // * a channel operating in Enhanced Retransmission or |
| // Streaming Mode, where |
| // * the Extended Window Size and Frame Checksum options are |
| // disabled |
| // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. |
| struct SimpleSupervisoryFrame : public EnhancedControlField { |
| explicit SimpleSupervisoryFrame(SupervisoryFunction sfunc) { |
| ZX_DEBUG_ASSERT(sfunc <= SupervisoryFunction::SelectiveReject); |
| set_supervisory_frame(); |
| // See Vol 3, Part A, Table 3.2. |
| raw_value = |
| htole16(le16toh(raw_value) | (static_cast<uint8_t>(sfunc) << 2)); |
| } |
| |
| bool is_poll_request() const { |
| return le16toh(raw_value) & 0b1'0000; // See Vol 3, Part A, Table 3.2. |
| } |
| |
| bool is_poll_response() const { |
| // See Vol 3, Part A, Table 3.2. The spec calls this the 'final' bit. But |
| // poll response seems more intuitive. |
| return le16toh(raw_value) & 0b1000'0000; |
| } |
| |
| SupervisoryFunction function() const { |
| // See Vol 3, Part A, Table 3.2. |
| return static_cast<SupervisoryFunction>((le16toh(raw_value) >> 2) & 0b11); |
| } |
| |
| void set_is_poll_request() { |
| // See Vol 3, Part A, Table 3.2. |
| raw_value = htole16(le16toh(raw_value) | 0b1'0000); |
| } |
| |
| void set_is_poll_response() { |
| // See Vol 3, Part A, Table 3.2. The spec calls this the 'final' bit. But |
| // poll response seems more intuitive. |
| raw_value = htole16(le16toh(raw_value) | 0b1000'0000); |
| } |
| } __PACKED; |
| |
| struct SimpleReceiverReadyFrame : public SimpleSupervisoryFrame { |
| SimpleReceiverReadyFrame() |
| : SimpleSupervisoryFrame(SupervisoryFunction::ReceiverReady) {} |
| } __PACKED; |
| |
| } // namespace internal |
| } // namespace l2cap |
| } // namespace bt |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_L2CAP_INTERNAL_H_ |