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