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