1 use num_derive::{FromPrimitive, ToPrimitive};
2 use num_traits::cast::{FromPrimitive, ToPrimitive};
3 use std::convert::{TryFrom, TryInto};
4 use std::ffi::CString;
5 use std::fs::File;
6 use std::os::unix::io::FromRawFd;
7 
8 use crate::bindings::root as bindings;
9 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, Uuid, Uuid128Bit};
10 use crate::ccall;
11 use crate::utils::{LTCheckedPtr, LTCheckedPtrMut};
12 
13 #[derive(Clone, Debug, FromPrimitive, ToPrimitive)]
14 #[repr(u32)]
15 /// Socket interface type.
16 pub enum SocketType {
17     /// Unknown socket type value.
18     Unknown = 0,
19 
20     Rfcomm = 1,
21     Sco = 2,
22     L2cap = 3,
23     L2capLe = 4,
24 }
25 
26 impl From<bindings::btsock_type_t> for SocketType {
from(item: bindings::btsock_type_t) -> Self27     fn from(item: bindings::btsock_type_t) -> Self {
28         SocketType::from_u32(item).unwrap_or(SocketType::Unknown)
29     }
30 }
31 
32 impl From<SocketType> for bindings::btsock_type_t {
from(item: SocketType) -> Self33     fn from(item: SocketType) -> Self {
34         item.to_u32().unwrap_or(0)
35     }
36 }
37 
38 /// Socket flag: No flags (used for insecure connections).
39 pub const SOCK_FLAG_NONE: i32 = 0;
40 /// Socket flag: connection must be encrypted.
41 pub const SOCK_FLAG_ENCRYPT: i32 = 1 << 0;
42 /// Socket flag: require authentication.
43 pub const SOCK_FLAG_AUTH: i32 = 1 << 1;
44 /// Socket flag: don't generate SDP entry for listening socket.
45 pub const SOCK_FLAG_NO_SDP: i32 = 1 << 2;
46 /// Socket flag: require authentication with MITM protection.
47 pub const SOCK_FLAG_AUTH_MITM: i32 = 1 << 3;
48 /// Socket flag: require a minimum of 16 digits for sec mode 2 connections.
49 pub const SOCK_FLAG_AUTH_16_DIGIT: i32 = 1 << 4;
50 /// Socket flag: LE connection oriented channel.
51 pub const SOCK_FLAG_LE_COC: i32 = 1 << 5;
52 
53 /// Combination of SOCK_FLAG_ENCRYPT and SOCK_FLAG_AUTH.
54 pub const SOCK_META_FLAG_SECURE: i32 = SOCK_FLAG_ENCRYPT | SOCK_FLAG_AUTH;
55 
56 /// Struct showing a completed socket event. This is the first data that should
57 /// arrive on a connecting socket once it is connected.
58 pub struct ConnectionComplete {
59     pub size: u16,
60     pub addr: RawAddress,
61     pub channel: i32,
62     pub status: i32,
63     pub max_tx_packet_size: u16,
64     pub max_rx_packet_size: u16,
65 }
66 
67 /// Size of connect complete data. The data read from libbluetooth is packed but
68 /// the Rust struct is not, so depend on this value for validation.
69 pub const CONNECT_COMPLETE_SIZE: usize = 20;
70 
71 // Convert from raw bytes to struct.
72 impl TryFrom<&[u8]> for ConnectionComplete {
73     type Error = String;
74 
try_from(bytes: &[u8]) -> Result<Self, Self::Error>75     fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
76         if bytes.len() != CONNECT_COMPLETE_SIZE {
77             return Err(format!("Wrong number of bytes for Connection Complete: {}", bytes.len()));
78         }
79 
80         // The ConnectComplete event is constructed within libbluetooth and uses
81         // the native endianness of the machine when writing to the socket. When
82         // parsing, make sure to use native endianness here.
83         let (size_bytes, rest) = bytes.split_at(std::mem::size_of::<u16>());
84         if u16::from_ne_bytes(size_bytes.clone().try_into().unwrap())
85             != (CONNECT_COMPLETE_SIZE as u16)
86         {
87             return Err(format!("Wrong size in Connection Complete: {:?}", size_bytes));
88         }
89 
90         // We know from previous size checks that all these splits will work.
91         let (addr_bytes, rest) = rest.split_at(std::mem::size_of::<RawAddress>());
92         let (channel_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
93         let (status_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
94         let (max_tx_packet_size_bytes, rest) = rest.split_at(std::mem::size_of::<u16>());
95         let (max_rx_packet_size_bytes, _unused) = rest.split_at(std::mem::size_of::<u16>());
96 
97         let addr = match RawAddress::from_bytes(addr_bytes) {
98             Some(v) => v,
99             None => {
100                 return Err("Invalid address in Connection Complete".into());
101             }
102         };
103 
104         Ok(ConnectionComplete {
105             size: CONNECT_COMPLETE_SIZE.try_into().unwrap_or_default(),
106             addr,
107             channel: i32::from_ne_bytes(channel_bytes.try_into().unwrap()),
108             status: i32::from_ne_bytes(status_bytes.try_into().unwrap()),
109             max_tx_packet_size: u16::from_ne_bytes(max_tx_packet_size_bytes.try_into().unwrap()),
110             max_rx_packet_size: u16::from_ne_bytes(max_rx_packet_size_bytes.try_into().unwrap()),
111         })
112     }
113 }
114 
115 /// Represents the standard BT SOCKET interface.
116 ///
117 /// For parameter documentation, see the type |sock_connect_signal_t|.
118 pub type SocketConnectSignal = bindings::sock_connect_signal_t;
119 
120 struct RawBtSockWrapper {
121     raw: *const bindings::btsock_interface_t,
122 }
123 
124 // Pointers unsafe due to ownership but this is a static pointer so Send is ok.
125 unsafe impl Send for RawBtSockWrapper {}
126 
127 /// Bluetooth socket interface wrapper. This allows creation of RFCOMM and L2CAP sockets.
128 /// For documentation of functions, see definition of |btsock_interface_t|.
129 pub struct BtSocket {
130     internal: RawBtSockWrapper,
131 }
132 
133 pub type FdError = &'static str;
134 
try_from_fd(fd: i32) -> Result<File, FdError>135 pub fn try_from_fd(fd: i32) -> Result<File, FdError> {
136     if fd >= 0 {
137         Ok(unsafe { File::from_raw_fd(fd) })
138     } else {
139         Err("Invalid FD")
140     }
141 }
142 
143 impl BtSocket {
new(intf: &BluetoothInterface) -> Self144     pub fn new(intf: &BluetoothInterface) -> Self {
145         let r = intf.get_profile_interface(SupportedProfiles::Socket);
146         BtSocket { internal: RawBtSockWrapper { raw: r as *const bindings::btsock_interface_t } }
147     }
148 
listen( &self, sock_type: SocketType, service_name: String, service_uuid: Option<Uuid128Bit>, channel: i32, flags: i32, calling_uid: i32, ) -> (BtStatus, Result<File, FdError>)149     pub fn listen(
150         &self,
151         sock_type: SocketType,
152         service_name: String,
153         service_uuid: Option<Uuid128Bit>,
154         channel: i32,
155         flags: i32,
156         calling_uid: i32,
157     ) -> (BtStatus, Result<File, FdError>) {
158         let mut sockfd: i32 = -1;
159         let sockfd_ptr = LTCheckedPtrMut::from_ref(&mut sockfd);
160 
161         let uuid = match service_uuid {
162             Some(uu) => Some(Uuid::from(uu)),
163             None => Some(Uuid::from([0; 16])),
164         };
165         let uuid_ptr = LTCheckedPtr::from(&uuid);
166 
167         let name = CString::new(service_name).expect("Service name has null in it.");
168         let name_ptr = LTCheckedPtr::from(&name);
169 
170         let status: BtStatus = ccall!(
171             self,
172             listen,
173             sock_type.into(),
174             name_ptr.into(),
175             uuid_ptr.into(),
176             channel,
177             sockfd_ptr.into(),
178             flags,
179             calling_uid
180         )
181         .into();
182 
183         (status, try_from_fd(sockfd))
184     }
185 
connect( &self, addr: RawAddress, sock_type: SocketType, service_uuid: Option<Uuid128Bit>, channel: i32, flags: i32, calling_uid: i32, ) -> (BtStatus, Result<File, FdError>)186     pub fn connect(
187         &self,
188         addr: RawAddress,
189         sock_type: SocketType,
190         service_uuid: Option<Uuid128Bit>,
191         channel: i32,
192         flags: i32,
193         calling_uid: i32,
194     ) -> (BtStatus, Result<File, FdError>) {
195         let mut sockfd: i32 = -1;
196         let sockfd_ptr = LTCheckedPtrMut::from_ref(&mut sockfd);
197 
198         let uuid = match service_uuid {
199             Some(uu) => Some(Uuid::from(uu)),
200             None => None,
201         };
202         let uuid_ptr = LTCheckedPtr::from(&uuid);
203 
204         let addr_ptr = LTCheckedPtr::from_ref(&addr);
205 
206         let status: BtStatus = ccall!(
207             self,
208             connect,
209             addr_ptr.into(),
210             sock_type.into(),
211             uuid_ptr.into(),
212             channel,
213             sockfd_ptr.into(),
214             flags,
215             calling_uid
216         )
217         .into();
218 
219         (status, try_from_fd(sockfd))
220     }
221 
request_max_tx_data_length(&self, addr: RawAddress)222     pub fn request_max_tx_data_length(&self, addr: RawAddress) {
223         ccall!(self, request_max_tx_data_length, &addr);
224     }
225 
send_msc(&self, dlci: u8, addr: RawAddress) -> BtStatus226     pub fn send_msc(&self, dlci: u8, addr: RawAddress) -> BtStatus {
227         // PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON
228         const DEFAULT_MODEM_SIGNAL: u8 = 0x01 | 0x02 | 0x08;
229 
230         const DEFAULT_BREAK_SIGNAL: u8 = 0;
231         const DEFAULT_DISCARD_BUFFERS: u8 = 0;
232         const DEFAULT_BREAK_SIGNAL_SEQ: u8 = 1; // In sequence.
233 
234         // In RFCOMM/DEVA-DEVB/RFC/BV-21-C and RFCOMM/DEVA-DEVB/RFC/BV-22-C test flow
235         // we are requested to send an MSC command with FC=0.
236         const FC: bool = false;
237 
238         ccall!(
239             self,
240             control_req,
241             dlci,
242             &addr,
243             DEFAULT_MODEM_SIGNAL,
244             DEFAULT_BREAK_SIGNAL,
245             DEFAULT_DISCARD_BUFFERS,
246             DEFAULT_BREAK_SIGNAL_SEQ,
247             FC
248         )
249         .into()
250     }
251 }
252 
253 #[cfg(test)]
254 mod tests {
255     use super::*;
256 
257     #[test]
test_conncomplete_parsing()258     fn test_conncomplete_parsing() {
259         // Actual slice size doesn't match
260         let small_input = [0u8; 18];
261         let large_input = [0u8; 21];
262 
263         assert_eq!(false, ConnectionComplete::try_from(&small_input[0..]).is_ok());
264         assert_eq!(false, ConnectionComplete::try_from(&large_input[0..]).is_ok());
265 
266         // Size param in slice doesn't match.
267         let mut size_no_match = vec![0x0u8, 0x13u8];
268         size_no_match.extend([0u8; 18]);
269 
270         assert_eq!(false, ConnectionComplete::try_from(size_no_match.as_slice()).is_ok());
271 
272         // Valid input with various values.
273         let raw_addr = RawAddress { address: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6] };
274         let mut valid: Vec<u8> = vec![];
275         valid.extend(u16::to_ne_bytes(20));
276         valid.extend(raw_addr.to_byte_arr());
277         valid.extend(i32::to_ne_bytes(1));
278         valid.extend(i32::to_ne_bytes(5));
279         valid.extend(u16::to_ne_bytes(16));
280         valid.extend(u16::to_ne_bytes(17));
281 
282         let result = ConnectionComplete::try_from(valid.as_slice());
283         assert_eq!(true, result.is_ok());
284 
285         if let Ok(cc) = result {
286             assert_eq!(cc.size, 20u16);
287             assert_eq!(cc.channel, 1);
288             assert_eq!(cc.status, 5);
289             assert_eq!(cc.max_tx_packet_size, 16u16);
290             assert_eq!(cc.max_rx_packet_size, 17u16);
291         }
292     }
293 }
294