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