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};
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. This is the packed data length from libbluetooth.
68 pub const CONNECT_COMPLETE_SIZE: usize = std::mem::size_of::<bindings::sock_connect_signal_t>();
69 
70 // Convert from raw bytes to struct.
71 impl TryFrom<&[u8]> for ConnectionComplete {
72     type Error = String;
73 
try_from(bytes: &[u8]) -> Result<Self, Self::Error>74     fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
75         if bytes.len() != CONNECT_COMPLETE_SIZE {
76             return Err(format!("Wrong number of bytes for Connection Complete: {}", bytes.len()));
77         }
78 
79         // The ConnectComplete event is constructed within libbluetooth and uses
80         // the native endianness of the machine when writing to the socket. When
81         // parsing, make sure to use native endianness here.
82         let (size_bytes, rest) = bytes.split_at(std::mem::size_of::<u16>());
83         if u16::from_ne_bytes(size_bytes.try_into().unwrap()) != (CONNECT_COMPLETE_SIZE as u16) {
84             return Err(format!("Wrong size in Connection Complete: {:?}", size_bytes));
85         }
86 
87         // We know from previous size checks that all these splits will work.
88         let (addr_bytes, rest) = rest.split_at(std::mem::size_of::<RawAddress>());
89         let (channel_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
90         let (status_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
91         let (max_tx_packet_size_bytes, rest) = rest.split_at(std::mem::size_of::<u16>());
92         let (max_rx_packet_size_bytes, _unused) = rest.split_at(std::mem::size_of::<u16>());
93 
94         let addr = match RawAddress::from_bytes(addr_bytes) {
95             Some(v) => v,
96             None => {
97                 return Err("Invalid address in Connection Complete".into());
98             }
99         };
100 
101         Ok(ConnectionComplete {
102             size: CONNECT_COMPLETE_SIZE.try_into().unwrap_or_default(),
103             addr,
104             channel: i32::from_ne_bytes(channel_bytes.try_into().unwrap()),
105             status: i32::from_ne_bytes(status_bytes.try_into().unwrap()),
106             max_tx_packet_size: u16::from_ne_bytes(max_tx_packet_size_bytes.try_into().unwrap()),
107             max_rx_packet_size: u16::from_ne_bytes(max_rx_packet_size_bytes.try_into().unwrap()),
108         })
109     }
110 }
111 
112 /// Represents the standard BT SOCKET interface.
113 ///
114 /// For parameter documentation, see the type |sock_connect_signal_t|.
115 pub type SocketConnectSignal = bindings::sock_connect_signal_t;
116 
117 struct RawBtSockWrapper {
118     raw: *const bindings::btsock_interface_t,
119 }
120 
121 // Pointers unsafe due to ownership but this is a static pointer so Send is ok.
122 unsafe impl Send for RawBtSockWrapper {}
123 
124 /// Bluetooth socket interface wrapper. This allows creation of RFCOMM and L2CAP sockets.
125 /// For documentation of functions, see definition of |btsock_interface_t|.
126 pub struct BtSocket {
127     internal: RawBtSockWrapper,
128 }
129 
130 pub type FdError = &'static str;
131 
try_from_fd(fd: i32) -> Result<File, FdError>132 pub fn try_from_fd(fd: i32) -> Result<File, FdError> {
133     if fd >= 0 {
134         Ok(unsafe { File::from_raw_fd(fd) })
135     } else {
136         Err("Invalid FD")
137     }
138 }
139 
140 impl BtSocket {
new(intf: &BluetoothInterface) -> Self141     pub fn new(intf: &BluetoothInterface) -> Self {
142         let r = intf.get_profile_interface(SupportedProfiles::Socket);
143         if r.is_null() {
144             panic!("Failed to get Socket interface");
145         }
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<Uuid>, 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<Uuid>,
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 = service_uuid.or(Some(Uuid::from([0; 16])));
162         let uuid_ptr = LTCheckedPtr::from(&uuid);
163 
164         let name = CString::new(service_name).expect("Service name has null in it.");
165         let name_ptr = LTCheckedPtr::from(&name);
166 
167         let data_path: u32 = 0;
168         let sock_name = CString::new("test").expect("Socket name has null in it");
169         let hub_id: u64 = 0;
170         let endpoint_id: u64 = 0;
171         let max_rx_packet_size: i32 = 0;
172 
173         let status: BtStatus = ccall!(
174             self,
175             listen,
176             sock_type.into(),
177             name_ptr.into(),
178             uuid_ptr.into(),
179             channel,
180             sockfd_ptr.into(),
181             flags,
182             calling_uid,
183             data_path,
184             sock_name.as_ptr(),
185             hub_id,
186             endpoint_id,
187             max_rx_packet_size
188         )
189         .into();
190 
191         (status, try_from_fd(sockfd))
192     }
193 
connect( &self, addr: RawAddress, sock_type: SocketType, service_uuid: Option<Uuid>, channel: i32, flags: i32, calling_uid: i32, ) -> (BtStatus, Result<File, FdError>)194     pub fn connect(
195         &self,
196         addr: RawAddress,
197         sock_type: SocketType,
198         service_uuid: Option<Uuid>,
199         channel: i32,
200         flags: i32,
201         calling_uid: i32,
202     ) -> (BtStatus, Result<File, FdError>) {
203         let mut sockfd: i32 = -1;
204         let sockfd_ptr = LTCheckedPtrMut::from_ref(&mut sockfd);
205         let uuid_ptr = LTCheckedPtr::from(&service_uuid);
206         let addr_ptr = LTCheckedPtr::from_ref(&addr);
207 
208         let data_path: u32 = 0;
209         let sock_name = CString::new("test").expect("Socket name has null in it");
210         let hub_id: u64 = 0;
211         let endpoint_id: u64 = 0;
212         let max_rx_packet_size: i32 = 0;
213 
214         let status: BtStatus = ccall!(
215             self,
216             connect,
217             addr_ptr.into(),
218             sock_type.into(),
219             uuid_ptr.into(),
220             channel,
221             sockfd_ptr.into(),
222             flags,
223             calling_uid,
224             data_path,
225             sock_name.as_ptr(),
226             hub_id,
227             endpoint_id,
228             max_rx_packet_size
229         )
230         .into();
231 
232         (status, try_from_fd(sockfd))
233     }
234 
request_max_tx_data_length(&self, addr: RawAddress)235     pub fn request_max_tx_data_length(&self, addr: RawAddress) {
236         ccall!(self, request_max_tx_data_length, &addr);
237     }
238 
send_msc(&self, dlci: u8, addr: RawAddress) -> BtStatus239     pub fn send_msc(&self, dlci: u8, addr: RawAddress) -> BtStatus {
240         // PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON
241         const DEFAULT_MODEM_SIGNAL: u8 = 0x01 | 0x02 | 0x08;
242 
243         const DEFAULT_BREAK_SIGNAL: u8 = 0;
244         const DEFAULT_DISCARD_BUFFERS: u8 = 0;
245         const DEFAULT_BREAK_SIGNAL_SEQ: u8 = 1; // In sequence.
246 
247         // In RFCOMM/DEVA-DEVB/RFC/BV-21-C and RFCOMM/DEVA-DEVB/RFC/BV-22-C test flow
248         // we are requested to send an MSC command with FC=0.
249         const FC: bool = false;
250 
251         ccall!(
252             self,
253             control_req,
254             dlci,
255             &addr,
256             DEFAULT_MODEM_SIGNAL,
257             DEFAULT_BREAK_SIGNAL,
258             DEFAULT_DISCARD_BUFFERS,
259             DEFAULT_BREAK_SIGNAL_SEQ,
260             FC
261         )
262         .into()
263     }
264 
disconnect_all(&self, addr: RawAddress) -> BtStatus265     pub fn disconnect_all(&self, addr: RawAddress) -> BtStatus {
266         ccall!(self, disconnect_all, &addr).into()
267     }
268 }
269 
270 #[cfg(test)]
271 mod tests {
272     use super::*;
273 
274     #[test]
test_conncomplete_parsing()275     fn test_conncomplete_parsing() {
276         // Actual slice size doesn't match
277         let small_input = [0u8; CONNECT_COMPLETE_SIZE - 1];
278         let large_input = [0u8; CONNECT_COMPLETE_SIZE + 1];
279 
280         assert_eq!(false, ConnectionComplete::try_from(&small_input[0..]).is_ok());
281         assert_eq!(false, ConnectionComplete::try_from(&large_input[0..]).is_ok());
282 
283         // Size param in slice doesn't match.
284         let mut size_no_match: Vec<u8> = vec![];
285         size_no_match.extend(i16::to_ne_bytes((CONNECT_COMPLETE_SIZE - 1) as i16));
286         size_no_match.extend([0u8; CONNECT_COMPLETE_SIZE - 2]);
287 
288         assert_eq!(false, ConnectionComplete::try_from(size_no_match.as_slice()).is_ok());
289 
290         let valid_signal = bindings::sock_connect_signal_t {
291             size: CONNECT_COMPLETE_SIZE as i16,
292             bd_addr: RawAddress { address: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6] },
293             channel: 1_i32,
294             status: 5_i32,
295             max_tx_packet_size: 16_u16,
296             max_rx_packet_size: 17_u16,
297             conn_uuid_lsb: 0x0000113500001135_u64,
298             conn_uuid_msb: 0x1135000011350000_u64,
299             socket_id: 0x1135113511351135_u64,
300         };
301         // SAFETY: The sock_connect_signal_t type has size CONNECT_COMPLETE_SIZE,
302         // and has no padding, so it's safe to convert it to a byte array.
303         let valid_raw_data: &[u8] = unsafe {
304             std::slice::from_raw_parts(
305                 (&valid_signal as *const bindings::sock_connect_signal_t) as *const u8,
306                 CONNECT_COMPLETE_SIZE,
307             )
308         };
309 
310         let result = ConnectionComplete::try_from(valid_raw_data);
311         assert_eq!(true, result.is_ok());
312 
313         if let Ok(cc) = result {
314             assert_eq!(cc.size, CONNECT_COMPLETE_SIZE as u16);
315             assert_eq!(cc.addr, RawAddress { address: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6] });
316             assert_eq!(cc.channel, 1_i32);
317             assert_eq!(cc.status, 5_i32);
318             assert_eq!(cc.max_tx_packet_size, 16_u16);
319             assert_eq!(cc.max_rx_packet_size, 17_u16);
320         }
321     }
322 }
323