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 #pragma clang diagnostic ignored "-Wc99-extensions" 26 #pragma clang diagnostic ignored "-Wflexible-array-extensions" 27 28 namespace bt::att { 29 30 // v5.0, Vol 3, Part G, 5.1.2 31 constexpr uint16_t kLEMinMTU = 23; 32 33 // v5.0, Vol 3, Part G, 5.1.1 34 constexpr uint16_t kBREDRMinMTU = 48; 35 36 constexpr uint16_t kLEMaxMTU = 37 hci_spec::kMaxLEExtendedDataLength - sizeof(l2cap::BasicHeader); 38 39 // The maximum length of an attribute value (v5.0, Vol 3, Part F, 3.2.9). 40 constexpr size_t kMaxAttributeValueLength = 512; 41 42 // The ATT protocol transaction timeout. 43 // (see v5.0, Vol 3, Part F, Section 3.3.3). 44 constexpr pw::chrono::SystemClock::duration kTransactionTimeout = 45 std::chrono::seconds(30); 46 47 // A server identifies each attribute using a 16-bit handle. 48 using Handle = uint16_t; 49 50 constexpr Handle kInvalidHandle = 0x0000; 51 constexpr Handle kHandleMin = 0x0001; 52 constexpr Handle kHandleMax = 0xFFFF; 53 54 // We represent the read and write permissions of an attribute using separate 55 // bitfields. 56 // clang-format off 57 constexpr uint8_t kAttributePermissionBitAllowed = (1 << 0); 58 constexpr uint8_t kAttributePermissionBitEncryptionRequired = (1 << 1); 59 constexpr uint8_t kAttributePermissionBitAuthenticationRequired = (1 << 2); 60 constexpr uint8_t kAttributePermissionBitAuthorizationRequired = (1 << 3); 61 // clang-format on 62 63 // The opcode identifies the protocol method being invoked. 64 using OpCode = uint8_t; 65 66 // The flag bits of an ATT opcode. Bits 0-5 identify the protocol method. 67 constexpr OpCode kAuthenticationSignatureFlag = (1 << 7); 68 constexpr OpCode kCommandFlag = (1 << 6); 69 70 // The length of an authentication signature used in a signed PDU. 71 constexpr size_t kAuthenticationSignatureLength = 12; 72 73 // The maximum number of write requests that can be queued for submission in a 74 // ATT Prepare Write Request. 75 constexpr uint8_t kPrepareQueueMaxCapacity = 20; 76 77 enum class MethodType { 78 kInvalid, 79 kRequest, 80 kResponse, 81 kCommand, 82 kNotification, 83 kIndication, 84 kConfirmation, 85 }; 86 87 struct Header { 88 OpCode opcode; 89 } __attribute__((packed)); 90 91 enum class ErrorCode : uint8_t { 92 kInvalidHandle = 0x01, 93 kReadNotPermitted = 0x02, 94 kWriteNotPermitted = 0x03, 95 kInvalidPDU = 0x04, 96 kInsufficientAuthentication = 0x05, 97 kRequestNotSupported = 0x06, 98 kInvalidOffset = 0x07, 99 kInsufficientAuthorization = 0x08, 100 kPrepareQueueFull = 0x09, 101 kAttributeNotFound = 0x0A, 102 kAttributeNotLong = 0x0B, 103 kInsufficientEncryptionKeySize = 0x0C, 104 kInvalidAttributeValueLength = 0x0D, 105 kUnlikelyError = 0x0E, 106 kInsufficientEncryption = 0x0F, 107 kUnsupportedGroupType = 0x10, 108 kInsufficientResources = 0x11, 109 kValueNotAllowed = 0x13, 110 }; 111 112 // Many ATT protocol PDUs allow using both a 16-bit and a 128-bit representation 113 // for the attribute type (which is a Bluetooth UUID). 114 // 115 // The assigned values can be used in a Find Information Response. 116 enum class UUIDType : uint8_t { 117 k16Bit = 0x01, 118 k128Bit = 0x02, 119 }; 120 121 template <UUIDType Type> 122 using AttributeType = typename std:: 123 conditional<Type == UUIDType::k16Bit, uint16_t, UInt128>::type; 124 125 using AttributeType16 = AttributeType<UUIDType::k16Bit>; 126 using AttributeType128 = AttributeType<UUIDType::k128Bit>; 127 128 enum class ExecuteWriteFlag : uint8_t { 129 kCancelAll = 0x00, 130 kWritePending = 0x01, 131 }; 132 133 struct AttributeData { 134 AttributeData() = default; 135 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(AttributeData); 136 137 Handle handle; 138 uint8_t value[]; 139 } __attribute__((packed)); 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 struct FindByTypeValueRequestParams { 202 FindByTypeValueRequestParams() = default; 203 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(FindByTypeValueRequestParams); 204 205 Handle start_handle; 206 Handle end_handle; 207 AttributeType16 type; 208 uint8_t value[]; 209 } __attribute__((packed)); 210 211 struct HandlesInformationList { 212 Handle handle; 213 Handle group_end_handle; 214 } __attribute__((packed)); 215 216 struct FindByTypeValueResponseParams { 217 // Contains at least 1 entry 218 HandlesInformationList handles_information_list[1]; 219 } __attribute__((packed)); 220 221 // ============ 222 // Read By Type 223 constexpr OpCode kReadByTypeRequest = 0x08; 224 constexpr OpCode kReadByTypeResponse = 0x09; 225 226 // (see Vol 3, Part F, 3.4.4.2) 227 constexpr uint8_t kMaxReadByTypeValueLength = 253; 228 229 template <UUIDType Format> 230 struct ReadByTypeRequestParams { 231 Handle start_handle; 232 Handle end_handle; 233 AttributeType<Format> type; 234 } __attribute__((packed)); 235 236 using ReadByTypeRequestParams16 = ReadByTypeRequestParams<UUIDType::k16Bit>; 237 using ReadByTypeRequestParams128 = ReadByTypeRequestParams<UUIDType::k128Bit>; 238 239 struct ReadByTypeResponseParams { 240 ReadByTypeResponseParams() = default; 241 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(ReadByTypeResponseParams); 242 243 uint8_t length; 244 AttributeData attribute_data_list[]; 245 } __attribute__((packed)); 246 247 // ==== 248 // Read 249 constexpr OpCode kReadRequest = 0x0A; 250 constexpr OpCode kReadResponse = 0x0B; 251 252 struct ReadRequestParams { 253 Handle handle; 254 } __attribute__((packed)); 255 256 // The Read Response PDU contains the attribute value requested. 257 258 // ========= 259 // Read Blob 260 constexpr OpCode kReadBlobRequest = 0x0C; 261 constexpr OpCode kReadBlobResponse = 0x0D; 262 263 struct ReadBlobRequestParams { 264 Handle handle; 265 uint16_t offset; 266 } __attribute__((packed)); 267 268 // The Read Blob Response PDU contains the partial attribute value requested. 269 270 // ============= 271 // Read Multiple 272 constexpr OpCode kReadMultipleRequest = 0x0E; 273 constexpr OpCode kReadMultipleResponse = 0x0F; 274 275 // The Read Multiple Request PDU contains 2 or more attribute handles. 276 // The Read Multiple Response PDU contains attribute values concatenated in the 277 // order requested. 278 279 // ================== 280 // Read By Group Type 281 constexpr OpCode kReadByGroupTypeRequest = 0x10; 282 constexpr OpCode kReadByGroupTypeResponse = 0x11; 283 284 // (see Vol 3, Part F, 3.4.4.10) 285 constexpr uint8_t kMaxReadByGroupTypeValueLength = 251; 286 287 // The Read By Group Type and Read By Type requests use identical payloads. 288 using ReadByGroupTypeRequestParams16 = ReadByTypeRequestParams16; 289 using ReadByGroupTypeRequestParams128 = ReadByTypeRequestParams128; 290 291 struct AttributeGroupDataEntry { 292 AttributeGroupDataEntry() = default; 293 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(AttributeGroupDataEntry); 294 295 Handle start_handle; 296 Handle group_end_handle; 297 uint8_t value[]; 298 } __attribute__((packed)); 299 300 struct ReadByGroupTypeResponseParams { 301 ReadByGroupTypeResponseParams() = default; 302 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(ReadByGroupTypeResponseParams); 303 304 uint8_t length; 305 AttributeGroupDataEntry attribute_data_list[]; 306 } __attribute__((packed)); 307 308 // ===== 309 // Write 310 constexpr OpCode kWriteRequest = 0x12; 311 constexpr OpCode kWriteCommand = 0x52; 312 constexpr OpCode kSignedWriteCommand = 0xD2; 313 constexpr OpCode kWriteResponse = 0x13; 314 315 using WriteRequestParams = AttributeData; 316 317 // ============= 318 // Prepare Write 319 constexpr OpCode kPrepareWriteRequest = 0x16; 320 constexpr OpCode kPrepareWriteResponse = 0x17; 321 322 struct PrepareWriteRequestParams { 323 PrepareWriteRequestParams() = default; 324 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(PrepareWriteRequestParams); 325 326 Handle handle; 327 uint16_t offset; 328 uint8_t part_value[]; 329 } __attribute__((packed)); 330 331 using PrepareWriteResponseParams = PrepareWriteRequestParams; 332 333 // ============= 334 // Execute Write 335 constexpr OpCode kExecuteWriteRequest = 0x18; 336 constexpr OpCode kExecuteWriteResponse = 0x19; 337 338 struct ExecuteWriteRequestParams { 339 ExecuteWriteFlag flags; 340 } __attribute__((packed)); 341 342 // ========================= 343 // Handle Value Notification 344 constexpr OpCode kNotification = 0x1B; 345 using NotificationParams = AttributeData; 346 347 // ========================= 348 // Handle Value Indication 349 constexpr OpCode kIndication = 0x1D; 350 constexpr OpCode kConfirmation = 0x1E; 351 using IndicationParams = NotificationParams; 352 353 } // namespace bt::att 354