xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/public/pw_bluetooth_sapphire/internal/host/att/att.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 #include <cstddef>
17 #include <cstdint>
18 #include <type_traits>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
22 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
24 
25 namespace bt::att {
26 
27 // v5.0, Vol 3, Part G, 5.1.2
28 constexpr uint16_t kLEMinMTU = 23;
29 
30 // v5.0, Vol 3, Part G, 5.1.1
31 constexpr uint16_t kBREDRMinMTU = 48;
32 
33 constexpr uint16_t kLEMaxMTU =
34     hci_spec::kMaxLEExtendedDataLength - sizeof(l2cap::BasicHeader);
35 
36 // The maximum length of an attribute value (v5.0, Vol 3, Part F, 3.2.9).
37 constexpr size_t kMaxAttributeValueLength = 512;
38 
39 // The ATT protocol transaction timeout.
40 // (see v5.0, Vol 3, Part F, Section 3.3.3).
41 constexpr pw::chrono::SystemClock::duration kTransactionTimeout =
42     std::chrono::seconds(30);
43 
44 // A server identifies each attribute using a 16-bit handle.
45 using Handle = uint16_t;
46 
47 constexpr Handle kInvalidHandle = 0x0000;
48 constexpr Handle kHandleMin = 0x0001;
49 constexpr Handle kHandleMax = 0xFFFF;
50 
51 // We represent the read and write permissions of an attribute using separate
52 // bitfields.
53 // clang-format off
54 constexpr uint8_t kAttributePermissionBitAllowed                = (1 << 0);
55 constexpr uint8_t kAttributePermissionBitEncryptionRequired     = (1 << 1);
56 constexpr uint8_t kAttributePermissionBitAuthenticationRequired = (1 << 2);
57 constexpr uint8_t kAttributePermissionBitAuthorizationRequired  = (1 << 3);
58 // clang-format on
59 
60 // The opcode identifies the protocol method being invoked.
61 using OpCode = uint8_t;
62 
63 // The flag bits of an ATT opcode. Bits 0-5 identify the protocol method.
64 constexpr OpCode kAuthenticationSignatureFlag = (1 << 7);
65 constexpr OpCode kCommandFlag = (1 << 6);
66 
67 // The length of an authentication signature used in a signed PDU.
68 constexpr size_t kAuthenticationSignatureLength = 12;
69 
70 // The maximum number of write requests that can be queued for submission in a
71 // ATT Prepare Write Request.
72 constexpr uint8_t kPrepareQueueMaxCapacity = 20;
73 
74 enum class MethodType {
75   kInvalid,
76   kRequest,
77   kResponse,
78   kCommand,
79   kNotification,
80   kIndication,
81   kConfirmation,
82 };
83 
84 struct Header {
85   OpCode opcode;
86 } __attribute__((packed));
87 
88 enum class ErrorCode : uint8_t {
89   kInvalidHandle = 0x01,
90   kReadNotPermitted = 0x02,
91   kWriteNotPermitted = 0x03,
92   kInvalidPDU = 0x04,
93   kInsufficientAuthentication = 0x05,
94   kRequestNotSupported = 0x06,
95   kInvalidOffset = 0x07,
96   kInsufficientAuthorization = 0x08,
97   kPrepareQueueFull = 0x09,
98   kAttributeNotFound = 0x0A,
99   kAttributeNotLong = 0x0B,
100   kInsufficientEncryptionKeySize = 0x0C,
101   kInvalidAttributeValueLength = 0x0D,
102   kUnlikelyError = 0x0E,
103   kInsufficientEncryption = 0x0F,
104   kUnsupportedGroupType = 0x10,
105   kInsufficientResources = 0x11,
106   kValueNotAllowed = 0x13,
107 };
108 
109 // Many ATT protocol PDUs allow using both a 16-bit and a 128-bit representation
110 // for the attribute type (which is a Bluetooth UUID).
111 //
112 // The assigned values can be used in a Find Information Response.
113 enum class UUIDType : uint8_t {
114   k16Bit = 0x01,
115   k128Bit = 0x02,
116 };
117 
118 template <UUIDType Type>
119 using AttributeType = typename std::
120     conditional<Type == UUIDType::k16Bit, uint16_t, UInt128>::type;
121 
122 using AttributeType16 = AttributeType<UUIDType::k16Bit>;
123 using AttributeType128 = AttributeType<UUIDType::k128Bit>;
124 
125 enum class ExecuteWriteFlag : uint8_t {
126   kCancelAll = 0x00,
127   kWritePending = 0x01,
128 };
129 
130 PW_MODIFY_DIAGNOSTICS_PUSH();
131 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
132 struct AttributeData {
133   AttributeData() = default;
134   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(AttributeData);
135 
136   Handle handle;
137   uint8_t value[];
138 } __attribute__((packed));
139 PW_MODIFY_DIAGNOSTICS_POP();
140 
141 // ============== ATT PDUs ==============
142 constexpr OpCode kInvalidOpCode = 0x00;
143 
144 // ==============
145 // Error Handling
146 constexpr OpCode kErrorResponse = 0x01;
147 struct ErrorResponseParams {
148   OpCode request_opcode;
149   Handle attribute_handle;
150   ErrorCode error_code;
151 } __attribute__((packed));
152 
153 // ============
154 // MTU Exchange
155 constexpr OpCode kExchangeMTURequest = 0x02;
156 constexpr OpCode kExchangeMTUResponse = 0x03;
157 
158 struct ExchangeMTURequestParams {
159   uint16_t client_rx_mtu;
160 } __attribute__((packed));
161 
162 struct ExchangeMTUResponseParams {
163   uint16_t server_rx_mtu;
164 } __attribute__((packed));
165 
166 // ================
167 // Find Information
168 constexpr OpCode kFindInformationRequest = 0x04;
169 constexpr OpCode kFindInformationResponse = 0x05;
170 
171 struct FindInformationRequestParams {
172   Handle start_handle;
173   Handle end_handle;
174 } __attribute__((packed));
175 
176 struct FindInformationResponseParams {
177   UUIDType format;
178 
179   // The type of the next member depends on the type of |format|.
180   // If type == InformationDataFormat::kUUID16:
181   // InformationData16 information_data[];
182   //
183   // If type == InformationDataFormat::kUUID28:
184   // InformationData128 information_data[];
185 } __attribute__((packed));
186 
187 template <UUIDType Format>
188 struct InformationData {
189   Handle handle;
190   AttributeType<Format> uuid;
191 } __attribute__((packed));
192 
193 using InformationData16 = InformationData<UUIDType::k16Bit>;
194 using InformationData128 = InformationData<UUIDType::k128Bit>;
195 
196 // ==================
197 // Find By Type Value
198 constexpr OpCode kFindByTypeValueRequest = 0x06;
199 constexpr OpCode kFindByTypeValueResponse = 0x07;
200 
201 PW_MODIFY_DIAGNOSTICS_PUSH();
202 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
203 struct FindByTypeValueRequestParams {
204   FindByTypeValueRequestParams() = default;
205   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(FindByTypeValueRequestParams);
206 
207   Handle start_handle;
208   Handle end_handle;
209   AttributeType16 type;
210   uint8_t value[];
211 } __attribute__((packed));
212 PW_MODIFY_DIAGNOSTICS_POP();
213 
214 struct HandlesInformationList {
215   Handle handle;
216   Handle group_end_handle;
217 } __attribute__((packed));
218 
219 struct FindByTypeValueResponseParams {
220   // Contains at least 1 entry
221   HandlesInformationList handles_information_list[1];
222 } __attribute__((packed));
223 
224 // ============
225 // Read By Type
226 constexpr OpCode kReadByTypeRequest = 0x08;
227 constexpr OpCode kReadByTypeResponse = 0x09;
228 
229 // (see Vol 3, Part F, 3.4.4.2)
230 constexpr uint8_t kMaxReadByTypeValueLength = 253;
231 
232 template <UUIDType Format>
233 struct ReadByTypeRequestParams {
234   Handle start_handle;
235   Handle end_handle;
236   AttributeType<Format> type;
237 } __attribute__((packed));
238 
239 using ReadByTypeRequestParams16 = ReadByTypeRequestParams<UUIDType::k16Bit>;
240 using ReadByTypeRequestParams128 = ReadByTypeRequestParams<UUIDType::k128Bit>;
241 
242 PW_MODIFY_DIAGNOSTICS_PUSH();
243 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
244 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wflexible-array-extensions");
245 struct ReadByTypeResponseParams {
246   ReadByTypeResponseParams() = default;
247   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(ReadByTypeResponseParams);
248 
249   uint8_t length;
250   AttributeData attribute_data_list[];
251 } __attribute__((packed));
252 PW_MODIFY_DIAGNOSTICS_POP();
253 
254 // ====
255 // Read
256 constexpr OpCode kReadRequest = 0x0A;
257 constexpr OpCode kReadResponse = 0x0B;
258 
259 struct ReadRequestParams {
260   Handle handle;
261 } __attribute__((packed));
262 
263 // The Read Response PDU contains the attribute value requested.
264 
265 // =========
266 // Read Blob
267 constexpr OpCode kReadBlobRequest = 0x0C;
268 constexpr OpCode kReadBlobResponse = 0x0D;
269 
270 struct ReadBlobRequestParams {
271   Handle handle;
272   uint16_t offset;
273 } __attribute__((packed));
274 
275 // The Read Blob Response PDU contains the partial attribute value requested.
276 
277 // =============
278 // Read Multiple
279 constexpr OpCode kReadMultipleRequest = 0x0E;
280 constexpr OpCode kReadMultipleResponse = 0x0F;
281 
282 // The Read Multiple Request PDU contains 2 or more attribute handles.
283 // The Read Multiple Response PDU contains attribute values concatenated in the
284 // order requested.
285 
286 // ==================
287 // Read By Group Type
288 constexpr OpCode kReadByGroupTypeRequest = 0x10;
289 constexpr OpCode kReadByGroupTypeResponse = 0x11;
290 
291 // (see Vol 3, Part F, 3.4.4.10)
292 constexpr uint8_t kMaxReadByGroupTypeValueLength = 251;
293 
294 // The Read By Group Type and Read By Type requests use identical payloads.
295 using ReadByGroupTypeRequestParams16 = ReadByTypeRequestParams16;
296 using ReadByGroupTypeRequestParams128 = ReadByTypeRequestParams128;
297 
298 PW_MODIFY_DIAGNOSTICS_PUSH();
299 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
300 struct AttributeGroupDataEntry {
301   AttributeGroupDataEntry() = default;
302   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(AttributeGroupDataEntry);
303 
304   Handle start_handle;
305   Handle group_end_handle;
306   uint8_t value[];
307 } __attribute__((packed));
308 PW_MODIFY_DIAGNOSTICS_POP();
309 
310 PW_MODIFY_DIAGNOSTICS_PUSH();
311 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
312 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wflexible-array-extensions");
313 struct ReadByGroupTypeResponseParams {
314   ReadByGroupTypeResponseParams() = default;
315   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(ReadByGroupTypeResponseParams);
316 
317   uint8_t length;
318   AttributeGroupDataEntry attribute_data_list[];
319 } __attribute__((packed));
320 PW_MODIFY_DIAGNOSTICS_POP();
321 
322 // =====
323 // Write
324 constexpr OpCode kWriteRequest = 0x12;
325 constexpr OpCode kWriteCommand = 0x52;
326 constexpr OpCode kSignedWriteCommand = 0xD2;
327 constexpr OpCode kWriteResponse = 0x13;
328 
329 using WriteRequestParams = AttributeData;
330 
331 // =============
332 // Prepare Write
333 constexpr OpCode kPrepareWriteRequest = 0x16;
334 constexpr OpCode kPrepareWriteResponse = 0x17;
335 
336 PW_MODIFY_DIAGNOSTICS_PUSH();
337 PW_MODIFY_DIAGNOSTIC_CLANG(ignored, "-Wc99-extensions");
338 struct PrepareWriteRequestParams {
339   PrepareWriteRequestParams() = default;
340   BT_DISALLOW_COPY_ASSIGN_AND_MOVE(PrepareWriteRequestParams);
341 
342   Handle handle;
343   uint16_t offset;
344   uint8_t part_value[];
345 } __attribute__((packed));
346 PW_MODIFY_DIAGNOSTICS_POP();
347 
348 using PrepareWriteResponseParams = PrepareWriteRequestParams;
349 
350 // =============
351 // Execute Write
352 constexpr OpCode kExecuteWriteRequest = 0x18;
353 constexpr OpCode kExecuteWriteResponse = 0x19;
354 
355 struct ExecuteWriteRequestParams {
356   ExecuteWriteFlag flags;
357 } __attribute__((packed));
358 
359 // =========================
360 // Handle Value Notification
361 constexpr OpCode kNotification = 0x1B;
362 using NotificationParams = AttributeData;
363 
364 // =========================
365 // Handle Value Indication
366 constexpr OpCode kIndication = 0x1D;
367 constexpr OpCode kConfirmation = 0x1E;
368 using IndicationParams = NotificationParams;
369 
370 }  // namespace bt::att
371