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 <lib/fit/result.h> 17 #include <pw_assert/check.h> 18 19 #include "pw_bluetooth_sapphire/internal/host/common/error.h" 20 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h" 21 22 namespace bt::sdp { 23 24 inline constexpr uint64_t kInvalidContState = 0xFFFFFFFF; 25 26 // Maximum length of continuation information is 16 bytes, and the InfoLength 27 // is one byte. See v5.0, Vol 3, Part B, Sec 4.3 28 inline constexpr size_t kMaxContStateLength = 17; 29 30 // Minimum length allowed by the Maximum Attribute Byte Count in 31 // ServiceAttribute and ServiceSearchAttribute requests 32 inline constexpr size_t kMinMaximumAttributeByteCount = 0x0007; 33 34 // Selected to be larger than FIDL limit of 512. Prevent poor performance in 35 // worst case scenarios. Clients should use larger ranges if they need anywhere 36 // near this number of attributes. 37 inline constexpr size_t kMaxAttributeRangesInRequest = 520; 38 39 class Request { 40 public: 41 Request(); 42 virtual ~Request() = default; 43 44 // Returns true if the request is valid. 45 virtual bool valid() const = 0; 46 47 // Gets a buffer containing the PDU representation of this request. 48 // Returns nullptr if the request is not valid. 49 virtual ByteBufferPtr GetPDU(TransactionId tid) const = 0; 50 51 // Returns a view with the current continuation state. 52 // In a response packet with more than one packet, this contains the most 53 // recent continuation state (so it can be read to request a continuation). ContinuationState()54 const BufferView ContinuationState() const { 55 return cont_state_.view(1, cont_info_size()); 56 } 57 58 // Sets the continuation state for this request. 59 void SetContinuationState(const ByteBuffer& buf); 60 61 protected: 62 // Parses the continuation state portion of a packet, which is in |buf|. 63 // Returns true if the parsing succeeded. 64 bool ParseContinuationState(const ByteBuffer& buf); 65 66 // Writes the continuation state to |buf|, which must have at least 67 // cont_info_size() + 1 bytes available. 68 size_t WriteContinuationState(MutableByteBuffer* buf) const; 69 cont_info_size()70 uint8_t cont_info_size() const { return cont_state_.data()[0]; } 71 72 private: 73 // Continuation information, including the length. 74 StaticByteBuffer<kMaxContStateLength> cont_state_; 75 }; 76 77 // SDP Response objects are used in two places: 78 // - to construct a response for returning from a request on the server 79 // - to receive responses from a server as a client, possibly building from 80 // multiple response PDUs 81 class Response { 82 public: 83 virtual ~Response() = default; 84 85 // Returns true if these parameters represent a complete response. 86 virtual bool complete() const = 0; 87 88 // Returns the continuation state from a partial response, used to 89 // make an additional request. Returns an empty view if this packet 90 // is complete. 91 virtual const BufferView ContinuationState() const = 0; 92 93 // Parses parameters from a PDU response, storing a partial result if 94 // necessary. 95 // Returns a success status if the parameters could ba parsed, or a status 96 // containing: 97 // - kNotReady if this response is already complete. 98 // - kPacketMalformed: if the parameters couldn't be parsed. 99 // - kOutOfMemory: if memory isn't available to store a partial response. 100 virtual fit::result<Error<>> Parse(const ByteBuffer& buf) = 0; 101 102 // Returns a buffer containing the PDU representation of this response, 103 // including the header, which will have the transaction id |tid|. 104 // |req_max| will control the maximum size of the parameters based on the 105 // transaction type: 106 // - for ServiceSearchResponse, this should be the maximum records requested 107 // to be included from the ServiceSearchRequest 108 // - for ServiceAttributeResponse or ServiceSearchAttributeResponse, this 109 // is the MaximumAttributeByteCount from the request 110 // |max_size| is the maximum size of a PDU generated by this method. 111 // The buffer parameters will contain continuation state if it does not 112 // contain the end of the response. If that continuation state is passed to 113 // this function with the same |req_max| argument it will produce the next 114 // section of response. 115 virtual MutableByteBufferPtr GetPDU(uint16_t req_max, 116 TransactionId tid, 117 uint16_t max_size, 118 const ByteBuffer& cont_state) const = 0; 119 }; 120 121 // Error Response PDU, generated when the SDP server can't respond to a PDU 122 // because it is malformed or for another reason. 123 // See v5.0, Vol 3, Part B, 4.4.1 124 class ErrorResponse : public Response { 125 public: 126 ErrorResponse(std::optional<ErrorCode> code = std::nullopt) error_code_(code)127 : error_code_(code) {} 128 // Response overrides. complete()129 bool complete() const override { return error_code_.has_value(); } 130 ContinuationState()131 const BufferView ContinuationState() const override { 132 // ErrorResponses never have continuation state. 133 return BufferView(); 134 } 135 136 fit::result<Error<>> Parse(const ByteBuffer& buf) override; 137 138 // Note: |max_size| and |cont_state| are ignored. 139 // Error Responses do not have a valid continuation. 140 MutableByteBufferPtr GetPDU(uint16_t req_max, 141 TransactionId tid, 142 uint16_t max_size, 143 const ByteBuffer& cont_state) const override; 144 error_code()145 const std::optional<ErrorCode>& error_code() const { return error_code_; } set_error_code(ErrorCode code)146 void set_error_code(ErrorCode code) { error_code_ = code; } 147 148 private: 149 std::optional<ErrorCode> error_code_; 150 }; 151 152 // Used to locate service records that match a pattern. 153 // Note: there is no mechanism to retrieve all service records. 154 // See v5.0, Vol 3, Part B, 4.5.1 155 class ServiceSearchRequest : public Request { 156 public: 157 // Create an empty search request. 158 ServiceSearchRequest(); 159 // Parse the parameters given in |params| to initialize this request. 160 explicit ServiceSearchRequest(const ByteBuffer& params); 161 162 // Request overrides 163 bool valid() const override; 164 ByteBufferPtr GetPDU(TransactionId tid) const override; 165 166 // A service search pattern matches if every UUID in the pattern is contained 167 // within one of the services' attribute values. They don't need to be in any 168 // specific attribute or in any particular order, and extraneous UUIDs are 169 // allowed to exist in the attribute value. 170 // See v5.0, Volume 3, Part B, Sec 2.5.2 set_search_pattern(std::unordered_set<UUID> pattern)171 void set_search_pattern(std::unordered_set<UUID> pattern) { 172 service_search_pattern_ = pattern; 173 } service_search_pattern()174 const std::unordered_set<UUID>& service_search_pattern() const { 175 return service_search_pattern_; 176 } 177 178 // The maximum count of records that should be included in any 179 // response. set_max_service_record_count(uint16_t count)180 void set_max_service_record_count(uint16_t count) { 181 max_service_record_count_ = count; 182 } max_service_record_count()183 uint16_t max_service_record_count() const { 184 return max_service_record_count_; 185 } 186 187 private: 188 std::unordered_set<UUID> service_search_pattern_; 189 uint16_t max_service_record_count_; 190 }; 191 192 // Generated by the SDP server in response to a ServiceSearchRequest. 193 // See v5.0, Volume 3, Part B, Sec 4.5.2 194 class ServiceSearchResponse : public Response { 195 public: 196 ServiceSearchResponse(); 197 198 // Response overrides 199 bool complete() const override; 200 const BufferView ContinuationState() const override; 201 fit::result<Error<>> Parse(const ByteBuffer& buf) override; 202 MutableByteBufferPtr GetPDU(uint16_t req_max, 203 TransactionId tid, 204 uint16_t max_size, 205 const ByteBuffer& cont_state) const override; 206 207 // The ServiceRecordHandleList contains as list of service record handles. 208 // This should be set to the list of handles that match the request. 209 // Limiting the response to the maximum requested is handled by 210 // GetPDU(); set_service_record_handle_list(std::vector<ServiceHandle> handles)211 void set_service_record_handle_list(std::vector<ServiceHandle> handles) { 212 service_record_handle_list_ = handles; 213 total_service_record_count_ = static_cast<uint16_t>(handles.size()); 214 } service_record_handle_list()215 std::vector<ServiceHandle> service_record_handle_list() const { 216 return service_record_handle_list_; 217 } 218 219 private: 220 // The list of service record handles. 221 std::vector<ServiceHandle> service_record_handle_list_; 222 // The total number of service records in the full response. 223 uint16_t total_service_record_count_; 224 225 MutableByteBufferPtr continuation_state_; 226 }; 227 228 // Represents a range of attributes, inclusive of |start| and |end|. 229 struct AttributeRange { AttributeRangeAttributeRange230 AttributeRange(AttributeId attribute_range_start, 231 AttributeId attribute_range_end) 232 : start(attribute_range_start), end(attribute_range_end) { 233 PW_DCHECK(start <= end); 234 } 235 236 AttributeId start; 237 AttributeId end; 238 }; 239 240 // Used to retrieve a set of attributes from a specific service record. 241 // See v5.0, Volume 3, Part B, Sec 4.6.1 242 class ServiceAttributeRequest : public Request { 243 public: 244 // Create an empty search request. 245 ServiceAttributeRequest(); 246 // Parse the parameters in |params| to initialize this request. 247 // valid() will be false if |params| don't represent valid a valid request. 248 explicit ServiceAttributeRequest(const ByteBuffer& params); 249 250 // Request overrides 251 bool valid() const override; 252 ByteBufferPtr GetPDU(TransactionId tid) const override; 253 set_service_record_handle(ServiceHandle handle)254 void set_service_record_handle(ServiceHandle handle) { 255 service_record_handle_ = handle; 256 } service_record_handle()257 ServiceHandle service_record_handle() const { return service_record_handle_; } 258 259 // Set the maximum size allowed in the response in the Attribute list 260 // Not allowed to be lower than kMinMaximumAttributeByteCount (7) set_max_attribute_byte_count(uint16_t count)261 void set_max_attribute_byte_count(uint16_t count) { 262 PW_DCHECK(count >= kMinMaximumAttributeByteCount); 263 max_attribute_byte_count_ = count; 264 } max_attribute_byte_count()265 uint16_t max_attribute_byte_count() const { 266 return max_attribute_byte_count_; 267 } 268 269 // Adds a single attribute to the requested IDs. Used to ensure a specific 270 // attribute is requested. 271 // Automatically merges attribute ranges that are contiguous to save bytes in 272 // the request. 273 void AddAttribute(AttributeId id); 274 275 // Adds a range of attributes to the requested IDs. 276 // Like AddAttribute(), attribute ranges that are contiguous are merged to 277 // save bytes in the resulting request. 278 void AddAttributeRange(AttributeId start, AttributeId end); 279 attribute_ranges()280 const std::list<AttributeRange>& attribute_ranges() { 281 return attribute_ranges_; 282 } 283 284 private: 285 // The service record handle for which attributes should be retrieved. 286 // Should be obtained by using a ServiceSearch transaction. 287 ServiceHandle service_record_handle_; 288 289 // Maximum number of bytes of attribute data to be returned in the response. 290 // If the attributes don't fit, the server decides how to segment them. 291 // Clients should use continuation state to request more data. 292 uint16_t max_attribute_byte_count_; 293 294 // The attribute(s) to retrieve. 295 // This is a list of ranges, inclusive of the ends. 296 // They are non-overlapping and sorted by the start id of each range. 297 std::list<AttributeRange> attribute_ranges_; 298 }; 299 300 // Generated upon receiving a ServiceAttributeRequest. 301 // See v5.0, Volume 3, Part B, Sec 4.6.2 302 class ServiceAttributeResponse : public Response { 303 public: 304 ServiceAttributeResponse(); 305 306 // Response overrides 307 const BufferView ContinuationState() const override; 308 bool complete() const override; 309 fit::result<Error<>> Parse(const ByteBuffer& buf) override; 310 MutableByteBufferPtr GetPDU(uint16_t req_max, 311 TransactionId tid, 312 uint16_t max_size, 313 const ByteBuffer& cont_state) const override; 314 set_attribute(AttributeId id,DataElement value)315 void set_attribute(AttributeId id, DataElement value) { 316 attributes_.emplace(id, std::move(value)); 317 } attributes()318 const std::map<AttributeId, DataElement>& attributes() const { 319 return attributes_; 320 } 321 322 private: 323 // The list of attributes that matched the search and their values. 324 // This is sorted (it is in ascending order in the response). 325 std::map<AttributeId, DataElement> attributes_; 326 327 // Attribute List(s) can be truncated due to: 328 // - Response too long for MTU 329 // - MaxAttributeListByteCount is set too low 330 // - Because the server wants to 331 // 332 // This contains the partial attribute list response if there is continuation 333 // state. 334 MutableByteBufferPtr partial_response_; 335 336 MutableByteBufferPtr continuation_state_; 337 }; 338 339 // Combines the capabilities of ServiceSearchRequest and ServiceAttributeRequest 340 // Note that the record handle is not included in the response by default, and 341 // myst be requested if needed. 342 // See v5.0, Volume 3, Part B,Sec 4.7.1 343 class ServiceSearchAttributeRequest : public Request { 344 public: 345 // Create an empty service search attribute request. 346 ServiceSearchAttributeRequest(); 347 // Parse the parameters in |params| to initialize this request. 348 explicit ServiceSearchAttributeRequest(const ByteBuffer& params); 349 350 // Request overrides 351 bool valid() const override; 352 ByteBufferPtr GetPDU(TransactionId tid) const override; 353 354 // A service search pattern matches if every UUID in the pattern is contained 355 // within one of the services' attribute values. They don't need to be in any 356 // specific attribute or in any particular order, and extraneous UUIDs are 357 // allowed to exist in the attribute value. 358 // See v5.0, Volume 3, Part B, Sec 2.5.2. set_search_pattern(std::unordered_set<UUID> pattern)359 void set_search_pattern(std::unordered_set<UUID> pattern) { 360 service_search_pattern_ = pattern; 361 } service_search_pattern()362 const std::unordered_set<UUID>& service_search_pattern() const { 363 return service_search_pattern_; 364 } 365 366 // Set the maximum size allowed in the response in the Attribute list 367 // Not allowed to be lower than kMinMaximumAttributeByteCount (7) set_max_attribute_byte_count(uint16_t count)368 void set_max_attribute_byte_count(uint16_t count) { 369 PW_DCHECK(count >= kMinMaximumAttributeByteCount); 370 max_attribute_byte_count_ = count; 371 } max_attribute_byte_count()372 uint16_t max_attribute_byte_count() const { 373 return max_attribute_byte_count_; 374 } 375 376 // Adds a single attribute to the requested IDs 377 void AddAttribute(AttributeId id); 378 379 // Adds a range of attributes to the requested IDs. 380 void AddAttributeRange(AttributeId start, AttributeId end); 381 attribute_ranges()382 const std::list<AttributeRange>& attribute_ranges() { 383 return attribute_ranges_; 384 } 385 386 private: 387 // The service search pattern to match services. 388 std::unordered_set<UUID> service_search_pattern_; 389 390 // Maximum number of bytes of attribute data to be returned in the response. 391 // If the attributes don't fit, the server decides how to segment them. 392 // Clients should use continuation state to request more data. 393 uint16_t max_attribute_byte_count_; 394 395 // The attribute(s) to retrieve. 396 // This is a list of ranges, inclusive of the ends. 397 // They are non-overlapping and sorted by the first attribute id. 398 std::list<AttributeRange> attribute_ranges_; 399 }; 400 401 // Generated in response to a ServiceSearchAttributeRequest 402 // See v5.0, Volume 3, Part B,Sec 4.7.2 403 class ServiceSearchAttributeResponse : public Response { 404 public: 405 ServiceSearchAttributeResponse(); 406 407 // Response overrides 408 const BufferView ContinuationState() const override; 409 bool complete() const override; 410 fit::result<Error<>> Parse(const ByteBuffer& buf) override; 411 MutableByteBufferPtr GetPDU(uint16_t req_max, 412 TransactionId tid, 413 uint16_t max_size, 414 const ByteBuffer& cont_state) const override; 415 416 // Set an attribute to be included in the response. 417 // |idx| is used to group attributes and does not need to be contiguous for 418 // convenience (i.e. a service's handle), although parsed responses will 419 // be numbered starting from 0. 420 void SetAttribute(uint32_t idx, AttributeId id, DataElement value); 421 422 // The number of attribute lists in this response. num_attribute_lists()423 size_t num_attribute_lists() const { return attribute_lists_.size(); } 424 425 // Retrieve attributes in response from a specific index. 426 // Attribute lists are numbered starting from 0 when parsed. attributes(uint32_t idx)427 const std::map<AttributeId, DataElement>& attributes(uint32_t idx) const { 428 return attribute_lists_.at(idx); 429 } 430 431 private: 432 // The list of lists that is to be returned / was returned in the response. 433 // They are in ascending order of index, which has no relation to the 434 // service IDs (they may not be included). 435 std::map<uint32_t, std::map<AttributeId, DataElement>> attribute_lists_; 436 437 // The Attribute Lists can be truncated due to: 438 // - Response too long for MTU 439 // - MaxAttributeListByteCount is set too low 440 // - Because the server wants to 441 // 442 // This contains the partial attribute list response if there is continuation 443 // state. 444 MutableByteBufferPtr partial_response_; 445 446 MutableByteBufferPtr continuation_state_; 447 }; 448 449 } // namespace bt::sdp 450