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