• 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 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