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