• 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 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
16 
17 #include <cpp-string/utf_codecs.h>
18 #include <endian.h>
19 
20 #include <type_traits>
21 
22 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
26 
27 #pragma clang diagnostic ignored "-Wswitch-enum"
28 
29 namespace bt {
30 
31 namespace {
32 
ServiceUuidTypeForUuidSize(UUIDElemSize size,bool complete)33 DataType ServiceUuidTypeForUuidSize(UUIDElemSize size, bool complete) {
34   switch (size) {
35     case UUIDElemSize::k16Bit:
36       return complete ? DataType::kComplete16BitServiceUuids
37                       : DataType::kIncomplete16BitServiceUuids;
38     case UUIDElemSize::k32Bit:
39       return complete ? DataType::kComplete32BitServiceUuids
40                       : DataType::kIncomplete32BitServiceUuids;
41     case UUIDElemSize::k128Bit:
42       return complete ? DataType::kComplete128BitServiceUuids
43                       : DataType::kIncomplete128BitServiceUuids;
44     default:
45       BT_PANIC(
46           "called ServiceUuidTypeForUuidSize with unknown UUIDElemSize %du",
47           size);
48   }
49 }
50 
ServiceDataTypeForUuidSize(UUIDElemSize size)51 DataType ServiceDataTypeForUuidSize(UUIDElemSize size) {
52   switch (size) {
53     case UUIDElemSize::k16Bit:
54       return DataType::kServiceData16Bit;
55     case UUIDElemSize::k32Bit:
56       return DataType::kServiceData32Bit;
57     case UUIDElemSize::k128Bit:
58       return DataType::kServiceData128Bit;
59     default:
60       BT_PANIC(
61           "called ServiceDataTypeForUuidSize with unknown UUIDElemSize %du",
62           size);
63   };
64 }
65 
EncodedServiceDataSize(const UUID & uuid,const BufferView data)66 size_t EncodedServiceDataSize(const UUID& uuid, const BufferView data) {
67   return uuid.CompactSize() + data.size();
68 }
69 
70 // clang-format off
71 // https://www.bluetooth.com/specifications/assigned-numbers/uri-scheme-name-string-mapping
72 const char* kUriSchemes[] = {"aaa:", "aaas:", "about:", "acap:", "acct:", "cap:", "cid:",
73         "coap:", "coaps:", "crid:", "data:", "dav:", "dict:", "dns:", "file:", "ftp:", "geo:",
74         "go:", "gopher:", "h323:", "http:", "https:", "iax:", "icap:", "im:", "imap:", "info:",
75         "ipp:", "ipps:", "iris:", "iris.beep:", "iris.xpc:", "iris.xpcs:", "iris.lwz:", "jabber:",
76         "ldap:", "mailto:", "mid:", "msrp:", "msrps:", "mtqp:", "mupdate:", "news:", "nfs:", "ni:",
77         "nih:", "nntp:", "opaquelocktoken:", "pop:", "pres:", "reload:", "rtsp:", "rtsps:", "rtspu:",
78         "service:", "session:", "shttp:", "sieve:", "sip:", "sips:", "sms:", "snmp:", "soap.beep:",
79         "soap.beeps:", "stun:", "stuns:", "tag:", "tel:", "telnet:", "tftp:", "thismessage:",
80         "tn3270:", "tip:", "turn:", "turns:", "tv:", "urn:", "vemmi:", "ws:", "wss:", "xcon:",
81         "xcon-userid:", "xmlrpc.beep:", "xmlrpc.beeps:", "xmpp:", "z39.50r:", "z39.50s:", "acr:",
82         "adiumxtra:", "afp:", "afs:", "aim:", "apt:", "attachment:", "aw:", "barion:", "beshare:",
83         "bitcoin:", "bolo:", "callto:", "chrome:", "chrome-extension:", "com-eventbrite-attendee:",
84         "content:", "cvs:", "dlna-playsingle:", "dlna-playcontainer:", "dtn:", "dvb:", "ed2k:",
85         "facetime:", "feed:", "feedready:", "finger:", "fish:", "gg:", "git:", "gizmoproject:",
86         "gtalk:", "ham:", "hcp:", "icon:", "ipn:", "irc:", "irc6:", "ircs:", "itms:", "jar:",
87         "jms:", "keyparc:", "lastfm:", "ldaps:", "magnet:", "maps:", "market:", "message:", "mms:",
88         "ms-help:", "ms-settings-power:", "msnim:", "mumble:", "mvn:", "notes:", "oid:", "palm:",
89         "paparazzi:", "pkcs11:", "platform:", "proxy:", "psyc:", "query:", "res:", "resource:",
90         "rmi:", "rsync:", "rtmfp:", "rtmp:", "secondlife:", "sftp:", "sgn:", "skype:", "smb:",
91         "smtp:", "soldat:", "spotify:", "ssh:", "steam:", "submit:", "svn:", "teamspeak:",
92         "teliaeid:", "things:", "udp:", "unreal:", "ut2004:", "ventrilo:", "view-source:",
93         "webcal:", "wtai:", "wyciwyg:", "xfire:", "xri:", "ymsgr:", "example:",
94         "ms-settings-cloudstorage:"};
95 // clang-format on
96 
97 const size_t kUriSchemesSize = std::extent<decltype(kUriSchemes)>::value;
98 
EncodeUri(const std::string & uri)99 std::string EncodeUri(const std::string& uri) {
100   std::string encoded_scheme;
101   for (uint32_t i = 0; i < kUriSchemesSize; i++) {
102     const char* scheme = kUriSchemes[i];
103     size_t scheme_len = strlen(scheme);
104     if (std::equal(scheme, scheme + scheme_len, uri.begin())) {
105       bt_lib_cpp_string::WriteUnicodeCharacter(i + 2, &encoded_scheme);
106       return encoded_scheme + uri.substr(scheme_len);
107     }
108   }
109   // First codepoint (U+0001) is for uncompressed schemes.
110   bt_lib_cpp_string::WriteUnicodeCharacter(1, &encoded_scheme);
111   return encoded_scheme + uri;
112 }
113 
114 const char kUndefinedScheme = 0x01;
115 
DecodeUri(const std::string & uri)116 std::string DecodeUri(const std::string& uri) {
117   if (uri[0] == kUndefinedScheme) {
118     return uri.substr(1);
119   }
120   uint32_t code_point = 0;
121   size_t index = 0;
122 
123   // NOTE: as we are reading UTF-8 from `uri`, it is possible that `code_point`
124   // corresponds to > 1 byte of `uri` (even for valid URI encoding schemes, as
125   // U+00(>7F) encodes to 2 bytes).
126   if (!bt_lib_cpp_string::ReadUnicodeCharacter(
127           uri.c_str(), uri.size(), &index, &code_point)) {
128     bt_log(INFO,
129            "gap-le",
130            "Attempted to decode malformed UTF-8 in AdvertisingData URI");
131     return "";
132   }
133   // `uri` is not a c-string, so URIs that start with '\0' after c_str
134   // conversion (i.e. both empty URIs and URIs with leading null bytes '\0') are
135   // caught by the code_point < 2 check. We check
136   // "< 2" instead of "== 0" for redundancy (extra safety!) with the
137   // kUndefinedScheme check above.
138   if (code_point >= kUriSchemesSize + 2 || code_point < 2) {
139     bt_log(
140         ERROR,
141         "gap-le",
142         "Failed to decode URI - supplied UTF-8 encoding scheme codepoint %u "
143         "must be in the "
144         "range 2-kUriSchemesSize + 1 (2-%lu) to correspond to a URI encoding",
145         code_point,
146         kUriSchemesSize + 1);
147     return "";
148   }
149   return kUriSchemes[code_point - 2] + uri.substr(index + 1);
150 }
151 
152 template <typename T>
BufferWrite(MutableByteBuffer * buffer,size_t pos,const T & var)153 inline size_t BufferWrite(MutableByteBuffer* buffer, size_t pos, const T& var) {
154   buffer->Write((const uint8_t*)(uintptr_t)(&var), sizeof(T), pos);
155   return sizeof(T);
156 }
157 
158 }  // namespace
159 
AdvertisingData(AdvertisingData && other)160 AdvertisingData::AdvertisingData(AdvertisingData&& other) noexcept {
161   *this = std::move(other);
162 }
163 
operator =(AdvertisingData && other)164 AdvertisingData& AdvertisingData::operator=(AdvertisingData&& other) noexcept {
165   // Reset `other`'s state to that of a fresh, empty AdvertisingData
166   local_name_ = std::exchange(other.local_name_, {});
167   tx_power_ = std::exchange(other.tx_power_, {});
168   appearance_ = std::exchange(other.appearance_, {});
169   service_uuids_ = std::exchange(other.service_uuids_, kEmptyServiceUuidMap);
170   manufacturer_data_ = std::exchange(other.manufacturer_data_, {});
171   service_data_ = std::exchange(other.service_data_, {});
172   uris_ = std::exchange(other.uris_, {});
173   flags_ = std::exchange(other.flags_, {});
174   return *this;
175 }
176 
ParseErrorToString(ParseError e)177 std::string AdvertisingData::ParseErrorToString(ParseError e) {
178   switch (e) {
179     case ParseError::kInvalidTlvFormat:
180       return "provided bytes are not a valid type-length-value container";
181     case ParseError::kTxPowerLevelMalformed:
182       return "malformed tx power level";
183     case ParseError::kLocalNameTooLong:
184       return "local name exceeds max length (248)";
185     case ParseError::kUuidsMalformed:
186       return "malformed service UUIDs list";
187     case ParseError::kManufacturerSpecificDataTooSmall:
188       return "manufacturer specific data too small";
189     case ParseError::kServiceDataTooSmall:
190       return "service data too small to fit UUIDs";
191     case ParseError::kServiceDataUuidMalformed:
192       return "UUIDs associated with service data are malformed";
193     case ParseError::kAppearanceMalformed:
194       return "malformed appearance field";
195     case ParseError::kMissing:
196       return "data missing";
197   }
198 }
199 
FromBytes(const ByteBuffer & data)200 AdvertisingData::ParseResult AdvertisingData::FromBytes(
201     const ByteBuffer& data) {
202   if (data.size() == 0) {
203     return fit::error(ParseError::kMissing);
204   }
205   SupplementDataReader reader(data);
206   if (!reader.is_valid()) {
207     return fit::error(ParseError::kInvalidTlvFormat);
208   }
209 
210   AdvertisingData out_ad;
211   DataType type;
212   BufferView field;
213   while (reader.GetNextField(&type, &field)) {
214     // While parsing through the advertising data fields, we do not need to
215     // validate that per-field sizes do not overflow a uint8_t because they, by
216     // construction, are obtained from a uint8_t.
217     BT_DEBUG_ASSERT(field.size() <= std::numeric_limits<uint8_t>::max());
218     switch (type) {
219       case DataType::kTxPowerLevel: {
220         if (field.size() != kTxPowerLevelSize) {
221           return fit::error(ParseError::kTxPowerLevelMalformed);
222         }
223 
224         out_ad.SetTxPower(static_cast<int8_t>(field[0]));
225         break;
226       }
227       case DataType::kShortenedLocalName: {
228         if (field.ToString().size() > kMaxNameLength) {
229           return fit::error(ParseError::kLocalNameTooLong);
230         }
231 
232         (void)out_ad.SetLocalName(field.ToString(), /*is_complete=*/false);
233         break;
234       }
235       case DataType::kCompleteLocalName: {
236         if (field.ToString().size() > kMaxNameLength) {
237           return fit::error(ParseError::kLocalNameTooLong);
238         }
239 
240         (void)out_ad.SetLocalName(field.ToString(), /*is_complete=*/true);
241         break;
242       }
243       case DataType::kIncomplete16BitServiceUuids:
244       case DataType::kComplete16BitServiceUuids:
245       case DataType::kIncomplete32BitServiceUuids:
246       case DataType::kComplete32BitServiceUuids:
247       case DataType::kIncomplete128BitServiceUuids:
248       case DataType::kComplete128BitServiceUuids: {
249         // AddServiceUuid fails when the number of N bit UUIDs exceed the
250         // kMaxNBitUuids bounds. These bounds are based on the number of UUIDs
251         // that fit in the wire (byte) representation of an AdvertisingData, so
252         // for valid AdvertisingData packets, the number of N bit service UUIDs
253         // cannot exceed the bounds limits. However, because invalid packets may
254         // provide multiple DataType fields for the same UUID (not allowed by
255         // CSS v9 Part A 1.1.1), this limit may be exceeded, in which case we
256         // reject the packet.
257         if (!ParseUuids(
258                 field,
259                 SizeForType(type),
260                 fit::bind_member<&AdvertisingData::AddServiceUuid>(&out_ad))) {
261           return fit::error(ParseError::kUuidsMalformed);
262         }
263         break;
264       }
265       case DataType::kManufacturerSpecificData: {
266         if (field.size() < kManufacturerSpecificDataSizeMin) {
267           return fit::error(ParseError::kManufacturerSpecificDataTooSmall);
268         }
269 
270         uint16_t id = le16toh(*reinterpret_cast<const uint16_t*>(field.data()));
271         const BufferView manuf_data(field.data() + kManufacturerIdSize,
272                                     field.size() - kManufacturerIdSize);
273 
274         BT_ASSERT(out_ad.SetManufacturerData(id, manuf_data));
275         break;
276       }
277       case DataType::kServiceData16Bit:
278       case DataType::kServiceData32Bit:
279       case DataType::kServiceData128Bit: {
280         UUID uuid;
281         size_t uuid_size = SizeForType(type);
282         if (field.size() < uuid_size) {
283           return fit::error(ParseError::kServiceDataTooSmall);
284         }
285         const BufferView uuid_bytes(field.data(), uuid_size);
286         if (!UUID::FromBytes(uuid_bytes, &uuid)) {
287           // This is impossible given that uuid_bytes.size() is guaranteed to be
288           // a valid UUID size, and the current UUID::FromBytes implementation
289           // only fails if given an invalid size. We leave it in anyway in case
290           // this implementation changes in the future.
291           return fit::error(ParseError::kServiceDataUuidMalformed);
292         }
293         const BufferView service_data(field.data() + uuid_size,
294                                       field.size() - uuid_size);
295         BT_ASSERT(out_ad.SetServiceData(uuid, service_data));
296         break;
297       }
298       case DataType::kAppearance: {
299         // TODO(armansito): Peer should have a function to return the
300         // device appearance, as it can be obtained either from advertising data
301         // or via GATT.
302         if (field.size() != kAppearanceSize) {
303           return fit::error(ParseError::kAppearanceMalformed);
304         }
305 
306         out_ad.SetAppearance(le16toh(field.To<uint16_t>()));
307         break;
308       }
309       case DataType::kURI: {
310         // Assertion is safe as AddUri only fails when field size > uint8_t,
311         // which is impossible.
312         BT_ASSERT(out_ad.AddUri(DecodeUri(field.ToString())));
313         break;
314       }
315       case DataType::kFlags: {
316         // Flags field may be zero or more octets long but we only store the
317         // first octet.
318         if (field.size() > 0) {
319           out_ad.SetFlags(field[0]);
320         } else {
321           out_ad.SetFlags(0);
322         }
323         break;
324       }
325       default:
326         bt_log(DEBUG,
327                "gap",
328                "ignored advertising field (type %#.2x)",
329                static_cast<unsigned int>(type));
330         break;
331     }
332   }
333 
334   return fit::ok(std::move(out_ad));
335 }
336 
Copy(AdvertisingData * out) const337 void AdvertisingData::Copy(AdvertisingData* out) const {
338   *out = AdvertisingData();
339 
340   if (local_name_) {
341     BT_ASSERT(out->SetLocalName(*local_name_));
342   }
343 
344   if (tx_power_) {
345     out->SetTxPower(*tx_power_);
346   }
347 
348   if (appearance_) {
349     out->SetAppearance(*appearance_);
350   }
351 
352   out->service_uuids_ = service_uuids_;
353 
354   for (const auto& it : manufacturer_data_) {
355     BT_ASSERT(out->SetManufacturerData(it.first, it.second.view()));
356   }
357 
358   for (const auto& it : service_data_) {
359     BT_ASSERT(out->SetServiceData(it.first, it.second.view()));
360   }
361 
362   for (const auto& it : uris_) {
363     BT_ASSERT_MSG(out->AddUri(it), "Copying invalid AD with too-long URI");
364   }
365 }
366 
AddServiceUuid(const UUID & uuid)367 [[nodiscard]] bool AdvertisingData::AddServiceUuid(const UUID& uuid) {
368   auto iter = service_uuids_.find(uuid.CompactSize());
369   BT_ASSERT(iter != service_uuids_.end());
370   BoundedUuids& uuids = iter->second;
371   return uuids.AddUuid(uuid);
372 }
373 
service_uuids() const374 std::unordered_set<UUID> AdvertisingData::service_uuids() const {
375   std::unordered_set<UUID> out;
376   for (auto& [_elemsize, uuids] : service_uuids_) {
377     out.insert(uuids.set().begin(), uuids.set().end());
378   }
379   return out;
380 }
381 
SetServiceData(const UUID & uuid,const ByteBuffer & data)382 [[nodiscard]] bool AdvertisingData::SetServiceData(const UUID& uuid,
383                                                    const ByteBuffer& data) {
384   size_t encoded_size = EncodedServiceDataSize(uuid, data.view());
385   if (encoded_size > kMaxEncodedServiceDataLength) {
386     bt_log(WARN,
387            "gap-le",
388            "SetServiceData for UUID %s failed: (UUID+data) size %zu > maximum "
389            "allowed size %du",
390            bt_str(uuid),
391            encoded_size,
392            kMaxEncodedServiceDataLength);
393     return false;
394   }
395   service_data_[uuid] = DynamicByteBuffer(data);
396   return true;
397 }
398 
service_data_uuids() const399 std::unordered_set<UUID> AdvertisingData::service_data_uuids() const {
400   std::unordered_set<UUID> uuids;
401   for (const auto& it : service_data_) {
402     uuids.emplace(it.first);
403   }
404   return uuids;
405 }
406 
service_data(const UUID & uuid) const407 BufferView AdvertisingData::service_data(const UUID& uuid) const {
408   auto iter = service_data_.find(uuid);
409   if (iter == service_data_.end())
410     return BufferView();
411   return BufferView(iter->second);
412 }
413 
SetManufacturerData(const uint16_t company_id,const BufferView & data)414 [[nodiscard]] bool AdvertisingData::SetManufacturerData(
415     const uint16_t company_id, const BufferView& data) {
416   size_t field_size = data.size();
417   if (field_size > kMaxManufacturerDataLength) {
418     bt_log(WARN,
419            "gap-le",
420            "SetManufacturerData for company id %#.4x failed: (UUID+data) size "
421            "%zu > maximum allowed "
422            "size %hhu",
423            company_id,
424            field_size,
425            kMaxManufacturerDataLength);
426     return false;
427   }
428   manufacturer_data_[company_id] = DynamicByteBuffer(data);
429   return true;
430 }
431 
manufacturer_data_ids() const432 std::unordered_set<uint16_t> AdvertisingData::manufacturer_data_ids() const {
433   std::unordered_set<uint16_t> manuf_ids;
434   for (const auto& it : manufacturer_data_) {
435     manuf_ids.emplace(it.first);
436   }
437   return manuf_ids;
438 }
439 
manufacturer_data(const uint16_t company_id) const440 BufferView AdvertisingData::manufacturer_data(const uint16_t company_id) const {
441   auto iter = manufacturer_data_.find(company_id);
442   if (iter == manufacturer_data_.end())
443     return BufferView();
444   return BufferView(iter->second);
445 }
446 
SetTxPower(int8_t dbm)447 void AdvertisingData::SetTxPower(int8_t dbm) { tx_power_ = dbm; }
448 
tx_power() const449 std::optional<int8_t> AdvertisingData::tx_power() const { return tx_power_; }
450 
SetLocalName(const LocalName & local_name)451 bool AdvertisingData::SetLocalName(const LocalName& local_name) {
452   if (local_name.name.size() > kMaxNameLength) {
453     return false;
454   }
455   if (local_name_.has_value() && local_name_->is_complete &&
456       !local_name.is_complete) {
457     return false;
458   }
459   local_name_ = local_name;
460   return true;
461 }
462 
local_name() const463 std::optional<AdvertisingData::LocalName> AdvertisingData::local_name() const {
464   return local_name_;
465 }
466 
AddUri(const std::string & uri)467 [[nodiscard]] bool AdvertisingData::AddUri(const std::string& uri) {
468   if (EncodeUri(uri).size() > kMaxEncodedUriLength) {
469     bt_log(WARN,
470            "gap-le",
471            "not inserting uri %s as it exceeds the max URI size for AD",
472            uri.c_str());
473     return false;
474   }
475   if (uri.empty()) {
476     bt_log(WARN, "gap-le", "skipping insertion of empty uri to AD");
477     return true;
478   }
479   uris_.insert(uri);
480   return true;
481 }
482 
uris() const483 const std::unordered_set<std::string>& AdvertisingData::uris() const {
484   return uris_;
485 }
486 
SetAppearance(uint16_t appearance)487 void AdvertisingData::SetAppearance(uint16_t appearance) {
488   appearance_ = appearance;
489 }
490 
appearance() const491 std::optional<uint16_t> AdvertisingData::appearance() const {
492   return appearance_;
493 }
494 
SetFlags(AdvFlags flags)495 void AdvertisingData::SetFlags(AdvFlags flags) { flags_ = flags; }
496 
flags() const497 std::optional<AdvFlags> AdvertisingData::flags() const { return flags_; }
498 
CalculateBlockSize(bool include_flags) const499 size_t AdvertisingData::CalculateBlockSize(bool include_flags) const {
500   size_t len = 0;
501   if (include_flags) {
502     len += kTLVFlagsSize;
503   }
504 
505   if (tx_power_) {
506     len += kTLVTxPowerLevelSize;
507   }
508 
509   if (appearance_) {
510     len += kTLVAppearanceSize;
511   }
512 
513   if (local_name_) {
514     len += 2 + local_name_->name.size();
515   }
516 
517   for (const auto& manuf_pair : manufacturer_data_) {
518     len += 2 + 2 + manuf_pair.second.size();
519   }
520 
521   for (const auto& service_data_pair : service_data_) {
522     len += 2 + service_data_pair.first.CompactSize() +
523            service_data_pair.second.size();
524   }
525 
526   for (const auto& uri : uris_) {
527     len += 2 + EncodeUri(uri).size();
528   }
529 
530   for (const auto& [uuid_size, bounded_uuids] : service_uuids_) {
531     if (bounded_uuids.set().empty()) {
532       continue;
533     }
534     len += 2;  // 1 byte for # of UUIDs and 1 for UUID type
535     len += uuid_size * bounded_uuids.set().size();
536   }
537 
538   return len;
539 }
540 
WriteBlock(MutableByteBuffer * buffer,std::optional<AdvFlags> flags) const541 bool AdvertisingData::WriteBlock(MutableByteBuffer* buffer,
542                                  std::optional<AdvFlags> flags) const {
543   BT_DEBUG_ASSERT(buffer);
544 
545   size_t min_buf_size = CalculateBlockSize(flags.has_value());
546   if (buffer->size() < min_buf_size) {
547     return false;
548   }
549 
550   size_t pos = 0;
551   if (flags) {
552     (*buffer)[pos++] =
553         kTLVFlagsSize - 1;  // size variable includes current field, subtract 1
554     (*buffer)[pos++] = static_cast<uint8_t>(DataType::kFlags);
555     (*buffer)[pos++] = static_cast<uint8_t>(flags.value());
556   }
557 
558   if (tx_power_) {
559     (*buffer)[pos++] = kTLVTxPowerLevelSize -
560                        1;  // size variable includes current field, subtract 1
561     (*buffer)[pos++] = static_cast<uint8_t>(DataType::kTxPowerLevel);
562     (*buffer)[pos++] = static_cast<uint8_t>(tx_power_.value());
563   }
564 
565   if (appearance_) {
566     (*buffer)[pos++] = kTLVAppearanceSize -
567                        1;  // size variable includes current field, subtract 1
568     (*buffer)[pos++] = static_cast<uint8_t>(DataType::kAppearance);
569     pos += BufferWrite(buffer, pos, appearance_.value());
570   }
571 
572   if (local_name_) {
573     BT_ASSERT(local_name_->name.size() <= kMaxNameLength);
574     (*buffer)[pos++] =
575         static_cast<uint8_t>(local_name_->name.size()) + 1;  // 1 for null char
576     (*buffer)[pos++] = static_cast<uint8_t>(DataType::kCompleteLocalName);
577     buffer->Write(reinterpret_cast<const uint8_t*>(local_name_->name.c_str()),
578                   local_name_->name.size(),
579                   pos);
580     pos += local_name_->name.size();
581   }
582 
583   for (const auto& manuf_pair : manufacturer_data_) {
584     size_t data_size = manuf_pair.second.size();
585     BT_ASSERT(data_size <= kMaxManufacturerDataLength);
586     (*buffer)[pos++] =
587         1 + 2 +
588         static_cast<uint8_t>(data_size);  // 1 for type, 2 for Manuf. Code
589     (*buffer)[pos++] =
590         static_cast<uint8_t>(DataType::kManufacturerSpecificData);
591     pos += BufferWrite(buffer, pos, manuf_pair.first);
592     buffer->Write(manuf_pair.second, pos);
593     pos += data_size;
594   }
595 
596   for (const auto& service_data_pair : service_data_) {
597     UUID uuid = service_data_pair.first;
598     size_t encoded_service_data_size =
599         EncodedServiceDataSize(uuid, service_data_pair.second.view());
600     BT_ASSERT(encoded_service_data_size <= kMaxEncodedServiceDataLength);
601     (*buffer)[pos++] =
602         1 + static_cast<uint8_t>(encoded_service_data_size);  // 1 for type
603     (*buffer)[pos++] =
604         static_cast<uint8_t>(ServiceDataTypeForUuidSize(uuid.CompactSize()));
605     auto target = buffer->mutable_view(pos);
606     pos += service_data_pair.first.ToBytes(&target);
607     buffer->Write(service_data_pair.second, pos);
608     pos += service_data_pair.second.size();
609   }
610 
611   for (const auto& uri : uris_) {
612     std::string s = EncodeUri(uri);
613     BT_ASSERT(s.size() <= kMaxEncodedUriLength);
614     (*buffer)[pos++] = 1 + static_cast<uint8_t>(s.size());  // 1 for type
615     (*buffer)[pos++] = static_cast<uint8_t>(DataType::kURI);
616     buffer->Write(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), pos);
617     pos += s.size();
618   }
619 
620   for (const auto& [uuid_width, bounded_uuids] : service_uuids_) {
621     if (bounded_uuids.set().empty()) {
622       continue;
623     }
624 
625     // 1 for type
626     BT_ASSERT(1 + uuid_width * bounded_uuids.set().size() <=
627               std::numeric_limits<uint8_t>::max());
628     (*buffer)[pos++] =
629         1 + uuid_width * static_cast<uint8_t>(bounded_uuids.set().size());
630     (*buffer)[pos++] = static_cast<uint8_t>(
631         ServiceUuidTypeForUuidSize(uuid_width, /*complete=*/false));
632     for (const auto& uuid : bounded_uuids.set()) {
633       BT_ASSERT_MSG(uuid.CompactSize() == uuid_width,
634                     "UUID: %s - Expected Width: %d",
635                     bt_str(uuid),
636                     uuid_width);
637       auto target = buffer->mutable_view(pos);
638       pos += uuid.ToBytes(&target);
639     }
640   }
641 
642   return true;
643 }
644 
operator ==(const AdvertisingData & other) const645 bool AdvertisingData::operator==(const AdvertisingData& other) const {
646   if ((local_name_ != other.local_name_) || (tx_power_ != other.tx_power_) ||
647       (appearance_ != other.appearance_) ||
648       (service_uuids_ != other.service_uuids_) || (uris_ != other.uris_) ||
649       (flags_ != other.flags_)) {
650     return false;
651   }
652 
653   if (manufacturer_data_.size() != other.manufacturer_data_.size()) {
654     return false;
655   }
656 
657   for (const auto& it : manufacturer_data_) {
658     auto that = other.manufacturer_data_.find(it.first);
659     if (that == other.manufacturer_data_.end()) {
660       return false;
661     }
662     size_t bytes = it.second.size();
663     if (bytes != that->second.size()) {
664       return false;
665     }
666     if (std::memcmp(it.second.data(), that->second.data(), bytes) != 0) {
667       return false;
668     }
669   }
670 
671   if (service_data_.size() != other.service_data_.size()) {
672     return false;
673   }
674 
675   for (const auto& it : service_data_) {
676     auto that = other.service_data_.find(it.first);
677     if (that == other.service_data_.end()) {
678       return false;
679     }
680     size_t bytes = it.second.size();
681     if (bytes != that->second.size()) {
682       return false;
683     }
684     if (std::memcmp(it.second.data(), that->second.data(), bytes) != 0) {
685       return false;
686     }
687   }
688 
689   return true;
690 }
691 
operator !=(const AdvertisingData & other) const692 bool AdvertisingData::operator!=(const AdvertisingData& other) const {
693   return !(*this == other);
694 }
695 
AddUuid(UUID uuid)696 bool AdvertisingData::BoundedUuids::AddUuid(UUID uuid) {
697   BT_ASSERT(set_.size() <= bound_);
698   if (set_.size() < bound_) {
699     if (!set_.insert(uuid).second) {
700       bt_log(INFO,
701              "gap-le",
702              "Skipping addition of duplicate UUID %s to AD",
703              bt_str(uuid));
704     }
705     return true;
706   }
707   if (set_.find(uuid) != set_.end()) {
708     bt_log(INFO,
709            "gap-le",
710            "Skipping addition of duplicate UUID %s to AD",
711            bt_str(uuid));
712     return true;
713   }
714   bt_log(WARN,
715          "gap-le",
716          "Failed to add service UUID %s to AD - no space left",
717          bt_str(uuid));
718   return false;
719 }
720 }  // namespace bt
721