Skip to main content

fuchsia_bluetooth/
profile.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// BR/EDR types for the AVRCP profile.
24pub mod avrcp;
25
26/// The Protocol and Service Multiplexer (PSM) for L2cap connections.
27#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
28pub struct Psm(u16);
29
30impl Psm {
31    /// PSMs commonly used in the codebase.
32    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
51/// Try to interpret a DataElement as a ProfileDesciptor.
52/// Returns None if the DataElement is not in the correct format to represent a ProfileDescriptor.
53pub 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
82/// Find an element representing the Bluetooth Profile Descriptor List in `attributes`, and
83/// convert the elements in the list into ProfileDescriptors.
84/// Returns an Error if no matching element was found, or if any element of the list couldn't be converted
85/// into a ProfileDescriptor.
86pub 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
115/// Returns the PSM from the provided `protocol`. Returns None if the protocol
116/// is not L2CAP or does not contain a PSM.
117pub 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
133/// Returns the RFCOMM or L2CAP channel number from the provided `protocol`.
134/// Returns an Error if the protocol is not a valid L2CAP or RFCOMM service.
135pub 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            // Get the L2CAP PSM from the protocol descriptor. May be empty if the service
144            // requests RFCOMM. If so, we can skip to the next entry in the protocol list.
145            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            // If RFCOMM is specified, then the RFCOMM port must be populated.
153            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
162/// Returns the L2CAP or RFCOMM channel number from the BR/EDR connection parameters.
163/// Returns Error if the provided `parameters` are invalid.
164pub 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
180/// Search for Service Class UUIDs of well known services from a list of attributes (such as returned via Service Search)
181pub 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
192/// Search for all Service Class UUID from a list of attributes (such as returned via Service Search)
193pub 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
213/// Given two SecurityRequirements, combines both into requirements as strict as either.
214/// A stricter SecurityRequirements is defined as:
215///   1) Authentication required is stricter than not.
216///   2) Secure Connections required is stricter than not.
217pub 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
236/// Given two ChannelParameters, combines both into a set of ChannelParameters
237/// with the least requesting of resources.
238/// This is defined as:
239///   1) Basic requires fewer resources than ERTM.
240///   2) A smaller SDU size is more restrictive.
241pub 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 (&params.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/// The basic building block for elements in a SDP record.
267/// Corresponds directly to the FIDL `DataElement` definition - with the extra
268/// properties of Clone and PartialEq.
269/// See [fuchsia.bluetooth.bredr.DataElement] for more documentation.
270#[derive(Clone, Debug, Eq, 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 std::hash::Hash for DataElement {
289    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
290        core::mem::discriminant(self).hash(state);
291        match self {
292            DataElement::Int8(x) => x.hash(state),
293            DataElement::Int16(x) => x.hash(state),
294            DataElement::Int32(x) => x.hash(state),
295            DataElement::Int64(x) => x.hash(state),
296            DataElement::Uint8(x) => x.hash(state),
297            DataElement::Uint16(x) => x.hash(state),
298            DataElement::Uint32(x) => x.hash(state),
299            DataElement::Uint64(x) => x.hash(state),
300            DataElement::Str(x) => x.hash(state),
301            DataElement::Url(x) => x.hash(state),
302            DataElement::Uuid(x) => x.value.hash(state),
303            DataElement::Bool(x) => x.hash(state),
304            DataElement::Sequence(x) => x.hash(state),
305            DataElement::Alternatives(x) => x.hash(state),
306        }
307    }
308}
309
310impl TryFrom<&fidl_bredr::DataElement> for DataElement {
311    type Error = Error;
312
313    fn try_from(src: &fidl_bredr::DataElement) -> Result<DataElement, Error> {
314        use fidl_bredr::DataElement as fDataElement;
315        let element = match src {
316            fDataElement::Int8(x) => DataElement::Int8(*x),
317            fDataElement::Int16(x) => DataElement::Int16(*x),
318            fDataElement::Int32(x) => DataElement::Int32(*x),
319            fDataElement::Int64(x) => DataElement::Int64(*x),
320            fDataElement::Uint8(x) => DataElement::Uint8(*x),
321            fDataElement::Uint16(x) => DataElement::Uint16(*x),
322            fDataElement::Uint32(x) => DataElement::Uint32(*x),
323            fDataElement::Uint64(x) => DataElement::Uint64(*x),
324            // TODO(https://fxbug.dev/42058871) Replace clones with moves where possible.
325            fDataElement::Str(v) => DataElement::Str(v.clone()),
326            fDataElement::Url(s) => DataElement::Url(s.to_string()),
327            fDataElement::Uuid(uuid) => DataElement::Uuid(uuid.clone()),
328            fDataElement::B(b) => DataElement::Bool(*b),
329            fDataElement::Sequence(x) => {
330                let mapped = x
331                    .iter()
332                    .filter_map(|opt| {
333                        opt.as_ref().map(|t| match DataElement::try_from(&**t) {
334                            Ok(elem) => Ok(Box::new(elem)),
335                            Err(err) => Err(err),
336                        })
337                    })
338                    .collect::<Result<Vec<_>, Error>>()?;
339                DataElement::Sequence(mapped)
340            }
341            fDataElement::Alternatives(x) => {
342                let mapped = x
343                    .iter()
344                    .filter_map(|opt| {
345                        opt.as_ref().map(|t| match DataElement::try_from(&**t) {
346                            Ok(elem) => Ok(Box::new(elem)),
347                            Err(err) => Err(err),
348                        })
349                    })
350                    .collect::<Result<Vec<_>, Error>>()?;
351                DataElement::Alternatives(mapped)
352            }
353            _ => return Err(Error::conversion("Unknown DataElement type")),
354        };
355        Ok(element)
356    }
357}
358
359impl From<&DataElement> for fidl_bredr::DataElement {
360    fn from(src: &DataElement) -> fidl_bredr::DataElement {
361        use fidl_bredr::DataElement as fDataElement;
362        match src {
363            DataElement::Int8(x) => fDataElement::Int8(*x),
364            DataElement::Int16(x) => fDataElement::Int16(*x),
365            DataElement::Int32(x) => fDataElement::Int32(*x),
366            DataElement::Int64(x) => fDataElement::Int64(*x),
367            DataElement::Uint8(x) => fDataElement::Uint8(*x),
368            DataElement::Uint16(x) => fDataElement::Uint16(*x),
369            DataElement::Uint32(x) => fDataElement::Uint32(*x),
370            DataElement::Uint64(x) => fDataElement::Uint64(*x),
371            DataElement::Str(v) => fDataElement::Str(v.clone()),
372            DataElement::Url(s) => fDataElement::Url(s.to_string()),
373            DataElement::Uuid(uuid) => fDataElement::Uuid(uuid.clone()),
374            DataElement::Bool(b) => fDataElement::B(*b),
375            DataElement::Sequence(x) => {
376                let mapped =
377                    x.iter().map(|t| Some(Box::new(fDataElement::from(&**t)))).collect::<Vec<_>>();
378                fDataElement::Sequence(mapped)
379            }
380            DataElement::Alternatives(x) => {
381                let mapped =
382                    x.iter().map(|t| Some(Box::new(fDataElement::from(&**t)))).collect::<Vec<_>>();
383                fDataElement::Alternatives(mapped)
384            }
385        }
386    }
387}
388
389#[derive(Debug, PartialEq)]
390pub struct DataElementConversionError {
391    pub data_element: DataElement,
392}
393
394// Macro for generating impls for converting between rust types and their DataElement wrappers.
395macro_rules! generate_data_element_conversion {
396    ($variant: ident, $type: ty) => {
397        impl TryFrom<DataElement> for $type {
398            type Error = DataElementConversionError;
399
400            fn try_from(data_element: DataElement) -> Result<$type, DataElementConversionError> {
401                match data_element {
402                    DataElement::$variant(x) => Ok(x),
403                    _ => Err(DataElementConversionError { data_element }),
404                }
405            }
406        }
407
408        impl From<$type> for DataElement {
409            fn from(x: $type) -> DataElement {
410                DataElement::$variant(x)
411            }
412        }
413    };
414}
415
416// Generate the impls for converting between rust types and their DataElement wrappers.
417generate_data_element_conversion!(Int8, i8);
418generate_data_element_conversion!(Int16, i16);
419generate_data_element_conversion!(Int32, i32);
420generate_data_element_conversion!(Int64, i64);
421generate_data_element_conversion!(Uint8, u8);
422generate_data_element_conversion!(Uint16, u16);
423generate_data_element_conversion!(Uint32, u32);
424generate_data_element_conversion!(Uint64, u64);
425generate_data_element_conversion!(Str, Vec<u8>);
426generate_data_element_conversion!(Uuid, fidl_bt::Uuid);
427generate_data_element_conversion!(Url, String);
428generate_data_element_conversion!(Bool, bool);
429
430/// Information about a communications protocol.
431/// Corresponds directly to the FIDL `ProtocolDescriptor` definition - with the extra
432/// properties of Clone and PartialEq.
433/// See [fuchsia.bluetooth.bredr.ProtocolDescriptor] for more documentation.
434#[derive(Clone, Debug, Eq, Hash, PartialEq)]
435pub struct ProtocolDescriptor {
436    pub protocol: fidl_bredr::ProtocolIdentifier,
437    pub params: Vec<DataElement>,
438}
439
440impl TryFrom<&fidl_bredr::ProtocolDescriptor> for ProtocolDescriptor {
441    type Error = Error;
442
443    fn try_from(src: &fidl_bredr::ProtocolDescriptor) -> Result<ProtocolDescriptor, Self::Error> {
444        let Some(protocol) = src.protocol else {
445            return Err(Error::missing("Missing ProtocolDescriptor.protocol"));
446        };
447        let params = src.params.as_ref().map_or(Ok(vec![]), |elems| {
448            elems
449                .iter()
450                .map(|elem| DataElement::try_from(elem))
451                .collect::<Result<Vec<DataElement>, Error>>()
452        })?;
453        Ok(ProtocolDescriptor { protocol, params })
454    }
455}
456
457impl From<&ProtocolDescriptor> for fidl_bredr::ProtocolDescriptor {
458    fn from(src: &ProtocolDescriptor) -> fidl_bredr::ProtocolDescriptor {
459        let params = src.params.iter().map(|elem| fidl_bredr::DataElement::from(elem)).collect();
460        fidl_bredr::ProtocolDescriptor {
461            protocol: Some(src.protocol),
462            params: Some(params),
463            ..Default::default()
464        }
465    }
466}
467
468pub fn l2cap_connect_parameters(
469    psm: Psm,
470    mode: fidl_bt::ChannelMode,
471) -> fidl_bredr::ConnectParameters {
472    fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
473        psm: Some(psm.into()),
474        parameters: Some(fidl_bt::ChannelParameters {
475            channel_mode: Some(mode),
476            ..fidl_bt::ChannelParameters::default()
477        }),
478        ..fidl_bredr::L2capParameters::default()
479    })
480}
481
482/// A generic attribute used for protocol information.
483/// Corresponds directly to the FIDL `Attribute` definition - with the extra
484/// properties of Clone and PartialEq.
485/// See [fuchsia.bluetooth.bredr.Attribute] for more documentation.
486#[derive(Clone, Debug, Eq, Hash, PartialEq)]
487pub struct Attribute {
488    pub id: u16,
489    pub element: DataElement,
490}
491
492impl TryFrom<&fidl_bredr::Attribute> for Attribute {
493    type Error = Error;
494
495    fn try_from(src: &fidl_bredr::Attribute) -> Result<Attribute, Self::Error> {
496        let Some(id) = src.id else {
497            return Err(Error::missing("Attribute.id"));
498        };
499        let Some(element) = src.element.as_ref() else {
500            return Err(Error::missing("Attribute.element"));
501        };
502        let element = DataElement::try_from(element)?;
503        Ok(Attribute { id, element })
504    }
505}
506
507impl From<&Attribute> for fidl_bredr::Attribute {
508    fn from(src: &Attribute) -> fidl_bredr::Attribute {
509        fidl_bredr::Attribute {
510            id: Some(src.id),
511            element: Some(fidl_bredr::DataElement::from(&src.element)),
512            ..Default::default()
513        }
514    }
515}
516
517/// Human-readable information about a service.
518/// Corresponds directly to the FIDL `Information` definition - with the extra
519/// properties of Clone and PartialEq.
520/// See [fuchsia.bluetooth.bredr.Information] for more documentation.
521#[derive(Clone, Debug, Eq, Hash, PartialEq)]
522pub struct Information {
523    pub language: String,
524    pub name: Option<String>,
525    pub description: Option<String>,
526    pub provider: Option<String>,
527}
528
529impl TryFrom<&fidl_bredr::Information> for Information {
530    type Error = Error;
531
532    fn try_from(src: &fidl_bredr::Information) -> Result<Information, Self::Error> {
533        let language = match src.language.as_ref().map(String::as_str) {
534            None | Some("") => return Err(Error::missing("bredr.Information.language")),
535            Some(l) => l.to_string(),
536        };
537
538        Ok(Information {
539            language,
540            name: src.name.clone(),
541            description: src.description.clone(),
542            provider: src.provider.clone(),
543        })
544    }
545}
546
547impl TryFrom<&Information> for fidl_bredr::Information {
548    type Error = Error;
549
550    fn try_from(src: &Information) -> Result<fidl_bredr::Information, Self::Error> {
551        if src.language.is_empty() {
552            return Err(Error::missing("Information.language"));
553        }
554
555        Ok(fidl_bredr::Information {
556            language: Some(src.language.clone()),
557            name: src.name.clone(),
558            description: src.description.clone(),
559            provider: src.provider.clone(),
560            ..Default::default()
561        })
562    }
563}
564
565/// Definition of a service that is to be advertised via Bluetooth BR/EDR.
566/// Corresponds directly to the FIDL `ServiceDefinition` definition - with the extra
567/// properties of Clone and PartialEq.
568/// See [fuchsia.bluetooth.bredr.ServiceDefinition] for more documentation.
569#[derive(Clone, Debug, Default, PartialEq)]
570pub struct ServiceDefinition {
571    pub service_class_uuids: Vec<Uuid>,
572    pub protocol_descriptor_list: Vec<ProtocolDescriptor>,
573    pub additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>>,
574    pub profile_descriptors: Vec<fidl_bredr::ProfileDescriptor>,
575    pub information: Vec<Information>,
576    pub additional_attributes: Vec<Attribute>,
577}
578
579impl Eq for ServiceDefinition {}
580
581impl std::hash::Hash for ServiceDefinition {
582    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
583        self.service_class_uuids.hash(state);
584        self.protocol_descriptor_list.hash(state);
585        self.additional_protocol_descriptor_lists.hash(state);
586        // Hash profile_descriptors manually as FIDL table doesn't derive Hash
587        for desc in &self.profile_descriptors {
588            desc.profile_id.hash(state);
589            desc.major_version.hash(state);
590            desc.minor_version.hash(state);
591        }
592        self.information.hash(state);
593        self.additional_attributes.hash(state);
594    }
595}
596
597impl ServiceDefinition {
598    pub fn try_into_fidl(this: &Vec<Self>) -> Result<Vec<fidl_bredr::ServiceDefinition>, Error> {
599        this.iter().map(fidl_bredr::ServiceDefinition::try_from).collect::<Result<Vec<_>, _>>()
600    }
601
602    pub fn try_from_fidl(src: &Vec<fidl_bredr::ServiceDefinition>) -> Result<Vec<Self>, Error> {
603        src.iter().map(Self::try_from).collect::<Result<Vec<_>, _>>()
604    }
605
606    /// Returns the primary PSM associated with this ServiceDefinition.
607    pub fn primary_psm(&self) -> Option<Psm> {
608        psm_from_protocol(&self.protocol_descriptor_list)
609    }
610
611    /// Returns the additional PSMs associated with this ServiceDefinition.
612    pub fn additional_psms(&self) -> HashSet<Psm> {
613        self.additional_protocol_descriptor_lists
614            .iter()
615            .filter_map(|protocol| psm_from_protocol(protocol))
616            .collect()
617    }
618
619    /// Returns the PSM in the GOEP L2CAP Attribute, if provided.
620    pub fn goep_l2cap_psm(&self) -> Option<Psm> {
621        const GOEP_L2CAP_PSM_ATTRIBUTE: u16 = 0x0200;
622        let Some(attribute) =
623            self.additional_attributes.iter().find(|attr| attr.id == GOEP_L2CAP_PSM_ATTRIBUTE)
624        else {
625            return None;
626        };
627
628        let DataElement::Uint16(psm) = attribute.element else {
629            return None;
630        };
631
632        Some(Psm::new(psm))
633    }
634
635    /// Returns all the PSMs associated with this ServiceDefinition.
636    ///
637    /// It's possible that the definition doesn't provide any PSMs, in which
638    /// case the returned set will be empty.
639    pub fn psm_set(&self) -> HashSet<Psm> {
640        let mut psms = self.additional_psms();
641        if let Some(psm) = self.primary_psm() {
642            let _ = psms.insert(psm);
643        }
644        if let Some(psm) = self.goep_l2cap_psm() {
645            let _ = psms.insert(psm);
646        }
647
648        psms
649    }
650}
651
652impl TryFrom<&fidl_bredr::ServiceDefinition> for ServiceDefinition {
653    type Error = Error;
654
655    fn try_from(src: &fidl_bredr::ServiceDefinition) -> Result<ServiceDefinition, Self::Error> {
656        let service_class_uuids = match &src.service_class_uuids {
657            Some(uuids) if !uuids.is_empty() => uuids.iter().map(Uuid::from).collect(),
658            _ => {
659                return Err(Error::conversion(
660                    "bredr.ServiceDefinition.service_class_uuids is empty",
661                ));
662            }
663        };
664
665        let protocol_descriptor_list: Vec<ProtocolDescriptor> =
666            src.protocol_descriptor_list.as_ref().map_or(Ok(vec![]), |p| {
667                p.iter()
668                    .map(|d| ProtocolDescriptor::try_from(d))
669                    .collect::<Result<Vec<ProtocolDescriptor>, Error>>()
670            })?;
671        let additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>> =
672            src.additional_protocol_descriptor_lists.as_ref().map_or(Ok(vec![]), |desc_lists| {
673                desc_lists
674                    .iter()
675                    .map(|desc_list| {
676                        desc_list.iter().map(|d| ProtocolDescriptor::try_from(d)).collect::<Result<
677                            Vec<ProtocolDescriptor>,
678                            Error,
679                        >>(
680                        )
681                    })
682                    .collect::<Result<Vec<Vec<ProtocolDescriptor>>, Error>>()
683            })?;
684        let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
685            src.profile_descriptors.clone().unwrap_or_default();
686        let information: Result<Vec<Information>, Error> = src
687            .information
688            .as_ref()
689            .map_or(Ok(vec![]), |infos| infos.iter().map(|i| Information::try_from(i)).collect());
690        let additional_attributes: Vec<Attribute> =
691            src.additional_attributes.as_ref().map_or(Ok(vec![]), |attrs| {
692                attrs
693                    .iter()
694                    .map(|a| Attribute::try_from(a))
695                    .collect::<Result<Vec<Attribute>, Error>>()
696            })?;
697
698        Ok(ServiceDefinition {
699            service_class_uuids,
700            protocol_descriptor_list,
701            additional_protocol_descriptor_lists,
702            profile_descriptors,
703            information: information?,
704            additional_attributes,
705        })
706    }
707}
708
709impl TryFrom<&ServiceDefinition> for fidl_bredr::ServiceDefinition {
710    type Error = Error;
711
712    fn try_from(src: &ServiceDefinition) -> Result<fidl_bredr::ServiceDefinition, Self::Error> {
713        if src.service_class_uuids.is_empty() {
714            return Err(Error::conversion("ServiceDefinitions.service_class_uuids is empty"));
715        }
716        let service_class_uuids = src.service_class_uuids.iter().map(fidl_bt::Uuid::from).collect();
717
718        let protocol_descriptor_list: Vec<fidl_bredr::ProtocolDescriptor> = src
719            .protocol_descriptor_list
720            .iter()
721            .map(|d| fidl_bredr::ProtocolDescriptor::from(d))
722            .collect();
723        let additional_protocol_descriptor_lists: Vec<Vec<fidl_bredr::ProtocolDescriptor>> = src
724            .additional_protocol_descriptor_lists
725            .iter()
726            .map(|desc_list| {
727                desc_list.iter().map(|d| fidl_bredr::ProtocolDescriptor::from(d)).collect()
728            })
729            .collect();
730        let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
731            src.profile_descriptors.clone();
732        let information: Result<Vec<fidl_bredr::Information>, Error> =
733            src.information.iter().map(|i| fidl_bredr::Information::try_from(i)).collect();
734        let additional_attributes: Vec<fidl_bredr::Attribute> =
735            src.additional_attributes.iter().map(|a| fidl_bredr::Attribute::from(a)).collect();
736
737        Ok(fidl_bredr::ServiceDefinition {
738            service_class_uuids: Some(service_class_uuids),
739            protocol_descriptor_list: Some(protocol_descriptor_list),
740            additional_protocol_descriptor_lists: Some(additional_protocol_descriptor_lists),
741            profile_descriptors: Some(profile_descriptors),
742            information: Some(information?),
743            additional_attributes: Some(additional_attributes),
744            ..Default::default()
745        })
746    }
747}
748
749/// Authentication and permission requirements for an advertised service.
750/// Corresponds directly to the FIDL `SecurityRequirements` definition - with the extra properties
751/// of Clone and PartialEq.
752/// See [fuchsia.bluetooth.bredr.SecurityRequirements] for more documentation.
753#[derive(Clone, Debug, Default, PartialEq)]
754pub struct SecurityRequirements {
755    pub authentication_required: Option<bool>,
756    pub secure_connections_required: Option<bool>,
757}
758
759impl From<&fidl_bt::SecurityRequirements> for SecurityRequirements {
760    fn from(src: &fidl_bt::SecurityRequirements) -> SecurityRequirements {
761        SecurityRequirements {
762            authentication_required: src.authentication_required,
763            secure_connections_required: src.secure_connections_required,
764        }
765    }
766}
767
768impl From<&SecurityRequirements> for fidl_bt::SecurityRequirements {
769    fn from(src: &SecurityRequirements) -> fidl_bt::SecurityRequirements {
770        fidl_bt::SecurityRequirements {
771            authentication_required: src.authentication_required,
772            secure_connections_required: src.secure_connections_required,
773            ..Default::default()
774        }
775    }
776}
777
778/// Minimum SDU size the service is capable of accepting.
779/// See [fuchsia.bluetooth.bredr.ChannelParameters] for more documentation.
780const MIN_RX_SDU_SIZE: u16 = 48;
781
782/// Preferred L2CAP channel parameters for an advertised service.
783/// Corresponds directly to the FIDL `ChannelParameters` definition - with the extra properties
784/// of Clone and PartialEq.
785/// The invariants of the FIDL definition are enforced - the max SDU size must be >= 48.
786/// See [fuchsia.bluetooth.bredr.ChannelParameters] for more documentation.
787#[derive(Clone, Debug, Default, PartialEq)]
788pub struct ChannelParameters {
789    pub channel_mode: Option<fidl_bt::ChannelMode>,
790    pub max_rx_sdu_size: Option<u16>,
791    pub security_requirements: Option<SecurityRequirements>,
792}
793
794impl TryFrom<&fidl_bt::ChannelParameters> for ChannelParameters {
795    type Error = Error;
796
797    fn try_from(src: &fidl_bt::ChannelParameters) -> Result<ChannelParameters, Self::Error> {
798        if let Some(size) = src.max_rx_packet_size {
799            if size < MIN_RX_SDU_SIZE {
800                return Err(Error::conversion(format!(
801                    "bredr.ChannelParameters.max_rx_sdu_size is too small: {size}"
802                )));
803            }
804        }
805
806        Ok(ChannelParameters {
807            channel_mode: src.channel_mode,
808            max_rx_sdu_size: src.max_rx_packet_size,
809            security_requirements: src
810                .security_requirements
811                .as_ref()
812                .map(SecurityRequirements::from),
813        })
814    }
815}
816
817impl TryFrom<&ChannelParameters> for fidl_bt::ChannelParameters {
818    type Error = Error;
819
820    fn try_from(src: &ChannelParameters) -> Result<fidl_bt::ChannelParameters, Self::Error> {
821        if let Some(size) = src.max_rx_sdu_size {
822            if size < MIN_RX_SDU_SIZE {
823                return Err(Error::conversion(format!(
824                    "ChannelParameters.max_rx_sdu_size is too small: {size}"
825                )));
826            }
827        }
828
829        Ok(fidl_bt::ChannelParameters {
830            channel_mode: src.channel_mode,
831            max_rx_packet_size: src.max_rx_sdu_size,
832            security_requirements: src
833                .security_requirements
834                .as_ref()
835                .map(fidl_bt::SecurityRequirements::from),
836            ..Default::default()
837        })
838    }
839}
840
841#[derive(Debug, Clone, ValidFidlTable, PartialEq)]
842#[fidl_table_src(fidl_bredr::ScoConnectionParameters)]
843pub struct ValidScoConnectionParameters {
844    pub parameter_set: fidl_bredr::HfpParameterSet,
845    pub air_coding_format: fidl_bt::AssignedCodingFormat,
846    pub air_frame_size: u16,
847    pub io_bandwidth: u32,
848    pub io_coding_format: fidl_bt::AssignedCodingFormat,
849    pub io_frame_size: u16,
850    #[fidl_field_type(optional)]
851    pub io_pcm_data_format: Option<fidl_fuchsia_hardware_audio::SampleFormat>,
852    #[fidl_field_type(optional)]
853    pub io_pcm_sample_payload_msb_position: Option<u8>,
854    pub path: fidl_bredr::DataPath,
855}
856
857#[cfg(target_os = "fuchsia")]
858impl Unit for ValidScoConnectionParameters {
859    type Data = inspect::Node;
860    fn inspect_create(&self, parent: &inspect::Node, name: impl AsRef<str>) -> Self::Data {
861        let mut node = parent.create_child(name.as_ref());
862        self.inspect_update(&mut node);
863        node
864    }
865
866    fn inspect_update(&self, data: &mut Self::Data) {
867        data.record_string("parameter_set", &format!("{:?}", self.parameter_set));
868        data.record_string("air_coding_format", &format!("{:?}", self.air_coding_format));
869        data.record_uint("air_frame_size", self.air_frame_size.into());
870        data.record_uint("io_bandwidth", self.io_bandwidth.into());
871        data.record_string("io_coding_format", &format!("{:?}", self.io_coding_format));
872        data.record_uint("io_frame_size", self.io_frame_size.into());
873        if let Some(io_pcm_data_format) = &self.io_pcm_data_format {
874            data.record_string("io_pcm_data_format", &format!("{:?}", io_pcm_data_format));
875        }
876        if let Some(io_pcm_sample_payload_msb_position) = &self.io_pcm_sample_payload_msb_position {
877            data.record_uint(
878                "io_pcm_sample_payload_msb_position",
879                (*io_pcm_sample_payload_msb_position).into(),
880            );
881        }
882        data.record_string("path", &format!("{:?}", self.path));
883    }
884}
885
886#[cfg(target_os = "fuchsia")]
887impl Inspect for &mut ValidScoConnectionParameters {
888    fn iattach(self, parent: &inspect::Node, name: impl AsRef<str>) -> Result<(), AttachError> {
889        // The created node is owned by the provided `parent`.
890        parent.record(self.inspect_create(parent, name));
891        Ok(())
892    }
893}
894
895#[cfg(test)]
896mod tests {
897    use super::*;
898    use diagnostics_assertions::assert_data_tree;
899    use std::collections::hash_map::DefaultHasher;
900    use std::hash::{Hash, Hasher};
901
902    #[test]
903    fn test_find_descriptors_fails_with_no_descriptors() {
904        assert!(find_profile_descriptors(&[]).is_err());
905
906        let mut attributes = vec![fidl_bredr::Attribute {
907            id: Some(0x3001),
908            element: Some(fidl_bredr::DataElement::Uint32(0xF00FC0DE)),
909            ..Default::default()
910        }];
911
912        assert!(find_profile_descriptors(&attributes).is_err());
913
914        // Wrong element type
915        attributes.push(fidl_bredr::Attribute {
916            id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
917            element: Some(fidl_bredr::DataElement::Uint32(0xABADC0DE)),
918            ..Default::default()
919        });
920
921        assert!(find_profile_descriptors(&attributes).is_err());
922
923        // Empty sequence
924        attributes[1].element = Some(fidl_bredr::DataElement::Sequence(vec![]));
925
926        assert!(find_profile_descriptors(&attributes).is_err());
927    }
928
929    #[test]
930    fn test_find_descriptors_returns_descriptors() {
931        let attributes = vec![fidl_bredr::Attribute {
932            id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
933            element: Some(fidl_bredr::DataElement::Sequence(vec![
934                Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
935                    Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
936                    Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
937                ]))),
938                Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
939                    Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
940                    Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
941                ]))),
942            ])),
943            ..Default::default()
944        }];
945
946        let result = find_profile_descriptors(&attributes);
947        assert!(result.is_ok());
948        let result = result.expect("result");
949        assert_eq!(2, result.len());
950
951        assert_eq!(
952            fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
953            result[0].profile_id.unwrap()
954        );
955        assert_eq!(1, result[0].major_version.unwrap());
956        assert_eq!(3, result[0].minor_version.unwrap());
957    }
958
959    #[test]
960    fn test_find_service_classes_attribute_missing() {
961        assert_eq!(find_service_classes(&[]), Vec::new());
962        let attributes = vec![fidl_bredr::Attribute {
963            id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
964            element: Some(fidl_bredr::DataElement::Sequence(vec![
965                Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
966                    Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
967                    Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
968                ]))),
969                Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
970                    Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
971                    Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
972                ]))),
973            ])),
974            ..Default::default()
975        }];
976        assert_eq!(find_service_classes(&attributes), Vec::new());
977    }
978
979    #[test]
980    fn test_find_service_classes_wrong_type() {
981        let attributes = vec![fidl_bredr::Attribute {
982            id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
983            element: Some(fidl_bredr::DataElement::Uint32(0xc0defae5u32)),
984            ..Default::default()
985        }];
986        assert_eq!(find_service_classes(&attributes), Vec::new());
987    }
988
989    #[test]
990    fn test_find_service_classes_returns_known_classes() {
991        let attribute = fidl_bredr::Attribute {
992            id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
993            element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
994                fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()),
995            ))])),
996            ..Default::default()
997        };
998
999        let result = find_service_classes(&[attribute]);
1000        assert_eq!(1, result.len());
1001        let assigned_num = result.first().unwrap();
1002        assert_eq!(0x1101, assigned_num.number); // 0x1101 is the 16-bit UUID of SerialPort
1003        assert_eq!("SerialPort", assigned_num.name);
1004
1005        let unknown_uuids = fidl_bredr::Attribute {
1006            id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
1007            element: Some(fidl_bredr::DataElement::Sequence(vec![
1008                Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1009                Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0xc0de).into()))),
1010            ])),
1011            ..Default::default()
1012        };
1013
1014        // Discards unknown UUIDs
1015        let result = find_service_classes(&[unknown_uuids]);
1016        assert_eq!(1, result.len());
1017        let assigned_num = result.first().unwrap();
1018        assert_eq!(0x1101, assigned_num.number); // 0x1101 is the 16-bit UUID of SerialPort
1019        assert_eq!("SerialPort", assigned_num.name);
1020    }
1021
1022    #[test]
1023    fn test_psm_from_protocol() {
1024        let empty = vec![];
1025        assert_eq!(None, psm_from_protocol(&empty));
1026
1027        let no_psm = vec![ProtocolDescriptor {
1028            protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1029            params: vec![],
1030        }];
1031        assert_eq!(None, psm_from_protocol(&no_psm));
1032
1033        let psm = Psm::new(10);
1034        let valid_psm = vec![ProtocolDescriptor {
1035            protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1036            params: vec![DataElement::Uint16(psm.into())],
1037        }];
1038        assert_eq!(Some(psm), psm_from_protocol(&valid_psm));
1039
1040        let rfcomm = vec![
1041            ProtocolDescriptor {
1042                protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1043                params: vec![], // PSM omitted for RFCOMM.
1044            },
1045            ProtocolDescriptor {
1046                protocol: fidl_bredr::ProtocolIdentifier::Rfcomm,
1047                params: vec![DataElement::Uint8(10)], // Server channel
1048            },
1049        ];
1050        assert_eq!(None, psm_from_protocol(&rfcomm));
1051    }
1052
1053    #[test]
1054    fn test_elem_to_profile_descriptor_works() {
1055        let element = fidl_bredr::DataElement::Sequence(vec![
1056            Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1057            Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
1058        ]);
1059
1060        let descriptor =
1061            elem_to_profile_descriptor(&element).expect("descriptor should be returned");
1062
1063        assert_eq!(
1064            fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
1065            descriptor.profile_id.unwrap()
1066        );
1067        assert_eq!(1, descriptor.major_version.unwrap());
1068        assert_eq!(3, descriptor.minor_version.unwrap());
1069    }
1070
1071    #[test]
1072    fn test_elem_to_profile_descriptor_wrong_element_types() {
1073        let element = fidl_bredr::DataElement::Sequence(vec![
1074            Some(Box::new(fidl_bredr::DataElement::Uint16(0x1101))),
1075            Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
1076        ]);
1077        assert!(elem_to_profile_descriptor(&element).is_none());
1078
1079        let element = fidl_bredr::DataElement::Sequence(vec![
1080            Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1081            Some(Box::new(fidl_bredr::DataElement::Uint32(0x0103))),
1082        ]);
1083        assert!(elem_to_profile_descriptor(&element).is_none());
1084
1085        let element = fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1086            fidl_bredr::DataElement::Uint32(0x0103),
1087        ))]);
1088        assert!(elem_to_profile_descriptor(&element).is_none());
1089
1090        let element = fidl_bredr::DataElement::Sequence(vec![None]);
1091        assert!(elem_to_profile_descriptor(&element).is_none());
1092
1093        let element = fidl_bredr::DataElement::Uint32(0xDEADC0DE);
1094        assert!(elem_to_profile_descriptor(&element).is_none());
1095    }
1096
1097    #[test]
1098    fn test_invalid_information_fails_gracefully() {
1099        let empty_language = "".to_string();
1100
1101        let invalid_local = Information {
1102            language: empty_language.clone(),
1103            name: None,
1104            description: None,
1105            provider: None,
1106        };
1107        let fidl = fidl_bredr::Information::try_from(&invalid_local);
1108        assert!(fidl.is_err());
1109
1110        // No language.
1111        let local = Information::try_from(&fidl_bredr::Information::default());
1112        assert!(local.is_err());
1113
1114        let empty_lang_fidl =
1115            fidl_bredr::Information { language: Some(empty_language), ..Default::default() };
1116        let local = Information::try_from(&empty_lang_fidl);
1117        assert!(local.is_err());
1118    }
1119
1120    #[test]
1121    fn get_psm_from_empty_service_definition() {
1122        let def = ServiceDefinition {
1123            service_class_uuids: vec![Uuid::new32(1234)],
1124            protocol_descriptor_list: vec![],
1125            additional_protocol_descriptor_lists: vec![],
1126            profile_descriptors: vec![],
1127            information: vec![],
1128            additional_attributes: vec![],
1129        };
1130
1131        assert_eq!(def.primary_psm(), None);
1132        assert_eq!(def.additional_psms(), HashSet::new());
1133        assert_eq!(def.psm_set(), HashSet::new());
1134    }
1135
1136    #[test]
1137    fn test_get_psm_from_service_definition() {
1138        let uuid = Uuid::new32(1234);
1139        let psm1 = Psm(10);
1140        let psm2 = Psm(12);
1141        let psm3 = Psm(4000);
1142        let mut def = ServiceDefinition {
1143            service_class_uuids: vec![uuid],
1144            protocol_descriptor_list: vec![ProtocolDescriptor {
1145                protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1146                params: vec![DataElement::Uint16(psm1.into())],
1147            }],
1148            additional_protocol_descriptor_lists: vec![],
1149            profile_descriptors: vec![],
1150            information: vec![],
1151            additional_attributes: vec![],
1152        };
1153
1154        // Primary protocol contains one PSM.
1155        assert_eq!(def.primary_psm(), Some(psm1));
1156        assert_eq!(def.additional_psms(), HashSet::new());
1157        assert_eq!(def.psm_set(), HashSet::from([psm1]));
1158
1159        def.additional_protocol_descriptor_lists = vec![
1160            vec![ProtocolDescriptor {
1161                protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1162                params: vec![DataElement::Uint16(psm2.into())],
1163            }],
1164            vec![ProtocolDescriptor {
1165                protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1166                params: vec![DataElement::Uint16(0x0103)],
1167            }],
1168        ];
1169
1170        // Additional protocol contains one PSM.
1171        assert_eq!(def.primary_psm(), Some(psm1));
1172        assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1173        assert_eq!(def.psm_set(), HashSet::from([psm1, psm2]));
1174
1175        // Additional attributes contain one PSM.
1176        def.additional_attributes =
1177            vec![Attribute { id: 0x0200, element: DataElement::Uint16(psm3.into()) }];
1178        assert_eq!(def.primary_psm(), Some(psm1));
1179        assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1180        assert_eq!(def.goep_l2cap_psm(), Some(psm3));
1181        assert_eq!(def.psm_set(), HashSet::from([psm1, psm2, psm3]));
1182    }
1183
1184    #[test]
1185    fn test_service_definition_conversions() {
1186        let uuid = fidl_bt::Uuid { value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] };
1187        let prof_descs = vec![ProfileDescriptor {
1188            profile_id: Some(fidl_bredr::ServiceClassProfileIdentifier::AvRemoteControl),
1189            major_version: Some(1),
1190            minor_version: Some(6),
1191            ..Default::default()
1192        }];
1193        let language = "en".to_string();
1194        let name = "foobar".to_string();
1195        let description = "fake".to_string();
1196        let provider = "random".to_string();
1197        let attribute_id = 0x3001;
1198        let attribute_value = 0xF00FC0DE;
1199
1200        let local = ServiceDefinition {
1201            service_class_uuids: vec![uuid.into()],
1202            protocol_descriptor_list: vec![ProtocolDescriptor {
1203                protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1204                params: vec![DataElement::Uint16(10)],
1205            }],
1206            additional_protocol_descriptor_lists: vec![
1207                vec![ProtocolDescriptor {
1208                    protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1209                    params: vec![DataElement::Uint16(12)],
1210                }],
1211                vec![ProtocolDescriptor {
1212                    protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1213                    params: vec![DataElement::Uint16(3)],
1214                }],
1215            ],
1216            profile_descriptors: prof_descs.clone(),
1217            information: vec![Information {
1218                language: language.clone(),
1219                name: Some(name.clone()),
1220                description: Some(description.clone()),
1221                provider: Some(provider.clone()),
1222            }],
1223            additional_attributes: vec![Attribute {
1224                id: attribute_id,
1225                element: DataElement::Sequence(vec![Box::new(DataElement::Uint32(
1226                    attribute_value,
1227                ))]),
1228            }],
1229        };
1230
1231        let fidl = fidl_bredr::ServiceDefinition {
1232            service_class_uuids: Some(vec![uuid]),
1233            protocol_descriptor_list: Some(vec![fidl_bredr::ProtocolDescriptor {
1234                protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1235                params: Some(vec![fidl_bredr::DataElement::Uint16(10)]),
1236                ..Default::default()
1237            }]),
1238            additional_protocol_descriptor_lists: Some(vec![
1239                vec![fidl_bredr::ProtocolDescriptor {
1240                    protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1241                    params: Some(vec![fidl_bredr::DataElement::Uint16(12)]),
1242                    ..Default::default()
1243                }],
1244                vec![fidl_bredr::ProtocolDescriptor {
1245                    protocol: Some(fidl_bredr::ProtocolIdentifier::Avdtp),
1246                    params: Some(vec![fidl_bredr::DataElement::Uint16(3)]),
1247                    ..Default::default()
1248                }],
1249            ]),
1250            profile_descriptors: Some(prof_descs.clone()),
1251            information: Some(vec![fidl_bredr::Information {
1252                language: Some(language.clone()),
1253                name: Some(name.clone()),
1254                description: Some(description.clone()),
1255                provider: Some(provider.clone()),
1256                ..Default::default()
1257            }]),
1258            additional_attributes: Some(vec![fidl_bredr::Attribute {
1259                id: Some(attribute_id),
1260                element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1261                    fidl_bredr::DataElement::Uint32(attribute_value),
1262                ))])),
1263                ..Default::default()
1264            }]),
1265            ..Default::default()
1266        };
1267
1268        // Converting from local ServiceDefinition to the FIDL ServiceDefinition should work.
1269        let local_to_fidl: fidl_bredr::ServiceDefinition =
1270            fidl_bredr::ServiceDefinition::try_from(&local).expect("should work");
1271        assert_eq!(local_to_fidl, fidl);
1272
1273        // Converting from FIDL ServiceDefinition to the local ServiceDefinition should work.
1274        let fidl_to_local: ServiceDefinition =
1275            ServiceDefinition::try_from(&fidl).expect("should work");
1276        assert_eq!(fidl_to_local, local);
1277    }
1278
1279    #[test]
1280    fn test_invalid_service_definition_fails_gracefully() {
1281        let no_uuids_fidl = fidl_bredr::ServiceDefinition::default();
1282        let fidl_to_local = ServiceDefinition::try_from(&no_uuids_fidl);
1283        assert!(fidl_to_local.is_err());
1284
1285        let empty_uuids_fidl = fidl_bredr::ServiceDefinition {
1286            service_class_uuids: Some(vec![]),
1287            ..Default::default()
1288        };
1289        let fidl_to_local = ServiceDefinition::try_from(&empty_uuids_fidl);
1290        assert!(fidl_to_local.is_err());
1291    }
1292
1293    #[test]
1294    fn test_channel_parameters_conversions() {
1295        let channel_mode = Some(fidl_bt::ChannelMode::EnhancedRetransmission);
1296        let max_rx_sdu_size = Some(MIN_RX_SDU_SIZE);
1297
1298        let local =
1299            ChannelParameters { channel_mode, max_rx_sdu_size, security_requirements: None };
1300        let fidl = fidl_bt::ChannelParameters {
1301            channel_mode,
1302            max_rx_packet_size: max_rx_sdu_size,
1303            ..Default::default()
1304        };
1305
1306        let local_to_fidl =
1307            fidl_bt::ChannelParameters::try_from(&local).expect("conversion should work");
1308        assert_eq!(local_to_fidl, fidl);
1309
1310        let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1311        assert_eq!(fidl_to_local, local);
1312
1313        // Empty FIDL parameters is OK.
1314        let fidl = fidl_bt::ChannelParameters::default();
1315        let expected = ChannelParameters {
1316            channel_mode: None,
1317            max_rx_sdu_size: None,
1318            security_requirements: None,
1319        };
1320
1321        let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1322        assert_eq!(fidl_to_local, expected);
1323    }
1324
1325    #[test]
1326    fn test_invalid_channel_parameters_fails_gracefully() {
1327        let too_small_sdu = Some(MIN_RX_SDU_SIZE - 1);
1328        let local = ChannelParameters {
1329            channel_mode: None,
1330            max_rx_sdu_size: too_small_sdu,
1331            security_requirements: None,
1332        };
1333        let fidl =
1334            fidl_bt::ChannelParameters { max_rx_packet_size: too_small_sdu, ..Default::default() };
1335
1336        let local_to_fidl = fidl_bt::ChannelParameters::try_from(&local);
1337        assert!(local_to_fidl.is_err());
1338
1339        let fidl_to_local = ChannelParameters::try_from(&fidl);
1340        assert!(fidl_to_local.is_err());
1341    }
1342
1343    #[test]
1344    fn test_security_requirements_conversions() {
1345        let authentication_required = Some(false);
1346        let secure_connections_required = Some(true);
1347
1348        let local = SecurityRequirements { authentication_required, secure_connections_required };
1349        let fidl = fidl_bt::SecurityRequirements {
1350            authentication_required,
1351            secure_connections_required,
1352            ..Default::default()
1353        };
1354
1355        let local_to_fidl = fidl_bt::SecurityRequirements::from(&local);
1356        assert_eq!(local_to_fidl, fidl);
1357
1358        let fidl_to_local = SecurityRequirements::from(&fidl);
1359        assert_eq!(fidl_to_local, local);
1360    }
1361
1362    #[test]
1363    fn test_combine_security_requirements() {
1364        let req1 = SecurityRequirements {
1365            authentication_required: None,
1366            secure_connections_required: None,
1367        };
1368        let req2 = SecurityRequirements {
1369            authentication_required: None,
1370            secure_connections_required: None,
1371        };
1372        let expected = SecurityRequirements {
1373            authentication_required: None,
1374            secure_connections_required: None,
1375        };
1376        assert_eq!(combine_security_requirements(&req1, &req2), expected);
1377
1378        let req1 = SecurityRequirements {
1379            authentication_required: Some(true),
1380            secure_connections_required: None,
1381        };
1382        let req2 = SecurityRequirements {
1383            authentication_required: None,
1384            secure_connections_required: Some(true),
1385        };
1386        let expected = SecurityRequirements {
1387            authentication_required: Some(true),
1388            secure_connections_required: Some(true),
1389        };
1390        assert_eq!(combine_security_requirements(&req1, &req2), expected);
1391
1392        let req1 = SecurityRequirements {
1393            authentication_required: Some(false),
1394            secure_connections_required: Some(true),
1395        };
1396        let req2 = SecurityRequirements {
1397            authentication_required: None,
1398            secure_connections_required: Some(true),
1399        };
1400        let expected = SecurityRequirements {
1401            authentication_required: Some(false),
1402            secure_connections_required: Some(true),
1403        };
1404        assert_eq!(combine_security_requirements(&req1, &req2), expected);
1405
1406        let req1 = SecurityRequirements {
1407            authentication_required: Some(true),
1408            secure_connections_required: Some(false),
1409        };
1410        let req2 = SecurityRequirements {
1411            authentication_required: Some(false),
1412            secure_connections_required: Some(true),
1413        };
1414        let expected = SecurityRequirements {
1415            authentication_required: Some(true),
1416            secure_connections_required: Some(true),
1417        };
1418        assert_eq!(combine_security_requirements(&req1, &req2), expected);
1419    }
1420
1421    #[test]
1422    fn test_combine_channel_parameters() {
1423        let p1 = ChannelParameters::default();
1424        let p2 = ChannelParameters::default();
1425        let expected = ChannelParameters::default();
1426        assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1427
1428        let p1 = ChannelParameters {
1429            channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1430            max_rx_sdu_size: None,
1431            security_requirements: None,
1432        };
1433        let p2 = ChannelParameters {
1434            channel_mode: Some(fidl_bt::ChannelMode::Basic),
1435            max_rx_sdu_size: Some(70),
1436            security_requirements: None,
1437        };
1438        let expected = ChannelParameters {
1439            channel_mode: Some(fidl_bt::ChannelMode::Basic),
1440            max_rx_sdu_size: Some(70),
1441            security_requirements: None,
1442        };
1443        assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1444
1445        let empty_seq_reqs = SecurityRequirements::default();
1446        let p1 = ChannelParameters {
1447            channel_mode: None,
1448            max_rx_sdu_size: Some(75),
1449            security_requirements: Some(empty_seq_reqs.clone()),
1450        };
1451        let p2 = ChannelParameters {
1452            channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1453            max_rx_sdu_size: None,
1454            security_requirements: None,
1455        };
1456        let expected = ChannelParameters {
1457            channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1458            max_rx_sdu_size: Some(75),
1459            security_requirements: Some(empty_seq_reqs),
1460        };
1461        assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1462
1463        let reqs1 = SecurityRequirements {
1464            authentication_required: Some(true),
1465            secure_connections_required: None,
1466        };
1467        let reqs2 = SecurityRequirements {
1468            authentication_required: Some(false),
1469            secure_connections_required: Some(false),
1470        };
1471        let combined_reqs = combine_security_requirements(&reqs1, &reqs2);
1472        let p1 = ChannelParameters {
1473            channel_mode: None,
1474            max_rx_sdu_size: Some(90),
1475            security_requirements: Some(reqs1),
1476        };
1477        let p2 = ChannelParameters {
1478            channel_mode: Some(fidl_bt::ChannelMode::Basic),
1479            max_rx_sdu_size: Some(70),
1480            security_requirements: Some(reqs2),
1481        };
1482        let expected = ChannelParameters {
1483            channel_mode: Some(fidl_bt::ChannelMode::Basic),
1484            max_rx_sdu_size: Some(70),
1485            security_requirements: Some(combined_reqs),
1486        };
1487        assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1488    }
1489
1490    #[fuchsia::test]
1491    async fn local_sco_parameters_inspect_tree() {
1492        let inspect = inspect::Inspector::default();
1493        assert_data_tree!(inspect, root: {});
1494
1495        let params = fidl_bredr::ScoConnectionParameters {
1496            parameter_set: Some(fidl_bredr::HfpParameterSet::D1),
1497            air_coding_format: Some(fidl_bt::AssignedCodingFormat::Cvsd),
1498            air_frame_size: Some(60),
1499            io_bandwidth: Some(16000),
1500            io_coding_format: Some(fidl_bt::AssignedCodingFormat::LinearPcm),
1501            io_frame_size: Some(16),
1502            io_pcm_data_format: Some(fidl_fuchsia_hardware_audio::SampleFormat::PcmSigned),
1503            io_pcm_sample_payload_msb_position: Some(1),
1504            path: Some(fidl_bredr::DataPath::Offload),
1505            ..Default::default()
1506        };
1507
1508        let mut local: ValidScoConnectionParameters = params.try_into().expect("can convert");
1509        assert_data_tree!(inspect, root: {});
1510
1511        let _ = local.iattach(&inspect.root(), "state").expect("can attach inspect");
1512        assert_data_tree!(inspect, root: {
1513            state: {
1514                parameter_set: "D1",
1515                air_coding_format: "Cvsd",
1516                air_frame_size: 60u64,
1517                io_bandwidth: 16000u64,
1518                io_coding_format: "LinearPcm",
1519                io_frame_size: 16u64,
1520                io_pcm_data_format: "PcmSigned",
1521                io_pcm_sample_payload_msb_position: 1u64,
1522                path: "Offload",
1523            }
1524        });
1525    }
1526
1527    #[test]
1528    fn data_element_primitve_conversions() {
1529        type Result<T> = std::result::Result<T, DataElementConversionError>;
1530
1531        let rust_u8 = 8u8;
1532        let data_element_uint8 = DataElement::Uint8(8u8);
1533        let data_element_uint8_into: DataElement = rust_u8.into();
1534        let rust_u8_ok: Result<u8> = data_element_uint8.clone().try_into();
1535        let rust_u8_err: Result<u16> = data_element_uint8.clone().try_into();
1536        assert_eq!(data_element_uint8_into, data_element_uint8);
1537        assert_eq!(rust_u8_ok, Ok(rust_u8));
1538        assert_eq!(
1539            rust_u8_err,
1540            Err(DataElementConversionError { data_element: data_element_uint8 })
1541        );
1542
1543        let rust_i8 = 9i8;
1544        let data_element_int8 = DataElement::Int8(9i8);
1545        let data_element_int8_into: DataElement = rust_i8.into();
1546        let rust_i8_ok: Result<i8> = data_element_int8.clone().try_into();
1547        let rust_i8_err: Result<u16> = data_element_int8.clone().try_into();
1548        assert_eq!(data_element_int8_into, data_element_int8);
1549        assert_eq!(rust_i8_ok, Ok(rust_i8));
1550        assert_eq!(
1551            rust_i8_err,
1552            Err(DataElementConversionError { data_element: data_element_int8 })
1553        );
1554
1555        let rust_u16 = 16u16;
1556        let data_element_uint16 = DataElement::Uint16(16u16);
1557        let data_element_uint16_into: DataElement = rust_u16.into();
1558        let rust_u16_ok: Result<u16> = data_element_uint16.clone().try_into();
1559        let rust_u16_err: Result<i16> = data_element_uint16.clone().try_into();
1560        assert_eq!(data_element_uint16_into, data_element_uint16);
1561        assert_eq!(rust_u16_ok, Ok(rust_u16));
1562        assert_eq!(
1563            rust_u16_err,
1564            Err(DataElementConversionError { data_element: data_element_uint16 })
1565        );
1566
1567        let rust_i16 = 17i16;
1568        let data_element_int16 = DataElement::Int16(17i16);
1569        let data_element_int16_into: DataElement = rust_i16.into();
1570        let rust_i16_ok: Result<i16> = data_element_int16.clone().try_into();
1571        let rust_i16_err: Result<u16> = data_element_int16.clone().try_into();
1572        assert_eq!(data_element_int16_into, data_element_int16);
1573        assert_eq!(rust_i16_ok, Ok(rust_i16));
1574        assert_eq!(
1575            rust_i16_err,
1576            Err(DataElementConversionError { data_element: data_element_int16 })
1577        );
1578
1579        let rust_u32 = 32u32;
1580        let data_element_uint32 = DataElement::Uint32(32u32);
1581        let data_element_uint32_into: DataElement = rust_u32.into();
1582        let rust_u32_ok: Result<u32> = data_element_uint32.clone().try_into();
1583        let rust_u32_err: Result<u16> = data_element_uint32.clone().try_into();
1584        assert_eq!(data_element_uint32_into, data_element_uint32);
1585        assert_eq!(rust_u32_ok, Ok(rust_u32));
1586        assert_eq!(
1587            rust_u32_err,
1588            Err(DataElementConversionError { data_element: data_element_uint32 })
1589        );
1590
1591        let rust_i32 = 33i32;
1592        let data_element_int32 = DataElement::Int32(33i32);
1593        let data_element_int32_into: DataElement = rust_i32.into();
1594        let rust_i32_ok: Result<i32> = data_element_int32.clone().try_into();
1595        let rust_i32_err: Result<u16> = data_element_int32.clone().try_into();
1596        assert_eq!(data_element_int32_into, data_element_int32);
1597        assert_eq!(rust_i32_ok, Ok(rust_i32));
1598        assert_eq!(
1599            rust_i32_err,
1600            Err(DataElementConversionError { data_element: data_element_int32 })
1601        );
1602
1603        let rust_u64 = 64u64;
1604        let data_element_uint64 = DataElement::Uint64(64u64);
1605        let data_element_uint64_into: DataElement = rust_u64.into();
1606        let rust_u64_ok: Result<u64> = data_element_uint64.clone().try_into();
1607        let rust_u64_err: Result<u16> = data_element_uint64.clone().try_into();
1608        assert_eq!(data_element_uint64_into, data_element_uint64);
1609        assert_eq!(rust_u64_ok, Ok(rust_u64));
1610        assert_eq!(
1611            rust_u64_err,
1612            Err(DataElementConversionError { data_element: data_element_uint64 })
1613        );
1614
1615        let rust_i64 = 65i64;
1616        let data_element_int64 = DataElement::Int64(65i64);
1617        let data_element_int64_into: DataElement = rust_i64.into();
1618        let rust_i64_ok: Result<i64> = data_element_int64.clone().try_into();
1619        let rust_i64_err: Result<u16> = data_element_int64.clone().try_into();
1620        assert_eq!(data_element_int64_into, data_element_int64);
1621        assert_eq!(rust_i64_ok, Ok(rust_i64));
1622        assert_eq!(
1623            rust_i64_err,
1624            Err(DataElementConversionError { data_element: data_element_int64 })
1625        );
1626
1627        let rust_vec = "ABC".as_bytes().to_vec();
1628        let data_element_str = DataElement::Str("ABC".as_bytes().to_vec());
1629        let data_element_str_into: DataElement = rust_vec.clone().into();
1630        let rust_vec_ok: Result<Vec<u8>> = data_element_str.clone().try_into();
1631        let rust_vec_err: Result<u16> = data_element_str.clone().try_into();
1632        assert_eq!(data_element_str_into, data_element_str);
1633        assert_eq!(rust_vec_ok, Ok(rust_vec));
1634        assert_eq!(
1635            rust_vec_err,
1636            Err(DataElementConversionError { data_element: data_element_str })
1637        );
1638
1639        let rust_uuid: fidl_bt::Uuid = Uuid::new16(0x1101).into();
1640        let data_element_uuid = DataElement::Uuid(Uuid::new16(0x1101).into());
1641        let data_element_uuid_into: DataElement = rust_uuid.clone().into();
1642        let rust_uuid_ok: Result<fidl_bt::Uuid> = data_element_uuid.clone().try_into();
1643        let rust_uuid_err: Result<u16> = data_element_uuid.clone().try_into();
1644        assert_eq!(data_element_uuid_into, data_element_uuid);
1645        assert_eq!(rust_uuid_ok, Ok(rust_uuid));
1646        assert_eq!(
1647            rust_uuid_err,
1648            Err(DataElementConversionError { data_element: data_element_uuid })
1649        );
1650
1651        let rust_string = String::from("ABC");
1652        let data_element_url = DataElement::Url(String::from("ABC"));
1653        let data_element_url_into: DataElement = rust_string.clone().into();
1654        let rust_string_ok: Result<String> = data_element_url.clone().try_into();
1655        let rust_string_err: Result<u16> = data_element_url.clone().try_into();
1656        assert_eq!(data_element_url_into, data_element_url);
1657        assert_eq!(rust_string_ok, Ok(rust_string));
1658        assert_eq!(
1659            rust_string_err,
1660            Err(DataElementConversionError { data_element: data_element_url })
1661        );
1662
1663        let rust_bool = true;
1664        let data_element_bool = DataElement::Bool(true);
1665        let data_element_bool_into: DataElement = rust_bool.into();
1666        let rust_bool_ok: Result<bool> = data_element_bool.clone().try_into();
1667        let rust_bool_err: Result<u16> = data_element_bool.clone().try_into();
1668        assert_eq!(data_element_bool_into, data_element_bool);
1669        assert_eq!(rust_bool_ok, Ok(rust_bool));
1670        assert_eq!(
1671            rust_bool_err,
1672            Err(DataElementConversionError { data_element: data_element_bool })
1673        );
1674    }
1675
1676    #[test]
1677    fn test_find_service_class_uuids() {
1678        // No attributes -> empty vec.
1679        assert_eq!(find_all_service_classes(&[]), Vec::<Uuid>::new());
1680
1681        // No service class attribute -> empty vec.
1682        let attributes = vec![fidl_bredr::Attribute {
1683            id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
1684            element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1685                fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()),
1686            ))])),
1687            ..Default::default()
1688        }];
1689        assert_eq!(find_all_service_classes(&attributes), Vec::<Uuid>::new());
1690
1691        // Wrong element type for service class attribute -> empty vec.
1692        let attributes = vec![fidl_bredr::Attribute {
1693            id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
1694            element: Some(fidl_bredr::DataElement::Uint32(0xc0defae5u32)),
1695            ..Default::default()
1696        }];
1697        assert_eq!(find_all_service_classes(&attributes), Vec::<Uuid>::new());
1698
1699        // Valid attribute with a mix of elements -> returns only UUIDs.
1700        let uuid1 = Uuid::new16(0x1101);
1701        let uuid2 = Uuid::from_bytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
1702        let attribute = fidl_bredr::Attribute {
1703            id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
1704            element: Some(fidl_bredr::DataElement::Sequence(vec![
1705                Some(Box::new(fidl_bredr::DataElement::Uuid(uuid1.into()))),
1706                Some(Box::new(fidl_bredr::DataElement::Uint16(5))), // Not a UUID, should be ignored.
1707                Some(Box::new(fidl_bredr::DataElement::Uuid(uuid2.into()))),
1708                None, // Empty element, should be ignored.
1709            ])),
1710            ..Default::default()
1711        };
1712
1713        let result = find_all_service_classes(&[attribute]);
1714        assert_eq!(vec![uuid1, uuid2], result);
1715    }
1716
1717    #[test]
1718    fn test_channel_number_from_protocol() {
1719        // L2CAP service with valid PSM
1720        let l2cap_only = vec![fidl_bredr::ProtocolDescriptor {
1721            protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1722            params: Some(vec![fidl_bredr::DataElement::Uint16(42)]),
1723            ..Default::default()
1724        }];
1725        assert_eq!(channel_number_from_protocol(&l2cap_only).unwrap(), 42);
1726
1727        // RFCOMM with valid server channel number
1728        let rfcomm = vec![
1729            fidl_bredr::ProtocolDescriptor {
1730                protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1731                params: Some(vec![]), // No PSM for RFCOMM
1732                ..Default::default()
1733            },
1734            fidl_bredr::ProtocolDescriptor {
1735                protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1736                params: Some(vec![fidl_bredr::DataElement::Uint8(5)]),
1737                ..Default::default()
1738            },
1739        ];
1740        assert_eq!(channel_number_from_protocol(&rfcomm).unwrap(), 5);
1741
1742        // L2CAP with invalid params (empty) is an error
1743        let l2cap_invalid = vec![fidl_bredr::ProtocolDescriptor {
1744            protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1745            params: Some(vec![]),
1746            ..Default::default()
1747        }];
1748        assert!(channel_number_from_protocol(&l2cap_invalid).is_err());
1749
1750        // RFCOMM service with missing channel number is an error
1751        let rfcomm_invalid = vec![
1752            fidl_bredr::ProtocolDescriptor {
1753                protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1754                params: Some(vec![]),
1755                ..Default::default()
1756            },
1757            fidl_bredr::ProtocolDescriptor {
1758                protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1759                params: Some(vec![]),
1760                ..Default::default()
1761            },
1762        ];
1763        assert!(channel_number_from_protocol(&rfcomm_invalid).is_err());
1764
1765        // RFCOMM invalid channel type
1766        let rfcomm_wrong_type = vec![
1767            fidl_bredr::ProtocolDescriptor {
1768                protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1769                params: Some(vec![]),
1770                ..Default::default()
1771            },
1772            fidl_bredr::ProtocolDescriptor {
1773                protocol: Some(fidl_bredr::ProtocolIdentifier::Rfcomm),
1774                params: Some(vec![fidl_bredr::DataElement::Uint16(5)]),
1775                ..Default::default()
1776            },
1777        ];
1778        assert!(channel_number_from_protocol(&rfcomm_wrong_type).is_err());
1779
1780        // Empty service is an error
1781        assert!(channel_number_from_protocol(&vec![]).is_err());
1782    }
1783
1784    #[test]
1785    fn test_channel_number_from_parameters() {
1786        // RFCOMM with valid channel
1787        let rfcomm = fidl_bredr::ConnectParameters::Rfcomm(fidl_bredr::RfcommParameters {
1788            channel: Some(7),
1789            ..Default::default()
1790        });
1791        assert_eq!(channel_number_from_parameters(&rfcomm).unwrap(), 7);
1792
1793        // L2CAP with valid PSM
1794        let l2cap = fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
1795            psm: Some(42),
1796            ..Default::default()
1797        });
1798        assert_eq!(channel_number_from_parameters(&l2cap).unwrap(), 42);
1799
1800        // RFCOMM missing channel
1801        let rfcomm_invalid = fidl_bredr::ConnectParameters::Rfcomm(fidl_bredr::RfcommParameters {
1802            channel: None,
1803            ..Default::default()
1804        });
1805        assert!(channel_number_from_parameters(&rfcomm_invalid).is_err());
1806
1807        // L2CAP missing PSM
1808        let l2cap_invalid = fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
1809            psm: None,
1810            ..Default::default()
1811        });
1812        assert!(channel_number_from_parameters(&l2cap_invalid).is_err());
1813    }
1814
1815    fn calculate_hash<T: Hash>(t: &T) -> u64 {
1816        let mut s = DefaultHasher::new();
1817        t.hash(&mut s);
1818        s.finish()
1819    }
1820
1821    #[test]
1822    fn test_data_element_hash() {
1823        // Hash of same item
1824        let elem1 = DataElement::Int8(5);
1825        let elem2 = elem1.clone();
1826        assert_eq!(calculate_hash(&elem1), calculate_hash(&elem2));
1827
1828        // Different variant but same underlying value has different hash
1829        let elem3 = DataElement::Uint8(5);
1830        assert_ne!(calculate_hash(&elem1), calculate_hash(&elem3));
1831
1832        // Same variant but different value has different hash
1833        let elem4 = DataElement::Int8(6);
1834        assert_ne!(calculate_hash(&elem1), calculate_hash(&elem4));
1835
1836        // Sequence elements in different orders have different hash
1837        let seq1 = DataElement::Sequence(vec![
1838            Box::new(DataElement::Int8(1)),
1839            Box::new(DataElement::Int8(2)),
1840        ]);
1841        let seq2 = DataElement::Sequence(vec![
1842            Box::new(DataElement::Int8(2)),
1843            Box::new(DataElement::Int8(1)),
1844        ]);
1845        assert_ne!(calculate_hash(&seq1), calculate_hash(&seq2));
1846
1847        // Sequence of sequences with same values but different grouping.
1848        // [[1, 2], [3]] != [[1], [2, 3]]
1849        let seq_seq1 = DataElement::Sequence(vec![
1850            Box::new(DataElement::Sequence(vec![
1851                Box::new(DataElement::Int8(1)),
1852                Box::new(DataElement::Int8(2)),
1853            ])),
1854            Box::new(DataElement::Sequence(vec![Box::new(DataElement::Int8(3))])),
1855        ]);
1856        let seq_seq2 = DataElement::Sequence(vec![
1857            Box::new(DataElement::Sequence(vec![Box::new(DataElement::Int8(1))])),
1858            Box::new(DataElement::Sequence(vec![
1859                Box::new(DataElement::Int8(2)),
1860                Box::new(DataElement::Int8(3)),
1861            ])),
1862        ]);
1863        assert_ne!(calculate_hash(&seq_seq1), calculate_hash(&seq_seq2));
1864    }
1865
1866    #[test]
1867    fn test_service_definition_hash() {
1868        let def1 = ServiceDefinition {
1869            service_class_uuids: vec![Uuid::new16(0x1101)],
1870            ..Default::default()
1871        };
1872        let def2 = def1.clone();
1873
1874        // Same service definition has the same hash
1875        assert_eq!(calculate_hash(&def1), calculate_hash(&def2));
1876
1877        // Different UUID has different hash
1878        let def3 =
1879            ServiceDefinition { service_class_uuids: vec![Uuid::new16(0x1102)], ..def1.clone() };
1880        assert_ne!(calculate_hash(&def1), calculate_hash(&def3));
1881
1882        // Different ProfileDescriptor has different hash (manual hash impl)
1883        let def4 = ServiceDefinition {
1884            profile_descriptors: vec![fidl_bredr::ProfileDescriptor {
1885                profile_id: Some(fidl_bredr::ServiceClassProfileIdentifier::SerialPort),
1886                major_version: Some(1),
1887                minor_version: Some(0),
1888                ..Default::default()
1889            }],
1890            ..def1.clone()
1891        };
1892        assert_ne!(calculate_hash(&def1), calculate_hash(&def4));
1893
1894        let mut def5 = def4.clone();
1895        def5.profile_descriptors[0].minor_version = Some(1);
1896        assert_ne!(calculate_hash(&def4), calculate_hash(&def5));
1897    }
1898}