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