• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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