• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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/fuchsia/host/fidl/helpers.h"
16 
17 #include <endian.h>
18 #include <fidl/fuchsia.bluetooth.bredr/cpp/natural_types.h>
19 #include <fidl/fuchsia.hardware.bluetooth/cpp/fidl.h>
20 #include <fuchsia/bluetooth/sys/cpp/fidl.h>
21 #include <fuchsia/media/cpp/fidl.h>
22 #include <pw_assert/check.h>
23 #include <pw_bluetooth/hci_data.emb.h>
24 
25 #include <charconv>
26 #include <memory>
27 #include <optional>
28 #include <unordered_set>
29 #include <utility>
30 
31 #include "fuchsia/bluetooth/bredr/cpp/fidl.h"
32 #include "fuchsia/bluetooth/cpp/fidl.h"
33 #include "lib/fpromise/result.h"
34 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
35 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
36 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
37 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
38 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
39 #include "pw_bluetooth_sapphire/internal/host/hci/discovery_filter.h"
40 #include "pw_bluetooth_sapphire/internal/host/sco/sco.h"
41 #include "pw_bluetooth_sapphire/internal/host/sdp/data_element.h"
42 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
43 #include "pw_bluetooth_sapphire/internal/host/sdp/service_record.h"
44 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
45 
46 using fuchsia::bluetooth::Error;
47 using fuchsia::bluetooth::ErrorCode;
48 using fuchsia::bluetooth::Int8;
49 using fuchsia::bluetooth::Status;
50 
51 namespace fble = fuchsia::bluetooth::le;
52 namespace fbredr = fuchsia::bluetooth::bredr;
53 namespace fbt = fuchsia::bluetooth;
54 namespace fgatt = fuchsia::bluetooth::gatt;
55 namespace fgatt2 = fuchsia::bluetooth::gatt2;
56 namespace fsys = fuchsia::bluetooth::sys;
57 namespace faudio = fuchsia::hardware::audio;
58 namespace fhbt = fuchsia_hardware_bluetooth;
59 namespace android_emb = pw::bluetooth::vendor::android_hci;
60 
61 const uint8_t BIT_SHIFT_8 = 8;
62 const uint8_t BIT_SHIFT_16 = 16;
63 
64 namespace bthost::fidl_helpers {
65 // TODO(fxbug.dev/42076395): Add remaining codecs
FidlToCodecType(const fbredr::AudioOffloadFeatures & codec)66 std::optional<android_emb::A2dpCodecType> FidlToCodecType(
67     const fbredr::AudioOffloadFeatures& codec) {
68   switch (codec.Which()) {
69     case fuchsia::bluetooth::bredr::AudioOffloadFeatures::kSbc:
70       return android_emb::A2dpCodecType::SBC;
71     case fuchsia::bluetooth::bredr::AudioOffloadFeatures::kAac:
72       return android_emb::A2dpCodecType::AAC;
73     default:
74       bt_log(WARN,
75              "fidl",
76              "Codec type not yet handled: %u",
77              static_cast<unsigned int>(codec.Which()));
78       return std::nullopt;
79   }
80 }
81 
FidlToScmsTEnable(bool scms_t_enable)82 bt::StaticPacket<android_emb::A2dpScmsTEnableWriter> FidlToScmsTEnable(
83     bool scms_t_enable) {
84   bt::StaticPacket<android_emb::A2dpScmsTEnableWriter> scms_t_enable_struct;
85 
86   if (scms_t_enable) {
87     scms_t_enable_struct.view().enabled().Write(
88         pw::bluetooth::emboss::GenericEnableParam::ENABLE);
89   } else {
90     scms_t_enable_struct.view().enabled().Write(
91         pw::bluetooth::emboss::GenericEnableParam::DISABLE);
92   }
93 
94   scms_t_enable_struct.view().header().Write(0x00);
95   return scms_t_enable_struct;
96 }
97 
FidlToSamplingFrequency(fbredr::AudioSamplingFrequency sampling_frequency)98 std::optional<android_emb::A2dpSamplingFrequency> FidlToSamplingFrequency(
99     fbredr::AudioSamplingFrequency sampling_frequency) {
100   switch (sampling_frequency) {
101     case fbredr::AudioSamplingFrequency::HZ_44100:
102       return android_emb::A2dpSamplingFrequency::HZ_44100;
103     case fbredr::AudioSamplingFrequency::HZ_48000:
104       return android_emb::A2dpSamplingFrequency::HZ_48000;
105     case fbredr::AudioSamplingFrequency::HZ_88200:
106       return android_emb::A2dpSamplingFrequency::HZ_88200;
107     case fbredr::AudioSamplingFrequency::HZ_96000:
108       return android_emb::A2dpSamplingFrequency::HZ_96000;
109     default:
110       return std::nullopt;
111   }
112 }
113 
FidlToBitsPerSample(fbredr::AudioBitsPerSample bits_per_sample)114 std::optional<android_emb::A2dpBitsPerSample> FidlToBitsPerSample(
115     fbredr::AudioBitsPerSample bits_per_sample) {
116   switch (bits_per_sample) {
117     case fbredr::AudioBitsPerSample::BPS_16:
118       return android_emb::A2dpBitsPerSample::BITS_PER_SAMPLE_16;
119     case fbredr::AudioBitsPerSample::BPS_24:
120       return android_emb::A2dpBitsPerSample::BITS_PER_SAMPLE_24;
121     case fbredr::AudioBitsPerSample::BPS_32:
122       return android_emb::A2dpBitsPerSample::BITS_PER_SAMPLE_32;
123     default:
124       return std::nullopt;
125   }
126 }
127 
FidlToChannelMode(fbredr::AudioChannelMode channel_mode)128 std::optional<android_emb::A2dpChannelMode> FidlToChannelMode(
129     fbredr::AudioChannelMode channel_mode) {
130   switch (channel_mode) {
131     case fbredr::AudioChannelMode::MONO:
132       return android_emb::A2dpChannelMode::MONO;
133     case fbredr::AudioChannelMode::STEREO:
134       return android_emb::A2dpChannelMode::STEREO;
135     default:
136       return std::nullopt;
137   }
138 }
139 
140 bt::StaticPacket<android_emb::SbcCodecInformationWriter>
FidlToEncoderSettingsSbc(const fbredr::AudioEncoderSettings & encoder_settings,fbredr::AudioSamplingFrequency sampling_frequency,fbredr::AudioChannelMode channel_mode)141 FidlToEncoderSettingsSbc(const fbredr::AudioEncoderSettings& encoder_settings,
142                          fbredr::AudioSamplingFrequency sampling_frequency,
143                          fbredr::AudioChannelMode channel_mode) {
144   bt::StaticPacket<android_emb::SbcCodecInformationWriter> sbc;
145 
146   switch (encoder_settings.sbc().allocation) {
147     case fuchsia::media::SbcAllocation::ALLOC_LOUDNESS:
148       sbc.view().allocation_method().Write(
149           android_emb::SbcAllocationMethod::LOUDNESS);
150       break;
151     case fuchsia::media::SbcAllocation::ALLOC_SNR:
152       sbc.view().allocation_method().Write(
153           android_emb::SbcAllocationMethod::SNR);
154       break;
155   }
156 
157   switch (encoder_settings.sbc().sub_bands) {
158     case fuchsia::media::SbcSubBands::SUB_BANDS_4:
159       sbc.view().subbands().Write(android_emb::SbcSubBands::SUBBANDS_4);
160       break;
161     case fuchsia::media::SbcSubBands::SUB_BANDS_8:
162       sbc.view().subbands().Write(android_emb::SbcSubBands::SUBBANDS_8);
163       break;
164   }
165 
166   switch (encoder_settings.sbc().block_count) {
167     case fuchsia::media::SbcBlockCount::BLOCK_COUNT_4:
168       sbc.view().block_length().Write(android_emb::SbcBlockLen::BLOCK_LEN_4);
169       break;
170     case fuchsia::media::SbcBlockCount::BLOCK_COUNT_8:
171       sbc.view().block_length().Write(android_emb::SbcBlockLen::BLOCK_LEN_8);
172       break;
173     case fuchsia::media::SbcBlockCount::BLOCK_COUNT_12:
174       sbc.view().block_length().Write(android_emb::SbcBlockLen::BLOCK_LEN_12);
175       break;
176     case fuchsia::media::SbcBlockCount::BLOCK_COUNT_16:
177       sbc.view().block_length().Write(android_emb::SbcBlockLen::BLOCK_LEN_16);
178       break;
179   }
180 
181   sbc.view().min_bitpool_value().Write(encoder_settings.sbc().bit_pool);
182   sbc.view().max_bitpool_value().Write(encoder_settings.sbc().bit_pool);
183 
184   switch (channel_mode) {
185     case fbredr::AudioChannelMode::MONO:
186       sbc.view().channel_mode().Write(android_emb::SbcChannelMode::MONO);
187       break;
188     case fbredr::AudioChannelMode::STEREO:
189       sbc.view().channel_mode().Write(android_emb::SbcChannelMode::STEREO);
190       break;
191   }
192 
193   switch (sampling_frequency) {
194     case fbredr::AudioSamplingFrequency::HZ_44100:
195       sbc.view().sampling_frequency().Write(
196           android_emb::SbcSamplingFrequency::HZ_44100);
197       break;
198     case fbredr::AudioSamplingFrequency::HZ_48000:
199       sbc.view().sampling_frequency().Write(
200           android_emb::SbcSamplingFrequency::HZ_48000);
201       break;
202     default:
203       bt_log(WARN,
204              "fidl",
205              "%s: sbc encoder cannot use sampling frequency %hhu",
206              __FUNCTION__,
207              static_cast<uint8_t>(sampling_frequency));
208   }
209 
210   return sbc;
211 }
212 
213 bt::StaticPacket<android_emb::AacCodecInformationWriter>
FidlToEncoderSettingsAac(const fbredr::AudioEncoderSettings & encoder_settings,fbredr::AudioSamplingFrequency sampling_frequency,fbredr::AudioChannelMode channel_mode)214 FidlToEncoderSettingsAac(const fbredr::AudioEncoderSettings& encoder_settings,
215                          fbredr::AudioSamplingFrequency sampling_frequency,
216                          fbredr::AudioChannelMode channel_mode) {
217   bt::StaticPacket<android_emb::AacCodecInformationWriter> aac;
218   aac.view().object_type().Write(
219       static_cast<uint8_t>(encoder_settings.aac().aot));
220 
221   if (encoder_settings.aac().bit_rate.is_variable()) {
222     aac.view().variable_bit_rate().Write(
223         android_emb::AacEnableVariableBitRate::ENABLE);
224   }
225 
226   if (encoder_settings.aac().bit_rate.is_constant()) {
227     aac.view().variable_bit_rate().Write(
228         android_emb::AacEnableVariableBitRate::DISABLE);
229   }
230 
231   return aac;
232 }
233 
FidlToDataElement(const fbredr::DataElement & fidl)234 std::optional<bt::sdp::DataElement> FidlToDataElement(
235     const fbredr::DataElement& fidl) {
236   bt::sdp::DataElement out;
237   switch (fidl.Which()) {
238     case fbredr::DataElement::Tag::kInt8:
239       return bt::sdp::DataElement(fidl.int8());
240     case fbredr::DataElement::Tag::kInt16:
241       return bt::sdp::DataElement(fidl.int16());
242     case fbredr::DataElement::Tag::kInt32:
243       return bt::sdp::DataElement(fidl.int32());
244     case fbredr::DataElement::Tag::kInt64:
245       return bt::sdp::DataElement(fidl.int64());
246     case fbredr::DataElement::Tag::kUint8:
247       return bt::sdp::DataElement(fidl.uint8());
248     case fbredr::DataElement::Tag::kUint16:
249       return bt::sdp::DataElement(fidl.uint16());
250     case fbredr::DataElement::Tag::kUint32:
251       return bt::sdp::DataElement(fidl.uint32());
252     case fbredr::DataElement::Tag::kUint64:
253       return bt::sdp::DataElement(fidl.uint64());
254     case fbredr::DataElement::Tag::kStr: {
255       const std::vector<uint8_t>& str = fidl.str();
256       bt::DynamicByteBuffer bytes((bt::BufferView(str)));
257       return bt::sdp::DataElement(bytes);
258     }
259     case fbredr::DataElement::Tag::kUrl:
260       out.SetUrl(fidl.url());
261       break;
262     case fbredr::DataElement::Tag::kB:
263       return bt::sdp::DataElement(fidl.b());
264     case fbredr::DataElement::Tag::kUuid:
265       out.Set(fidl_helpers::UuidFromFidl(fidl.uuid()));
266       break;
267     case fbredr::DataElement::Tag::kSequence: {
268       std::vector<bt::sdp::DataElement> seq;
269       for (const auto& fidl_elem : fidl.sequence()) {
270         std::optional<bt::sdp::DataElement> elem =
271             FidlToDataElement(*fidl_elem);
272         if (!elem) {
273           return std::nullopt;
274         }
275         seq.emplace_back(std::move(elem.value()));
276       }
277       out.Set(std::move(seq));
278       break;
279     }
280     case fbredr::DataElement::Tag::kAlternatives: {
281       std::vector<bt::sdp::DataElement> alts;
282       for (const auto& fidl_elem : fidl.alternatives()) {
283         auto elem = FidlToDataElement(*fidl_elem);
284         if (!elem) {
285           return std::nullopt;
286         }
287         alts.emplace_back(std::move(elem.value()));
288       }
289       out.SetAlternative(std::move(alts));
290       break;
291     }
292     default:
293       // Types not handled: Null datatype (never used)
294       bt_log(WARN, "fidl", "Encountered FidlToDataElement type not handled.");
295       return std::nullopt;
296   }
297   return out;
298 }
299 
NewFidlToDataElement(const fuchsia_bluetooth_bredr::DataElement & fidl)300 std::optional<bt::sdp::DataElement> NewFidlToDataElement(
301     const fuchsia_bluetooth_bredr::DataElement& fidl) {
302   bt::sdp::DataElement out;
303   switch (fidl.Which()) {
304     case fuchsia_bluetooth_bredr::DataElement::Tag::kInt8:
305       return bt::sdp::DataElement(fidl.int8().value());
306     case fuchsia_bluetooth_bredr::DataElement::Tag::kInt16:
307       return bt::sdp::DataElement(fidl.int16().value());
308     case fuchsia_bluetooth_bredr::DataElement::Tag::kInt32:
309       return bt::sdp::DataElement(fidl.int32().value());
310     case fuchsia_bluetooth_bredr::DataElement::Tag::kInt64:
311       return bt::sdp::DataElement(fidl.int64().value());
312     case fuchsia_bluetooth_bredr::DataElement::Tag::kUint8:
313       return bt::sdp::DataElement(fidl.uint8().value());
314     case fuchsia_bluetooth_bredr::DataElement::Tag::kUint16:
315       return bt::sdp::DataElement(fidl.uint16().value());
316     case fuchsia_bluetooth_bredr::DataElement::Tag::kUint32:
317       return bt::sdp::DataElement(fidl.uint32().value());
318     case fuchsia_bluetooth_bredr::DataElement::Tag::kUint64:
319       return bt::sdp::DataElement(fidl.uint64().value());
320     case fuchsia_bluetooth_bredr::DataElement::Tag::kStr: {
321       bt::DynamicByteBuffer bytes((bt::BufferView(fidl.str().value())));
322       return bt::sdp::DataElement(bytes);
323     }
324     case fuchsia_bluetooth_bredr::DataElement::Tag::kUrl: {
325       out.SetUrl(fidl.url().value());
326       break;
327     }
328     case fuchsia_bluetooth_bredr::DataElement::Tag::kB:
329       return bt::sdp::DataElement(fidl.b().value());
330     case fuchsia_bluetooth_bredr::DataElement::Tag::kUuid:
331       out.Set(NewUuidFromFidl(fidl.uuid()->value()));
332       break;
333     case fuchsia_bluetooth_bredr::DataElement::Tag::kSequence: {
334       std::vector<bt::sdp::DataElement> seq;
335       for (const auto& fidl_elem : fidl.sequence().value()) {
336         std::optional<bt::sdp::DataElement> elem =
337             NewFidlToDataElement(*fidl_elem);
338         if (!elem) {
339           return std::nullopt;
340         }
341         seq.emplace_back(std::move(elem.value()));
342       }
343       out.Set(std::move(seq));
344       break;
345     }
346     case fuchsia_bluetooth_bredr::DataElement::Tag::kAlternatives: {
347       std::vector<bt::sdp::DataElement> alts;
348       for (const auto& fidl_elem : fidl.alternatives().value()) {
349         auto elem = NewFidlToDataElement(*fidl_elem);
350         if (!elem) {
351           return std::nullopt;
352         }
353         alts.emplace_back(std::move(elem.value()));
354       }
355       out.SetAlternative(std::move(alts));
356       break;
357     }
358     default:
359       // Types not handled: Null datatype (never used)
360       bt_log(
361           WARN, "fidl", "Encountered NewFidlToDataElement type not handled.");
362       return std::nullopt;
363   }
364   return out;
365 }
366 
DataElementToFidl(const bt::sdp::DataElement & data_element)367 std::optional<fbredr::DataElement> DataElementToFidl(
368     const bt::sdp::DataElement& data_element) {
369   fbredr::DataElement out;
370   switch (data_element.type()) {
371     case bt::sdp::DataElement::Type::kNull:
372       return std::nullopt;
373     case bt::sdp::DataElement::Type::kUnsignedInt:
374       switch (data_element.size()) {
375         case bt::sdp::DataElement::Size::kOneByte:
376           out.set_uint8(*data_element.Get<uint8_t>());
377           break;
378         case bt::sdp::DataElement::Size::kTwoBytes:
379           out.set_uint16(*data_element.Get<uint16_t>());
380           break;
381         case bt::sdp::DataElement::Size::kFourBytes:
382           out.set_uint32(*data_element.Get<uint32_t>());
383           break;
384         case bt::sdp::DataElement::Size::kEightBytes:
385           out.set_uint64(*data_element.Get<uint64_t>());
386           break;
387         case bt::sdp::DataElement::Size::kSixteenBytes:
388         case bt::sdp::DataElement::Size::kNextOne:
389         case bt::sdp::DataElement::Size::kNextTwo:
390         case bt::sdp::DataElement::Size::kNextFour:
391           bt_log(
392               WARN, "fidl", "Encountered DataElementToFidl type not handled.");
393           return std::nullopt;
394       }
395       break;
396     case bt::sdp::DataElement::Type::kSignedInt:
397       switch (data_element.size()) {
398         case bt::sdp::DataElement::Size::kOneByte:
399           out.set_int8(*data_element.Get<int8_t>());
400           break;
401         case bt::sdp::DataElement::Size::kTwoBytes:
402           out.set_int16(*data_element.Get<int16_t>());
403           break;
404         case bt::sdp::DataElement::Size::kFourBytes:
405           out.set_int32(*data_element.Get<int32_t>());
406           break;
407         case bt::sdp::DataElement::Size::kEightBytes:
408           out.set_int64(*data_element.Get<int64_t>());
409           break;
410         case bt::sdp::DataElement::Size::kSixteenBytes:
411         case bt::sdp::DataElement::Size::kNextOne:
412         case bt::sdp::DataElement::Size::kNextTwo:
413         case bt::sdp::DataElement::Size::kNextFour:
414           bt_log(
415               WARN, "fidl", "Encountered DataElementToFidl type not handled.");
416           return std::nullopt;
417       }
418       break;
419     case bt::sdp::DataElement::Type::kUuid:
420       out.set_uuid(UuidToFidl(*data_element.Get<bt::UUID>()));
421       break;
422     case bt::sdp::DataElement::Type::kString:
423       out.set_str(data_element.Get<bt::DynamicByteBuffer>()->ToVector());
424       break;
425     case bt::sdp::DataElement::Type::kBoolean:
426       out.set_b(*data_element.Get<bool>());
427       break;
428     case bt::sdp::DataElement::Type::kSequence: {
429       std::vector<std::unique_ptr<fbredr::DataElement>> seq;
430       auto data_element_sequence =
431           data_element.Get<std::vector<bt::sdp::DataElement>>();
432       for (const auto& elem : data_element_sequence.value()) {
433         std::optional<fbredr::DataElement> fidl_elem = DataElementToFidl(elem);
434         if (!fidl_elem) {
435           bt_log(WARN,
436                  "fidl",
437                  "Encountered DataElementToFidl sequence type not handled.");
438           return std::nullopt;
439         }
440         seq.emplace_back(std::make_unique<fbredr::DataElement>(
441             std::move(fidl_elem.value())));
442       }
443       out.set_sequence(std::move(seq));
444       break;
445     }
446     case bt::sdp::DataElement::Type::kAlternative: {
447       std::vector<std::unique_ptr<fbredr::DataElement>> alt;
448       auto data_element_alt =
449           data_element.Get<std::vector<bt::sdp::DataElement>>();
450       for (const auto& elem : data_element_alt.value()) {
451         std::optional<fbredr::DataElement> fidl_elem = DataElementToFidl(elem);
452         if (!fidl_elem) {
453           bt_log(WARN,
454                  "fidl",
455                  "Encountered DataElementToFidl alternate type not handled.");
456           return std::nullopt;
457         }
458         alt.emplace_back(std::make_unique<fbredr::DataElement>(
459             std::move(fidl_elem.value())));
460       }
461       out.set_alternatives(std::move(alt));
462       break;
463     }
464     case bt::sdp::DataElement::Type::kUrl:
465       out.set_url(*data_element.GetUrl());
466       break;
467   }
468   return out;
469 }
470 
471 namespace {
472 
AddressTypeToFidl(bt::DeviceAddress::Type type)473 fbt::AddressType AddressTypeToFidl(bt::DeviceAddress::Type type) {
474   switch (type) {
475     case bt::DeviceAddress::Type::kBREDR:
476       [[fallthrough]];
477     case bt::DeviceAddress::Type::kLEPublic:
478       return fbt::AddressType::PUBLIC;
479     case bt::DeviceAddress::Type::kLERandom:
480       [[fallthrough]];
481     case bt::DeviceAddress::Type::kLEAnonymous:
482       return fbt::AddressType::RANDOM;
483   }
484   return fbt::AddressType::PUBLIC;
485 }
486 
AddressToFidl(fbt::AddressType type,const bt::DeviceAddressBytes & value)487 fbt::Address AddressToFidl(fbt::AddressType type,
488                            const bt::DeviceAddressBytes& value) {
489   fbt::Address output;
490   output.type = type;
491   bt::MutableBufferView value_dst(output.bytes.data(), output.bytes.size());
492   value_dst.Write(value.bytes());
493   return output;
494 }
495 
AddressToFidl(const bt::DeviceAddress & input)496 fbt::Address AddressToFidl(const bt::DeviceAddress& input) {
497   return AddressToFidl(AddressTypeToFidl(input.type()), input.value());
498 }
499 
SecurityPropsFromFidl(const fsys::SecurityProperties & sec_prop)500 bt::sm::SecurityProperties SecurityPropsFromFidl(
501     const fsys::SecurityProperties& sec_prop) {
502   auto level = bt::sm::SecurityLevel::kEncrypted;
503   if (sec_prop.authenticated) {
504     level = bt::sm::SecurityLevel::kAuthenticated;
505   }
506   return bt::sm::SecurityProperties(
507       level, sec_prop.encryption_key_size, sec_prop.secure_connections);
508 }
509 
SecurityPropsToFidl(const bt::sm::SecurityProperties & sec_prop)510 fsys::SecurityProperties SecurityPropsToFidl(
511     const bt::sm::SecurityProperties& sec_prop) {
512   return fsys::SecurityProperties{
513       .authenticated = sec_prop.authenticated(),
514       .secure_connections = sec_prop.secure_connections(),
515 
516       // TODO(armansito): Declare the key size as uint8_t in bt::sm?
517       .encryption_key_size = static_cast<uint8_t>(sec_prop.enc_key_size()),
518   };
519 }
520 
LtkFromFidl(const fsys::Ltk & ltk)521 bt::sm::LTK LtkFromFidl(const fsys::Ltk& ltk) {
522   return bt::sm::LTK(
523       SecurityPropsFromFidl(ltk.key.security),
524       bt::hci_spec::LinkKey(ltk.key.data.value, ltk.rand, ltk.ediv));
525 }
526 
LtkToFidlPeerKey(const bt::sm::LTK & ltk)527 fsys::PeerKey LtkToFidlPeerKey(const bt::sm::LTK& ltk) {
528   return fsys::PeerKey{
529       .security = SecurityPropsToFidl(ltk.security()),
530       .data = fsys::Key{ltk.key().value()},
531   };
532 }
533 
LtkToFidl(const bt::sm::LTK & ltk)534 fsys::Ltk LtkToFidl(const bt::sm::LTK& ltk) {
535   return fsys::Ltk{
536       .key = LtkToFidlPeerKey(ltk),
537       .ediv = ltk.key().ediv(),
538       .rand = ltk.key().rand(),
539   };
540 }
541 
PeerKeyFromFidl(const fsys::PeerKey & key)542 bt::sm::Key PeerKeyFromFidl(const fsys::PeerKey& key) {
543   return bt::sm::Key(SecurityPropsFromFidl(key.security), key.data.value);
544 }
545 
PeerKeyToFidl(const bt::sm::Key & key)546 fsys::PeerKey PeerKeyToFidl(const bt::sm::Key& key) {
547   return fsys::PeerKey{
548       .security = SecurityPropsToFidl(key.security()),
549       .data = {key.value()},
550   };
551 }
552 
DeviceClassToFidl(bt::DeviceClass input)553 fbt::DeviceClass DeviceClassToFidl(bt::DeviceClass input) {
554   auto bytes = input.bytes();
555   fbt::DeviceClass output{static_cast<uint32_t>(
556       bytes[0] | (bytes[1] << BIT_SHIFT_8) | (bytes[2] << BIT_SHIFT_16))};
557   return output;
558 }
559 
560 std::optional<fbredr::ServiceClassProfileIdentifier>
UuidToServiceClassIdentifier(const bt::UUID uuid)561 UuidToServiceClassIdentifier(const bt::UUID uuid) {
562   std::optional<uint16_t> uuid_16 = uuid.As16Bit();
563   if (!uuid_16) {
564     return std::nullopt;
565   }
566   return fbredr::ServiceClassProfileIdentifier(*uuid_16);
567 }
568 
UuidToProtocolIdentifier(const bt::UUID uuid)569 std::optional<fbredr::ProtocolIdentifier> UuidToProtocolIdentifier(
570     const bt::UUID uuid) {
571   std::optional<uint16_t> uuid_16 = uuid.As16Bit();
572   if (!uuid_16) {
573     return std::nullopt;
574   }
575   return fbredr::ProtocolIdentifier(*uuid_16);
576 }
577 
InformationToFidl(const bt::sdp::ServiceRecord::Information & info)578 fbredr::Information InformationToFidl(
579     const bt::sdp::ServiceRecord::Information& info) {
580   fbredr::Information out;
581   out.set_language(info.language_code);
582   if (info.name) {
583     out.set_name(info.name.value());
584   }
585   if (info.description) {
586     out.set_description(info.description.value());
587   }
588   if (info.provider) {
589     out.set_provider(info.provider.value());
590   }
591   return out;
592 }
593 
594 fpromise::result<std::vector<fuchsia::bluetooth::Uuid>,
595                  fuchsia::bluetooth::ErrorCode>
DataElementToServiceUuids(const bt::sdp::DataElement & uuids_element)596 DataElementToServiceUuids(const bt::sdp::DataElement& uuids_element) {
597   std::vector<fuchsia::bluetooth::Uuid> out;
598 
599   const auto service_uuids_list =
600       uuids_element.Get<std::vector<bt::sdp::DataElement>>();
601   if (!service_uuids_list) {
602     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
603   }
604 
605   for (const auto& uuid_element : service_uuids_list.value()) {
606     if (uuid_element.type() != bt::sdp::DataElement::Type::kUuid) {
607       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
608     }
609     out.push_back(UuidToFidl(*uuid_element.Get<bt::UUID>()));
610   }
611 
612   return fpromise::ok(std::move(out));
613 }
614 
615 fpromise::result<std::vector<fbredr::ProtocolDescriptor>,
616                  fuchsia::bluetooth::ErrorCode>
DataElementToProtocolDescriptorList(const bt::sdp::DataElement & protocols_element)617 DataElementToProtocolDescriptorList(
618     const bt::sdp::DataElement& protocols_element) {
619   std::vector<fbredr::ProtocolDescriptor> out;
620 
621   const auto protocol_list =
622       protocols_element.Get<std::vector<bt::sdp::DataElement>>();
623   if (!protocol_list) {
624     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
625   }
626 
627   for (const auto& protocol_elt : protocol_list.value()) {
628     if (protocol_elt.type() != bt::sdp::DataElement::Type::kSequence) {
629       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
630     }
631 
632     const auto protocol =
633         protocol_elt.Get<std::vector<bt::sdp::DataElement>>().value();
634     if (protocol.size() < 1 ||
635         protocol.at(0).type() != bt::sdp::DataElement::Type::kUuid) {
636       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
637     }
638 
639     fbredr::ProtocolDescriptor desc;
640     std::vector<fbredr::DataElement> params;
641     for (size_t i = 0; i < protocol.size(); i++) {
642       if (i == 0) {
643         std::optional<fbredr::ProtocolIdentifier> protocol_id =
644             UuidToProtocolIdentifier((protocol.at(i).Get<bt::UUID>()).value());
645         if (!protocol_id) {
646           return fpromise::error(
647               fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
648         }
649         desc.set_protocol(protocol_id.value());
650       } else {
651         std::optional<fbredr::DataElement> param =
652             DataElementToFidl(protocol.at(i));
653         if (!param) {
654           return fpromise::error(
655               fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
656         }
657         params.emplace_back(std::move(*param));
658       }
659     }
660     desc.set_params(std::move(params));
661     out.emplace_back(std::move(desc));
662   }
663 
664   return fpromise::ok(std::move(out));
665 }
666 
667 // Returns the major and minor versions from a combined |version|.
VersionToMajorMinor(uint16_t version)668 std::pair<uint8_t, uint8_t> VersionToMajorMinor(uint16_t version) {
669   const uint16_t kMajorBitmask = 0xFF00;
670   const uint16_t kMinorBitmask = 0x00FF;
671   uint8_t major = static_cast<uint8_t>((version & kMajorBitmask) >>
672                                        std::numeric_limits<uint8_t>::digits);
673   uint8_t minor = static_cast<uint8_t>(version & kMinorBitmask);
674   return std::make_pair(major, minor);
675 }
676 
677 fpromise::result<std::vector<fbredr::ProfileDescriptor>,
678                  fuchsia::bluetooth::ErrorCode>
DataElementToProfileDescriptors(const bt::sdp::DataElement & profile_element)679 DataElementToProfileDescriptors(const bt::sdp::DataElement& profile_element) {
680   std::vector<fbredr::ProfileDescriptor> out;
681 
682   const auto profile_desc_list =
683       profile_element.Get<std::vector<bt::sdp::DataElement>>();
684   if (!profile_desc_list) {
685     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
686   }
687 
688   // [[UUID, Version]]
689   for (const auto& profile_desc_element : (*profile_desc_list)) {
690     if (profile_desc_element.type() != bt::sdp::DataElement::Type::kSequence) {
691       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
692     }
693 
694     // Each profile descriptor entry contains a UUID and uint16_t version.
695     const auto profile_desc =
696         *profile_desc_element.Get<std::vector<bt::sdp::DataElement>>();
697     if (profile_desc.size() != 2) {
698       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
699     }
700 
701     std::optional<bt::UUID> profile_id = profile_desc.at(0).Get<bt::UUID>();
702     std::optional<uint16_t> version = profile_desc.at(1).Get<uint16_t>();
703     if (!profile_id || !version) {
704       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
705     }
706 
707     fbredr::ProfileDescriptor desc;
708     std::optional<fbredr::ServiceClassProfileIdentifier> service_class_id =
709         UuidToServiceClassIdentifier(*profile_id);
710     if (!service_class_id) {
711       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
712     }
713     desc.set_profile_id(service_class_id.value());
714     auto [major, minor] = VersionToMajorMinor(version.value());
715     desc.set_major_version(major);
716     desc.set_minor_version(minor);
717     out.push_back(std::move(desc));
718   }
719 
720   return fpromise::ok(std::move(out));
721 }
722 
NewAddProtocolDescriptorList(bt::sdp::ServiceRecord * rec,bt::sdp::ServiceRecord::ProtocolListId id,const std::vector<fuchsia_bluetooth_bredr::ProtocolDescriptor> & descriptor_list)723 bool NewAddProtocolDescriptorList(
724     bt::sdp::ServiceRecord* rec,
725     bt::sdp::ServiceRecord::ProtocolListId id,
726     const std::vector<fuchsia_bluetooth_bredr::ProtocolDescriptor>&
727         descriptor_list) {
728   bt_log(TRACE, "fidl", "ProtocolDescriptorList %d", id);
729   for (auto& descriptor : descriptor_list) {
730     if (!descriptor.params().has_value() ||
731         !descriptor.protocol().has_value()) {
732       return false;
733     }
734     bt::sdp::DataElement protocol_params;
735     if (descriptor.params()->size() > 1) {
736       std::vector<bt::sdp::DataElement> params;
737       for (auto& fidl_param : *descriptor.params()) {
738         auto bt_param = NewFidlToDataElement(fidl_param);
739         if (bt_param) {
740           params.emplace_back(std::move(bt_param.value()));
741         } else {
742           return false;
743         }
744       }
745       protocol_params.Set(std::move(params));
746     } else if (descriptor.params()->size() == 1) {
747       auto param = NewFidlToDataElement(descriptor.params()->front());
748       if (param) {
749         protocol_params = std::move(param).value();
750       } else {
751         return false;
752       }
753       protocol_params =
754           NewFidlToDataElement(descriptor.params()->front()).value();
755     }
756 
757     bt_log(TRACE,
758            "fidl",
759            "Adding protocol descriptor: {%d : %s}",
760            fidl::ToUnderlying(*descriptor.protocol()),
761            protocol_params.ToString().c_str());
762     rec->AddProtocolDescriptor(
763         id,
764         bt::UUID(static_cast<uint16_t>(*descriptor.protocol())),
765         std::move(protocol_params));
766   }
767   return true;
768 }
769 
AddProtocolDescriptorList(bt::sdp::ServiceRecord * rec,bt::sdp::ServiceRecord::ProtocolListId id,const::std::vector<fbredr::ProtocolDescriptor> & descriptor_list)770 bool AddProtocolDescriptorList(
771     bt::sdp::ServiceRecord* rec,
772     bt::sdp::ServiceRecord::ProtocolListId id,
773     const ::std::vector<fbredr::ProtocolDescriptor>& descriptor_list) {
774   bt_log(TRACE, "fidl", "ProtocolDescriptorList %d", id);
775   for (auto& descriptor : descriptor_list) {
776     bt::sdp::DataElement protocol_params;
777     if (!descriptor.has_params() || !descriptor.has_protocol()) {
778       bt_log(WARN, "fidl", "ProtocolDescriptor missing params/protocol field");
779       return false;
780     }
781     if (descriptor.params().size() > 1) {
782       std::vector<bt::sdp::DataElement> params;
783       for (auto& fidl_param : descriptor.params()) {
784         auto bt_param = FidlToDataElement(fidl_param);
785         if (bt_param) {
786           params.emplace_back(std::move(bt_param.value()));
787         } else {
788           return false;
789         }
790       }
791       protocol_params.Set(std::move(params));
792     } else if (descriptor.params().size() == 1) {
793       auto param = FidlToDataElement(descriptor.params().front());
794       if (param) {
795         protocol_params = std::move(param).value();
796       } else {
797         return false;
798       }
799       protocol_params = FidlToDataElement(descriptor.params().front()).value();
800     }
801 
802     bt_log(TRACE,
803            "fidl",
804            "Adding protocol descriptor: {%d : %s}",
805            uint16_t(descriptor.protocol()),
806            bt_str(protocol_params));
807     rec->AddProtocolDescriptor(
808         id,
809         bt::UUID(static_cast<uint16_t>(descriptor.protocol())),
810         std::move(protocol_params));
811   }
812   return true;
813 }
814 
815 // Returns true if the appearance value (in host byte order) is included in
816 // fuchsia.bluetooth.Appearance, which is a subset of Bluetooth Assigned
817 // Numbers, "Appearance Values"
818 // (https://www.bluetooth.com/specifications/assigned-numbers/).
819 //
820 // TODO(fxbug.dev/42145156): Remove this compatibility check with the strict
821 // Appearance enum.
IsAppearanceValid(uint16_t appearance_raw)822 [[nodiscard]] bool IsAppearanceValid(uint16_t appearance_raw) {
823   switch (appearance_raw) {
824     case 0u:  // UNKNOWN
825       [[fallthrough]];
826     case 64u:  // PHONE
827       [[fallthrough]];
828     case 128u:  // COMPUTER
829       [[fallthrough]];
830     case 192u:  // WATCH
831       [[fallthrough]];
832     case 193u:  // WATCH_SPORTS
833       [[fallthrough]];
834     case 256u:  // CLOCK
835       [[fallthrough]];
836     case 320u:  // DISPLAY
837       [[fallthrough]];
838     case 384u:  // REMOTE_CONTROL
839       [[fallthrough]];
840     case 448u:  // EYE_GLASSES
841       [[fallthrough]];
842     case 512u:  // TAG
843       [[fallthrough]];
844     case 576u:  // KEYRING
845       [[fallthrough]];
846     case 640u:  // MEDIA_PLAYER
847       [[fallthrough]];
848     case 704u:  // BARCODE_SCANNER
849       [[fallthrough]];
850     case 768u:  // THERMOMETER
851       [[fallthrough]];
852     case 769u:  // THERMOMETER_EAR
853       [[fallthrough]];
854     case 832u:  // HEART_RATE_SENSOR
855       [[fallthrough]];
856     case 833u:  // HEART_RATE_SENSOR_BELT
857       [[fallthrough]];
858     case 896u:  // BLOOD_PRESSURE
859       [[fallthrough]];
860     case 897u:  // BLOOD_PRESSURE_ARM
861       [[fallthrough]];
862     case 898u:  // BLOOD_PRESSURE_WRIST
863       [[fallthrough]];
864     case 960u:  // HID
865       [[fallthrough]];
866     case 961u:  // HID_KEYBOARD
867       [[fallthrough]];
868     case 962u:  // HID_MOUSE
869       [[fallthrough]];
870     case 963u:  // HID_JOYSTICK
871       [[fallthrough]];
872     case 964u:  // HID_GAMEPAD
873       [[fallthrough]];
874     case 965u:  // HID_DIGITIZER_TABLET
875       [[fallthrough]];
876     case 966u:  // HID_CARD_READER
877       [[fallthrough]];
878     case 967u:  // HID_DIGITAL_PEN
879       [[fallthrough]];
880     case 968u:  // HID_BARCODE_SCANNER
881       [[fallthrough]];
882     case 1024u:  // GLUCOSE_METER
883       [[fallthrough]];
884     case 1088u:  // RUNNING_WALKING_SENSOR
885       [[fallthrough]];
886     case 1089u:  // RUNNING_WALKING_SENSOR_IN_SHOE
887       [[fallthrough]];
888     case 1090u:  // RUNNING_WALKING_SENSOR_ON_SHOE
889       [[fallthrough]];
890     case 1091u:  // RUNNING_WALKING_SENSOR_ON_HIP
891       [[fallthrough]];
892     case 1152u:  // CYCLING
893       [[fallthrough]];
894     case 1153u:  // CYCLING_COMPUTER
895       [[fallthrough]];
896     case 1154u:  // CYCLING_SPEED_SENSOR
897       [[fallthrough]];
898     case 1155u:  // CYCLING_CADENCE_SENSOR
899       [[fallthrough]];
900     case 1156u:  // CYCLING_POWER_SENSOR
901       [[fallthrough]];
902     case 1157u:  // CYCLING_SPEED_AND_CADENCE_SENSOR
903       [[fallthrough]];
904     case 3136u:  // PULSE_OXIMETER
905       [[fallthrough]];
906     case 3137u:  // PULSE_OXIMETER_FINGERTIP
907       [[fallthrough]];
908     case 3138u:  // PULSE_OXIMETER_WRIST
909       [[fallthrough]];
910     case 3200u:  // WEIGHT_SCALE
911       [[fallthrough]];
912     case 3264u:  // PERSONAL_MOBILITY
913       [[fallthrough]];
914     case 3265u:  // PERSONAL_MOBILITY_WHEELCHAIR
915       [[fallthrough]];
916     case 3266u:  // PERSONAL_MOBILITY_SCOOTER
917       [[fallthrough]];
918     case 3328u:  // GLUCOSE_MONITOR
919       [[fallthrough]];
920     case 5184u:  // SPORTS_ACTIVITY
921       [[fallthrough]];
922     case 5185u:  // SPORTS_ACTIVITY_LOCATION_DISPLAY
923       [[fallthrough]];
924     case 5186u:  // SPORTS_ACTIVITY_LOCATION_AND_NAV_DISPLAY
925       [[fallthrough]];
926     case 5187u:  // SPORTS_ACTIVITY_LOCATION_POD
927       [[fallthrough]];
928     case 5188u:  // SPORTS_ACTIVITY_LOCATION_AND_NAV_POD
929       return true;
930     default:
931       return false;
932   }
933 }
934 
AppearanceToFidl(uint16_t appearance_raw)935 [[nodiscard]] std::optional<fbt::Appearance> AppearanceToFidl(
936     uint16_t appearance_raw) {
937   if (IsAppearanceValid(appearance_raw)) {
938     return static_cast<fbt::Appearance>(appearance_raw);
939   }
940   return std::nullopt;
941 }
942 
943 }  // namespace
944 
PeerIdFromString(const std::string & id)945 std::optional<bt::PeerId> PeerIdFromString(const std::string& id) {
946   if (id.empty()) {
947     return std::nullopt;
948   }
949 
950   uint64_t value = 0;
951   auto [_, error] =
952       std::from_chars(id.data(), id.data() + id.size(), value, /*base=*/16);
953   if (error != std::errc()) {
954     return std::nullopt;
955   }
956   return bt::PeerId(value);
957 }
958 
HostErrorToFidlDeprecated(bt::HostError host_error)959 ErrorCode HostErrorToFidlDeprecated(bt::HostError host_error) {
960   switch (host_error) {
961     case bt::HostError::kFailed:
962       return ErrorCode::FAILED;
963     case bt::HostError::kTimedOut:
964       return ErrorCode::TIMED_OUT;
965     case bt::HostError::kInvalidParameters:
966       return ErrorCode::INVALID_ARGUMENTS;
967     case bt::HostError::kCanceled:
968       return ErrorCode::CANCELED;
969     case bt::HostError::kInProgress:
970       return ErrorCode::IN_PROGRESS;
971     case bt::HostError::kNotSupported:
972       return ErrorCode::NOT_SUPPORTED;
973     case bt::HostError::kNotFound:
974       return ErrorCode::NOT_FOUND;
975     default:
976       break;
977   }
978 
979   return ErrorCode::FAILED;
980 }
981 
NewFidlError(ErrorCode error_code,const std::string & description)982 Status NewFidlError(ErrorCode error_code, const std::string& description) {
983   Status status;
984   status.error = std::make_unique<Error>();
985   status.error->error_code = error_code;
986   status.error->description = description;
987   return status;
988 }
989 
HostErrorToFidl(bt::HostError error)990 fsys::Error HostErrorToFidl(bt::HostError error) {
991   switch (error) {
992     case bt::HostError::kFailed:
993       return fsys::Error::FAILED;
994     case bt::HostError::kTimedOut:
995       return fsys::Error::TIMED_OUT;
996     case bt::HostError::kInvalidParameters:
997       return fsys::Error::INVALID_ARGUMENTS;
998     case bt::HostError::kCanceled:
999       return fsys::Error::CANCELED;
1000     case bt::HostError::kInProgress:
1001       return fsys::Error::IN_PROGRESS;
1002     case bt::HostError::kNotSupported:
1003       return fsys::Error::NOT_SUPPORTED;
1004     case bt::HostError::kNotFound:
1005       return fsys::Error::PEER_NOT_FOUND;
1006     default:
1007       break;
1008   }
1009   return fsys::Error::FAILED;
1010 }
1011 
GattErrorToFidl(const bt::att::Error & error)1012 fuchsia::bluetooth::gatt::Error GattErrorToFidl(const bt::att::Error& error) {
1013   return error.Visit(
1014       [](bt::HostError host_error) {
1015         return host_error == bt::HostError::kPacketMalformed
1016                    ? fuchsia::bluetooth::gatt::Error::INVALID_RESPONSE
1017                    : fuchsia::bluetooth::gatt::Error::FAILURE;
1018       },
1019       [](bt::att::ErrorCode att_error) {
1020         switch (att_error) {
1021           case bt::att::ErrorCode::kInsufficientAuthorization:
1022             return fuchsia::bluetooth::gatt::Error::INSUFFICIENT_AUTHORIZATION;
1023           case bt::att::ErrorCode::kInsufficientAuthentication:
1024             return fuchsia::bluetooth::gatt::Error::INSUFFICIENT_AUTHENTICATION;
1025           case bt::att::ErrorCode::kInsufficientEncryptionKeySize:
1026             return fuchsia::bluetooth::gatt::Error::
1027                 INSUFFICIENT_ENCRYPTION_KEY_SIZE;
1028           case bt::att::ErrorCode::kInsufficientEncryption:
1029             return fuchsia::bluetooth::gatt::Error::INSUFFICIENT_ENCRYPTION;
1030           case bt::att::ErrorCode::kReadNotPermitted:
1031             return fuchsia::bluetooth::gatt::Error::READ_NOT_PERMITTED;
1032           default:
1033             break;
1034         }
1035         return fuchsia::bluetooth::gatt::Error::FAILURE;
1036       });
1037 }
1038 
AttErrorToGattFidlError(const bt::att::Error & error)1039 fuchsia::bluetooth::gatt2::Error AttErrorToGattFidlError(
1040     const bt::att::Error& error) {
1041   return error.Visit(
1042       [](bt::HostError host_error) {
1043         switch (host_error) {
1044           case bt::HostError::kPacketMalformed:
1045             return fuchsia::bluetooth::gatt2::Error::INVALID_PDU;
1046           case bt::HostError::kInvalidParameters:
1047             return fuchsia::bluetooth::gatt2::Error::INVALID_PARAMETERS;
1048           default:
1049             break;
1050         }
1051         return fuchsia::bluetooth::gatt2::Error::UNLIKELY_ERROR;
1052       },
1053       [](bt::att::ErrorCode att_error) {
1054         switch (att_error) {
1055           case bt::att::ErrorCode::kInsufficientAuthorization:
1056             return fuchsia::bluetooth::gatt2::Error::INSUFFICIENT_AUTHORIZATION;
1057           case bt::att::ErrorCode::kInsufficientAuthentication:
1058             return fuchsia::bluetooth::gatt2::Error::
1059                 INSUFFICIENT_AUTHENTICATION;
1060           case bt::att::ErrorCode::kInsufficientEncryptionKeySize:
1061             return fuchsia::bluetooth::gatt2::Error::
1062                 INSUFFICIENT_ENCRYPTION_KEY_SIZE;
1063           case bt::att::ErrorCode::kInsufficientEncryption:
1064             return fuchsia::bluetooth::gatt2::Error::INSUFFICIENT_ENCRYPTION;
1065           case bt::att::ErrorCode::kReadNotPermitted:
1066             return fuchsia::bluetooth::gatt2::Error::READ_NOT_PERMITTED;
1067           case bt::att::ErrorCode::kInvalidHandle:
1068             return fuchsia::bluetooth::gatt2::Error::INVALID_HANDLE;
1069           default:
1070             break;
1071         }
1072         return fuchsia::bluetooth::gatt2::Error::UNLIKELY_ERROR;
1073       });
1074 }
1075 
UuidFromFidl(const fuchsia::bluetooth::Uuid & input)1076 bt::UUID UuidFromFidl(const fuchsia::bluetooth::Uuid& input) {
1077   // Conversion must always succeed given the defined size of |input|.
1078   static_assert(sizeof(input.value) == 16, "FIDL UUID definition malformed!");
1079   return bt::UUID(bt::BufferView(input.value.data(), input.value.size()));
1080 }
1081 
UuidToFidl(const bt::UUID & uuid)1082 fuchsia::bluetooth::Uuid UuidToFidl(const bt::UUID& uuid) {
1083   fuchsia::bluetooth::Uuid output;
1084   // Conversion must always succeed given the defined size of |input|.
1085   static_assert(sizeof(output.value) == 16, "FIDL UUID definition malformed!");
1086   output.value = uuid.value();
1087   return output;
1088 }
1089 
NewUuidFromFidl(const fuchsia_bluetooth::Uuid & input)1090 bt::UUID NewUuidFromFidl(const fuchsia_bluetooth::Uuid& input) {
1091   // Conversion must always succeed given the defined size of |input|.
1092   static_assert(sizeof(input.value()) == 16, "FIDL UUID definition malformed!");
1093   return bt::UUID(bt::BufferView(input.value().data(), input.value().size()));
1094 }
1095 
IoCapabilityFromFidl(fsys::InputCapability input,fsys::OutputCapability output)1096 bt::sm::IOCapability IoCapabilityFromFidl(fsys::InputCapability input,
1097                                           fsys::OutputCapability output) {
1098   if (input == fsys::InputCapability::NONE &&
1099       output == fsys::OutputCapability::NONE) {
1100     return bt::sm::IOCapability::kNoInputNoOutput;
1101   }
1102 
1103   if (input == fsys::InputCapability::KEYBOARD &&
1104       output == fsys::OutputCapability::DISPLAY) {
1105     return bt::sm::IOCapability::kKeyboardDisplay;
1106   }
1107 
1108   if (input == fsys::InputCapability::KEYBOARD &&
1109       output == fsys::OutputCapability::NONE) {
1110     return bt::sm::IOCapability::kKeyboardOnly;
1111   }
1112 
1113   if (input == fsys::InputCapability::NONE &&
1114       output == fsys::OutputCapability::DISPLAY) {
1115     return bt::sm::IOCapability::kDisplayOnly;
1116   }
1117 
1118   if (input == fsys::InputCapability::CONFIRMATION &&
1119       output == fsys::OutputCapability::DISPLAY) {
1120     return bt::sm::IOCapability::kDisplayYesNo;
1121   }
1122 
1123   return bt::sm::IOCapability::kNoInputNoOutput;
1124 }
1125 
BrEdrSecurityModeFromFidl(const fsys::BrEdrSecurityMode mode)1126 std::optional<bt::gap::BrEdrSecurityMode> BrEdrSecurityModeFromFidl(
1127     const fsys::BrEdrSecurityMode mode) {
1128   switch (mode) {
1129     case fsys::BrEdrSecurityMode::MODE_4:
1130       return bt::gap::BrEdrSecurityMode::Mode4;
1131     case fsys::BrEdrSecurityMode::SECURE_CONNECTIONS_ONLY:
1132       return bt::gap::BrEdrSecurityMode::SecureConnectionsOnly;
1133     default:
1134       bt_log(WARN, "fidl", "BR/EDR security mode not recognized");
1135       return std::nullopt;
1136   }
1137 }
1138 
LeSecurityModeFromFidl(const fsys::LeSecurityMode mode)1139 bt::gap::LESecurityMode LeSecurityModeFromFidl(
1140     const fsys::LeSecurityMode mode) {
1141   switch (mode) {
1142     case fsys::LeSecurityMode::MODE_1:
1143       return bt::gap::LESecurityMode::Mode1;
1144     case fsys::LeSecurityMode::SECURE_CONNECTIONS_ONLY:
1145       return bt::gap::LESecurityMode::SecureConnectionsOnly;
1146   }
1147   bt_log(
1148       WARN,
1149       "fidl",
1150       "FIDL security mode not recognized, defaulting to SecureConnectionsOnly");
1151   return bt::gap::LESecurityMode::SecureConnectionsOnly;
1152 }
1153 
SecurityLevelFromFidl(const fsys::PairingSecurityLevel level)1154 std::optional<bt::sm::SecurityLevel> SecurityLevelFromFidl(
1155     const fsys::PairingSecurityLevel level) {
1156   switch (level) {
1157     case fsys::PairingSecurityLevel::ENCRYPTED:
1158       return bt::sm::SecurityLevel::kEncrypted;
1159     case fsys::PairingSecurityLevel::AUTHENTICATED:
1160       return bt::sm::SecurityLevel::kAuthenticated;
1161     default:
1162       return std::nullopt;
1163   };
1164 }
1165 
TechnologyTypeToFidl(bt::gap::TechnologyType type)1166 fsys::TechnologyType TechnologyTypeToFidl(bt::gap::TechnologyType type) {
1167   switch (type) {
1168     case bt::gap::TechnologyType::kLowEnergy:
1169       return fsys::TechnologyType::LOW_ENERGY;
1170     case bt::gap::TechnologyType::kClassic:
1171       return fsys::TechnologyType::CLASSIC;
1172     case bt::gap::TechnologyType::kDualMode:
1173       return fsys::TechnologyType::DUAL_MODE;
1174     default:
1175       PW_CRASH("invalid technology type: %u", static_cast<unsigned int>(type));
1176       break;
1177   }
1178 
1179   // This should never execute.
1180   return fsys::TechnologyType::DUAL_MODE;
1181 }
1182 
HostInfoToFidl(const bt::gap::Adapter & adapter)1183 fsys::HostInfo HostInfoToFidl(const bt::gap::Adapter& adapter) {
1184   fsys::HostInfo info;
1185   info.set_id(fbt::HostId{adapter.identifier().value()});
1186   info.set_technology(TechnologyTypeToFidl(adapter.state().type()));
1187   info.set_local_name(adapter.local_name());
1188   info.set_discoverable(adapter.IsDiscoverable());
1189   info.set_discovering(adapter.IsDiscovering());
1190   std::vector<fbt::Address> addresses;
1191   addresses.emplace_back(AddressToFidl(fbt::AddressType::PUBLIC,
1192                                        adapter.state().controller_address));
1193   if (adapter.le() && adapter.le()->PrivacyEnabled() &&
1194       (!adapter.le()->CurrentAddress().IsPublic())) {
1195     addresses.emplace_back(AddressToFidl(adapter.le()->CurrentAddress()));
1196   }
1197   info.set_addresses(std::move(addresses));
1198   return info;
1199 }
1200 
PeerToFidl(const bt::gap::Peer & peer)1201 fsys::Peer PeerToFidl(const bt::gap::Peer& peer) {
1202   fsys::Peer output;
1203   output.set_id(fbt::PeerId{peer.identifier().value()});
1204   output.set_address(AddressToFidl(peer.address()));
1205   output.set_technology(TechnologyTypeToFidl(peer.technology()));
1206   output.set_connected(peer.connected());
1207   output.set_bonded(peer.bonded());
1208 
1209   if (peer.name()) {
1210     output.set_name(*peer.name());
1211   }
1212 
1213   if (peer.le()) {
1214     const std::optional<std::reference_wrapper<const bt::AdvertisingData>>
1215         adv_data = peer.le()->parsed_advertising_data();
1216     if (adv_data.has_value()) {
1217       if (adv_data->get().appearance().has_value()) {
1218         if (auto appearance =
1219                 AppearanceToFidl(adv_data->get().appearance().value())) {
1220           output.set_appearance(appearance.value());
1221         } else {
1222           bt_log(DEBUG,
1223                  "fidl",
1224                  "omitting unencodeable appearance %#.4x of peer %s",
1225                  adv_data->get().appearance().value(),
1226                  bt_str(peer.identifier()));
1227         }
1228       }
1229       if (adv_data->get().tx_power()) {
1230         output.set_tx_power(adv_data->get().tx_power().value());
1231       }
1232     }
1233   }
1234   if (peer.bredr() && peer.bredr()->device_class()) {
1235     output.set_device_class(DeviceClassToFidl(*peer.bredr()->device_class()));
1236   }
1237   if (peer.rssi() != bt::hci_spec::kRSSIInvalid) {
1238     output.set_rssi(peer.rssi());
1239   }
1240 
1241   if (peer.bredr()) {
1242     std::transform(peer.bredr()->services().begin(),
1243                    peer.bredr()->services().end(),
1244                    std::back_inserter(*output.mutable_bredr_services()),
1245                    UuidToFidl);
1246   }
1247 
1248   // TODO(fxbug.dev/42135180): Populate le_service UUIDs based on GATT results
1249   // as well as advertising and inquiry data.
1250 
1251   return output;
1252 }
1253 
AddressFromFidlBondingData(const fuchsia::bluetooth::sys::BondingData & bond)1254 std::optional<bt::DeviceAddress> AddressFromFidlBondingData(
1255     const fuchsia::bluetooth::sys::BondingData& bond) {
1256   bt::DeviceAddressBytes bytes(bond.address().bytes);
1257   bt::DeviceAddress::Type type;
1258   if (bond.has_bredr_bond()) {
1259     // A random identity address can only be present in a LE-only bond.
1260     if (bond.address().type == fbt::AddressType::RANDOM) {
1261       bt_log(WARN,
1262              "fidl",
1263              "BR/EDR or Dual-Mode bond cannot have a random identity address!");
1264       return std::nullopt;
1265     }
1266     // TODO(fxbug.dev/42102158): We currently assign kBREDR as the address type
1267     // for dual-mode bonds. This makes address management for dual-mode devices
1268     // a bit confusing as we have two "public" address types (i.e. kBREDR and
1269     // kLEPublic). We should align the stack address types with the FIDL address
1270     // types, such that both kBREDR and kLEPublic are represented as the same
1271     // kind of "PUBLIC".
1272     type = bt::DeviceAddress::Type::kBREDR;
1273   } else {
1274     type = bond.address().type == fbt::AddressType::RANDOM
1275                ? bt::DeviceAddress::Type::kLERandom
1276                : bt::DeviceAddress::Type::kLEPublic;
1277   }
1278 
1279   bt::DeviceAddress address(type, bytes);
1280 
1281   if (!address.IsPublic() && !address.IsStaticRandom()) {
1282     bt_log(
1283         ERROR,
1284         "fidl",
1285         "%s: BondingData address is not public or static random (address: %s)",
1286         __FUNCTION__,
1287         bt_str(address));
1288     return std::nullopt;
1289   }
1290 
1291   return address;
1292 }
1293 
LePairingDataFromFidl(bt::DeviceAddress peer_address,const fuchsia::bluetooth::sys::LeBondData & data)1294 bt::sm::PairingData LePairingDataFromFidl(
1295     bt::DeviceAddress peer_address,
1296     const fuchsia::bluetooth::sys::LeBondData& data) {
1297   bt::sm::PairingData result;
1298 
1299   if (data.has_peer_ltk()) {
1300     result.peer_ltk = LtkFromFidl(data.peer_ltk());
1301   }
1302   if (data.has_local_ltk()) {
1303     result.local_ltk = LtkFromFidl(data.local_ltk());
1304   }
1305   if (data.has_irk()) {
1306     result.irk = PeerKeyFromFidl(data.irk());
1307     // If there is an IRK, there must also be an identity address. Assume that
1308     // the identity address is the peer address, since the peer address is set
1309     // to the identity address upon bonding.
1310     result.identity_address = peer_address;
1311   }
1312   if (data.has_csrk()) {
1313     result.csrk = PeerKeyFromFidl(data.csrk());
1314   }
1315   return result;
1316 }
1317 
BredrKeyFromFidl(const fsys::BredrBondData & data)1318 std::optional<bt::sm::LTK> BredrKeyFromFidl(const fsys::BredrBondData& data) {
1319   if (!data.has_link_key()) {
1320     return std::nullopt;
1321   }
1322   auto key = PeerKeyFromFidl(data.link_key());
1323   return bt::sm::LTK(key.security(), bt::hci_spec::LinkKey(key.value(), 0, 0));
1324 }
1325 
BredrServicesFromFidl(const fuchsia::bluetooth::sys::BredrBondData & data)1326 std::vector<bt::UUID> BredrServicesFromFidl(
1327     const fuchsia::bluetooth::sys::BredrBondData& data) {
1328   std::vector<bt::UUID> services_out;
1329   if (data.has_services()) {
1330     std::transform(data.services().begin(),
1331                    data.services().end(),
1332                    std::back_inserter(services_out),
1333                    UuidFromFidl);
1334   }
1335   return services_out;
1336 }
1337 
PeerToFidlBondingData(const bt::gap::Adapter & adapter,const bt::gap::Peer & peer)1338 fuchsia::bluetooth::sys::BondingData PeerToFidlBondingData(
1339     const bt::gap::Adapter& adapter, const bt::gap::Peer& peer) {
1340   fsys::BondingData out;
1341 
1342   out.set_identifier(fbt::PeerId{peer.identifier().value()});
1343   out.set_local_address(AddressToFidl(fbt::AddressType::PUBLIC,
1344                                       adapter.state().controller_address));
1345   out.set_address(AddressToFidl(peer.address()));
1346 
1347   if (peer.name()) {
1348     out.set_name(*peer.name());
1349   }
1350 
1351   // LE
1352   if (peer.le() && peer.le()->bond_data()) {
1353     fsys::LeBondData out_le;
1354     const bt::sm::PairingData& bond = *peer.le()->bond_data();
1355 
1356     // TODO(armansito): Store the peer's preferred connection parameters.
1357     // TODO(fxbug.dev/42137736): Store GATT and AD service UUIDs.
1358 
1359     if (bond.local_ltk) {
1360       out_le.set_local_ltk(LtkToFidl(*bond.local_ltk));
1361     }
1362     if (bond.peer_ltk) {
1363       out_le.set_peer_ltk(LtkToFidl(*bond.peer_ltk));
1364     }
1365     if (bond.irk) {
1366       out_le.set_irk(PeerKeyToFidl(*bond.irk));
1367     }
1368     if (bond.csrk) {
1369       out_le.set_csrk(PeerKeyToFidl(*bond.csrk));
1370     }
1371 
1372     out.set_le_bond(std::move(out_le));
1373   }
1374 
1375   // BR/EDR
1376   if (peer.bredr() && peer.bredr()->link_key()) {
1377     fsys::BredrBondData out_bredr;
1378 
1379     // TODO(fxbug.dev/42076955): Populate with history of role switches.
1380 
1381     const auto& services = peer.bredr()->services();
1382     std::transform(services.begin(),
1383                    services.end(),
1384                    std::back_inserter(*out_bredr.mutable_services()),
1385                    UuidToFidl);
1386     out_bredr.set_link_key(LtkToFidlPeerKey(*peer.bredr()->link_key()));
1387     out.set_bredr_bond(std::move(out_bredr));
1388   }
1389 
1390   return out;
1391 }
1392 
NewLERemoteDevice(const bt::gap::Peer & peer)1393 fble::RemoteDevicePtr NewLERemoteDevice(const bt::gap::Peer& peer) {
1394   bt::AdvertisingData ad;
1395   if (!peer.le()) {
1396     return nullptr;
1397   }
1398 
1399   auto fidl_device = std::make_unique<fble::RemoteDevice>();
1400   fidl_device->identifier = peer.identifier().ToString();
1401   fidl_device->connectable = peer.connectable();
1402 
1403   // Initialize advertising data only if its non-empty.
1404   const std::optional<std::reference_wrapper<const bt::AdvertisingData>>
1405       adv_data = peer.le()->parsed_advertising_data();
1406   if (adv_data.has_value()) {
1407     auto data = fidl_helpers::AdvertisingDataToFidlDeprecated(adv_data.value());
1408     fidl_device->advertising_data =
1409         std::make_unique<fble::AdvertisingDataDeprecated>(std::move(data));
1410   } else if (peer.le()->advertising_data_error().has_value()) {
1411     // If the peer advertising data has failed to parse, then this conversion
1412     // failed.
1413     return nullptr;
1414   }
1415 
1416   if (peer.rssi() != bt::hci_spec::kRSSIInvalid) {
1417     fidl_device->rssi = std::make_unique<Int8>();
1418     fidl_device->rssi->value = peer.rssi();
1419   }
1420 
1421   return fidl_device;
1422 }
1423 
IsScanFilterValid(const fble::ScanFilter & fidl_filter)1424 bool IsScanFilterValid(const fble::ScanFilter& fidl_filter) {
1425   // |service_uuids| and |service_data_uuids| are the only fields that can
1426   // potentially contain invalid data, since they are represented as strings.
1427   if (fidl_filter.service_uuids) {
1428     for (const auto& uuid_str : *fidl_filter.service_uuids) {
1429       if (!bt::IsStringValidUuid(uuid_str)) {
1430         return false;
1431       }
1432     }
1433   }
1434 
1435   if (fidl_filter.service_data_uuids) {
1436     for (const auto& uuid_str : *fidl_filter.service_data_uuids) {
1437       if (!bt::IsStringValidUuid(uuid_str))
1438         return false;
1439     }
1440   }
1441 
1442   return true;
1443 }
1444 
PopulateDiscoveryFilter(const fble::ScanFilter & fidl_filter,bt::hci::DiscoveryFilter * out_filter)1445 bool PopulateDiscoveryFilter(const fble::ScanFilter& fidl_filter,
1446                              bt::hci::DiscoveryFilter* out_filter) {
1447   PW_DCHECK(out_filter);
1448 
1449   if (fidl_filter.service_uuids) {
1450     std::vector<bt::UUID> uuids;
1451     for (const auto& uuid_str : *fidl_filter.service_uuids) {
1452       bt::UUID uuid;
1453       if (!bt::StringToUuid(uuid_str, &uuid)) {
1454         bt_log(WARN,
1455                "fidl",
1456                "invalid service UUID given to scan filter: %s",
1457                uuid_str.c_str());
1458         return false;
1459       }
1460       uuids.push_back(uuid);
1461     }
1462 
1463     if (!uuids.empty()) {
1464       out_filter->set_service_uuids(uuids);
1465     }
1466   }
1467 
1468   if (fidl_filter.service_data_uuids) {
1469     std::vector<bt::UUID> uuids;
1470     for (const auto& uuid_str : *fidl_filter.service_data_uuids) {
1471       bt::UUID uuid;
1472       if (!bt::StringToUuid(uuid_str, &uuid)) {
1473         bt_log(WARN,
1474                "fidl",
1475                "invalid service data UUID given to scan filter: %s",
1476                uuid_str.c_str());
1477         return false;
1478       }
1479       uuids.push_back(uuid);
1480     }
1481 
1482     if (!uuids.empty()) {
1483       out_filter->set_service_data_uuids(uuids);
1484     }
1485   }
1486 
1487   if (fidl_filter.connectable) {
1488     out_filter->set_connectable(fidl_filter.connectable->value);
1489   }
1490 
1491   if (fidl_filter.manufacturer_identifier) {
1492     out_filter->set_manufacturer_code(
1493         fidl_filter.manufacturer_identifier->value);
1494   }
1495 
1496   if (fidl_filter.name_substring &&
1497       !fidl_filter.name_substring.value_or("").empty()) {
1498     out_filter->set_name_substring(fidl_filter.name_substring.value_or(""));
1499   }
1500 
1501   if (fidl_filter.max_path_loss) {
1502     out_filter->set_pathloss(fidl_filter.max_path_loss->value);
1503   }
1504 
1505   return true;
1506 }
1507 
DiscoveryFilterFromFidl(const fuchsia::bluetooth::le::Filter & fidl_filter)1508 bt::hci::DiscoveryFilter DiscoveryFilterFromFidl(
1509     const fuchsia::bluetooth::le::Filter& fidl_filter) {
1510   bt::hci::DiscoveryFilter out;
1511 
1512   if (fidl_filter.has_service_uuid()) {
1513     out.set_service_uuids({bt::UUID(fidl_filter.service_uuid().value)});
1514   }
1515 
1516   if (fidl_filter.has_service_data_uuid()) {
1517     out.set_service_data_uuids(
1518         {bt::UUID(fidl_filter.service_data_uuid().value)});
1519   }
1520 
1521   if (fidl_filter.has_solicitation_uuid()) {
1522     out.set_solicitation_uuids(
1523         {bt::UUID(fidl_filter.solicitation_uuid().value)});
1524   }
1525 
1526   if (fidl_filter.has_manufacturer_id()) {
1527     out.set_manufacturer_code(fidl_filter.manufacturer_id());
1528   }
1529 
1530   if (fidl_filter.has_connectable()) {
1531     out.set_connectable(fidl_filter.connectable());
1532   }
1533 
1534   if (fidl_filter.has_name()) {
1535     out.set_name_substring(fidl_filter.name());
1536   }
1537 
1538   if (fidl_filter.has_max_path_loss()) {
1539     out.set_pathloss(fidl_filter.max_path_loss());
1540   }
1541 
1542   return out;
1543 }
1544 
AdvertisingIntervalFromFidl(fble::AdvertisingModeHint mode_hint)1545 bt::gap::AdvertisingInterval AdvertisingIntervalFromFidl(
1546     fble::AdvertisingModeHint mode_hint) {
1547   switch (mode_hint) {
1548     case fble::AdvertisingModeHint::VERY_FAST:
1549       return bt::gap::AdvertisingInterval::FAST1;
1550     case fble::AdvertisingModeHint::FAST:
1551       return bt::gap::AdvertisingInterval::FAST2;
1552     case fble::AdvertisingModeHint::SLOW:
1553       return bt::gap::AdvertisingInterval::SLOW;
1554   }
1555   return bt::gap::AdvertisingInterval::SLOW;
1556 }
1557 
AdvertisingDataFromFidl(const fble::AdvertisingData & input)1558 std::optional<bt::AdvertisingData> AdvertisingDataFromFidl(
1559     const fble::AdvertisingData& input) {
1560   bt::AdvertisingData output;
1561 
1562   if (input.has_name()) {
1563     if (!output.SetLocalName(input.name())) {
1564       return std::nullopt;
1565     }
1566   }
1567   if (input.has_appearance()) {
1568     output.SetAppearance(static_cast<uint16_t>(input.appearance()));
1569   }
1570   if (input.has_tx_power_level()) {
1571     output.SetTxPower(input.tx_power_level());
1572   }
1573   if (input.has_service_uuids()) {
1574     for (const auto& uuid : input.service_uuids()) {
1575       bt::UUID bt_uuid = UuidFromFidl(uuid);
1576       if (!output.AddServiceUuid(bt_uuid)) {
1577         bt_log(WARN,
1578                "fidl",
1579                "Received more Service UUIDs than fit in a single AD - "
1580                "truncating UUID %s",
1581                bt_str(bt_uuid));
1582       }
1583     }
1584   }
1585   if (input.has_service_data()) {
1586     for (const auto& entry : input.service_data()) {
1587       if (!output.SetServiceData(UuidFromFidl(entry.uuid),
1588                                  bt::BufferView(entry.data))) {
1589         return std::nullopt;
1590       }
1591     }
1592   }
1593   if (input.has_manufacturer_data()) {
1594     for (const auto& entry : input.manufacturer_data()) {
1595       bt::BufferView data(entry.data);
1596       if (!output.SetManufacturerData(entry.company_id, data)) {
1597         return std::nullopt;
1598       }
1599     }
1600   }
1601   if (input.has_uris()) {
1602     for (const auto& uri : input.uris()) {
1603       if (!output.AddUri(uri)) {
1604         return std::nullopt;
1605       }
1606     }
1607   }
1608   if (input.has_broadcast_name()) {
1609     output.SetBroadcastName(input.broadcast_name());
1610   }
1611   if (input.has_resolvable_set_identifier()) {
1612     output.SetResolvableSetIdentifier(input.resolvable_set_identifier());
1613   }
1614 
1615   return output;
1616 }
1617 
AdvertisingDataToFidl(const bt::AdvertisingData & input)1618 fble::AdvertisingData AdvertisingDataToFidl(const bt::AdvertisingData& input) {
1619   fble::AdvertisingData output;
1620 
1621   if (input.local_name()) {
1622     output.set_name(input.local_name()->name);
1623   }
1624   if (input.appearance()) {
1625     // TODO(fxbug.dev/42145156): Remove this to allow for passing arbitrary
1626     // appearance values to clients in a way that's forward-compatible with
1627     // future BLE revisions.
1628     const uint16_t appearance_raw = input.appearance().value();
1629     if (auto appearance = AppearanceToFidl(appearance_raw)) {
1630       output.set_appearance(appearance.value());
1631     } else {
1632       bt_log(DEBUG,
1633              "fidl",
1634              "omitting unencodeable appearance %#.4x of peer %s",
1635              appearance_raw,
1636              input.local_name().has_value() ? input.local_name()->name.c_str()
1637                                             : "");
1638     }
1639   }
1640   if (input.tx_power()) {
1641     output.set_tx_power_level(*input.tx_power());
1642   }
1643   std::unordered_set<bt::UUID> service_uuids = input.service_uuids();
1644   if (!service_uuids.empty()) {
1645     std::vector<fbt::Uuid> uuids;
1646     uuids.reserve(service_uuids.size());
1647     for (const auto& uuid : service_uuids) {
1648       uuids.push_back(fbt::Uuid{uuid.value()});
1649     }
1650     output.set_service_uuids(std::move(uuids));
1651   }
1652   if (!input.service_data_uuids().empty()) {
1653     std::vector<fble::ServiceData> entries;
1654     for (const auto& uuid : input.service_data_uuids()) {
1655       auto data = input.service_data(uuid);
1656       fble::ServiceData entry{fbt::Uuid{uuid.value()}, data.ToVector()};
1657       entries.push_back(std::move(entry));
1658     }
1659     output.set_service_data(std::move(entries));
1660   }
1661   if (!input.manufacturer_data_ids().empty()) {
1662     std::vector<fble::ManufacturerData> entries;
1663     for (const auto& id : input.manufacturer_data_ids()) {
1664       auto data = input.manufacturer_data(id);
1665       fble::ManufacturerData entry{id, data.ToVector()};
1666       entries.push_back(std::move(entry));
1667     }
1668     output.set_manufacturer_data(std::move(entries));
1669   }
1670   if (!input.uris().empty()) {
1671     std::vector<std::string> uris;
1672     for (const auto& uri : input.uris()) {
1673       uris.push_back(uri);
1674     }
1675     output.set_uris(std::move(uris));
1676   }
1677   if (input.broadcast_name()) {
1678     output.set_broadcast_name(*input.broadcast_name());
1679   }
1680   if (input.resolvable_set_identifier()) {
1681     output.set_resolvable_set_identifier(*input.resolvable_set_identifier());
1682   }
1683 
1684   return output;
1685 }
1686 
AdvertisingDataToFidlDeprecated(const bt::AdvertisingData & input)1687 fble::AdvertisingDataDeprecated AdvertisingDataToFidlDeprecated(
1688     const bt::AdvertisingData& input) {
1689   fble::AdvertisingDataDeprecated output;
1690 
1691   if (input.local_name()) {
1692     output.name = input.local_name()->name;
1693   }
1694   if (input.appearance()) {
1695     output.appearance = std::make_unique<fbt::UInt16>();
1696     output.appearance->value = *input.appearance();
1697   }
1698   if (input.tx_power()) {
1699     output.tx_power_level = std::make_unique<fbt::Int8>();
1700     output.tx_power_level->value = *input.tx_power();
1701   }
1702   if (!input.service_uuids().empty()) {
1703     output.service_uuids.emplace();
1704     for (const auto& uuid : input.service_uuids()) {
1705       output.service_uuids->push_back(uuid.ToString());
1706     }
1707   }
1708   if (!input.service_data_uuids().empty()) {
1709     output.service_data.emplace();
1710     for (const auto& uuid : input.service_data_uuids()) {
1711       auto data = input.service_data(uuid);
1712       fble::ServiceDataEntry entry{uuid.ToString(), data.ToVector()};
1713       output.service_data->push_back(std::move(entry));
1714     }
1715   }
1716   if (!input.manufacturer_data_ids().empty()) {
1717     output.manufacturer_specific_data.emplace();
1718     for (const auto& id : input.manufacturer_data_ids()) {
1719       auto data = input.manufacturer_data(id);
1720       fble::ManufacturerSpecificDataEntry entry{id, data.ToVector()};
1721       output.manufacturer_specific_data->push_back(std::move(entry));
1722     }
1723   }
1724   if (!input.uris().empty()) {
1725     output.uris.emplace();
1726     for (const auto& uri : input.uris()) {
1727       output.uris->push_back(uri);
1728     }
1729   }
1730 
1731   return output;
1732 }
1733 
AdvertisingDataToFidlScanData(const bt::AdvertisingData & input,pw::chrono::SystemClock::time_point timestamp)1734 fuchsia::bluetooth::le::ScanData AdvertisingDataToFidlScanData(
1735     const bt::AdvertisingData& input,
1736     pw::chrono::SystemClock::time_point timestamp) {
1737   // Reuse bt::AdvertisingData -> fble::AdvertisingData utility, since most
1738   // fields are the same as fble::ScanData.
1739   fble::AdvertisingData fidl_adv_data = AdvertisingDataToFidl(input);
1740   fble::ScanData out;
1741   if (fidl_adv_data.has_tx_power_level()) {
1742     out.set_tx_power(fidl_adv_data.tx_power_level());
1743   }
1744   if (fidl_adv_data.has_appearance()) {
1745     out.set_appearance(fidl_adv_data.appearance());
1746   }
1747   if (fidl_adv_data.has_service_uuids()) {
1748     out.set_service_uuids(std::move(*fidl_adv_data.mutable_service_uuids()));
1749   }
1750   if (fidl_adv_data.has_service_data()) {
1751     out.set_service_data(std::move(*fidl_adv_data.mutable_service_data()));
1752   }
1753   if (fidl_adv_data.has_manufacturer_data()) {
1754     out.set_manufacturer_data(
1755         std::move(*fidl_adv_data.mutable_manufacturer_data()));
1756   }
1757   if (fidl_adv_data.has_uris()) {
1758     out.set_uris(std::move(*fidl_adv_data.mutable_uris()));
1759   }
1760   zx_time_t timestamp_ns = timestamp.time_since_epoch().count();
1761   out.set_timestamp(timestamp_ns);
1762   return out;
1763 }
1764 
PeerToFidlLe(const bt::gap::Peer & peer)1765 fble::Peer PeerToFidlLe(const bt::gap::Peer& peer) {
1766   PW_CHECK(peer.le());
1767 
1768   fble::Peer output;
1769   output.set_id(fbt::PeerId{peer.identifier().value()});
1770   output.set_connectable(peer.connectable());
1771 
1772   if (peer.rssi() != bt::hci_spec::kRSSIInvalid) {
1773     output.set_rssi(peer.rssi());
1774   }
1775 
1776   const std::optional<std::reference_wrapper<const bt::AdvertisingData>>
1777       advertising_data = peer.le()->parsed_advertising_data();
1778   if (advertising_data.has_value()) {
1779     std::optional<pw::chrono::SystemClock::time_point> timestamp =
1780         peer.le()->parsed_advertising_data_timestamp();
1781     output.set_advertising_data(
1782         AdvertisingDataToFidl(advertising_data.value()));
1783     output.set_data(AdvertisingDataToFidlScanData(advertising_data.value(),
1784                                                   timestamp.value()));
1785   }
1786 
1787   if (peer.name()) {
1788     output.set_name(peer.name().value());
1789   }
1790 
1791   output.set_bonded(peer.bonded());
1792   zx_time_t last_updated_ns = peer.last_updated().time_since_epoch().count();
1793   output.set_last_updated(last_updated_ns);
1794 
1795   return output;
1796 }
1797 
ReliableModeFromFidl(const fgatt::WriteOptions & write_options)1798 bt::gatt::ReliableMode ReliableModeFromFidl(
1799     const fgatt::WriteOptions& write_options) {
1800   return (write_options.has_reliable_mode() &&
1801           write_options.reliable_mode() == fgatt::ReliableMode::ENABLED)
1802              ? bt::gatt::ReliableMode::kEnabled
1803              : bt::gatt::ReliableMode::kDisabled;
1804 }
1805 
1806 // TODO(fxbug.dev/42141942): The 64 bit `fidl_gatt_id` can overflow the 16 bits
1807 // of a bt:att::Handle that underlies CharacteristicHandles when directly
1808 // casted. Fix this.
CharacteristicHandleFromFidl(uint64_t fidl_gatt_id)1809 bt::gatt::CharacteristicHandle CharacteristicHandleFromFidl(
1810     uint64_t fidl_gatt_id) {
1811   if (fidl_gatt_id > std::numeric_limits<bt::att::Handle>::max()) {
1812     bt_log(ERROR,
1813            "fidl",
1814            "Casting a 64-bit FIDL GATT ID with `bits[16, 63] != 0` (0x%lX) to "
1815            "16-bit "
1816            "Characteristic Handle",
1817            fidl_gatt_id);
1818   }
1819   return bt::gatt::CharacteristicHandle(
1820       static_cast<bt::att::Handle>(fidl_gatt_id));
1821 }
1822 
1823 // TODO(fxbug.dev/42141942): The 64 bit `fidl_gatt_id` can overflow the 16 bits
1824 // of a bt:att::Handle that underlies DescriptorHandles when directly casted.
1825 // Fix this.
DescriptorHandleFromFidl(uint64_t fidl_gatt_id)1826 bt::gatt::DescriptorHandle DescriptorHandleFromFidl(uint64_t fidl_gatt_id) {
1827   if (fidl_gatt_id > std::numeric_limits<bt::att::Handle>::max()) {
1828     bt_log(ERROR,
1829            "fidl",
1830            "Casting a 64-bit FIDL GATT ID with `bits[16, 63] != 0` (0x%lX) to "
1831            "16-bit Descriptor "
1832            "Handle",
1833            fidl_gatt_id);
1834   }
1835   return bt::gatt::DescriptorHandle(static_cast<bt::att::Handle>(fidl_gatt_id));
1836 }
1837 
1838 fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
ServiceDefinitionToServiceRecord(const fuchsia_bluetooth_bredr::ServiceDefinition & definition)1839 ServiceDefinitionToServiceRecord(
1840     const fuchsia_bluetooth_bredr::ServiceDefinition& definition) {
1841   bt::sdp::ServiceRecord rec;
1842   std::vector<bt::UUID> classes;
1843 
1844   if (!definition.service_class_uuids().has_value()) {
1845     bt_log(WARN, "fidl", "Advertised service contains no Service UUIDs");
1846     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1847   }
1848 
1849   for (auto& uuid : definition.service_class_uuids().value()) {
1850     bt::UUID btuuid = fidl_helpers::NewUuidFromFidl(uuid);
1851     bt_log(TRACE, "fidl", "Setting Service Class UUID %s", bt_str(btuuid));
1852     classes.emplace_back(btuuid);
1853   }
1854 
1855   rec.SetServiceClassUUIDs(classes);
1856 
1857   if (definition.protocol_descriptor_list().has_value()) {
1858     if (!NewAddProtocolDescriptorList(
1859             &rec,
1860             bt::sdp::ServiceRecord::kPrimaryProtocolList,
1861             definition.protocol_descriptor_list().value())) {
1862       bt_log(ERROR, "fidl", "Failed to add protocol descriptor list");
1863       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1864     }
1865   }
1866 
1867   if (definition.additional_protocol_descriptor_lists().has_value()) {
1868     // It's safe to iterate through this list with a ProtocolListId as
1869     // ProtocolListId = uint8_t, and std::numeric_limits<uint8_t>::max() == 255
1870     // == the MAX_SEQUENCE_LENGTH vector limit from
1871     // fuchsia.bluetooth.bredr/ServiceDefinition.additional_protocol_descriptor_lists.
1872     PW_CHECK(
1873         definition.additional_protocol_descriptor_lists()->size() <=
1874         std::numeric_limits<bt::sdp::ServiceRecord::ProtocolListId>::max());
1875     bt::sdp::ServiceRecord::ProtocolListId protocol_list_id = 1;
1876     for (const auto& descriptor_list :
1877          definition.additional_protocol_descriptor_lists().value()) {
1878       if (!NewAddProtocolDescriptorList(
1879               &rec, protocol_list_id, descriptor_list)) {
1880         bt_log(
1881             ERROR, "fidl", "Failed to add additional protocol descriptor list");
1882         return fpromise::error(
1883             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1884       }
1885       protocol_list_id++;
1886     }
1887   }
1888 
1889   if (definition.profile_descriptors().has_value()) {
1890     for (const auto& profile : definition.profile_descriptors().value()) {
1891       if (!profile.profile_id().has_value() ||
1892           !profile.major_version().has_value() ||
1893           !profile.minor_version().has_value()) {
1894         bt_log(WARN, "fidl", "ProfileDescriptor missing required fields");
1895         return fpromise::error(
1896             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1897       }
1898       bt_log(TRACE,
1899              "fidl",
1900              "Adding Profile %#hx v%d.%d",
1901              static_cast<unsigned short>(*profile.profile_id()),
1902              *profile.major_version(),
1903              *profile.minor_version());
1904       rec.AddProfile(bt::UUID(static_cast<uint16_t>(*profile.profile_id())),
1905                      *profile.major_version(),
1906                      *profile.minor_version());
1907     }
1908   }
1909 
1910   if (definition.information().has_value()) {
1911     for (const auto& info : definition.information().value()) {
1912       if (!info.language().has_value()) {
1913         return fpromise::error(
1914             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1915       }
1916 
1917       const std::string& language = info.language().value();
1918       std::string name, description, provider;
1919       if (info.name().has_value()) {
1920         name = info.name().value();
1921       }
1922       if (info.description().has_value()) {
1923         description = info.description().value();
1924       }
1925       if (info.provider().has_value()) {
1926         provider = info.provider().value();
1927       }
1928       bt_log(TRACE,
1929              "fidl",
1930              "Adding Info (%s): (%s, %s, %s)",
1931              language.c_str(),
1932              name.c_str(),
1933              description.c_str(),
1934              provider.c_str());
1935       rec.AddInfo(language, name, description, provider);
1936     }
1937   }
1938 
1939   if (definition.additional_attributes().has_value()) {
1940     for (const auto& attribute : definition.additional_attributes().value()) {
1941       if (!attribute.element() || !attribute.id()) {
1942         bt_log(WARN, "fidl", "Attribute missing required fields");
1943         return fpromise::error(
1944             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1945       }
1946       auto elem = NewFidlToDataElement(*attribute.element());
1947       if (elem) {
1948         bt_log(TRACE,
1949                "fidl",
1950                "Adding attribute %#x : %s",
1951                *attribute.id(),
1952                elem.value().ToString().c_str());
1953         rec.SetAttribute(*attribute.id(), std::move(elem.value()));
1954       }
1955     }
1956   }
1957   return fpromise::ok(std::move(rec));
1958 }
1959 
1960 fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
ServiceDefinitionToServiceRecord(const fuchsia::bluetooth::bredr::ServiceDefinition & definition)1961 ServiceDefinitionToServiceRecord(
1962     const fuchsia::bluetooth::bredr::ServiceDefinition& definition) {
1963   bt::sdp::ServiceRecord rec;
1964   std::vector<bt::UUID> classes;
1965 
1966   if (!definition.has_service_class_uuids()) {
1967     bt_log(WARN, "fidl", "Advertised service contains no Service UUIDs");
1968     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1969   }
1970 
1971   for (auto& uuid : definition.service_class_uuids()) {
1972     bt::UUID btuuid = fidl_helpers::UuidFromFidl(uuid);
1973     bt_log(TRACE, "fidl", "Setting Service Class UUID %s", bt_str(btuuid));
1974     classes.emplace_back(btuuid);
1975   }
1976 
1977   rec.SetServiceClassUUIDs(classes);
1978 
1979   if (definition.has_protocol_descriptor_list()) {
1980     if (!AddProtocolDescriptorList(&rec,
1981                                    bt::sdp::ServiceRecord::kPrimaryProtocolList,
1982                                    definition.protocol_descriptor_list())) {
1983       bt_log(ERROR, "fidl", "Failed to add protocol descriptor list");
1984       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
1985     }
1986   }
1987 
1988   if (definition.has_additional_protocol_descriptor_lists()) {
1989     // It's safe to iterate through this list with a ProtocolListId as
1990     // ProtocolListId = uint8_t, and std::numeric_limits<uint8_t>::max() == 255
1991     // == the MAX_SEQUENCE_LENGTH vector limit from
1992     // fuchsia.bluetooth.bredr/ServiceDefinition.additional_protocol_descriptor_lists.
1993     PW_CHECK(
1994         definition.additional_protocol_descriptor_lists().size() <=
1995         std::numeric_limits<bt::sdp::ServiceRecord::ProtocolListId>::max());
1996     bt::sdp::ServiceRecord::ProtocolListId protocol_list_id = 1;
1997     for (const auto& descriptor_list :
1998          definition.additional_protocol_descriptor_lists()) {
1999       if (!AddProtocolDescriptorList(&rec, protocol_list_id, descriptor_list)) {
2000         bt_log(
2001             ERROR, "fidl", "Failed to add additional protocol descriptor list");
2002         return fpromise::error(
2003             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2004       }
2005       protocol_list_id++;
2006     }
2007   }
2008 
2009   if (definition.has_profile_descriptors()) {
2010     for (const auto& profile : definition.profile_descriptors()) {
2011       if (!profile.has_profile_id() || !profile.has_major_version() ||
2012           !profile.has_minor_version()) {
2013         bt_log(ERROR, "fidl", "ProfileDescriptor missing required fields");
2014         return fpromise::error(
2015             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2016       }
2017       bt_log(TRACE,
2018              "fidl",
2019              "Adding Profile %#hx v%d.%d",
2020              static_cast<unsigned short>(profile.profile_id()),
2021              profile.major_version(),
2022              profile.minor_version());
2023       rec.AddProfile(bt::UUID(static_cast<uint16_t>(profile.profile_id())),
2024                      profile.major_version(),
2025                      profile.minor_version());
2026     }
2027   }
2028 
2029   if (definition.has_information()) {
2030     for (const auto& info : definition.information()) {
2031       if (!info.has_language()) {
2032         return fpromise::error(
2033             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2034       }
2035       const std::string& language = info.language();
2036       std::string name, description, provider;
2037       if (info.has_name()) {
2038         name = info.name();
2039       }
2040       if (info.has_description()) {
2041         description = info.description();
2042       }
2043       if (info.has_provider()) {
2044         provider = info.provider();
2045       }
2046       bt_log(TRACE,
2047              "fidl",
2048              "Adding Info (%s): (%s, %s, %s)",
2049              language.c_str(),
2050              name.c_str(),
2051              description.c_str(),
2052              provider.c_str());
2053       rec.AddInfo(language, name, description, provider);
2054     }
2055   }
2056 
2057   if (definition.has_additional_attributes()) {
2058     for (const auto& attribute : definition.additional_attributes()) {
2059       if (!attribute.has_element() || !attribute.has_id()) {
2060         bt_log(WARN, "fidl", "Attribute missing required fields");
2061         return fpromise::error(
2062             fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2063       }
2064       auto elem = FidlToDataElement(attribute.element());
2065       if (elem) {
2066         bt_log(TRACE,
2067                "fidl",
2068                "Adding attribute %#x : %s",
2069                attribute.id(),
2070                elem.value().ToString().c_str());
2071         rec.SetAttribute(attribute.id(), std::move(elem.value()));
2072       }
2073     }
2074   }
2075   return fpromise::ok(std::move(rec));
2076 }
2077 
2078 fpromise::result<fuchsia::bluetooth::bredr::ServiceDefinition,
2079                  fuchsia::bluetooth::ErrorCode>
ServiceRecordToServiceDefinition(const bt::sdp::ServiceRecord & record)2080 ServiceRecordToServiceDefinition(const bt::sdp::ServiceRecord& record) {
2081   fuchsia::bluetooth::bredr::ServiceDefinition out;
2082 
2083   // Service class UUIDs are mandatory
2084   if (!record.HasAttribute(bt::sdp::kServiceClassIdList)) {
2085     return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2086   }
2087   const bt::sdp::DataElement& service_uuids_element =
2088       record.GetAttribute(bt::sdp::kServiceClassIdList);
2089   auto service_uuids = DataElementToServiceUuids(service_uuids_element);
2090   if (service_uuids.is_error()) {
2091     return fpromise::error(service_uuids.error());
2092   }
2093   out.set_service_class_uuids(std::move(service_uuids.value()));
2094 
2095   // Primary protocol descriptor list (optional)
2096   if (record.HasAttribute(bt::sdp::kProtocolDescriptorList)) {
2097     const bt::sdp::DataElement& primary_protocol_element =
2098         record.GetAttribute(bt::sdp::kProtocolDescriptorList);
2099     auto primary_protocol =
2100         DataElementToProtocolDescriptorList(primary_protocol_element);
2101     if (primary_protocol.is_error()) {
2102       return fpromise::error(primary_protocol.error());
2103     }
2104     out.set_protocol_descriptor_list(std::move(primary_protocol.value()));
2105   }
2106 
2107   // Additional protocol descriptor lists (optional)
2108   if (record.HasAttribute(bt::sdp::kAdditionalProtocolDescriptorList)) {
2109     const bt::sdp::DataElement& additional_protocols =
2110         record.GetAttribute(bt::sdp::kAdditionalProtocolDescriptorList);
2111     // Sequence of protocol descriptor list sequences.
2112     if (additional_protocols.type() != bt::sdp::DataElement::Type::kSequence) {
2113       bt_log(WARN, "fidl", "Invalid additional protocol descriptor list");
2114       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2115     }
2116 
2117     const auto additional_protocol_list =
2118         additional_protocols.Get<std::vector<bt::sdp::DataElement>>();
2119     for (const auto& addl_element : additional_protocol_list.value()) {
2120       auto additional_protocol =
2121           DataElementToProtocolDescriptorList(addl_element);
2122       if (additional_protocol.is_error()) {
2123         return fpromise::error(additional_protocol.error());
2124       }
2125       out.mutable_additional_protocol_descriptor_lists()->emplace_back(
2126           std::move(additional_protocol.value()));
2127     }
2128   }
2129 
2130   // Profile descriptors (optional)
2131   if (record.HasAttribute(bt::sdp::kBluetoothProfileDescriptorList)) {
2132     const bt::sdp::DataElement& profile_descriptors_element =
2133         record.GetAttribute(bt::sdp::kBluetoothProfileDescriptorList);
2134     auto profile_descriptors =
2135         DataElementToProfileDescriptors(profile_descriptors_element);
2136     if (profile_descriptors.is_error()) {
2137       return fpromise::error(profile_descriptors.error());
2138     }
2139     out.set_profile_descriptors(std::move(profile_descriptors.value()));
2140   }
2141 
2142   // Human-readable information (optional)
2143   const std::vector<bt::sdp::ServiceRecord::Information> information =
2144       record.GetInfo();
2145   for (const auto& info : information) {
2146     fbredr::Information fidl_info = InformationToFidl(info);
2147     out.mutable_information()->emplace_back(std::move(fidl_info));
2148   }
2149 
2150   // Additional attributes (optional)
2151   const bt::sdp::AttributeId kMinAdditionalAttribute = 0x200;
2152   const std::set<bt::sdp::AttributeId> additional_attribute_ids =
2153       record.GetAttributesInRange(kMinAdditionalAttribute, 0xffff);
2154   for (const auto additional_attr_id : additional_attribute_ids) {
2155     const bt::sdp::DataElement& additional_attr_elt =
2156         record.GetAttribute(additional_attr_id);
2157     std::optional<fbredr::DataElement> element =
2158         DataElementToFidl(additional_attr_elt);
2159     if (!element) {
2160       bt_log(WARN, "fidl", "Invalid additional attribute data element");
2161       return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
2162     }
2163     fbredr::Attribute attr;
2164     attr.set_id(additional_attr_id);
2165     attr.set_element(std::move(element.value()));
2166     out.mutable_additional_attributes()->emplace_back(std::move(attr));
2167   }
2168   return fpromise::ok(std::move(out));
2169 }
2170 
FidlToBrEdrSecurityRequirements(const fbt::ChannelParameters & fidl)2171 bt::gap::BrEdrSecurityRequirements FidlToBrEdrSecurityRequirements(
2172     const fbt::ChannelParameters& fidl) {
2173   bt::gap::BrEdrSecurityRequirements requirements{.authentication = false,
2174                                                   .secure_connections = false};
2175   if (fidl.has_security_requirements()) {
2176     if (fidl.security_requirements().has_authentication_required()) {
2177       requirements.authentication =
2178           fidl.security_requirements().authentication_required();
2179     }
2180 
2181     if (fidl.security_requirements().has_secure_connections_required()) {
2182       requirements.secure_connections =
2183           fidl.security_requirements().secure_connections_required();
2184     }
2185   }
2186   return requirements;
2187 }
2188 
FidlToScoParameterSet(const fbredr::HfpParameterSet param_set)2189 std::optional<bt::sco::ParameterSet> FidlToScoParameterSet(
2190     const fbredr::HfpParameterSet param_set) {
2191   switch (param_set) {
2192     case fbredr::HfpParameterSet::T1:
2193       return bt::sco::kParameterSetT1;
2194     case fbredr::HfpParameterSet::T2:
2195       return bt::sco::kParameterSetT2;
2196     case fbredr::HfpParameterSet::S1:
2197       return bt::sco::kParameterSetS1;
2198     case fbredr::HfpParameterSet::S2:
2199       return bt::sco::kParameterSetS2;
2200     case fbredr::HfpParameterSet::S3:
2201       return bt::sco::kParameterSetS3;
2202     case fbredr::HfpParameterSet::S4:
2203       return bt::sco::kParameterSetS4;
2204     case fbredr::HfpParameterSet::D0:
2205       return bt::sco::kParameterSetD0;
2206     case fbredr::HfpParameterSet::D1:
2207       return bt::sco::kParameterSetD1;
2208     default:
2209       return std::nullopt;
2210   }
2211 }
2212 
2213 std::optional<
2214     bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParameters::
2215                          VendorCodingFormatWriter>>
FidlToScoCodingFormat(const fbt::AssignedCodingFormat format)2216 FidlToScoCodingFormat(const fbt::AssignedCodingFormat format) {
2217   bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParameters::
2218                        VendorCodingFormatWriter>
2219       out;
2220   auto view = out.view();
2221   // Set to 0 since vendor specific coding formats are not supported.
2222   view.company_id().Write(0);
2223   view.vendor_codec_id().Write(0);
2224   switch (format) {
2225     case fbt::AssignedCodingFormat::A_LAW_LOG:
2226       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::A_LAW);
2227       break;
2228     case fbt::AssignedCodingFormat::U_LAW_LOG:
2229       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::U_LAW);
2230       break;
2231     case fbt::AssignedCodingFormat::CVSD:
2232       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::CVSD);
2233       break;
2234     case fbt::AssignedCodingFormat::TRANSPARENT:
2235       view.coding_format().Write(
2236           pw::bluetooth::emboss::CodingFormat::TRANSPARENT);
2237       break;
2238     case fbt::AssignedCodingFormat::LINEAR_PCM:
2239       view.coding_format().Write(
2240           pw::bluetooth::emboss::CodingFormat::LINEAR_PCM);
2241       break;
2242     case fbt::AssignedCodingFormat::MSBC:
2243       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::MSBC);
2244       break;
2245     case fbt::AssignedCodingFormat::LC3:
2246       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::LC3);
2247       break;
2248     case fbt::AssignedCodingFormat::G_729A:
2249       view.coding_format().Write(pw::bluetooth::emboss::CodingFormat::G729A);
2250       break;
2251     default:
2252       return std::nullopt;
2253   }
2254   return out;
2255 }
2256 
FidlToPcmDataFormat(const faudio::SampleFormat & format)2257 fpromise::result<pw::bluetooth::emboss::PcmDataFormat> FidlToPcmDataFormat(
2258     const faudio::SampleFormat& format) {
2259   switch (format) {
2260     case faudio::SampleFormat::PCM_SIGNED:
2261       return fpromise::ok(
2262           pw::bluetooth::emboss::PcmDataFormat::TWOS_COMPLEMENT);
2263     case faudio::SampleFormat::PCM_UNSIGNED:
2264       return fpromise::ok(pw::bluetooth::emboss::PcmDataFormat::UNSIGNED);
2265     default:
2266       // Other sample formats are not supported by SCO.
2267       return fpromise::error();
2268   }
2269 }
2270 
FidlToScoDataPath(const fbredr::DataPath & path)2271 pw::bluetooth::emboss::ScoDataPath FidlToScoDataPath(
2272     const fbredr::DataPath& path) {
2273   switch (path) {
2274     case fbredr::DataPath::HOST:
2275       return pw::bluetooth::emboss::ScoDataPath::HCI;
2276     case fbredr::DataPath::OFFLOAD: {
2277       // TODO(fxbug.dev/42136417): Use path from stack configuration file
2278       // instead of this hardcoded value. "6" is the data path usually used in
2279       // Broadcom controllers.
2280       return static_cast<pw::bluetooth::emboss::ScoDataPath>(6);
2281     }
2282     case fbredr::DataPath::TEST:
2283       return pw::bluetooth::emboss::ScoDataPath::AUDIO_TEST_MODE;
2284   }
2285 }
2286 
2287 fpromise::result<bt::StaticPacket<
2288     pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>
FidlToScoParameters(const fbredr::ScoConnectionParameters & params)2289 FidlToScoParameters(const fbredr::ScoConnectionParameters& params) {
2290   bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter>
2291       out;
2292   auto view = out.view();
2293 
2294   if (!params.has_parameter_set()) {
2295     bt_log(WARN, "fidl", "SCO parameters missing parameter_set");
2296     return fpromise::error();
2297   }
2298   auto param_set = FidlToScoParameterSet(params.parameter_set());
2299   if (!param_set.has_value()) {
2300     bt_log(WARN, "fidl", "Unrecognized SCO parameters parameter_set");
2301     return fpromise::error();
2302   }
2303   view.transmit_bandwidth().Write(param_set.value().transmit_receive_bandwidth);
2304   view.receive_bandwidth().Write(param_set.value().transmit_receive_bandwidth);
2305 
2306   if (!params.has_air_coding_format()) {
2307     bt_log(WARN, "fidl", "SCO parameters missing air_coding_format");
2308     return fpromise::error();
2309   }
2310   std::optional<
2311       bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParameters::
2312                            VendorCodingFormatWriter>>
2313       air_coding_format = FidlToScoCodingFormat(params.air_coding_format());
2314   if (!air_coding_format) {
2315     bt_log(WARN, "fidl", "SCO parameters contains unknown air_coding_format");
2316     return fpromise::error();
2317   }
2318   view.transmit_coding_format().CopyFrom(air_coding_format->view());
2319   view.receive_coding_format().CopyFrom(air_coding_format->view());
2320 
2321   if (!params.has_air_frame_size()) {
2322     bt_log(WARN, "fidl", "SCO parameters missing air_frame_size");
2323     return fpromise::error();
2324   }
2325   view.transmit_codec_frame_size_bytes().Write(params.air_frame_size());
2326   view.receive_codec_frame_size_bytes().Write(params.air_frame_size());
2327 
2328   if (!params.has_io_bandwidth()) {
2329     bt_log(WARN, "fidl", "SCO parameters missing io_bandwidth");
2330     return fpromise::error();
2331   }
2332   view.input_bandwidth().Write(params.io_bandwidth());
2333   view.output_bandwidth().Write(params.io_bandwidth());
2334 
2335   if (!params.has_io_coding_format()) {
2336     bt_log(WARN, "fidl", "SCO parameters missing io_coding_format");
2337     return fpromise::error();
2338   }
2339   std::optional<
2340       bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParameters::
2341                            VendorCodingFormatWriter>>
2342       io_coding_format = FidlToScoCodingFormat(params.io_coding_format());
2343   if (!io_coding_format) {
2344     bt_log(WARN, "fidl", "SCO parameters contains unknown io_coding_format");
2345     return fpromise::error();
2346   }
2347   view.input_coding_format().CopyFrom(io_coding_format->view());
2348   view.output_coding_format().CopyFrom(io_coding_format->view());
2349 
2350   if (!params.has_io_frame_size()) {
2351     bt_log(WARN, "fidl", "SCO parameters missing io_frame_size");
2352     return fpromise::error();
2353   }
2354   view.input_coded_data_size_bits().Write(params.io_frame_size());
2355   view.output_coded_data_size_bits().Write(params.io_frame_size());
2356 
2357   if (params.has_io_pcm_data_format() &&
2358       view.input_coding_format().coding_format().Read() ==
2359           pw::bluetooth::emboss::CodingFormat::LINEAR_PCM) {
2360     auto io_pcm_format = FidlToPcmDataFormat(params.io_pcm_data_format());
2361     if (io_pcm_format.is_error()) {
2362       bt_log(WARN, "fidl", "Unsupported IO PCM data format in SCO parameters");
2363       return fpromise::error();
2364     }
2365     view.input_pcm_data_format().Write(io_pcm_format.value());
2366     view.output_pcm_data_format().Write(io_pcm_format.value());
2367 
2368   } else if (view.input_coding_format().coding_format().Read() ==
2369              pw::bluetooth::emboss::CodingFormat::LINEAR_PCM) {
2370     bt_log(WARN,
2371            "fidl",
2372            "SCO parameters missing io_pcm_data_format (required for linear PCM "
2373            "IO coding format)");
2374     return fpromise::error();
2375   } else {
2376     view.input_pcm_data_format().Write(
2377         pw::bluetooth::emboss::PcmDataFormat::NOT_APPLICABLE);
2378     view.output_pcm_data_format().Write(
2379         pw::bluetooth::emboss::PcmDataFormat::NOT_APPLICABLE);
2380   }
2381 
2382   if (params.has_io_pcm_sample_payload_msb_position() &&
2383       view.input_coding_format().coding_format().Read() ==
2384           pw::bluetooth::emboss::CodingFormat::LINEAR_PCM) {
2385     view.input_pcm_sample_payload_msb_position().Write(
2386         params.io_pcm_sample_payload_msb_position());
2387     view.output_pcm_sample_payload_msb_position().Write(
2388         params.io_pcm_sample_payload_msb_position());
2389   } else {
2390     view.input_pcm_sample_payload_msb_position().Write(0u);
2391     view.output_pcm_sample_payload_msb_position().Write(0u);
2392   }
2393 
2394   if (!params.has_path()) {
2395     bt_log(WARN, "fidl", "SCO parameters missing data path");
2396     return fpromise::error();
2397   }
2398   auto path = FidlToScoDataPath(params.path());
2399   view.input_data_path().Write(path);
2400   view.output_data_path().Write(path);
2401 
2402   // For HCI Host transport the transport unit size should be "0". For PCM
2403   // transport the unit size is vendor specific. A unit size of "0" indicates
2404   // "not applicable".
2405   // TODO(fxbug.dev/42136417): Use unit size from stack configuration file
2406   // instead of hardcoding "not applicable".
2407   view.input_transport_unit_size_bits().Write(0u);
2408   view.output_transport_unit_size_bits().Write(0u);
2409 
2410   view.max_latency_ms().Write(param_set.value().max_latency_ms);
2411   view.packet_types().BackingStorage().WriteUInt(
2412       param_set.value().packet_types);
2413   view.retransmission_effort().Write(
2414       static_cast<pw::bluetooth::emboss::SynchronousConnectionParameters::
2415                       ScoRetransmissionEffort>(
2416           param_set.value().retransmission_effort));
2417 
2418   return fpromise::ok(out);
2419 }
2420 
2421 fpromise::result<std::vector<bt::StaticPacket<
2422     pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>>
FidlToScoParametersVector(const std::vector<fbredr::ScoConnectionParameters> & params)2423 FidlToScoParametersVector(
2424     const std::vector<fbredr::ScoConnectionParameters>& params) {
2425   std::vector<bt::StaticPacket<
2426       pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>
2427       out;
2428   out.reserve(params.size());
2429   for (const fbredr::ScoConnectionParameters& param : params) {
2430     fpromise::result<bt::StaticPacket<
2431         pw::bluetooth::emboss::SynchronousConnectionParametersWriter>>
2432         result = FidlToScoParameters(param);
2433     if (result.is_error()) {
2434       return fpromise::error();
2435     }
2436     out.push_back(result.take_value());
2437   }
2438   return fpromise::ok(std::move(out));
2439 }
2440 
IsFidlGattHandleValid(fuchsia::bluetooth::gatt2::Handle handle)2441 bool IsFidlGattHandleValid(fuchsia::bluetooth::gatt2::Handle handle) {
2442   if (handle.value > std::numeric_limits<bt::att::Handle>::max()) {
2443     bt_log(ERROR,
2444            "fidl",
2445            "Invalid 64-bit FIDL GATT ID with `bits[16, 63] != 0` (0x%lX)",
2446            handle.value);
2447     return false;
2448   }
2449   return true;
2450 }
2451 
IsFidlGattServiceHandleValid(fuchsia::bluetooth::gatt2::ServiceHandle handle)2452 bool IsFidlGattServiceHandleValid(
2453     fuchsia::bluetooth::gatt2::ServiceHandle handle) {
2454   if (handle.value > std::numeric_limits<bt::att::Handle>::max()) {
2455     bt_log(ERROR,
2456            "fidl",
2457            "Invalid 64-bit FIDL GATT ID with `bits[16, 63] != 0` (0x%lX)",
2458            handle.value);
2459     return false;
2460   }
2461   return true;
2462 }
2463 
ScoPacketStatusToFidl(bt::hci_spec::SynchronousDataPacketStatusFlag status)2464 fuchsia::bluetooth::bredr::RxPacketStatus ScoPacketStatusToFidl(
2465     bt::hci_spec::SynchronousDataPacketStatusFlag status) {
2466   switch (status) {
2467     case bt::hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived:
2468       return fuchsia::bluetooth::bredr::RxPacketStatus::CORRECTLY_RECEIVED_DATA;
2469     case bt::hci_spec::SynchronousDataPacketStatusFlag::kPossiblyInvalid:
2470       return fuchsia::bluetooth::bredr::RxPacketStatus::POSSIBLY_INVALID_DATA;
2471     case bt::hci_spec::SynchronousDataPacketStatusFlag::kNoDataReceived:
2472       return fuchsia::bluetooth::bredr::RxPacketStatus::NO_DATA_RECEIVED;
2473     case bt::hci_spec::SynchronousDataPacketStatusFlag::kDataPartiallyLost:
2474       return fuchsia::bluetooth::bredr::RxPacketStatus::DATA_PARTIALLY_LOST;
2475   }
2476 }
2477 
Gatt2ErrorCodeFromFidl(fgatt2::Error error_code)2478 bt::att::ErrorCode Gatt2ErrorCodeFromFidl(fgatt2::Error error_code) {
2479   switch (error_code) {
2480     case fgatt2::Error::INVALID_HANDLE:
2481       return bt::att::ErrorCode::kInvalidHandle;
2482     case fgatt2::Error::READ_NOT_PERMITTED:
2483       return bt::att::ErrorCode::kReadNotPermitted;
2484     case fgatt2::Error::WRITE_NOT_PERMITTED:
2485       return bt::att::ErrorCode::kWriteNotPermitted;
2486     case fgatt2::Error::INVALID_OFFSET:
2487       return bt::att::ErrorCode::kInvalidOffset;
2488     case fgatt2::Error::INVALID_ATTRIBUTE_VALUE_LENGTH:
2489       return bt::att::ErrorCode::kInvalidAttributeValueLength;
2490     case fgatt2::Error::INSUFFICIENT_RESOURCES:
2491       return bt::att::ErrorCode::kInsufficientResources;
2492     case fgatt2::Error::VALUE_NOT_ALLOWED:
2493       return bt::att::ErrorCode::kValueNotAllowed;
2494     default:
2495       break;
2496   }
2497   return bt::att::ErrorCode::kUnlikelyError;
2498 }
2499 
Gatt2AccessRequirementsFromFidl(const fuchsia::bluetooth::gatt2::SecurityRequirements & reqs)2500 bt::att::AccessRequirements Gatt2AccessRequirementsFromFidl(
2501     const fuchsia::bluetooth::gatt2::SecurityRequirements& reqs) {
2502   return bt::att::AccessRequirements(
2503       reqs.has_encryption_required() ? reqs.encryption_required() : false,
2504       reqs.has_authentication_required() ? reqs.authentication_required()
2505                                          : false,
2506       reqs.has_authorization_required() ? reqs.authorization_required()
2507                                         : false);
2508 }
2509 
Gatt2DescriptorFromFidl(const fgatt2::Descriptor & fidl_desc)2510 std::unique_ptr<bt::gatt::Descriptor> Gatt2DescriptorFromFidl(
2511     const fgatt2::Descriptor& fidl_desc) {
2512   if (!fidl_desc.has_permissions()) {
2513     bt_log(
2514         WARN, "fidl", "FIDL descriptor missing required `permissions` field");
2515     return nullptr;
2516   }
2517   const fgatt2::AttributePermissions& perm = fidl_desc.permissions();
2518   bt::att::AccessRequirements read_reqs =
2519       perm.has_read() ? Gatt2AccessRequirementsFromFidl(perm.read())
2520                       : bt::att::AccessRequirements();
2521   bt::att::AccessRequirements write_reqs =
2522       perm.has_write() ? Gatt2AccessRequirementsFromFidl(perm.write())
2523                        : bt::att::AccessRequirements();
2524 
2525   if (!fidl_desc.has_type()) {
2526     bt_log(WARN, "fidl", "FIDL descriptor missing required `type` field");
2527     return nullptr;
2528   }
2529   bt::UUID type(fidl_desc.type().value);
2530 
2531   if (!fidl_desc.has_handle()) {
2532     bt_log(WARN, "fidl", "FIDL characteristic missing required `handle` field");
2533     return nullptr;
2534   }
2535   return std::make_unique<bt::gatt::Descriptor>(
2536       fidl_desc.handle().value, type, read_reqs, write_reqs);
2537 }
2538 
Gatt2CharacteristicFromFidl(const fgatt2::Characteristic & fidl_chrc)2539 std::unique_ptr<bt::gatt::Characteristic> Gatt2CharacteristicFromFidl(
2540     const fgatt2::Characteristic& fidl_chrc) {
2541   if (!fidl_chrc.has_properties()) {
2542     bt_log(WARN,
2543            "fidl",
2544            "FIDL characteristic missing required `properties` field");
2545     return nullptr;
2546   }
2547   if (!fidl_chrc.has_permissions()) {
2548     bt_log(WARN,
2549            "fidl",
2550            "FIDL characteristic missing required `permissions` field");
2551     return nullptr;
2552   }
2553   if (!fidl_chrc.has_type()) {
2554     bt_log(WARN, "fidl", "FIDL characteristic missing required `type` field");
2555     return nullptr;
2556   }
2557   if (!fidl_chrc.has_handle()) {
2558     bt_log(WARN, "fidl", "FIDL characteristic missing required `handle` field");
2559     return nullptr;
2560   }
2561 
2562   uint8_t props = static_cast<uint8_t>(fidl_chrc.properties());
2563   const uint16_t ext_props =
2564       static_cast<uint16_t>(fidl_chrc.properties()) >> CHAR_BIT;
2565   if (ext_props) {
2566     props |= bt::gatt::Property::kExtendedProperties;
2567   }
2568 
2569   const fgatt2::AttributePermissions& permissions = fidl_chrc.permissions();
2570   bool supports_update = (props & bt::gatt::Property::kNotify) ||
2571                          (props & bt::gatt::Property::kIndicate);
2572   if (supports_update != permissions.has_update()) {
2573     bt_log(WARN,
2574            "fidl",
2575            "Characteristic update permission %s",
2576            supports_update ? "required" : "must be null");
2577     return nullptr;
2578   }
2579 
2580   bt::att::AccessRequirements read_reqs =
2581       permissions.has_read()
2582           ? Gatt2AccessRequirementsFromFidl(permissions.read())
2583           : bt::att::AccessRequirements();
2584   bt::att::AccessRequirements write_reqs =
2585       permissions.has_write()
2586           ? Gatt2AccessRequirementsFromFidl(permissions.write())
2587           : bt::att::AccessRequirements();
2588   bt::att::AccessRequirements update_reqs =
2589       permissions.has_update()
2590           ? Gatt2AccessRequirementsFromFidl(permissions.update())
2591           : bt::att::AccessRequirements();
2592 
2593   bt::UUID type(fidl_chrc.type().value);
2594 
2595   auto chrc =
2596       std::make_unique<bt::gatt::Characteristic>(fidl_chrc.handle().value,
2597                                                  type,
2598                                                  props,
2599                                                  ext_props,
2600                                                  read_reqs,
2601                                                  write_reqs,
2602                                                  update_reqs);
2603   if (fidl_chrc.has_descriptors()) {
2604     for (const auto& fidl_desc : fidl_chrc.descriptors()) {
2605       std::unique_ptr<bt::gatt::Descriptor> maybe_desc =
2606           fidl_helpers::Gatt2DescriptorFromFidl(fidl_desc);
2607       if (!maybe_desc) {
2608         // Specific failures are logged in Gatt2DescriptorFromFidl
2609         return nullptr;
2610       }
2611 
2612       chrc->AddDescriptor(std::move(maybe_desc));
2613     }
2614   }
2615 
2616   return chrc;
2617 }
2618 
DataPathDirectionToString(pw::bluetooth::emboss::DataPathDirection direction)2619 const char* DataPathDirectionToString(
2620     pw::bluetooth::emboss::DataPathDirection direction) {
2621   switch (direction) {
2622     case pw::bluetooth::emboss::DataPathDirection::INPUT:
2623       return "input";
2624     case pw::bluetooth::emboss::DataPathDirection::OUTPUT:
2625       return "output";
2626     default:
2627       return "invalid";
2628   }
2629 }
2630 
DataPathDirectionFromFidl(const fuchsia::bluetooth::DataDirection & fidl_direction)2631 pw::bluetooth::emboss::DataPathDirection DataPathDirectionFromFidl(
2632     const fuchsia::bluetooth::DataDirection& fidl_direction) {
2633   switch (fidl_direction) {
2634     case fuchsia::bluetooth::DataDirection::INPUT:
2635       return pw::bluetooth::emboss::DataPathDirection::INPUT;
2636     case fuchsia::bluetooth::DataDirection::OUTPUT:
2637       return pw::bluetooth::emboss::DataPathDirection::OUTPUT;
2638   }
2639   PW_CRASH("Unrecognized value for data direction: %" PRIu8, fidl_direction);
2640 }
2641 
2642 // Both of these types use the spec representation, so we can just assign the
2643 // underlying value directly.
CodingFormatFromFidl(const fuchsia::bluetooth::AssignedCodingFormat & fidl_format)2644 pw::bluetooth::emboss::CodingFormat CodingFormatFromFidl(
2645     const fuchsia::bluetooth::AssignedCodingFormat& fidl_format) {
2646   switch (fidl_format) {
2647     case fuchsia::bluetooth::AssignedCodingFormat::U_LAW_LOG:
2648       return pw::bluetooth::emboss::CodingFormat::U_LAW;
2649     case fuchsia::bluetooth::AssignedCodingFormat::A_LAW_LOG:
2650       return pw::bluetooth::emboss::CodingFormat::A_LAW;
2651     case fuchsia::bluetooth::AssignedCodingFormat::CVSD:
2652       return pw::bluetooth::emboss::CodingFormat::CVSD;
2653     case fuchsia::bluetooth::AssignedCodingFormat::TRANSPARENT:
2654       return pw::bluetooth::emboss::CodingFormat::TRANSPARENT;
2655     case fuchsia::bluetooth::AssignedCodingFormat::LINEAR_PCM:
2656       return pw::bluetooth::emboss::CodingFormat::LINEAR_PCM;
2657     case fuchsia::bluetooth::AssignedCodingFormat::MSBC:
2658       return pw::bluetooth::emboss::CodingFormat::MSBC;
2659     case fuchsia::bluetooth::AssignedCodingFormat::LC3:
2660       return pw::bluetooth::emboss::CodingFormat::LC3;
2661     case fuchsia::bluetooth::AssignedCodingFormat::G_729A:
2662       return pw::bluetooth::emboss::CodingFormat::G729A;
2663   }
2664   PW_CRASH("Unrecognized value for coding format: %u",
2665            static_cast<unsigned>(fidl_format));
2666 }
2667 
CodecIdFromFidl(const fuchsia::bluetooth::CodecId & fidl_codec_id)2668 bt::StaticPacket<pw::bluetooth::emboss::CodecIdWriter> CodecIdFromFidl(
2669     const fuchsia::bluetooth::CodecId& fidl_codec_id) {
2670   bt::StaticPacket<pw::bluetooth::emboss::CodecIdWriter> result;
2671   auto result_view = result.view();
2672 
2673   if (fidl_codec_id.is_assigned_format()) {
2674     pw::bluetooth::emboss::CodingFormat out_coding_format =
2675         CodingFormatFromFidl(fidl_codec_id.assigned_format());
2676     result_view.coding_format().Write(out_coding_format);
2677   } else {
2678     PW_CHECK(fidl_codec_id.is_vendor_format());
2679     result_view.coding_format().Write(
2680         pw::bluetooth::emboss::CodingFormat::VENDOR_SPECIFIC);
2681     result_view.company_id().Write(fidl_codec_id.vendor_format().company_id());
2682     result_view.vendor_codec_id().Write(
2683         fidl_codec_id.vendor_format().vendor_id());
2684   }
2685   return result;
2686 }
2687 
2688 // Note that:
2689 // a) The FIDL values used do not necessarily correspond to Core Spec values.
2690 // b) Only a subset of valid values are implemented in the FIDL type at the
2691 // moment.
LogicalTransportTypeFromFidl(const fuchsia::bluetooth::LogicalTransportType & fidl_transport_type)2692 pw::bluetooth::emboss::LogicalTransportType LogicalTransportTypeFromFidl(
2693     const fuchsia::bluetooth::LogicalTransportType& fidl_transport_type) {
2694   switch (fidl_transport_type) {
2695     case fuchsia::bluetooth::LogicalTransportType::LE_CIS:
2696       return pw::bluetooth::emboss::LogicalTransportType::LE_CIS;
2697     case fuchsia::bluetooth::LogicalTransportType::LE_BIS:
2698       return pw::bluetooth::emboss::LogicalTransportType::LE_BIS;
2699   }
2700   PW_CRASH("Unrecognized value for logical transport type: %u",
2701            static_cast<unsigned>(fidl_transport_type));
2702 }
2703 
FidlHciErrorToStatusCode(fhbt::HciError code)2704 pw::bluetooth::emboss::StatusCode FidlHciErrorToStatusCode(
2705     fhbt::HciError code) {
2706   switch (code) {
2707     case fuchsia_hardware_bluetooth::HciError::kSuccess:
2708       return pw::bluetooth::emboss::StatusCode::SUCCESS;
2709     case fuchsia_hardware_bluetooth::HciError::kUnknownCommand:
2710       return pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND;
2711     case fuchsia_hardware_bluetooth::HciError::kUnknownConnectionId:
2712       return pw::bluetooth::emboss::StatusCode::UNKNOWN_CONNECTION_ID;
2713     case fuchsia_hardware_bluetooth::HciError::kHardwareFailure:
2714       return pw::bluetooth::emboss::StatusCode::HARDWARE_FAILURE;
2715     case fuchsia_hardware_bluetooth::HciError::kPageTimeout:
2716       return pw::bluetooth::emboss::StatusCode::PAGE_TIMEOUT;
2717     case fuchsia_hardware_bluetooth::HciError::kAuthenticationFailure:
2718       return pw::bluetooth::emboss::StatusCode::AUTHENTICATION_FAILURE;
2719     case fuchsia_hardware_bluetooth::HciError::kPinOrKeyMissing:
2720       return pw::bluetooth::emboss::StatusCode::PIN_OR_KEY_MISSING;
2721     case fuchsia_hardware_bluetooth::HciError::kMemoryCapacityExceeded:
2722       return pw::bluetooth::emboss::StatusCode::MEMORY_CAPACITY_EXCEEDED;
2723     case fuchsia_hardware_bluetooth::HciError::kConnectionTimeout:
2724       return pw::bluetooth::emboss::StatusCode::CONNECTION_TIMEOUT;
2725     case fuchsia_hardware_bluetooth::HciError::kConnectionLimitExceeded:
2726       return pw::bluetooth::emboss::StatusCode::CONNECTION_LIMIT_EXCEEDED;
2727     case fuchsia_hardware_bluetooth::HciError::
2728         kSynchronousConnectionLimitExceeded:
2729       return pw::bluetooth::emboss::StatusCode::
2730           SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED;
2731     case fuchsia_hardware_bluetooth::HciError::kConnectionAlreadyExists:
2732       return pw::bluetooth::emboss::StatusCode::CONNECTION_ALREADY_EXISTS;
2733     case fuchsia_hardware_bluetooth::HciError::kCommandDisallowed:
2734       return pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED;
2735     case fuchsia_hardware_bluetooth::HciError::
2736         kConnectionRejectedLimitedResources:
2737       return pw::bluetooth::emboss::StatusCode::
2738           CONNECTION_REJECTED_LIMITED_RESOURCES;
2739     case fuchsia_hardware_bluetooth::HciError::kConnectionRejectedSecurity:
2740       return pw::bluetooth::emboss::StatusCode::CONNECTION_REJECTED_SECURITY;
2741     case fuchsia_hardware_bluetooth::HciError::kConnectionRejectedBadBdAddr:
2742       return pw::bluetooth::emboss::StatusCode::CONNECTION_REJECTED_BAD_BD_ADDR;
2743     case fuchsia_hardware_bluetooth::HciError::kConnectionAcceptTimeoutExceeded:
2744       return pw::bluetooth::emboss::StatusCode::
2745           CONNECTION_ACCEPT_TIMEOUT_EXCEEDED;
2746     case fuchsia_hardware_bluetooth::HciError::kUnsupportedFeatureOrParameter:
2747       return pw::bluetooth::emboss::StatusCode::
2748           UNSUPPORTED_FEATURE_OR_PARAMETER;
2749     case fuchsia_hardware_bluetooth::HciError::kInvalidHcicommandParameters:
2750       return pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS;
2751     case fuchsia_hardware_bluetooth::HciError::kRemoteUserTerminatedConnection:
2752       return pw::bluetooth::emboss::StatusCode::
2753           REMOTE_USER_TERMINATED_CONNECTION;
2754     case fuchsia_hardware_bluetooth::HciError::
2755         kRemoteDeviceTerminatedConnectionLowResources:
2756       return pw::bluetooth::emboss::StatusCode::
2757           REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES;
2758     case fuchsia_hardware_bluetooth::HciError::
2759         kRemoteDeviceTerminatedConnectionPowerOff:
2760       return pw::bluetooth::emboss::StatusCode::
2761           REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF;
2762     case fuchsia_hardware_bluetooth::HciError::kConnectionTerminatedByLocalHost:
2763       return pw::bluetooth::emboss::StatusCode::
2764           CONNECTION_TERMINATED_BY_LOCAL_HOST;
2765     case fuchsia_hardware_bluetooth::HciError::kRepeatedAttempts:
2766       return pw::bluetooth::emboss::StatusCode::REPEATED_ATTEMPTS;
2767     case fuchsia_hardware_bluetooth::HciError::kPairingNotAllowed:
2768       return pw::bluetooth::emboss::StatusCode::PAIRING_NOT_ALLOWED;
2769     case fuchsia_hardware_bluetooth::HciError::kUnknownLmpPdu:
2770       return pw::bluetooth::emboss::StatusCode::UNKNOWN_LMP_PDU;
2771     case fuchsia_hardware_bluetooth::HciError::kUnsupportedRemoteFeature:
2772       return pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE;
2773     case fuchsia_hardware_bluetooth::HciError::kScoOffsetRejected:
2774       return pw::bluetooth::emboss::StatusCode::SCO_OFFSET_REJECTED;
2775     case fuchsia_hardware_bluetooth::HciError::kScoIntervalRejected:
2776       return pw::bluetooth::emboss::StatusCode::SCO_INTERVAL_REJECTED;
2777     case fuchsia_hardware_bluetooth::HciError::kScoAirModeRejected:
2778       return pw::bluetooth::emboss::StatusCode::SCO_AIRMODE_REJECTED;
2779     case fuchsia_hardware_bluetooth::HciError::kInvalidLmpOrLlParameters:
2780       return pw::bluetooth::emboss::StatusCode::INVALID_LMP_OR_LL_PARAMETERS;
2781     case fuchsia_hardware_bluetooth::HciError::kUnspecifiedError:
2782       return pw::bluetooth::emboss::StatusCode::UNSPECIFIED_ERROR;
2783     case fuchsia_hardware_bluetooth::HciError::
2784         kUnsupportedLmpOrLlParameterValue:
2785       return pw::bluetooth::emboss::StatusCode::
2786           UNSUPPORTED_LMP_OR_LL_PARAMETER_VALUE;
2787     case fuchsia_hardware_bluetooth::HciError::kRoleChangeNotAllowed:
2788       return pw::bluetooth::emboss::StatusCode::ROLE_CHANGE_NOT_ALLOWED;
2789     case fuchsia_hardware_bluetooth::HciError::kLmpOrLlResponseTimeout:
2790       return pw::bluetooth::emboss::StatusCode::LMP_OR_LL_RESPONSE_TIMEOUT;
2791     case fuchsia_hardware_bluetooth::HciError::kLmpErrorTransactionCollision:
2792       return pw::bluetooth::emboss::StatusCode::LMP_ERROR_TRANSACTION_COLLISION;
2793     case fuchsia_hardware_bluetooth::HciError::kLmpPduNotAllowed:
2794       return pw::bluetooth::emboss::StatusCode::LMP_PDU_NOT_ALLOWED;
2795     case fuchsia_hardware_bluetooth::HciError::kEncryptionModeNotAcceptable:
2796       return pw::bluetooth::emboss::StatusCode::ENCRYPTION_MODE_NOT_ACCEPTABLE;
2797     case fuchsia_hardware_bluetooth::HciError::kLinkKeyCannotBeChanged:
2798       return pw::bluetooth::emboss::StatusCode::LINK_KEY_CANNOT_BE_CHANGED;
2799     case fuchsia_hardware_bluetooth::HciError::kRequestedQosNotSupported:
2800       return pw::bluetooth::emboss::StatusCode::REQUESTED_QOS_NOT_SUPPORTED;
2801     case fuchsia_hardware_bluetooth::HciError::kInstantPassed:
2802       return pw::bluetooth::emboss::StatusCode::INSTANT_PASSED;
2803     case fuchsia_hardware_bluetooth::HciError::kPairingWithUnitKeyNotSupported:
2804       return pw::bluetooth::emboss::StatusCode::
2805           PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED;
2806     case fuchsia_hardware_bluetooth::HciError::kDifferentTransactionCollision:
2807       return pw::bluetooth::emboss::StatusCode::DIFFERENT_TRANSACTION_COLLISION;
2808     case fuchsia_hardware_bluetooth::HciError::kReserved0:
2809       return pw::bluetooth::emboss::StatusCode::RESERVED_0;
2810     case fuchsia_hardware_bluetooth::HciError::kQosUnacceptableParameter:
2811       return pw::bluetooth::emboss::StatusCode::QOS_UNACCEPTABLE_PARAMETER;
2812     case fuchsia_hardware_bluetooth::HciError::kQosRejected:
2813       return pw::bluetooth::emboss::StatusCode::QOS_REJECTED;
2814     case fuchsia_hardware_bluetooth::HciError::
2815         kChannelClassificationNotSupported:
2816       return pw::bluetooth::emboss::StatusCode::
2817           CHANNEL_CLASSIFICATION_NOT_SUPPORTED;
2818     case fuchsia_hardware_bluetooth::HciError::kInsufficientSecurity:
2819       return pw::bluetooth::emboss::StatusCode::INSUFFICIENT_SECURITY;
2820     case fuchsia_hardware_bluetooth::HciError::kParameterOutOfMandatoryRange:
2821       return pw::bluetooth::emboss::StatusCode::
2822           PARAMETER_OUT_OF_MANDATORY_RANGE;
2823     case fuchsia_hardware_bluetooth::HciError::kReserved1:
2824       return pw::bluetooth::emboss::StatusCode::RESERVED_1;
2825     case fuchsia_hardware_bluetooth::HciError::kRoleSwitchPending:
2826       return pw::bluetooth::emboss::StatusCode::ROLE_SWITCH_PENDING;
2827     case fuchsia_hardware_bluetooth::HciError::kReserved2:
2828       return pw::bluetooth::emboss::StatusCode::RESERVED_2;
2829     case fuchsia_hardware_bluetooth::HciError::kReservedSlotViolation:
2830       return pw::bluetooth::emboss::StatusCode::RESERVED_SLOT_VIOLATION;
2831     case fuchsia_hardware_bluetooth::HciError::kRoleSwitchFailed:
2832       return pw::bluetooth::emboss::StatusCode::ROLE_SWITCH_FAILED;
2833     case fuchsia_hardware_bluetooth::HciError::kExtendedInquiryResponseTooLarge:
2834       return pw::bluetooth::emboss::StatusCode::
2835           EXTENDED_INQUIRY_RESPONSE_TOO_LARGE;
2836     case fuchsia_hardware_bluetooth::HciError::
2837         kSecureSimplePairingNotSupportedByHost:
2838       return pw::bluetooth::emboss::StatusCode::
2839           SECURE_SIMPLE_PAIRING_NOT_SUPPORTED_BY_HOST;
2840     case fuchsia_hardware_bluetooth::HciError::kHostBusyPairing:
2841       return pw::bluetooth::emboss::StatusCode::HOST_BUSY_PAIRING;
2842     case fuchsia_hardware_bluetooth::HciError::
2843         kConnectionRejectedNoSuitableChannelFound:
2844       return pw::bluetooth::emboss::StatusCode::
2845           CONNECTION_REJECTED_NO_SUITABLE_CHANNEL_FOUND;
2846     case fuchsia_hardware_bluetooth::HciError::kControllerBusy:
2847       return pw::bluetooth::emboss::StatusCode::CONTROLLER_BUSY;
2848     case fuchsia_hardware_bluetooth::HciError::
2849         kUnacceptableConnectionParameters:
2850       return pw::bluetooth::emboss::StatusCode::
2851           UNACCEPTABLE_CONNECTION_PARAMETERS;
2852     case fuchsia_hardware_bluetooth::HciError::kDirectedAdvertisingTimeout:
2853       return pw::bluetooth::emboss::StatusCode::DIRECTED_ADVERTISING_TIMEOUT;
2854     case fuchsia_hardware_bluetooth::HciError::kConnectionTerminatedMicFailure:
2855       return pw::bluetooth::emboss::StatusCode::
2856           CONNECTION_TERMINATED_MIC_FAILURE;
2857     case fuchsia_hardware_bluetooth::HciError::kConnectionFailedToBeEstablished:
2858       return pw::bluetooth::emboss::StatusCode::
2859           CONNECTION_FAILED_TO_BE_ESTABLISHED;
2860     case fuchsia_hardware_bluetooth::HciError::kMacConnectionFailed:
2861       return pw::bluetooth::emboss::StatusCode::MAC_CONNECTION_FAILED;
2862     case fuchsia_hardware_bluetooth::HciError::kCoarseClockAdjustmentRejected:
2863       return pw::bluetooth::emboss::StatusCode::
2864           COARSE_CLOCK_ADJUSTMENT_REJECTED;
2865     case fuchsia_hardware_bluetooth::HciError::kType0SubmapNotDefined:
2866       return pw::bluetooth::emboss::StatusCode::TYPE_0_SUBMAP_NOT_DEFINED;
2867     case fuchsia_hardware_bluetooth::HciError::kUnknownAdvertisingIdentifier:
2868       return pw::bluetooth::emboss::StatusCode::UNKNOWN_ADVERTISING_IDENTIFIER;
2869     case fuchsia_hardware_bluetooth::HciError::kLimitReached:
2870       return pw::bluetooth::emboss::StatusCode::LIMIT_REACHED;
2871     case fuchsia_hardware_bluetooth::HciError::kOperationCancelledByHost:
2872       return pw::bluetooth::emboss::StatusCode::OPERATION_CANCELLED_BY_HOST;
2873     case fuchsia_hardware_bluetooth::HciError::kPacketTooLong:
2874       return pw::bluetooth::emboss::StatusCode::PACKET_TOO_LONG;
2875     case fuchsia_hardware_bluetooth::HciError::kTooLate:
2876       return pw::bluetooth::emboss::StatusCode::TOO_LATE;
2877     case fuchsia_hardware_bluetooth::HciError::kTooEarly:
2878       return pw::bluetooth::emboss::StatusCode::TOO_EARLY;
2879     default:
2880       return pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND;
2881   }
2882 }
2883 
CisEstablishedParametersToFidl(const bt::iso::CisEstablishedParameters & params_in)2884 fuchsia::bluetooth::le::CisEstablishedParameters CisEstablishedParametersToFidl(
2885     const bt::iso::CisEstablishedParameters& params_in) {
2886   fuchsia::bluetooth::le::CisEstablishedParameters params_out;
2887 
2888   // General parameters
2889   zx::duration cig_sync_delay = zx::usec(params_in.cig_sync_delay);
2890   params_out.set_cig_sync_delay(cig_sync_delay.get());
2891   zx::duration cis_sync_delay = zx::usec(params_in.cis_sync_delay);
2892   params_out.set_cis_sync_delay(cis_sync_delay.get());
2893   params_out.set_max_subevents(params_in.max_subevents);
2894   zx::duration iso_interval =
2895       zx::usec(params_in.iso_interval *
2896                bt::iso::CisEstablishedParameters::kIsoIntervalToMicroseconds);
2897   params_out.set_iso_interval(iso_interval.get());
2898 
2899   // Central => Peripheral parameters
2900   // phy and max_pdu_size are not passed back to FIDL client
2901   if (params_in.c_to_p_params.burst_number > 0) {
2902     fuchsia::bluetooth::le::CisUnidirectionalParams c_to_p_params;
2903     zx::duration transport_latency =
2904         zx::usec(params_in.c_to_p_params.transport_latency);
2905     c_to_p_params.set_transport_latency(transport_latency.get());
2906     c_to_p_params.set_burst_number(params_in.c_to_p_params.burst_number);
2907     c_to_p_params.set_flush_timeout(params_in.c_to_p_params.flush_timeout);
2908     params_out.set_central_to_peripheral_params(std::move(c_to_p_params));
2909   }
2910 
2911   // Peripheral => Central parameters
2912   // phy and max_pdu_size are not passed back to FIDL client
2913   if (params_in.p_to_c_params.burst_number > 0) {
2914     fuchsia::bluetooth::le::CisUnidirectionalParams p_to_c_params;
2915     zx::duration transport_latency =
2916         zx::usec(params_in.p_to_c_params.transport_latency);
2917     p_to_c_params.set_transport_latency(transport_latency.get());
2918     p_to_c_params.set_burst_number(params_in.p_to_c_params.burst_number);
2919     p_to_c_params.set_flush_timeout(params_in.p_to_c_params.flush_timeout);
2920     params_out.set_peripheral_to_central_params(std::move(p_to_c_params));
2921   }
2922 
2923   return params_out;
2924 }
2925 
FidlToDeviceAddressType(fbt::AddressType addr_type)2926 bt::DeviceAddress::Type FidlToDeviceAddressType(fbt::AddressType addr_type) {
2927   switch (addr_type) {
2928     case fbt::AddressType::PUBLIC:
2929       return bt::DeviceAddress::Type::kLEPublic;
2930     case fbt::AddressType::RANDOM:
2931       return bt::DeviceAddress::Type::kLERandom;
2932   }
2933 }
2934 
EmbossIsoPacketStatusFlagToFidl(pw::bluetooth::emboss::IsoDataPacketStatus status_in)2935 fble::IsoPacketStatusFlag EmbossIsoPacketStatusFlagToFidl(
2936     pw::bluetooth::emboss::IsoDataPacketStatus status_in) {
2937   switch (status_in) {
2938     case pw::bluetooth::emboss::IsoDataPacketStatus::VALID_DATA:
2939       return fble::IsoPacketStatusFlag::VALID_DATA;
2940     case pw::bluetooth::emboss::IsoDataPacketStatus::POSSIBLY_INVALID_DATA:
2941       return fble::IsoPacketStatusFlag::DATA_WITH_POSSIBLE_ERRORS;
2942     case pw::bluetooth::emboss::IsoDataPacketStatus::LOST_DATA:
2943       return fble::IsoPacketStatusFlag::LOST_DATA;
2944   }
2945 }
2946 
2947 }  // namespace bthost::fidl_helpers
2948 
2949 // static
2950 std::vector<uint8_t>
Convert(const bt::ByteBuffer & from)2951 fidl::TypeConverter<std::vector<uint8_t>, bt::ByteBuffer>::Convert(
2952     const bt::ByteBuffer& from) {
2953   std::vector<uint8_t> to(from.size());
2954   bt::MutableBufferView view(to.data(), to.size());
2955   view.Write(from);
2956   return to;
2957 }
2958