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