1use fidl_fuchsia_bluetooth as fidl_bt;
6use fidl_fuchsia_bluetooth_bredr::{
7 self as fidl_bredr, ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, ATTR_SERVICE_CLASS_ID_LIST,
8 ProfileDescriptor,
9};
10use fidl_table_validation::ValidFidlTable;
11#[cfg(target_os = "fuchsia")]
12use fuchsia_inspect as inspect;
13#[cfg(target_os = "fuchsia")]
14use fuchsia_inspect_derive::{AttachError, Inspect, Unit};
15use std::cmp::min;
16use std::collections::HashSet;
17
18use crate::assigned_numbers::AssignedNumber;
19use crate::assigned_numbers::constants::SERVICE_CLASS_UUIDS;
20use crate::error::Error;
21use crate::types::Uuid;
22
23pub mod avrcp;
25
26#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
28pub struct Psm(u16);
29
30impl Psm {
31 pub const RFCOMM: Self = Self(fidl_bredr::PSM_RFCOMM);
33 pub const HID_CONTROL: Self = Self(fidl_bredr::PSM_HID_CONTROL);
34 pub const HID_INTERRUPT: Self = Self(fidl_bredr::PSM_HID_INTERRUPT);
35 pub const AVDTP: Self = Self(fidl_bredr::PSM_AVDTP);
36 pub const AVCTP: Self = Self(fidl_bredr::PSM_AVCTP);
37 pub const AVCTP_BROWSE: Self = Self(fidl_bredr::PSM_AVCTP_BROWSE);
38 pub const DYNAMIC: Self = Self(fidl_bredr::PSM_DYNAMIC);
39
40 pub fn new(value: u16) -> Self {
41 Self(value)
42 }
43}
44
45impl From<Psm> for u16 {
46 fn from(src: Psm) -> u16 {
47 src.0
48 }
49}
50
51pub fn elem_to_profile_descriptor(elem: &fidl_bredr::DataElement) -> Option<ProfileDescriptor> {
54 if let fidl_bredr::DataElement::Sequence(seq) = elem {
55 if seq.len() != 2 {
56 return None;
57 }
58
59 if seq[0].is_none() {
60 return None;
61 }
62 let profile_id = match **seq[0].as_ref().expect("not none") {
63 fidl_bredr::DataElement::Uuid(uuid) => {
64 let uuid: Uuid = uuid.into();
65 match uuid.try_into() {
66 Err(_) => return None,
67 Ok(profile_id) => profile_id,
68 }
69 }
70 _ => return None,
71 };
72
73 if seq[1].is_none() {
74 return None;
75 }
76 let [major_version, minor_version] = match **seq[1].as_ref().expect("not none") {
77 fidl_bredr::DataElement::Uint16(val) => val.to_be_bytes(),
78 _ => return None,
79 };
80 return Some(ProfileDescriptor {
81 profile_id: Some(profile_id),
82 major_version: Some(major_version),
83 minor_version: Some(minor_version),
84 ..Default::default()
85 });
86 }
87 None
88}
89
90pub fn find_profile_descriptors(
95 attributes: &[fidl_bredr::Attribute],
96) -> Result<Vec<ProfileDescriptor>, Error> {
97 let attr = attributes
98 .iter()
99 .find(|a| a.id == Some(ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST))
100 .ok_or_else(|| Error::profile("missing profile descriptor"))?;
101
102 let Some(fidl_bredr::DataElement::Sequence(profiles)) = &attr.element else {
103 return Err(Error::profile("attribute element is invalidly formatted"));
104 };
105 let mut result = Vec::new();
106 for elem in profiles {
107 let elem = elem.as_ref().ok_or_else(|| Error::profile("null DataElement in sequence"))?;
108 result.push(
109 elem_to_profile_descriptor(&*elem)
110 .ok_or_else(|| Error::profile("couldn't convert to a ProfileDescriptor"))?,
111 );
112 }
113 if result.is_empty() { Err(Error::profile("no profile descriptor found")) } else { Ok(result) }
114}
115
116pub fn profile_descriptor_to_assigned(profile_desc: &ProfileDescriptor) -> Option<AssignedNumber> {
117 let Some(id) = profile_desc.profile_id else {
118 return None;
119 };
120 SERVICE_CLASS_UUIDS.iter().find(|scn| id.into_primitive() == scn.number).cloned()
121}
122
123pub fn psm_from_protocol(protocol: &Vec<ProtocolDescriptor>) -> Option<Psm> {
126 for descriptor in protocol {
127 if descriptor.protocol == fidl_bredr::ProtocolIdentifier::L2Cap {
128 if descriptor.params.len() != 1 {
129 return None;
130 }
131
132 if let DataElement::Uint16(psm) = descriptor.params[0] {
133 return Some(Psm::new(psm));
134 }
135 return None;
136 }
137 }
138 None
139}
140
141pub fn channel_number_from_protocol(
144 protocol: &Vec<fidl_bredr::ProtocolDescriptor>,
145) -> Result<i32, Error> {
146 for prot in protocol {
147 let Some(params) = prot.params.as_ref() else {
148 return Err(Error::profile("Invalid service definition"));
149 };
150 if prot.protocol == Some(fidl_bredr::ProtocolIdentifier::L2Cap) {
151 let [fidl_bredr::DataElement::Uint16(l2cap_port)] = params[..] else {
154 continue;
155 };
156 return Ok(l2cap_port.into());
157 }
158
159 if prot.protocol == Some(fidl_bredr::ProtocolIdentifier::Rfcomm) {
160 let [fidl_bredr::DataElement::Uint8(rfcomm_port)] = params[..] else {
162 return Err(Error::profile("Invalid RFCOMM service definition"));
163 };
164 return Ok(rfcomm_port.into());
165 }
166 }
167 Err(Error::profile("ProtocolDescriptor missing channel number"))
168}
169
170pub fn channel_number_from_parameters(
173 parameters: &fidl_bredr::ConnectParameters,
174) -> Result<i32, Error> {
175 match parameters {
176 fidl_bredr::ConnectParameters::Rfcomm(fidl_bredr::RfcommParameters {
177 channel: Some(port),
178 ..
179 }) => Ok((*port).into()),
180 fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
181 psm: Some(psm),
182 ..
183 }) => Ok((*psm).into()),
184 _ => Err(Error::profile(format!("Invalid parameters: {parameters:?}"))),
185 }
186}
187
188pub fn find_service_classes(
190 attributes: &[fidl_fuchsia_bluetooth_bredr::Attribute],
191) -> Vec<AssignedNumber> {
192 let uuids = find_all_service_classes(attributes);
193 SERVICE_CLASS_UUIDS
194 .iter()
195 .filter(|scn| uuids.contains(&Uuid::new16(scn.number)))
196 .cloned()
197 .collect()
198}
199
200pub fn find_all_service_classes(
202 attributes: &[fidl_fuchsia_bluetooth_bredr::Attribute],
203) -> Vec<Uuid> {
204 let Some(attr) = attributes.iter().find(|a| a.id == Some(ATTR_SERVICE_CLASS_ID_LIST)) else {
205 return vec![];
206 };
207 let Some(fidl_fuchsia_bluetooth_bredr::DataElement::Sequence(elems)) = &attr.element else {
208 return vec![];
209 };
210 elems
211 .iter()
212 .filter_map(|e| {
213 e.as_ref().and_then(|e| match **e {
214 fidl_fuchsia_bluetooth_bredr::DataElement::Uuid(uuid) => Some(uuid.into()),
215 _ => None,
216 })
217 })
218 .collect()
219}
220
221pub fn combine_security_requirements(
226 reqs: &SecurityRequirements,
227 other: &SecurityRequirements,
228) -> SecurityRequirements {
229 let authentication_required =
230 match (reqs.authentication_required, other.authentication_required) {
231 (Some(true), _) | (_, Some(true)) => Some(true),
232 (Some(x), None) | (None, Some(x)) => Some(x),
233 _ => None,
234 };
235 let secure_connections_required =
236 match (reqs.secure_connections_required, other.secure_connections_required) {
237 (Some(true), _) | (_, Some(true)) => Some(true),
238 (Some(x), None) | (None, Some(x)) => Some(x),
239 _ => None,
240 };
241 SecurityRequirements { authentication_required, secure_connections_required }
242}
243
244pub fn combine_channel_parameters(
250 params: &ChannelParameters,
251 other: &ChannelParameters,
252) -> ChannelParameters {
253 let channel_mode = match (params.channel_mode, other.channel_mode) {
254 (Some(fidl_bt::ChannelMode::Basic), _) | (_, Some(fidl_bt::ChannelMode::Basic)) => {
255 Some(fidl_bt::ChannelMode::Basic)
256 }
257 (Some(x), None) | (None, Some(x)) => Some(x),
258 _ => None,
259 };
260 let max_rx_sdu_size = match (params.max_rx_sdu_size, other.max_rx_sdu_size) {
261 (Some(rx1), Some(rx2)) => Some(min(rx1, rx2)),
262 (Some(x), None) | (None, Some(x)) => Some(x),
263 _ => None,
264 };
265 let security_requirements = match (¶ms.security_requirements, &other.security_requirements)
266 {
267 (Some(reqs1), Some(reqs2)) => Some(combine_security_requirements(reqs1, reqs2)),
268 (Some(reqs), _) | (_, Some(reqs)) => Some(reqs.clone()),
269 _ => None,
270 };
271 ChannelParameters { channel_mode, max_rx_sdu_size, security_requirements }
272}
273
274#[derive(Clone, Debug, PartialEq)]
279pub enum DataElement {
280 Int8(i8),
281 Int16(i16),
282 Int32(i32),
283 Int64(i64),
284 Uint8(u8),
285 Uint16(u16),
286 Uint32(u32),
287 Uint64(u64),
288 Str(Vec<u8>),
289 Url(String),
290 Uuid(fidl_bt::Uuid),
291 Bool(bool),
292 Sequence(Vec<Box<DataElement>>),
293 Alternatives(Vec<Box<DataElement>>),
294}
295
296impl TryFrom<&fidl_bredr::DataElement> for DataElement {
297 type Error = Error;
298
299 fn try_from(src: &fidl_bredr::DataElement) -> Result<DataElement, Error> {
300 use fidl_bredr::DataElement as fDataElement;
301 let element = match src {
302 fDataElement::Int8(x) => DataElement::Int8(*x),
303 fDataElement::Int16(x) => DataElement::Int16(*x),
304 fDataElement::Int32(x) => DataElement::Int32(*x),
305 fDataElement::Int64(x) => DataElement::Int64(*x),
306 fDataElement::Uint8(x) => DataElement::Uint8(*x),
307 fDataElement::Uint16(x) => DataElement::Uint16(*x),
308 fDataElement::Uint32(x) => DataElement::Uint32(*x),
309 fDataElement::Uint64(x) => DataElement::Uint64(*x),
310 fDataElement::Str(v) => DataElement::Str(v.clone()),
312 fDataElement::Url(s) => DataElement::Url(s.to_string()),
313 fDataElement::Uuid(uuid) => DataElement::Uuid(uuid.clone()),
314 fDataElement::B(b) => DataElement::Bool(*b),
315 fDataElement::Sequence(x) => {
316 let mapped = x
317 .into_iter()
318 .filter_map(|opt| {
319 opt.as_ref().map(|t| match DataElement::try_from(&**t) {
320 Ok(elem) => Ok(Box::new(elem)),
321 Err(err) => Err(err),
322 })
323 })
324 .collect::<Result<Vec<_>, Error>>()?;
325 DataElement::Sequence(mapped)
326 }
327 fDataElement::Alternatives(x) => {
328 let mapped = x
329 .into_iter()
330 .filter_map(|opt| {
331 opt.as_ref().map(|t| match DataElement::try_from(&**t) {
332 Ok(elem) => Ok(Box::new(elem)),
333 Err(err) => Err(err),
334 })
335 })
336 .collect::<Result<Vec<_>, Error>>()?;
337 DataElement::Alternatives(mapped)
338 }
339 _ => return Err(Error::conversion("Unknown DataElement type")),
340 };
341 Ok(element)
342 }
343}
344
345impl From<&DataElement> for fidl_bredr::DataElement {
346 fn from(src: &DataElement) -> fidl_bredr::DataElement {
347 use fidl_bredr::DataElement as fDataElement;
348 match src {
349 DataElement::Int8(x) => fDataElement::Int8(*x),
350 DataElement::Int16(x) => fDataElement::Int16(*x),
351 DataElement::Int32(x) => fDataElement::Int32(*x),
352 DataElement::Int64(x) => fDataElement::Int64(*x),
353 DataElement::Uint8(x) => fDataElement::Uint8(*x),
354 DataElement::Uint16(x) => fDataElement::Uint16(*x),
355 DataElement::Uint32(x) => fDataElement::Uint32(*x),
356 DataElement::Uint64(x) => fDataElement::Uint64(*x),
357 DataElement::Str(v) => fDataElement::Str(v.clone()),
358 DataElement::Url(s) => fDataElement::Url(s.to_string()),
359 DataElement::Uuid(uuid) => fDataElement::Uuid(uuid.clone()),
360 DataElement::Bool(b) => fDataElement::B(*b),
361 DataElement::Sequence(x) => {
362 let mapped = x
363 .into_iter()
364 .map(|t| Some(Box::new(fDataElement::from(&**t))))
365 .collect::<Vec<_>>();
366 fDataElement::Sequence(mapped)
367 }
368 DataElement::Alternatives(x) => {
369 let mapped = x
370 .into_iter()
371 .map(|t| Some(Box::new(fDataElement::from(&**t))))
372 .collect::<Vec<_>>();
373 fDataElement::Alternatives(mapped)
374 }
375 }
376 }
377}
378
379#[derive(Debug, PartialEq)]
380pub struct DataElementConversionError {
381 pub data_element: DataElement,
382}
383
384macro_rules! generate_data_element_conversion {
386 ($variant: ident, $type: ty) => {
387 impl TryFrom<DataElement> for $type {
388 type Error = DataElementConversionError;
389
390 fn try_from(data_element: DataElement) -> Result<$type, DataElementConversionError> {
391 match data_element {
392 DataElement::$variant(x) => Ok(x),
393 _ => Err(DataElementConversionError { data_element }),
394 }
395 }
396 }
397
398 impl From<$type> for DataElement {
399 fn from(x: $type) -> DataElement {
400 DataElement::$variant(x)
401 }
402 }
403 };
404}
405
406generate_data_element_conversion!(Int8, i8);
408generate_data_element_conversion!(Int16, i16);
409generate_data_element_conversion!(Int32, i32);
410generate_data_element_conversion!(Int64, i64);
411generate_data_element_conversion!(Uint8, u8);
412generate_data_element_conversion!(Uint16, u16);
413generate_data_element_conversion!(Uint32, u32);
414generate_data_element_conversion!(Uint64, u64);
415generate_data_element_conversion!(Str, Vec<u8>);
416generate_data_element_conversion!(Uuid, fidl_bt::Uuid);
417generate_data_element_conversion!(Url, String);
418generate_data_element_conversion!(Bool, bool);
419
420#[derive(Clone, Debug, PartialEq)]
425pub struct ProtocolDescriptor {
426 pub protocol: fidl_bredr::ProtocolIdentifier,
427 pub params: Vec<DataElement>,
428}
429
430impl TryFrom<&fidl_bredr::ProtocolDescriptor> for ProtocolDescriptor {
431 type Error = Error;
432
433 fn try_from(src: &fidl_bredr::ProtocolDescriptor) -> Result<ProtocolDescriptor, Self::Error> {
434 let Some(protocol) = src.protocol else {
435 return Err(Error::missing("Missing ProtocolDescriptor.protocol"));
436 };
437 let params = src.params.as_ref().map_or(Ok(vec![]), |elems| {
438 elems
439 .into_iter()
440 .map(|elem| DataElement::try_from(elem))
441 .collect::<Result<Vec<DataElement>, Error>>()
442 })?;
443 Ok(ProtocolDescriptor { protocol, params })
444 }
445}
446
447impl From<&ProtocolDescriptor> for fidl_bredr::ProtocolDescriptor {
448 fn from(src: &ProtocolDescriptor) -> fidl_bredr::ProtocolDescriptor {
449 let params = src.params.iter().map(|elem| fidl_bredr::DataElement::from(elem)).collect();
450 fidl_bredr::ProtocolDescriptor {
451 protocol: Some(src.protocol),
452 params: Some(params),
453 ..Default::default()
454 }
455 }
456}
457
458pub fn l2cap_connect_parameters(
459 psm: Psm,
460 mode: fidl_bt::ChannelMode,
461) -> fidl_bredr::ConnectParameters {
462 fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
463 psm: Some(psm.into()),
464 parameters: Some(fidl_bt::ChannelParameters {
465 channel_mode: Some(mode),
466 ..fidl_bt::ChannelParameters::default()
467 }),
468 ..fidl_bredr::L2capParameters::default()
469 })
470}
471
472#[derive(Clone, Debug, PartialEq)]
477pub struct Attribute {
478 pub id: u16,
479 pub element: DataElement,
480}
481
482impl TryFrom<&fidl_bredr::Attribute> for Attribute {
483 type Error = Error;
484
485 fn try_from(src: &fidl_bredr::Attribute) -> Result<Attribute, Self::Error> {
486 let Some(id) = src.id else {
487 return Err(Error::missing("Attribute.id"));
488 };
489 let Some(element) = src.element.as_ref() else {
490 return Err(Error::missing("Attribute.element"));
491 };
492 let element = DataElement::try_from(element)?;
493 Ok(Attribute { id, element })
494 }
495}
496
497impl From<&Attribute> for fidl_bredr::Attribute {
498 fn from(src: &Attribute) -> fidl_bredr::Attribute {
499 fidl_bredr::Attribute {
500 id: Some(src.id),
501 element: Some(fidl_bredr::DataElement::from(&src.element)),
502 ..Default::default()
503 }
504 }
505}
506
507#[derive(Clone, Debug, PartialEq)]
512pub struct Information {
513 pub language: String,
514 pub name: Option<String>,
515 pub description: Option<String>,
516 pub provider: Option<String>,
517}
518
519impl TryFrom<&fidl_bredr::Information> for Information {
520 type Error = Error;
521
522 fn try_from(src: &fidl_bredr::Information) -> Result<Information, Self::Error> {
523 let language = match src.language.as_ref().map(String::as_str) {
524 None | Some("") => return Err(Error::missing("bredr.Information.language")),
525 Some(l) => l.to_string(),
526 };
527
528 Ok(Information {
529 language,
530 name: src.name.clone(),
531 description: src.description.clone(),
532 provider: src.provider.clone(),
533 })
534 }
535}
536
537impl TryFrom<&Information> for fidl_bredr::Information {
538 type Error = Error;
539
540 fn try_from(src: &Information) -> Result<fidl_bredr::Information, Self::Error> {
541 if src.language.is_empty() {
542 return Err(Error::missing("Information.language"));
543 }
544
545 Ok(fidl_bredr::Information {
546 language: Some(src.language.clone()),
547 name: src.name.clone(),
548 description: src.description.clone(),
549 provider: src.provider.clone(),
550 ..Default::default()
551 })
552 }
553}
554
555#[derive(Clone, Debug, Default, PartialEq)]
560pub struct ServiceDefinition {
561 pub service_class_uuids: Vec<Uuid>,
562 pub protocol_descriptor_list: Vec<ProtocolDescriptor>,
563 pub additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>>,
564 pub profile_descriptors: Vec<fidl_bredr::ProfileDescriptor>,
565 pub information: Vec<Information>,
566 pub additional_attributes: Vec<Attribute>,
567}
568
569impl ServiceDefinition {
570 pub fn try_into_fidl(this: &Vec<Self>) -> Result<Vec<fidl_bredr::ServiceDefinition>, Error> {
571 this.iter().map(fidl_bredr::ServiceDefinition::try_from).collect::<Result<Vec<_>, _>>()
572 }
573
574 pub fn try_from_fidl(src: &Vec<fidl_bredr::ServiceDefinition>) -> Result<Vec<Self>, Error> {
575 src.iter().map(Self::try_from).collect::<Result<Vec<_>, _>>()
576 }
577
578 pub fn primary_psm(&self) -> Option<Psm> {
580 psm_from_protocol(&self.protocol_descriptor_list)
581 }
582
583 pub fn additional_psms(&self) -> HashSet<Psm> {
585 self.additional_protocol_descriptor_lists
586 .iter()
587 .filter_map(|protocol| psm_from_protocol(protocol))
588 .collect()
589 }
590
591 pub fn goep_l2cap_psm(&self) -> Option<Psm> {
593 const GOEP_L2CAP_PSM_ATTRIBUTE: u16 = 0x0200;
594 let Some(attribute) =
595 self.additional_attributes.iter().find(|attr| attr.id == GOEP_L2CAP_PSM_ATTRIBUTE)
596 else {
597 return None;
598 };
599
600 let DataElement::Uint16(psm) = attribute.element else {
601 return None;
602 };
603
604 Some(Psm::new(psm))
605 }
606
607 pub fn psm_set(&self) -> HashSet<Psm> {
612 let mut psms = self.additional_psms();
613 if let Some(psm) = self.primary_psm() {
614 let _ = psms.insert(psm);
615 }
616 if let Some(psm) = self.goep_l2cap_psm() {
617 let _ = psms.insert(psm);
618 }
619
620 psms
621 }
622}
623
624impl TryFrom<&fidl_bredr::ServiceDefinition> for ServiceDefinition {
625 type Error = Error;
626
627 fn try_from(src: &fidl_bredr::ServiceDefinition) -> Result<ServiceDefinition, Self::Error> {
628 let service_class_uuids = match &src.service_class_uuids {
629 Some(uuids) if !uuids.is_empty() => uuids.iter().map(Uuid::from).collect(),
630 _ => {
631 return Err(Error::conversion(
632 "bredr.ServiceDefinition.service_class_uuids is empty",
633 ));
634 }
635 };
636
637 let protocol_descriptor_list: Vec<ProtocolDescriptor> =
638 src.protocol_descriptor_list.as_ref().map_or(Ok(vec![]), |p| {
639 p.into_iter()
640 .map(|d| ProtocolDescriptor::try_from(d))
641 .collect::<Result<Vec<ProtocolDescriptor>, Error>>()
642 })?;
643 let additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>> =
644 src.additional_protocol_descriptor_lists.as_ref().map_or(Ok(vec![]), |desc_lists| {
645 desc_lists
646 .into_iter()
647 .map(|desc_list| {
648 desc_list
649 .into_iter()
650 .map(|d| ProtocolDescriptor::try_from(d))
651 .collect::<Result<Vec<ProtocolDescriptor>, Error>>()
652 })
653 .collect::<Result<Vec<Vec<ProtocolDescriptor>>, Error>>()
654 })?;
655 let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
656 src.profile_descriptors.clone().unwrap_or(vec![]);
657 let information: Result<Vec<Information>, Error> =
658 src.information.as_ref().map_or(Ok(vec![]), |infos| {
659 infos.into_iter().map(|i| Information::try_from(i)).collect()
660 });
661 let additional_attributes: Vec<Attribute> =
662 src.additional_attributes.as_ref().map_or(Ok(vec![]), |attrs| {
663 attrs
664 .into_iter()
665 .map(|a| Attribute::try_from(a))
666 .collect::<Result<Vec<Attribute>, Error>>()
667 })?;
668
669 Ok(ServiceDefinition {
670 service_class_uuids,
671 protocol_descriptor_list,
672 additional_protocol_descriptor_lists,
673 profile_descriptors,
674 information: information?,
675 additional_attributes,
676 })
677 }
678}
679
680impl TryFrom<&ServiceDefinition> for fidl_bredr::ServiceDefinition {
681 type Error = Error;
682
683 fn try_from(src: &ServiceDefinition) -> Result<fidl_bredr::ServiceDefinition, Self::Error> {
684 if src.service_class_uuids.is_empty() {
685 return Err(Error::conversion("ServiceDefinitions.service_class_uuids is empty"));
686 }
687 let service_class_uuids = src.service_class_uuids.iter().map(fidl_bt::Uuid::from).collect();
688
689 let protocol_descriptor_list: Vec<fidl_bredr::ProtocolDescriptor> = src
690 .protocol_descriptor_list
691 .iter()
692 .map(|d| fidl_bredr::ProtocolDescriptor::from(d))
693 .collect();
694 let additional_protocol_descriptor_lists: Vec<Vec<fidl_bredr::ProtocolDescriptor>> = src
695 .additional_protocol_descriptor_lists
696 .iter()
697 .map(|desc_list| {
698 desc_list.into_iter().map(|d| fidl_bredr::ProtocolDescriptor::from(d)).collect()
699 })
700 .collect();
701 let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
702 src.profile_descriptors.clone();
703 let information: Result<Vec<fidl_bredr::Information>, Error> =
704 src.information.iter().map(|i| fidl_bredr::Information::try_from(i)).collect();
705 let additional_attributes: Vec<fidl_bredr::Attribute> =
706 src.additional_attributes.iter().map(|a| fidl_bredr::Attribute::from(a)).collect();
707
708 Ok(fidl_bredr::ServiceDefinition {
709 service_class_uuids: Some(service_class_uuids),
710 protocol_descriptor_list: Some(protocol_descriptor_list),
711 additional_protocol_descriptor_lists: Some(additional_protocol_descriptor_lists),
712 profile_descriptors: Some(profile_descriptors),
713 information: Some(information?),
714 additional_attributes: Some(additional_attributes),
715 ..Default::default()
716 })
717 }
718}
719
720#[derive(Clone, Debug, Default, PartialEq)]
725pub struct SecurityRequirements {
726 pub authentication_required: Option<bool>,
727 pub secure_connections_required: Option<bool>,
728}
729
730impl From<&fidl_bt::SecurityRequirements> for SecurityRequirements {
731 fn from(src: &fidl_bt::SecurityRequirements) -> SecurityRequirements {
732 SecurityRequirements {
733 authentication_required: src.authentication_required,
734 secure_connections_required: src.secure_connections_required,
735 }
736 }
737}
738
739impl From<&SecurityRequirements> for fidl_bt::SecurityRequirements {
740 fn from(src: &SecurityRequirements) -> fidl_bt::SecurityRequirements {
741 fidl_bt::SecurityRequirements {
742 authentication_required: src.authentication_required,
743 secure_connections_required: src.secure_connections_required,
744 ..Default::default()
745 }
746 }
747}
748
749const MIN_RX_SDU_SIZE: u16 = 48;
752
753#[derive(Clone, Debug, Default, PartialEq)]
759pub struct ChannelParameters {
760 pub channel_mode: Option<fidl_bt::ChannelMode>,
761 pub max_rx_sdu_size: Option<u16>,
762 pub security_requirements: Option<SecurityRequirements>,
763}
764
765impl TryFrom<&fidl_bt::ChannelParameters> for ChannelParameters {
766 type Error = Error;
767
768 fn try_from(src: &fidl_bt::ChannelParameters) -> Result<ChannelParameters, Self::Error> {
769 if let Some(size) = src.max_rx_packet_size {
770 if size < MIN_RX_SDU_SIZE {
771 return Err(Error::conversion(format!(
772 "bredr.ChannelParameters.max_rx_sdu_size is too small: {size}"
773 )));
774 }
775 }
776
777 Ok(ChannelParameters {
778 channel_mode: src.channel_mode,
779 max_rx_sdu_size: src.max_rx_packet_size,
780 security_requirements: src
781 .security_requirements
782 .as_ref()
783 .map(SecurityRequirements::from),
784 })
785 }
786}
787
788impl TryFrom<&ChannelParameters> for fidl_bt::ChannelParameters {
789 type Error = Error;
790
791 fn try_from(src: &ChannelParameters) -> Result<fidl_bt::ChannelParameters, Self::Error> {
792 if let Some(size) = src.max_rx_sdu_size {
793 if size < MIN_RX_SDU_SIZE {
794 return Err(Error::conversion(format!(
795 "ChannelParameters.max_rx_sdu_size is too small: {size}"
796 )));
797 }
798 }
799
800 Ok(fidl_bt::ChannelParameters {
801 channel_mode: src.channel_mode,
802 max_rx_packet_size: src.max_rx_sdu_size,
803 security_requirements: src
804 .security_requirements
805 .as_ref()
806 .map(fidl_bt::SecurityRequirements::from),
807 ..Default::default()
808 })
809 }
810}
811
812#[derive(Debug, Clone, ValidFidlTable, PartialEq)]
813#[fidl_table_src(fidl_bredr::ScoConnectionParameters)]
814pub struct ValidScoConnectionParameters {
815 pub parameter_set: fidl_bredr::HfpParameterSet,
816 pub air_coding_format: fidl_bt::AssignedCodingFormat,
817 pub air_frame_size: u16,
818 pub io_bandwidth: u32,
819 pub io_coding_format: fidl_bt::AssignedCodingFormat,
820 pub io_frame_size: u16,
821 #[fidl_field_type(optional)]
822 pub io_pcm_data_format: Option<fidl_fuchsia_hardware_audio::SampleFormat>,
823 #[fidl_field_type(optional)]
824 pub io_pcm_sample_payload_msb_position: Option<u8>,
825 pub path: fidl_bredr::DataPath,
826}
827
828#[cfg(target_os = "fuchsia")]
829impl Unit for ValidScoConnectionParameters {
830 type Data = inspect::Node;
831 fn inspect_create(&self, parent: &inspect::Node, name: impl AsRef<str>) -> Self::Data {
832 let mut node = parent.create_child(name.as_ref());
833 self.inspect_update(&mut node);
834 node
835 }
836
837 fn inspect_update(&self, data: &mut Self::Data) {
838 data.record_string("parameter_set", &format!("{:?}", self.parameter_set));
839 data.record_string("air_coding_format", &format!("{:?}", self.air_coding_format));
840 data.record_uint("air_frame_size", self.air_frame_size.into());
841 data.record_uint("io_bandwidth", self.io_bandwidth.into());
842 data.record_string("io_coding_format", &format!("{:?}", self.io_coding_format));
843 data.record_uint("io_frame_size", self.io_frame_size.into());
844 if let Some(io_pcm_data_format) = &self.io_pcm_data_format {
845 data.record_string("io_pcm_data_format", &format!("{:?}", io_pcm_data_format));
846 }
847 if let Some(io_pcm_sample_payload_msb_position) = &self.io_pcm_sample_payload_msb_position {
848 data.record_uint(
849 "io_pcm_sample_payload_msb_position",
850 (*io_pcm_sample_payload_msb_position).into(),
851 );
852 }
853 data.record_string("path", &format!("{:?}", self.path));
854 }
855}
856
857#[cfg(target_os = "fuchsia")]
858impl Inspect for &mut ValidScoConnectionParameters {
859 fn iattach(self, parent: &inspect::Node, name: impl AsRef<str>) -> Result<(), AttachError> {
860 parent.record(self.inspect_create(parent, name));
862 Ok(())
863 }
864}
865
866#[cfg(test)]
867mod tests {
868 use super::*;
869 use diagnostics_assertions::assert_data_tree;
870
871 #[test]
872 fn test_find_descriptors_fails_with_no_descriptors() {
873 assert!(find_profile_descriptors(&[]).is_err());
874
875 let mut attributes = vec![fidl_bredr::Attribute {
876 id: Some(0x3001),
877 element: Some(fidl_bredr::DataElement::Uint32(0xF00FC0DE)),
878 ..Default::default()
879 }];
880
881 assert!(find_profile_descriptors(&attributes).is_err());
882
883 attributes.push(fidl_bredr::Attribute {
885 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
886 element: Some(fidl_bredr::DataElement::Uint32(0xABADC0DE)),
887 ..Default::default()
888 });
889
890 assert!(find_profile_descriptors(&attributes).is_err());
891
892 attributes[1].element = Some(fidl_bredr::DataElement::Sequence(vec![]));
894
895 assert!(find_profile_descriptors(&attributes).is_err());
896 }
897
898 #[test]
899 fn test_find_descriptors_returns_descriptors() {
900 let attributes = vec![fidl_bredr::Attribute {
901 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
902 element: Some(fidl_bredr::DataElement::Sequence(vec![
903 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
904 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
905 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
906 ]))),
907 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
908 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
909 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
910 ]))),
911 ])),
912 ..Default::default()
913 }];
914
915 let result = find_profile_descriptors(&attributes);
916 assert!(result.is_ok());
917 let result = result.expect("result");
918 assert_eq!(2, result.len());
919
920 assert_eq!(
921 fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
922 result[0].profile_id.unwrap()
923 );
924 assert_eq!(1, result[0].major_version.unwrap());
925 assert_eq!(3, result[0].minor_version.unwrap());
926 }
927
928 #[test]
929 fn test_find_service_classes_attribute_missing() {
930 assert_eq!(find_service_classes(&[]), Vec::new());
931 let attributes = vec![fidl_bredr::Attribute {
932 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
933 element: Some(fidl_bredr::DataElement::Sequence(vec![
934 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
935 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
936 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
937 ]))),
938 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
939 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
940 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
941 ]))),
942 ])),
943 ..Default::default()
944 }];
945 assert_eq!(find_service_classes(&attributes), Vec::new());
946 }
947
948 #[test]
949 fn test_find_service_classes_wrong_type() {
950 let attributes = vec![fidl_bredr::Attribute {
951 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
952 element: Some(fidl_bredr::DataElement::Uint32(0xc0defae5u32)),
953 ..Default::default()
954 }];
955 assert_eq!(find_service_classes(&attributes), Vec::new());
956 }
957
958 #[test]
959 fn test_find_service_classes_returns_known_classes() {
960 let attribute = fidl_bredr::Attribute {
961 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
962 element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
963 fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()),
964 ))])),
965 ..Default::default()
966 };
967
968 let result = find_service_classes(&[attribute]);
969 assert_eq!(1, result.len());
970 let assigned_num = result.first().unwrap();
971 assert_eq!(0x1101, assigned_num.number); assert_eq!("SerialPort", assigned_num.name);
973
974 let unknown_uuids = fidl_bredr::Attribute {
975 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
976 element: Some(fidl_bredr::DataElement::Sequence(vec![
977 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
978 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0xc0de).into()))),
979 ])),
980 ..Default::default()
981 };
982
983 let result = find_service_classes(&[unknown_uuids]);
985 assert_eq!(1, result.len());
986 let assigned_num = result.first().unwrap();
987 assert_eq!(0x1101, assigned_num.number); assert_eq!("SerialPort", assigned_num.name);
989 }
990
991 #[test]
992 fn test_psm_from_protocol() {
993 let empty = vec![];
994 assert_eq!(None, psm_from_protocol(&empty));
995
996 let no_psm = vec![ProtocolDescriptor {
997 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
998 params: vec![],
999 }];
1000 assert_eq!(None, psm_from_protocol(&no_psm));
1001
1002 let psm = Psm::new(10);
1003 let valid_psm = vec![ProtocolDescriptor {
1004 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1005 params: vec![DataElement::Uint16(psm.into())],
1006 }];
1007 assert_eq!(Some(psm), psm_from_protocol(&valid_psm));
1008
1009 let rfcomm = vec![
1010 ProtocolDescriptor {
1011 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1012 params: vec![], },
1014 ProtocolDescriptor {
1015 protocol: fidl_bredr::ProtocolIdentifier::Rfcomm,
1016 params: vec![DataElement::Uint8(10)], },
1018 ];
1019 assert_eq!(None, psm_from_protocol(&rfcomm));
1020 }
1021
1022 #[test]
1023 fn test_elem_to_profile_descriptor_works() {
1024 let element = fidl_bredr::DataElement::Sequence(vec![
1025 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1026 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
1027 ]);
1028
1029 let descriptor =
1030 elem_to_profile_descriptor(&element).expect("descriptor should be returned");
1031
1032 assert_eq!(
1033 fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
1034 descriptor.profile_id.unwrap()
1035 );
1036 assert_eq!(1, descriptor.major_version.unwrap());
1037 assert_eq!(3, descriptor.minor_version.unwrap());
1038 }
1039
1040 #[test]
1041 fn test_elem_to_profile_descriptor_wrong_element_types() {
1042 let element = fidl_bredr::DataElement::Sequence(vec![
1043 Some(Box::new(fidl_bredr::DataElement::Uint16(0x1101))),
1044 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
1045 ]);
1046 assert!(elem_to_profile_descriptor(&element).is_none());
1047
1048 let element = fidl_bredr::DataElement::Sequence(vec![
1049 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1050 Some(Box::new(fidl_bredr::DataElement::Uint32(0x0103))),
1051 ]);
1052 assert!(elem_to_profile_descriptor(&element).is_none());
1053
1054 let element = fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1055 fidl_bredr::DataElement::Uint32(0x0103),
1056 ))]);
1057 assert!(elem_to_profile_descriptor(&element).is_none());
1058
1059 let element = fidl_bredr::DataElement::Sequence(vec![None]);
1060 assert!(elem_to_profile_descriptor(&element).is_none());
1061
1062 let element = fidl_bredr::DataElement::Uint32(0xDEADC0DE);
1063 assert!(elem_to_profile_descriptor(&element).is_none());
1064 }
1065
1066 #[test]
1067 fn test_invalid_information_fails_gracefully() {
1068 let empty_language = "".to_string();
1069
1070 let invalid_local = Information {
1071 language: empty_language.clone(),
1072 name: None,
1073 description: None,
1074 provider: None,
1075 };
1076 let fidl = fidl_bredr::Information::try_from(&invalid_local);
1077 assert!(fidl.is_err());
1078
1079 let local = Information::try_from(&fidl_bredr::Information::default());
1081 assert!(local.is_err());
1082
1083 let empty_lang_fidl =
1084 fidl_bredr::Information { language: Some(empty_language), ..Default::default() };
1085 let local = Information::try_from(&empty_lang_fidl);
1086 assert!(local.is_err());
1087 }
1088
1089 #[test]
1090 fn get_psm_from_empty_service_definition() {
1091 let def = ServiceDefinition {
1092 service_class_uuids: vec![Uuid::new32(1234)],
1093 protocol_descriptor_list: vec![],
1094 additional_protocol_descriptor_lists: vec![],
1095 profile_descriptors: vec![],
1096 information: vec![],
1097 additional_attributes: vec![],
1098 };
1099
1100 assert_eq!(def.primary_psm(), None);
1101 assert_eq!(def.additional_psms(), HashSet::new());
1102 assert_eq!(def.psm_set(), HashSet::new());
1103 }
1104
1105 #[test]
1106 fn test_get_psm_from_service_definition() {
1107 let uuid = Uuid::new32(1234);
1108 let psm1 = Psm(10);
1109 let psm2 = Psm(12);
1110 let psm3 = Psm(4000);
1111 let mut def = ServiceDefinition {
1112 service_class_uuids: vec![uuid],
1113 protocol_descriptor_list: vec![ProtocolDescriptor {
1114 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1115 params: vec![DataElement::Uint16(psm1.into())],
1116 }],
1117 additional_protocol_descriptor_lists: vec![],
1118 profile_descriptors: vec![],
1119 information: vec![],
1120 additional_attributes: vec![],
1121 };
1122
1123 assert_eq!(def.primary_psm(), Some(psm1));
1125 assert_eq!(def.additional_psms(), HashSet::new());
1126 assert_eq!(def.psm_set(), HashSet::from([psm1]));
1127
1128 def.additional_protocol_descriptor_lists = vec![
1129 vec![ProtocolDescriptor {
1130 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1131 params: vec![DataElement::Uint16(psm2.into())],
1132 }],
1133 vec![ProtocolDescriptor {
1134 protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1135 params: vec![DataElement::Uint16(0x0103)],
1136 }],
1137 ];
1138
1139 assert_eq!(def.primary_psm(), Some(psm1));
1141 assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1142 assert_eq!(def.psm_set(), HashSet::from([psm1, psm2]));
1143
1144 def.additional_attributes =
1146 vec![Attribute { id: 0x0200, element: DataElement::Uint16(psm3.into()) }];
1147 assert_eq!(def.primary_psm(), Some(psm1));
1148 assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1149 assert_eq!(def.goep_l2cap_psm(), Some(psm3));
1150 assert_eq!(def.psm_set(), HashSet::from([psm1, psm2, psm3]));
1151 }
1152
1153 #[test]
1154 fn test_service_definition_conversions() {
1155 let uuid = fidl_bt::Uuid { value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] };
1156 let prof_descs = vec![ProfileDescriptor {
1157 profile_id: Some(fidl_bredr::ServiceClassProfileIdentifier::AvRemoteControl),
1158 major_version: Some(1),
1159 minor_version: Some(6),
1160 ..Default::default()
1161 }];
1162 let language = "en".to_string();
1163 let name = "foobar".to_string();
1164 let description = "fake".to_string();
1165 let provider = "random".to_string();
1166 let attribute_id = 0x3001;
1167 let attribute_value = 0xF00FC0DE;
1168
1169 let local = ServiceDefinition {
1170 service_class_uuids: vec![uuid.into()],
1171 protocol_descriptor_list: vec![ProtocolDescriptor {
1172 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1173 params: vec![DataElement::Uint16(10)],
1174 }],
1175 additional_protocol_descriptor_lists: vec![
1176 vec![ProtocolDescriptor {
1177 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1178 params: vec![DataElement::Uint16(12)],
1179 }],
1180 vec![ProtocolDescriptor {
1181 protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1182 params: vec![DataElement::Uint16(3)],
1183 }],
1184 ],
1185 profile_descriptors: prof_descs.clone(),
1186 information: vec![Information {
1187 language: language.clone(),
1188 name: Some(name.clone()),
1189 description: Some(description.clone()),
1190 provider: Some(provider.clone()),
1191 }],
1192 additional_attributes: vec![Attribute {
1193 id: attribute_id,
1194 element: DataElement::Sequence(vec![Box::new(DataElement::Uint32(
1195 attribute_value,
1196 ))]),
1197 }],
1198 };
1199
1200 let fidl = fidl_bredr::ServiceDefinition {
1201 service_class_uuids: Some(vec![uuid]),
1202 protocol_descriptor_list: Some(vec![fidl_bredr::ProtocolDescriptor {
1203 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1204 params: Some(vec![fidl_bredr::DataElement::Uint16(10)]),
1205 ..Default::default()
1206 }]),
1207 additional_protocol_descriptor_lists: Some(vec![
1208 vec![fidl_bredr::ProtocolDescriptor {
1209 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1210 params: Some(vec![fidl_bredr::DataElement::Uint16(12)]),
1211 ..Default::default()
1212 }],
1213 vec![fidl_bredr::ProtocolDescriptor {
1214 protocol: Some(fidl_bredr::ProtocolIdentifier::Avdtp),
1215 params: Some(vec![fidl_bredr::DataElement::Uint16(3)]),
1216 ..Default::default()
1217 }],
1218 ]),
1219 profile_descriptors: Some(prof_descs.clone()),
1220 information: Some(vec![fidl_bredr::Information {
1221 language: Some(language.clone()),
1222 name: Some(name.clone()),
1223 description: Some(description.clone()),
1224 provider: Some(provider.clone()),
1225 ..Default::default()
1226 }]),
1227 additional_attributes: Some(vec![fidl_bredr::Attribute {
1228 id: Some(attribute_id),
1229 element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1230 fidl_bredr::DataElement::Uint32(attribute_value),
1231 ))])),
1232 ..Default::default()
1233 }]),
1234 ..Default::default()
1235 };
1236
1237 let local_to_fidl: fidl_bredr::ServiceDefinition =
1239 fidl_bredr::ServiceDefinition::try_from(&local).expect("should work");
1240 assert_eq!(local_to_fidl, fidl);
1241
1242 let fidl_to_local: ServiceDefinition =
1244 ServiceDefinition::try_from(&fidl).expect("should work");
1245 assert_eq!(fidl_to_local, local);
1246 }
1247
1248 #[test]
1249 fn test_invalid_service_definition_fails_gracefully() {
1250 let no_uuids_fidl = fidl_bredr::ServiceDefinition::default();
1251 let fidl_to_local = ServiceDefinition::try_from(&no_uuids_fidl);
1252 assert!(fidl_to_local.is_err());
1253
1254 let empty_uuids_fidl = fidl_bredr::ServiceDefinition {
1255 service_class_uuids: Some(vec![]),
1256 ..Default::default()
1257 };
1258 let fidl_to_local = ServiceDefinition::try_from(&empty_uuids_fidl);
1259 assert!(fidl_to_local.is_err());
1260 }
1261
1262 #[test]
1263 fn test_channel_parameters_conversions() {
1264 let channel_mode = Some(fidl_bt::ChannelMode::EnhancedRetransmission);
1265 let max_rx_sdu_size = Some(MIN_RX_SDU_SIZE);
1266
1267 let local =
1268 ChannelParameters { channel_mode, max_rx_sdu_size, security_requirements: None };
1269 let fidl = fidl_bt::ChannelParameters {
1270 channel_mode,
1271 max_rx_packet_size: max_rx_sdu_size,
1272 ..Default::default()
1273 };
1274
1275 let local_to_fidl =
1276 fidl_bt::ChannelParameters::try_from(&local).expect("conversion should work");
1277 assert_eq!(local_to_fidl, fidl);
1278
1279 let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1280 assert_eq!(fidl_to_local, local);
1281
1282 let fidl = fidl_bt::ChannelParameters::default();
1284 let expected = ChannelParameters {
1285 channel_mode: None,
1286 max_rx_sdu_size: None,
1287 security_requirements: None,
1288 };
1289
1290 let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1291 assert_eq!(fidl_to_local, expected);
1292 }
1293
1294 #[test]
1295 fn test_invalid_channel_parameters_fails_gracefully() {
1296 let too_small_sdu = Some(MIN_RX_SDU_SIZE - 1);
1297 let local = ChannelParameters {
1298 channel_mode: None,
1299 max_rx_sdu_size: too_small_sdu,
1300 security_requirements: None,
1301 };
1302 let fidl =
1303 fidl_bt::ChannelParameters { max_rx_packet_size: too_small_sdu, ..Default::default() };
1304
1305 let local_to_fidl = fidl_bt::ChannelParameters::try_from(&local);
1306 assert!(local_to_fidl.is_err());
1307
1308 let fidl_to_local = ChannelParameters::try_from(&fidl);
1309 assert!(fidl_to_local.is_err());
1310 }
1311
1312 #[test]
1313 fn test_security_requirements_conversions() {
1314 let authentication_required = Some(false);
1315 let secure_connections_required = Some(true);
1316
1317 let local = SecurityRequirements { authentication_required, secure_connections_required };
1318 let fidl = fidl_bt::SecurityRequirements {
1319 authentication_required,
1320 secure_connections_required,
1321 ..Default::default()
1322 };
1323
1324 let local_to_fidl = fidl_bt::SecurityRequirements::from(&local);
1325 assert_eq!(local_to_fidl, fidl);
1326
1327 let fidl_to_local = SecurityRequirements::from(&fidl);
1328 assert_eq!(fidl_to_local, local);
1329 }
1330
1331 #[test]
1332 fn test_combine_security_requirements() {
1333 let req1 = SecurityRequirements {
1334 authentication_required: None,
1335 secure_connections_required: None,
1336 };
1337 let req2 = SecurityRequirements {
1338 authentication_required: None,
1339 secure_connections_required: None,
1340 };
1341 let expected = SecurityRequirements {
1342 authentication_required: None,
1343 secure_connections_required: None,
1344 };
1345 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1346
1347 let req1 = SecurityRequirements {
1348 authentication_required: Some(true),
1349 secure_connections_required: None,
1350 };
1351 let req2 = SecurityRequirements {
1352 authentication_required: None,
1353 secure_connections_required: Some(true),
1354 };
1355 let expected = SecurityRequirements {
1356 authentication_required: Some(true),
1357 secure_connections_required: Some(true),
1358 };
1359 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1360
1361 let req1 = SecurityRequirements {
1362 authentication_required: Some(false),
1363 secure_connections_required: Some(true),
1364 };
1365 let req2 = SecurityRequirements {
1366 authentication_required: None,
1367 secure_connections_required: Some(true),
1368 };
1369 let expected = SecurityRequirements {
1370 authentication_required: Some(false),
1371 secure_connections_required: Some(true),
1372 };
1373 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1374
1375 let req1 = SecurityRequirements {
1376 authentication_required: Some(true),
1377 secure_connections_required: Some(false),
1378 };
1379 let req2 = SecurityRequirements {
1380 authentication_required: Some(false),
1381 secure_connections_required: Some(true),
1382 };
1383 let expected = SecurityRequirements {
1384 authentication_required: Some(true),
1385 secure_connections_required: Some(true),
1386 };
1387 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1388 }
1389
1390 #[test]
1391 fn test_combine_channel_parameters() {
1392 let p1 = ChannelParameters::default();
1393 let p2 = ChannelParameters::default();
1394 let expected = ChannelParameters::default();
1395 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1396
1397 let p1 = ChannelParameters {
1398 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1399 max_rx_sdu_size: None,
1400 security_requirements: None,
1401 };
1402 let p2 = ChannelParameters {
1403 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1404 max_rx_sdu_size: Some(70),
1405 security_requirements: None,
1406 };
1407 let expected = ChannelParameters {
1408 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1409 max_rx_sdu_size: Some(70),
1410 security_requirements: None,
1411 };
1412 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1413
1414 let empty_seq_reqs = SecurityRequirements::default();
1415 let p1 = ChannelParameters {
1416 channel_mode: None,
1417 max_rx_sdu_size: Some(75),
1418 security_requirements: Some(empty_seq_reqs.clone()),
1419 };
1420 let p2 = ChannelParameters {
1421 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1422 max_rx_sdu_size: None,
1423 security_requirements: None,
1424 };
1425 let expected = ChannelParameters {
1426 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1427 max_rx_sdu_size: Some(75),
1428 security_requirements: Some(empty_seq_reqs),
1429 };
1430 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1431
1432 let reqs1 = SecurityRequirements {
1433 authentication_required: Some(true),
1434 secure_connections_required: None,
1435 };
1436 let reqs2 = SecurityRequirements {
1437 authentication_required: Some(false),
1438 secure_connections_required: Some(false),
1439 };
1440 let combined_reqs = combine_security_requirements(&reqs1, &reqs2);
1441 let p1 = ChannelParameters {
1442 channel_mode: None,
1443 max_rx_sdu_size: Some(90),
1444 security_requirements: Some(reqs1),
1445 };
1446 let p2 = ChannelParameters {
1447 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1448 max_rx_sdu_size: Some(70),
1449 security_requirements: Some(reqs2),
1450 };
1451 let expected = ChannelParameters {
1452 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1453 max_rx_sdu_size: Some(70),
1454 security_requirements: Some(combined_reqs),
1455 };
1456 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1457 }
1458
1459 #[fuchsia::test]
1460 async fn local_sco_parameters_inspect_tree() {
1461 let inspect = inspect::Inspector::default();
1462 assert_data_tree!(inspect, root: {});
1463
1464 let params = fidl_bredr::ScoConnectionParameters {
1465 parameter_set: Some(fidl_bredr::HfpParameterSet::D1),
1466 air_coding_format: Some(fidl_bt::AssignedCodingFormat::Cvsd),
1467 air_frame_size: Some(60),
1468 io_bandwidth: Some(16000),
1469 io_coding_format: Some(fidl_bt::AssignedCodingFormat::LinearPcm),
1470 io_frame_size: Some(16),
1471 io_pcm_data_format: Some(fidl_fuchsia_hardware_audio::SampleFormat::PcmSigned),
1472 io_pcm_sample_payload_msb_position: Some(1),
1473 path: Some(fidl_bredr::DataPath::Offload),
1474 ..Default::default()
1475 };
1476
1477 let mut local: ValidScoConnectionParameters = params.try_into().expect("can convert");
1478 assert_data_tree!(inspect, root: {});
1479
1480 let _ = local.iattach(&inspect.root(), "state").expect("can attach inspect");
1481 assert_data_tree!(inspect, root: {
1482 state: {
1483 parameter_set: "D1",
1484 air_coding_format: "Cvsd",
1485 air_frame_size: 60u64,
1486 io_bandwidth: 16000u64,
1487 io_coding_format: "LinearPcm",
1488 io_frame_size: 16u64,
1489 io_pcm_data_format: "PcmSigned",
1490 io_pcm_sample_payload_msb_position: 1u64,
1491 path: "Offload",
1492 }
1493 });
1494 }
1495
1496 #[test]
1497 fn data_element_primitve_conversions() {
1498 type Result<T> = std::result::Result<T, DataElementConversionError>;
1499
1500 let rust_u8 = 8u8;
1501 let data_element_uint8 = DataElement::Uint8(8u8);
1502 let data_element_uint8_into: DataElement = rust_u8.into();
1503 let rust_u8_ok: Result<u8> = data_element_uint8.clone().try_into();
1504 let rust_u8_err: Result<u16> = data_element_uint8.clone().try_into();
1505 assert_eq!(data_element_uint8_into, data_element_uint8);
1506 assert_eq!(rust_u8_ok, Ok(rust_u8));
1507 assert_eq!(
1508 rust_u8_err,
1509 Err(DataElementConversionError { data_element: data_element_uint8 })
1510 );
1511
1512 let rust_i8 = 9i8;
1513 let data_element_int8 = DataElement::Int8(9i8);
1514 let data_element_int8_into: DataElement = rust_i8.into();
1515 let rust_i8_ok: Result<i8> = data_element_int8.clone().try_into();
1516 let rust_i8_err: Result<u16> = data_element_int8.clone().try_into();
1517 assert_eq!(data_element_int8_into, data_element_int8);
1518 assert_eq!(rust_i8_ok, Ok(rust_i8));
1519 assert_eq!(
1520 rust_i8_err,
1521 Err(DataElementConversionError { data_element: data_element_int8 })
1522 );
1523
1524 let rust_u16 = 16u16;
1525 let data_element_uint16 = DataElement::Uint16(16u16);
1526 let data_element_uint16_into: DataElement = rust_u16.into();
1527 let rust_u16_ok: Result<u16> = data_element_uint16.clone().try_into();
1528 let rust_u16_err: Result<i16> = data_element_uint16.clone().try_into();
1529 assert_eq!(data_element_uint16_into, data_element_uint16);
1530 assert_eq!(rust_u16_ok, Ok(rust_u16));
1531 assert_eq!(
1532 rust_u16_err,
1533 Err(DataElementConversionError { data_element: data_element_uint16 })
1534 );
1535
1536 let rust_i16 = 17i16;
1537 let data_element_int16 = DataElement::Int16(17i16);
1538 let data_element_int16_into: DataElement = rust_i16.into();
1539 let rust_i16_ok: Result<i16> = data_element_int16.clone().try_into();
1540 let rust_i16_err: Result<u16> = data_element_int16.clone().try_into();
1541 assert_eq!(data_element_int16_into, data_element_int16);
1542 assert_eq!(rust_i16_ok, Ok(rust_i16));
1543 assert_eq!(
1544 rust_i16_err,
1545 Err(DataElementConversionError { data_element: data_element_int16 })
1546 );
1547
1548 let rust_u32 = 32u32;
1549 let data_element_uint32 = DataElement::Uint32(32u32);
1550 let data_element_uint32_into: DataElement = rust_u32.into();
1551 let rust_u32_ok: Result<u32> = data_element_uint32.clone().try_into();
1552 let rust_u32_err: Result<u16> = data_element_uint32.clone().try_into();
1553 assert_eq!(data_element_uint32_into, data_element_uint32);
1554 assert_eq!(rust_u32_ok, Ok(rust_u32));
1555 assert_eq!(
1556 rust_u32_err,
1557 Err(DataElementConversionError { data_element: data_element_uint32 })
1558 );
1559
1560 let rust_i32 = 33i32;
1561 let data_element_int32 = DataElement::Int32(33i32);
1562 let data_element_int32_into: DataElement = rust_i32.into();
1563 let rust_i32_ok: Result<i32> = data_element_int32.clone().try_into();
1564 let rust_i32_err: Result<u16> = data_element_int32.clone().try_into();
1565 assert_eq!(data_element_int32_into, data_element_int32);
1566 assert_eq!(rust_i32_ok, Ok(rust_i32));
1567 assert_eq!(
1568 rust_i32_err,
1569 Err(DataElementConversionError { data_element: data_element_int32 })
1570 );
1571
1572 let rust_u64 = 64u64;
1573 let data_element_uint64 = DataElement::Uint64(64u64);
1574 let data_element_uint64_into: DataElement = rust_u64.into();
1575 let rust_u64_ok: Result<u64> = data_element_uint64.clone().try_into();
1576 let rust_u64_err: Result<u16> = data_element_uint64.clone().try_into();
1577 assert_eq!(data_element_uint64_into, data_element_uint64);
1578 assert_eq!(rust_u64_ok, Ok(rust_u64));
1579 assert_eq!(
1580 rust_u64_err,
1581 Err(DataElementConversionError { data_element: data_element_uint64 })
1582 );
1583
1584 let rust_i64 = 65i64;
1585 let data_element_int64 = DataElement::Int64(65i64);
1586 let data_element_int64_into: DataElement = rust_i64.into();
1587 let rust_i64_ok: Result<i64> = data_element_int64.clone().try_into();
1588 let rust_i64_err: Result<u16> = data_element_int64.clone().try_into();
1589 assert_eq!(data_element_int64_into, data_element_int64);
1590 assert_eq!(rust_i64_ok, Ok(rust_i64));
1591 assert_eq!(
1592 rust_i64_err,
1593 Err(DataElementConversionError { data_element: data_element_int64 })
1594 );
1595
1596 let rust_vec = "ABC".as_bytes().to_vec();
1597 let data_element_str = DataElement::Str("ABC".as_bytes().to_vec());
1598 let data_element_str_into: DataElement = rust_vec.clone().into();
1599 let rust_vec_ok: Result<Vec<u8>> = data_element_str.clone().try_into();
1600 let rust_vec_err: Result<u16> = data_element_str.clone().try_into();
1601 assert_eq!(data_element_str_into, data_element_str);
1602 assert_eq!(rust_vec_ok, Ok(rust_vec));
1603 assert_eq!(
1604 rust_vec_err,
1605 Err(DataElementConversionError { data_element: data_element_str })
1606 );
1607
1608 let rust_uuid: fidl_bt::Uuid = Uuid::new16(0x1101).into();
1609 let data_element_uuid = DataElement::Uuid(Uuid::new16(0x1101).into());
1610 let data_element_uuid_into: DataElement = rust_uuid.clone().into();
1611 let rust_uuid_ok: Result<fidl_bt::Uuid> = data_element_uuid.clone().try_into();
1612 let rust_uuid_err: Result<u16> = data_element_uuid.clone().try_into();
1613 assert_eq!(data_element_uuid_into, data_element_uuid);
1614 assert_eq!(rust_uuid_ok, Ok(rust_uuid));
1615 assert_eq!(
1616 rust_uuid_err,
1617 Err(DataElementConversionError { data_element: data_element_uuid })
1618 );
1619
1620 let rust_string = String::from("ABC");
1621 let data_element_url = DataElement::Url(String::from("ABC"));
1622 let data_element_url_into: DataElement = rust_string.clone().into();
1623 let rust_string_ok: Result<String> = data_element_url.clone().try_into();
1624 let rust_string_err: Result<u16> = data_element_url.clone().try_into();
1625 assert_eq!(data_element_url_into, data_element_url);
1626 assert_eq!(rust_string_ok, Ok(rust_string));
1627 assert_eq!(
1628 rust_string_err,
1629 Err(DataElementConversionError { data_element: data_element_url })
1630 );
1631
1632 let rust_bool = true;
1633 let data_element_bool = DataElement::Bool(true);
1634 let data_element_bool_into: DataElement = rust_bool.into();
1635 let rust_bool_ok: Result<bool> = data_element_bool.clone().try_into();
1636 let rust_bool_err: Result<u16> = data_element_bool.clone().try_into();
1637 assert_eq!(data_element_bool_into, data_element_bool);
1638 assert_eq!(rust_bool_ok, Ok(rust_bool));
1639 assert_eq!(
1640 rust_bool_err,
1641 Err(DataElementConversionError { data_element: data_element_bool })
1642 );
1643 }
1644
1645 #[test]
1646 fn test_find_service_class_uuids() {
1647 assert_eq!(find_all_service_classes(&[]), Vec::<Uuid>::new());
1649
1650 let attributes = vec![fidl_bredr::Attribute {
1652 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
1653 element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1654 fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()),
1655 ))])),
1656 ..Default::default()
1657 }];
1658 assert_eq!(find_all_service_classes(&attributes), Vec::<Uuid>::new());
1659
1660 let attributes = vec![fidl_bredr::Attribute {
1662 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
1663 element: Some(fidl_bredr::DataElement::Uint32(0xc0defae5u32)),
1664 ..Default::default()
1665 }];
1666 assert_eq!(find_all_service_classes(&attributes), Vec::<Uuid>::new());
1667
1668 let uuid1 = Uuid::new16(0x1101);
1670 let uuid2 = Uuid::from_bytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
1671 let attribute = fidl_bredr::Attribute {
1672 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
1673 element: Some(fidl_bredr::DataElement::Sequence(vec![
1674 Some(Box::new(fidl_bredr::DataElement::Uuid(uuid1.into()))),
1675 Some(Box::new(fidl_bredr::DataElement::Uint16(5))), Some(Box::new(fidl_bredr::DataElement::Uuid(uuid2.into()))),
1677 None, ])),
1679 ..Default::default()
1680 };
1681
1682 let result = find_all_service_classes(&[attribute]);
1683 assert_eq!(vec![uuid1, uuid2], result);
1684 }
1685
1686 #[test]
1687 fn test_channel_number_from_protocol() {
1688 let l2cap_only = vec![fidl_bredr::ProtocolDescriptor {
1690 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1691 params: Some(vec![fidl_bredr::DataElement::Uint16(42)]),
1692 ..Default::default()
1693 }];
1694 assert_eq!(channel_number_from_protocol(&l2cap_only).unwrap(), 42);
1695
1696 let rfcomm = vec![
1698 fidl_bredr::ProtocolDescriptor {
1699 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1700 params: Some(vec![]), ..Default::default()
1702 },
1703 fidl_bredr::ProtocolDescriptor {
1704 protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1705 params: Some(vec![fidl_bredr::DataElement::Uint8(5)]),
1706 ..Default::default()
1707 },
1708 ];
1709 assert_eq!(channel_number_from_protocol(&rfcomm).unwrap(), 5);
1710
1711 let l2cap_invalid = vec![fidl_bredr::ProtocolDescriptor {
1713 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1714 params: Some(vec![]),
1715 ..Default::default()
1716 }];
1717 assert!(channel_number_from_protocol(&l2cap_invalid).is_err());
1718
1719 let rfcomm_invalid = vec![
1721 fidl_bredr::ProtocolDescriptor {
1722 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1723 params: Some(vec![]),
1724 ..Default::default()
1725 },
1726 fidl_bredr::ProtocolDescriptor {
1727 protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1728 params: Some(vec![]),
1729 ..Default::default()
1730 },
1731 ];
1732 assert!(channel_number_from_protocol(&rfcomm_invalid).is_err());
1733
1734 let rfcomm_wrong_type = vec![
1736 fidl_bredr::ProtocolDescriptor {
1737 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1738 params: Some(vec![]),
1739 ..Default::default()
1740 },
1741 fidl_bredr::ProtocolDescriptor {
1742 protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1743 params: Some(vec![fidl_bredr::DataElement::Uint16(5)]),
1744 ..Default::default()
1745 },
1746 ];
1747 assert!(channel_number_from_protocol(&rfcomm_wrong_type).is_err());
1748
1749 assert!(channel_number_from_protocol(&vec![]).is_err());
1751 }
1752
1753 #[test]
1754 fn test_channel_number_from_parameters() {
1755 let rfcomm = fidl_bredr::ConnectParameters::Rfcomm(fidl_bredr::RfcommParameters {
1757 channel: Some(7),
1758 ..Default::default()
1759 });
1760 assert_eq!(channel_number_from_parameters(&rfcomm).unwrap(), 7);
1761
1762 let l2cap = fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
1764 psm: Some(42),
1765 ..Default::default()
1766 });
1767 assert_eq!(channel_number_from_parameters(&l2cap).unwrap(), 42);
1768
1769 let rfcomm_invalid = fidl_bredr::ConnectParameters::Rfcomm(fidl_bredr::RfcommParameters {
1771 channel: None,
1772 ..Default::default()
1773 });
1774 assert!(channel_number_from_parameters(&rfcomm_invalid).is_err());
1775
1776 let l2cap_invalid = fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
1778 psm: None,
1779 ..Default::default()
1780 });
1781 assert!(channel_number_from_parameters(&l2cap_invalid).is_err());
1782 }
1783}