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