• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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