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 #pragma once 16 17 #include <pw_bytes/endian.h> 18 19 #include <cstdint> 20 #include <type_traits> 21 22 #include "pw_bluetooth_sapphire/internal/host/common/assert.h" 23 24 namespace bt::l2cap::internal { 25 26 // The definitions within this namespace don't directly map to full frame 27 // formats. Rather, they provide access to mode-specific headers beyond the 28 // L2CAP basic frame header. 29 // 30 // The structs can be used in two ways: to parse inbound data, or to format 31 // outbound data. When used to parse inbound data, the structs due not provide 32 // any validation. When used to format outbound data, the structs initialize 33 // bits to 0, or (if appropriate) a value appropriate for that struct. 34 35 // For Retransmission and Flow Control Modes. (Vol 3, Part A, Sec 3.3.2) 36 using StandardControlField = uint16_t; 37 38 // See Vol 3, Part A, Sec 3.3.2, Table 3.4. 39 enum class SegmentationStatus { 40 Unsegmented = 0b00, 41 FirstSegment = 0b01, // AKA "Start of L2CAP SDU" 42 LastSegment = 0b10, // AKA "End of L2CAP SDU" 43 MiddleSegment = 0b11 // AKA "Continuation of L2CAP SDU" 44 }; 45 46 // For Enhanced Retransmission and Streaming Modes _without_ Extended Window 47 // Size. (Vol 3, Part A, Sec 3.3.2) 48 struct EnhancedControlField { 49 // See Core Spec v5, Vol 3, Part A, Sec 8.3. 50 static constexpr auto kMaxSeqNum{63}; 51 EnhancedControlFieldEnhancedControlField52 EnhancedControlField() : raw_value(0) {} 53 designates_information_frameEnhancedControlField54 bool designates_information_frame() const { 55 return !(pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 56 0b1); 57 } designates_supervisory_frameEnhancedControlField58 bool designates_supervisory_frame() const { 59 return pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 0x1; 60 } designates_start_of_segmented_sduEnhancedControlField61 bool designates_start_of_segmented_sdu() const { 62 return designates_information_frame() && 63 ((pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 64 (0b11 << 14)) == (0b01 << 14)); 65 } 66 // Returns true for all segmented frames, including the start-of-segment frame 67 // (even though the start-of-segment frame has a different header format). designates_part_of_segmented_sduEnhancedControlField68 bool designates_part_of_segmented_sdu() const { 69 return designates_information_frame() && 70 (pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 71 (0b11 << 14)); 72 } 73 set_supervisory_frameEnhancedControlField74 void set_supervisory_frame() { 75 // See Vol 3, Part A, Section 3.3.2, Table 3.2. 76 uint16_t host_val = 77 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 78 host_val |= 0x1; 79 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 80 } 81 receive_seq_numEnhancedControlField82 uint8_t receive_seq_num() const { 83 // "Receive Sequence Number - ReqSeq" Vol 3, Part A, Section 3.3.2, 84 // Table 3.2. 85 return (pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) >> 86 8) & 87 0b11'1111; 88 } 89 90 bool is_poll_response() const { 91 // See Vol 3, Part A, Sec 3.3.2, Table 3.2. The spec calls this the 'final' 92 // bit. But poll response seems more intuitive. 93 return pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 94 0b1000'0000; 95 } 96 set_receive_seq_numEnhancedControlField97 void set_receive_seq_num(uint8_t seq_num) { 98 PW_DCHECK(seq_num <= kMaxSeqNum); 99 // "Receive Sequence Number - ReqSeq" Vol 3, Part A, Section 3.3.2, 100 // Table 3.2. 101 uint16_t host_val = 102 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 103 host_val |= seq_num << 8; 104 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 105 } 106 set_is_poll_responseEnhancedControlField107 void set_is_poll_response() { 108 // See Vol 3, Part A, Sec 3.3.2, Table 3.2. The spec calls this the 'final' 109 // bit. But poll response seems more intuitive. 110 uint16_t host_val = 111 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 112 host_val |= 0b1000'0000; 113 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 114 } 115 116 void set_segmentation_status(SegmentationStatus status) { 117 // "Segmentation and Reassembly - SAR" Vol 3, Part A, Section 3.3.2, 118 // Table 3.4. 119 uint16_t host_val = 120 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 121 host_val &= 0b0011'1111'1111'1111; 122 host_val |= static_cast<uint8_t>(status) << 14; 123 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 124 } 125 126 protected: 127 uint16_t raw_value; // In protocol byte-order (little-endian). 128 } __attribute__((packed)); 129 130 // For Enhanced Retransmission and Streaming Modes _with_ Extended Window 131 // Size. (Vol 3, Part A, Secs 3.3.2 and 5.7. Feature 2/39.) 132 using ExtendedControlField = uint32_t; 133 134 // Represents an I-frame header for: 135 // * a channel operating in Enhanced Retransmission or 136 // Streaming Mode, where 137 // * the Extended Window Size and Frame Checksum options are 138 // disabled, and 139 // * the frame is _not_ a "Start of L2CAP SDU" frame. 140 // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. 141 struct SimpleInformationFrameHeader : public EnhancedControlField { 142 SimpleInformationFrameHeader() = default; 143 SimpleInformationFrameHeaderSimpleInformationFrameHeader144 explicit SimpleInformationFrameHeader(uint8_t tx_seq) { 145 PW_DCHECK(tx_seq <= kMaxSeqNum); 146 uint16_t host_val = 147 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 148 host_val |= (tx_seq << 1); 149 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 150 } 151 tx_seqSimpleInformationFrameHeader152 uint8_t tx_seq() const { 153 PW_DCHECK(!designates_supervisory_frame()); 154 return (pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 155 (0b0111'1110)) >> 156 1; 157 } 158 } __attribute__((packed)); 159 160 // Represents an I-frame header for: 161 // * a channel operating in Enhanced Retransmission or 162 // Streaming Mode, where 163 // * the Extended Window Size and Frame Checksum options are 164 // disabled, and 165 // * the frame _is_ a "Start of L2CAP SDU" frame. 166 // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. 167 struct SimpleStartOfSduFrameHeader : public SimpleInformationFrameHeader { 168 SimpleStartOfSduFrameHeader() = default; 169 170 explicit SimpleStartOfSduFrameHeader(uint8_t tx_seq) 171 : SimpleInformationFrameHeader(tx_seq), sdu_len(0) { 172 set_segmentation_status(SegmentationStatus::FirstSegment); 173 } 174 uint16_t sdu_len; 175 } __attribute__((packed)); 176 177 // See Vol 3, Part A, Sec 3.3.2, Table 3.5. 178 enum class SupervisoryFunction { 179 ReceiverReady = 0, 180 Reject = 1, 181 ReceiverNotReady = 2, 182 SelectiveReject = 3 183 }; 184 185 // Represents an S-frame for: 186 // * a channel operating in Enhanced Retransmission or 187 // Streaming Mode, where 188 // * the Extended Window Size and Frame Checksum options are 189 // disabled 190 // Omits the Basic L2CAP header. See Vol 3, Part A, Sec 3.3. 191 struct SimpleSupervisoryFrame : public EnhancedControlField { 192 SimpleSupervisoryFrame() = default; 193 194 explicit SimpleSupervisoryFrame(SupervisoryFunction sfunc) { 195 PW_DCHECK(sfunc <= SupervisoryFunction::SelectiveReject); 196 set_supervisory_frame(); 197 // See Vol 3, Part A, Sec 3.3.2, Table 3.2. 198 uint16_t host_val = 199 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 200 host_val |= static_cast<uint8_t>(sfunc) << 2; 201 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 202 } 203 204 bool is_poll_request() const { 205 return pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) & 206 0b1'0000; // See Vol 3, Part A, Sec 3.3.2, Table 3.2. 207 } 208 functionSimpleSupervisoryFrame209 SupervisoryFunction function() const { 210 // See Vol 3, Part A, Sec 3.3.2, Table 3.2. 211 return static_cast<SupervisoryFunction>( 212 (pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value) >> 2) & 213 0b11); 214 } 215 set_is_poll_requestSimpleSupervisoryFrame216 void set_is_poll_request() { 217 // See Vol 3, Part A, Sec 3.3.2, Table 3.2. 218 uint16_t host_val = 219 pw::bytes::ConvertOrderFrom(cpp20::endian::little, raw_value); 220 host_val |= 0b1'0000; 221 raw_value = pw::bytes::ConvertOrderTo(cpp20::endian::little, host_val); 222 } 223 } __attribute__((packed)); 224 225 struct SimpleReceiverReadyFrame : public SimpleSupervisoryFrame { 226 SimpleReceiverReadyFrame() 227 : SimpleSupervisoryFrame(SupervisoryFunction::ReceiverReady) {} 228 } __attribute__((packed)); 229 230 } // namespace bt::l2cap::internal 231