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