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