1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use fidl_fuchsia_bluetooth_bredr as bredr;
use fuchsia_bluetooth::profile::{DataElement, ProtocolDescriptor};

use crate::dlci::ServerChannel;

/// Returns a ProtocolDescriptorList for an RFCOMM service with the provided `server_channel`.
pub fn build_rfcomm_protocol(server_channel: ServerChannel) -> Vec<ProtocolDescriptor> {
    // The PSM for L2CAP is empty when RFCOMM is used.
    vec![
        ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::L2Cap, params: vec![] },
        ProtocolDescriptor {
            protocol: bredr::ProtocolIdentifier::Rfcomm,
            params: vec![DataElement::Uint8(server_channel.into())],
        },
    ]
}

/// Returns true if the provided `protocol` is RFCOMM.
///
/// Protocols are generally specified by a vector of ProtocolDescriptors which
/// are ordered from lowest level (typically L2CAP) to highest.
pub fn is_rfcomm_protocol(protocol: &Vec<ProtocolDescriptor>) -> bool {
    protocol.iter().any(|descriptor| descriptor.protocol == bredr::ProtocolIdentifier::Rfcomm)
}

/// Returns the ServerChannel number from the provided `protocol` or None if it
/// does not exist.
pub fn server_channel_from_protocol(protocol: &Vec<ProtocolDescriptor>) -> Option<ServerChannel> {
    for descriptor in protocol {
        if descriptor.protocol == bredr::ProtocolIdentifier::Rfcomm {
            // If the Protocol is RFCOMM, there should be one element with the Server Channel.
            if descriptor.params.len() != 1 {
                return None;
            }

            if let DataElement::Uint8(sc) = descriptor.params[0] {
                return ServerChannel::try_from(sc).ok();
            }
            return None;
        }
    }
    None
}

/// Returns the connect parameters for the provided RFCOMM `server_channel`.
pub fn rfcomm_connect_parameters(server_channel: ServerChannel) -> bredr::ConnectParameters {
    bredr::ConnectParameters::Rfcomm(bredr::RfcommParameters {
        channel: Some(server_channel.into()),
        ..bredr::RfcommParameters::default()
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn server_channel_from_l2cap_is_none() {
        // Just L2CAP - should be no server channel.
        let protocol = vec![ProtocolDescriptor {
            protocol: bredr::ProtocolIdentifier::L2Cap,
            params: vec![DataElement::Uint16(bredr::PSM_AVDTP)],
        }];
        assert_eq!(server_channel_from_protocol(&protocol), None);
    }

    #[test]
    fn server_channel_from_empty_rfcomm_is_none() {
        // RFCOMM but un-allocated Server Channel.
        let protocol = vec![
            ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::L2Cap, params: vec![] },
            ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::Rfcomm, params: vec![] },
        ];
        assert_eq!(server_channel_from_protocol(&protocol), None);
    }

    #[test]
    fn server_channel_from_invalid_rfcomm_is_none() {
        // RFCOMM but invalidly formatted.
        let protocol = vec![
            ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::L2Cap, params: vec![] },
            ProtocolDescriptor {
                protocol: bredr::ProtocolIdentifier::Rfcomm,
                params: vec![DataElement::Uint16(100)], // Should be Uint8
            },
        ];
        assert_eq!(server_channel_from_protocol(&protocol), None);
    }

    #[test]
    fn invalid_server_channel_number_is_none() {
        // Valid RFCOMM but ServerChannel number is invalid.
        let protocol = vec![
            ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::L2Cap, params: vec![] },
            ProtocolDescriptor {
                protocol: bredr::ProtocolIdentifier::Rfcomm,
                params: vec![DataElement::Uint8(200)], // Too large
            },
        ];
        assert_eq!(server_channel_from_protocol(&protocol), None);
    }

    #[test]
    fn server_channel_from_valid_rfcomm_is_present() {
        // RFCOMM service with assigned server channel.
        let sc = 10;
        let protocol = vec![
            ProtocolDescriptor { protocol: bredr::ProtocolIdentifier::L2Cap, params: vec![] },
            ProtocolDescriptor {
                protocol: bredr::ProtocolIdentifier::Rfcomm,
                params: vec![DataElement::Uint8(sc)],
            },
        ];
        let expected = ServerChannel::try_from(sc).ok();
        assert_eq!(server_channel_from_protocol(&protocol), expected);
    }

    #[test]
    fn server_channel_from_only_rfcomm_protocol_is_present() {
        // While unusual, getting the server channel from a protocol descriptor list that only
        // contains RFCOMM is ok.
        let sc = 12;
        let protocol = vec![ProtocolDescriptor {
            protocol: bredr::ProtocolIdentifier::Rfcomm,
            params: vec![DataElement::Uint8(sc)],
        }];
        let expected = ServerChannel::try_from(sc).ok();
        assert_eq!(server_channel_from_protocol(&protocol), expected);
    }
}