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