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