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/function.h> 17 #include <lib/fit/result.h> 18 19 #include <cstddef> 20 #include <limits> 21 #include <optional> 22 #include <unordered_map> 23 #include <unordered_set> 24 25 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 26 #include "pw_bluetooth_sapphire/internal/host/common/supplement_data.h" 27 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h" 28 29 namespace bt { 30 31 // Potential values that can be provided in the "Flags" advertising data 32 // bitfield. 33 // clang-format off 34 enum AdvFlag : uint8_t { 35 // Octet 0 36 kLELimitedDiscoverableMode = (1 << 0), 37 kLEGeneralDiscoverableMode = (1 << 1), 38 kBREDRNotSupported = (1 << 2), 39 kSimultaneousLEAndBREDRController = (1 << 3), 40 kSimultaneousLEAndBREDRHost = (1 << 4), 41 }; 42 // clang-format on 43 44 // The Flags bitfield used in advertising data. 45 // Only the first octet (octet0) is represented in |AdvFlags|. 46 // 47 // See the Core Specification Supplement v9 for more information. 48 using AdvFlags = uint8_t; 49 50 inline constexpr uint8_t kDefaultNoAdvFlags = 0; 51 52 // The TLV size of the Flags datatype. 53 inline constexpr size_t kTLVFlagsSize = 3; 54 55 // The TLV size of the TX power data type 56 inline constexpr size_t kTLVTxPowerLevelSize = 3; 57 58 // The TLV size of the appearance data type 59 inline constexpr size_t kTLVAppearanceSize = 4; 60 61 // The TLV side of the resolvable set identifier data type 62 inline constexpr size_t kTLVResolvableSetIdentifierSize = 8; 63 64 // Constants for the expected size (in octets) of an 65 // advertising/EIR/scan-response data field. 66 // 67 // * If a constant contains the word "Min", then it specifies a minimum 68 // expected length rather than an exact length. 69 // 70 // * If a constants contains the word "ElemSize", then the data field is 71 // expected to contain a contiguous array of elements of the specified size. 72 inline constexpr size_t kAppearanceSize = 2; 73 inline constexpr size_t kManufacturerIdSize = 2; 74 inline constexpr size_t kTxPowerLevelSize = 1; 75 inline constexpr size_t kResolvableSetIdentifierSize = 6; 76 77 inline constexpr size_t kFlagsSizeMin = 1; 78 inline constexpr size_t kManufacturerSpecificDataSizeMin = kManufacturerIdSize; 79 80 inline constexpr uint8_t kMaxUint8 = std::numeric_limits<uint8_t>::max(); 81 // The maximum length of a friendly name, derived from v5.2, Vol 4, Part 82 // E, 7.3.11 and Vol 3, Part C, 12.1 83 inline constexpr uint8_t kMaxNameLength = 248; 84 85 // The minimum length of a Broadcast Name, as defined by Public Broadcast 86 // Profile, in bytes. Defined as 4 UTF-8 characters 87 inline constexpr uint8_t kMinBroadcastNameBytes = 4; 88 // The maximum length of a Broadcast Name, as defined by Public Broadcast 89 // Profile, in bytes. Defined as 32 UTF-8 characters 90 inline constexpr uint8_t kMaxBroadcastNameBytes = 128; 91 92 // The length of the entire manufacturer-specific data field must fit in a 93 // uint8_t, so the maximum data length is uint8_t::MAX - 1 byte for type - 2 94 // bytes for manufacturer ID. 95 inline constexpr uint8_t kMaxManufacturerDataLength = kMaxUint8 - 3; 96 97 // The length of the service data field must fit in a uint8_t, so uint8_t::MAX - 98 // 1 byte for type. 99 inline constexpr uint8_t kMaxEncodedServiceDataLength = kMaxUint8 - 1; 100 101 // The length of an encoded URI together with its 1-byte type field must not 102 // exceed uint8_t limits 103 inline constexpr uint8_t kMaxEncodedUriLength = kMaxUint8 - 1; 104 105 // "A packet or data block shall not contain more than one instance for each 106 // Service UUID data size." (Core Specification Supplement v9 Part A 1.1.1). For 107 // each UUID size, 1 (type byte) + # of UUIDs * UUID size = length of that 108 // size's encoded UUIDs. This length must fit in a uint8_t, hence there is a 109 // per-UUID-size limit on the # of UUIDs. 110 inline constexpr uint8_t kMax16BitUuids = 111 (kMaxUint8 - 1) / UUIDElemSize::k16Bit; 112 inline constexpr uint8_t kMax32BitUuids = 113 (kMaxUint8 - 1) / UUIDElemSize::k32Bit; 114 inline constexpr uint8_t kMax128BitUuids = 115 (kMaxUint8 - 1) / UUIDElemSize::k128Bit; 116 117 // A helper to build Adversiting Data, Scan Response Data, or Extended Inquiry 118 // Response Data fields. 119 // TODO(jamuraa): Add functionality for ACAD and OOB 120 // 121 // This can be viewed as a complex container type which has a specified byte 122 // view that is valid for: 123 // - Core Spec v5.0 Vol 3, Part C, Section 11 in the case of Advertising or 124 // Scan Response Data 125 // - Core Spec v5.0 Vol 3, Part C, Section 8 for Extended Inquiry Response data 126 // 127 // See those sections, and the Core Specification Supplement v7 for more 128 // information. 129 class AdvertisingData { 130 public: 131 // Possible failure modes for parsing an AdvertisingData from raw bytes. 132 enum class ParseError { 133 // The bytes provided are not a valid type-length-value container. 134 kInvalidTlvFormat, 135 // The length of a TxPowerLevel-type field does not match the TxPowerLevel 136 // value size. 137 kTxPowerLevelMalformed, 138 // The length of a LocalName-type field exceeds the length allowed by the 139 // spec (kMaxNameLength). 140 kLocalNameTooLong, 141 // A UUID-type field is malformed. 142 kUuidsMalformed, 143 // A ManufacturerSpecificData-type field is smaller than the minimum 144 // allowable length. 145 kManufacturerSpecificDataTooSmall, 146 // A ServiceData-type field is too small to fit its expected UUID size. 147 kServiceDataTooSmall, 148 // A UUID associated with a ServiceData-type field is malformed. 149 kServiceDataUuidMalformed, 150 // The length of an Appearance-type field does not match the Appearance 151 // value size. 152 kAppearanceMalformed, 153 // Advertising Data missing 154 kMissing, 155 // Resolvable Set Identifier is the wrong size 156 kResolvableSetIdentifierSize, 157 // Broadcast name is too short 158 kBroadcastNameTooShort, 159 // Broadcast name is too long 160 kBroadcastNameTooLong, 161 }; 162 163 // Both complete and shortened forms of the local name can be advertised. 164 struct LocalName { 165 std::string name; 166 bool is_complete; 167 168 bool operator==(const LocalName& other) const { 169 return (name == other.name) && (is_complete == other.is_complete); 170 } 171 bool operator!=(const LocalName& other) const { return !(*this == other); } 172 }; 173 174 // Creates an empty advertising data. 175 AdvertisingData() = default; 176 ~AdvertisingData() = default; 177 178 // When these move operations return, `other` is specified to be an empty 179 // AdvertisingData - i.e. `other`'s state is as if `other = AdvertisingData()` 180 // was performed. 181 AdvertisingData(AdvertisingData&& other) noexcept; 182 AdvertisingData& operator=(AdvertisingData&& other) noexcept; 183 184 // Construct from the raw Bluetooth field block |data|. Returns std::nullopt 185 // if |data| is not formatted correctly or on a parsing error. 186 using ParseResult = fit::result<ParseError, AdvertisingData>; 187 static ParseResult FromBytes(const ByteBuffer& data); 188 static std::string ParseErrorToString(ParseError e); 189 190 // Copies all of the data in this object to |out|, including making a copy of 191 // any data in manufacturing data or service data. The result is |out| being 192 // an exact copy of this object. 193 void Copy(AdvertisingData* out) const; 194 195 // Add a UUID to the set of services advertised. 196 // These service UUIDs will automatically be compressed to be represented in 197 // the smallest space possible. Returns true if the Service UUID was 198 // successfully added or already existed in the set of advertised services, or 199 // false if the UUID set was full and `uuid` could not be added. 200 [[nodiscard]] bool AddServiceUuid(const UUID& uuid); 201 202 // Get the service UUIDs represented in this advertisement. 203 std::unordered_set<UUID> service_uuids() const; 204 205 // Set service data for the service specified by |uuid|. Returns true if the 206 // data was set, false otherwise. Failure occurs if |uuid| + |data| exceed 207 // kMaxEncodedServiceDataLength when encoded. 208 [[nodiscard]] bool SetServiceData(const UUID& uuid, const ByteBuffer& data); 209 210 // Get a set of which UUIDs have service data in this advertisement. 211 std::unordered_set<UUID> service_data_uuids() const; 212 213 // View the currently set service data for |uuid|. 214 // This view is not stable; it should be used only ephemerally. 215 // Returns an empty BufferView if no service data is set for |uuid| 216 BufferView service_data(const UUID& uuid) const; 217 218 // Add a UUID to the set of services to solicit for from a peer. 219 // These service UUIDs will automatically be compressed to be represented in 220 // the smallest space possible. Returns true if the Service UUID was 221 // successfully added or already existed in the set of advertised services, or 222 // false if the UUID set was full and `uuid` could not be added. 223 [[nodiscard]] bool AddSolicitationUuid(const UUID& uuid); 224 225 // Get a set of the solicitation UUIDs included in this advertisement. 226 std::unordered_set<UUID> solicitation_uuids() const; 227 228 // Set Manufacturer specific data for the company identified by |company_id|. 229 // Returns false & does not set the data if |data|.size() exceeds 230 // kMaxManufacturerDataLength, otherwise returns true. 231 [[nodiscard]] bool SetManufacturerData(uint16_t company_id, 232 const BufferView& data); 233 234 // Get a set of which IDs have manufacturer data in this advertisement. 235 std::unordered_set<uint16_t> manufacturer_data_ids() const; 236 237 // View the currently set manufacturer data for the company |company_id|. 238 // Returns an empty BufferView if no manufacturer data is set for 239 // |company_id|. 240 // NOTE: it is valid to send a manufacturer data with no data. Check that one 241 // exists using manufacturer_data_ids() first. 242 // This view is not stable; it should be used only ephemerally. 243 BufferView manufacturer_data(uint16_t company_id) const; 244 245 // Sets the local TX Power 246 // TODO(jamuraa): add documentation about where to get this number from 247 void SetTxPower(int8_t dbm); 248 249 // Gets the TX power 250 std::optional<int8_t> tx_power() const; 251 252 // Returns false if `name` is not set, which happens if `name` is shortened 253 // and a complete name is currently set, or if `name` exceeds kMaxLocalName 254 // bytes. Returns true if `name` is set. 255 [[nodiscard]] bool SetLocalName(const LocalName& local_name); 256 [[nodiscard]] bool SetLocalName(const std::string& name, 257 bool is_complete = true) { 258 return SetLocalName(LocalName{name, is_complete}); 259 } 260 261 // Gets the local name 262 std::optional<LocalName> local_name() const; 263 264 // Sets the resolvable set identifier 265 void SetResolvableSetIdentifier( 266 std::array<uint8_t, kResolvableSetIdentifierSize> identifier); 267 268 // Gets the resolvable set identifier 269 const std::optional<std::array<uint8_t, kResolvableSetIdentifierSize>>& 270 resolvable_set_identifier() const; 271 272 // Sets the broadcast name 273 void SetBroadcastName(const std::string& name); 274 // Gets the broadcast name 275 const std::optional<std::string>& broadcast_name() const; 276 277 // Adds a URI to the set of URIs advertised. 278 // Does nothing if |uri| is empty or, when encoded, exceeds 279 // kMaxEncodedUriLength. 280 [[nodiscard]] bool AddUri(const std::string& uri); 281 282 // Get the URIs in this advertisement 283 const std::unordered_set<std::string>& uris() const; 284 285 // Sets the appearance 286 void SetAppearance(uint16_t appearance); 287 288 // Get the appearance 289 std::optional<uint16_t> appearance() const; 290 291 // Sets the Advertising Flags 292 void SetFlags(AdvFlags flags); 293 294 // Get the currently-set flags. 295 std::optional<AdvFlags> flags() const; 296 297 // Converts the AdvertisingData class attributes to a single string. 298 std::string ToString() const; 299 300 // Calculates the size of the current set of fields if they were to be written 301 // to a buffer using WriteBlock(). 302 // 303 // If |include_flags| is set, then the returned block size will include the 304 // expected size of writing advertising data flags. 305 size_t CalculateBlockSize(bool include_flags = false) const; 306 307 // Writes the byte representation of this to |buffer| with the included 308 // |flags|. Returns false without modifying |buffer| if there is not enough 309 // space (i.e If the buffer size is less than CalculateBlockSize()). 310 // 311 // The responsibility is on the caller to provide a buffer that is large 312 // enough to encode the |AdvertisingData| and the optional flags. 313 bool WriteBlock(MutableByteBuffer* buffer, 314 std::optional<AdvFlags> flags) const; 315 316 // Relation operators 317 bool operator==(const AdvertisingData& other) const; 318 bool operator!=(const AdvertisingData& other) const; 319 320 private: 321 // This class enforces that a set of UUIDs does not grow beyond its provided 322 // upper bound. 323 class BoundedUuids { 324 public: 325 // `bound` is the maximum number of UUIDs allowed in this set. BoundedUuids(uint8_t bound)326 explicit BoundedUuids(uint8_t bound) : bound_(bound) {} 327 328 // Adds a UUID to the set. Returns false if the UUID couldn't be added to 329 // the set due to the size bound, true otherwise. 330 bool AddUuid(UUID uuid); 331 set()332 const std::unordered_set<UUID>& set() const { return set_; } 333 bool operator==(const BoundedUuids& other) const { 334 return bound_ == other.bound_ && set_ == other.set_; 335 } 336 bool operator!=(const BoundedUuids& other) const { 337 return !(*this == other); 338 } 339 340 private: 341 std::unordered_set<UUID> set_ = std::unordered_set<UUID>{}; 342 uint8_t bound_; 343 }; 344 345 // AD stores a map from service UUID size -> BoundedUuids. As the number of 346 // allowed UUID sizes is static, we define this default variable to represent 347 // the "empty" state of the UUID set. 348 const std::unordered_map<UUIDElemSize, BoundedUuids> kEmptyServiceUuidMap = { 349 {UUIDElemSize::k16Bit, BoundedUuids(kMax16BitUuids)}, 350 {UUIDElemSize::k32Bit, BoundedUuids(kMax32BitUuids)}, 351 {UUIDElemSize::k128Bit, BoundedUuids(kMax128BitUuids)}}; 352 353 // TODO(armansito): Consider storing the payload in its serialized form and 354 // have these point into the structure (see fxbug.dev/42172180). 355 std::optional<LocalName> local_name_; 356 std::optional<int8_t> tx_power_; 357 std::optional<uint16_t> appearance_; 358 359 // Each service UUID size is associated with a BoundedUuids. The BoundedUuids 360 // invariant that |bound| >= |set|.size() field is maintained by the AD class, 361 // not the BoundedUuids struct. 362 std::unordered_map<UUIDElemSize, BoundedUuids> service_uuids_ = 363 kEmptyServiceUuidMap; 364 365 std::unordered_map<UUIDElemSize, BoundedUuids> solicitation_uuids_ = 366 kEmptyServiceUuidMap; 367 368 // The length of each manufacturer data buffer is always <= 369 // kMaxManufacturerDataLength. 370 std::unordered_map<uint16_t, DynamicByteBuffer> manufacturer_data_; 371 372 // For each element in `service_data_`, the compact size of the UUID + the 373 // buffer length is always <= kkMaxEncodedServiceDataLength 374 std::unordered_map<UUID, DynamicByteBuffer> service_data_; 375 376 std::unordered_set<std::string> uris_; 377 378 std::optional<std::array<uint8_t, kResolvableSetIdentifierSize>> 379 resolvable_set_identifier_; 380 381 std::optional<std::string> broadcast_name_; 382 383 // Flags, if they have been parsed or set. 384 // Note: When using `WriteBlock`, the passed flags override these. 385 std::optional<AdvFlags> flags_; 386 387 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AdvertisingData); 388 }; 389 390 } // namespace bt 391