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