• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use num_derive::{FromPrimitive, ToPrimitive};
2 use num_traits::cast::{FromPrimitive, ToPrimitive};
3 use std::convert::TryFrom;
4 use std::fmt::{Debug, Formatter, Result};
5 use std::os::raw::c_char;
6 use std::sync::{Arc, Mutex};
7 use std::vec::Vec;
8 
9 use crate::bindings::root as bindings;
10 use crate::btif::{
11     ascii_to_string, ptr_to_vec, BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, Uuid,
12 };
13 use crate::ccall;
14 use crate::topstack::get_dispatchers;
15 use crate::utils::{LTCheckedPtr, LTCheckedPtrMut};
16 use topshim_macros::{cb_variant, log_args};
17 
18 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
19 #[repr(u32)]
20 pub enum BtSdpType {
21     Raw = 0,
22     MapMas,
23     MapMns,
24     PbapPse,
25     PbapPce,
26     OppServer,
27     SapServer,
28     Dip,
29     Mps,
30 }
31 
32 impl From<bindings::bluetooth_sdp_types> for BtSdpType {
from(item: bindings::bluetooth_sdp_types) -> Self33     fn from(item: bindings::bluetooth_sdp_types) -> Self {
34         BtSdpType::from_u32(item).unwrap_or(BtSdpType::Raw)
35     }
36 }
37 
38 impl From<&BtSdpRecord> for BtSdpType {
from(record: &BtSdpRecord) -> Self39     fn from(record: &BtSdpRecord) -> Self {
40         match record {
41             BtSdpRecord::HeaderOverlay(header) => header.sdp_type.clone(),
42             BtSdpRecord::MapMas(record) => record.hdr.sdp_type.clone(),
43             BtSdpRecord::MapMns(record) => record.hdr.sdp_type.clone(),
44             BtSdpRecord::PbapPse(record) => record.hdr.sdp_type.clone(),
45             BtSdpRecord::PbapPce(record) => record.hdr.sdp_type.clone(),
46             BtSdpRecord::OppServer(record) => record.hdr.sdp_type.clone(),
47             BtSdpRecord::SapServer(record) => record.hdr.sdp_type.clone(),
48             BtSdpRecord::Dip(record) => record.hdr.sdp_type.clone(),
49             BtSdpRecord::Mps(record) => record.hdr.sdp_type.clone(),
50         }
51     }
52 }
53 
54 #[derive(Clone, Debug)]
55 pub struct BtSdpHeaderOverlay {
56     pub sdp_type: BtSdpType,
57     pub uuid: Uuid,
58     pub service_name_length: u32,
59     pub service_name: String,
60     pub rfcomm_channel_number: i32,
61     pub l2cap_psm: i32,
62     pub profile_version: i32,
63 
64     pub user1_len: i32,
65     pub user1_data: Vec<u8>,
66     pub user2_len: i32,
67     pub user2_data: Vec<u8>,
68 }
69 
70 impl From<bindings::_bluetooth_sdp_hdr_overlay> for BtSdpHeaderOverlay {
from(item: bindings::_bluetooth_sdp_hdr_overlay) -> Self71     fn from(item: bindings::_bluetooth_sdp_hdr_overlay) -> Self {
72         let user1_len = item.user1_ptr_len;
73         let user1_data = unsafe {
74             std::slice::from_raw_parts(item.user1_ptr, item.user1_ptr_len as usize).to_vec()
75         };
76         let user2_len = item.user2_ptr_len;
77         let user2_data = unsafe {
78             std::slice::from_raw_parts(item.user2_ptr, item.user2_ptr_len as usize).to_vec()
79         };
80 
81         let sdp_hdr = unsafe {
82             *((&item as *const bindings::_bluetooth_sdp_hdr_overlay)
83                 as *const bindings::_bluetooth_sdp_hdr)
84         };
85         let sdp_type = BtSdpType::from(sdp_hdr.type_);
86         let uuid = sdp_hdr.uuid;
87         let service_name_length = sdp_hdr.service_name_length;
88         let service_name = ascii_to_string(
89             unsafe {
90                 std::slice::from_raw_parts(
91                     sdp_hdr.service_name as *const u8,
92                     sdp_hdr.service_name_length as usize,
93                 )
94             },
95             sdp_hdr.service_name_length as usize,
96         );
97         let rfcomm_channel_number = sdp_hdr.rfcomm_channel_number;
98         let l2cap_psm = sdp_hdr.l2cap_psm;
99         let profile_version = sdp_hdr.profile_version;
100         BtSdpHeaderOverlay {
101             sdp_type,
102             uuid,
103             service_name_length,
104             service_name,
105             rfcomm_channel_number,
106             l2cap_psm,
107             profile_version,
108             user1_len,
109             user1_data,
110             user2_len,
111             user2_data,
112         }
113     }
114 }
115 
116 #[derive(Clone, Debug)]
117 pub struct BtSdpMasRecord {
118     pub hdr: BtSdpHeaderOverlay,
119     pub mas_instance_id: u32,
120     pub supported_features: u32,
121     pub supported_message_types: u32,
122 }
123 
124 impl From<bindings::_bluetooth_sdp_mas_record> for BtSdpMasRecord {
from(item: bindings::_bluetooth_sdp_mas_record) -> Self125     fn from(item: bindings::_bluetooth_sdp_mas_record) -> Self {
126         BtSdpMasRecord {
127             hdr: BtSdpHeaderOverlay::from(item.hdr),
128             mas_instance_id: item.mas_instance_id,
129             supported_features: item.supported_features,
130             supported_message_types: item.supported_message_types,
131         }
132     }
133 }
134 
135 #[derive(Clone, Debug)]
136 pub struct BtSdpMnsRecord {
137     pub hdr: BtSdpHeaderOverlay,
138     pub supported_features: u32,
139 }
140 
141 impl From<bindings::_bluetooth_sdp_mns_record> for BtSdpMnsRecord {
from(item: bindings::_bluetooth_sdp_mns_record) -> Self142     fn from(item: bindings::_bluetooth_sdp_mns_record) -> Self {
143         BtSdpMnsRecord {
144             hdr: BtSdpHeaderOverlay::from(item.hdr),
145             supported_features: item.supported_features,
146         }
147     }
148 }
149 
150 #[derive(Clone, Debug)]
151 pub struct BtSdpPseRecord {
152     pub hdr: BtSdpHeaderOverlay,
153     pub supported_features: u32,
154     pub supported_repositories: u32,
155 }
156 
157 impl From<bindings::_bluetooth_sdp_pse_record> for BtSdpPseRecord {
from(item: bindings::_bluetooth_sdp_pse_record) -> Self158     fn from(item: bindings::_bluetooth_sdp_pse_record) -> Self {
159         BtSdpPseRecord {
160             hdr: BtSdpHeaderOverlay::from(item.hdr),
161             supported_features: item.supported_features,
162             supported_repositories: item.supported_repositories,
163         }
164     }
165 }
166 
167 #[derive(Clone, Debug)]
168 pub struct BtSdpPceRecord {
169     pub hdr: BtSdpHeaderOverlay,
170 }
171 
172 impl From<bindings::_bluetooth_sdp_pce_record> for BtSdpPceRecord {
from(item: bindings::_bluetooth_sdp_pce_record) -> Self173     fn from(item: bindings::_bluetooth_sdp_pce_record) -> Self {
174         BtSdpPceRecord { hdr: BtSdpHeaderOverlay::from(item.hdr) }
175     }
176 }
177 
178 pub type SupportedFormatsList = [u8; 15usize];
179 
180 #[derive(Clone, Debug)]
181 pub struct BtSdpOpsRecord {
182     pub hdr: BtSdpHeaderOverlay,
183     pub supported_formats_list_len: i32,
184     pub supported_formats_list: SupportedFormatsList,
185 }
186 
187 impl From<bindings::_bluetooth_sdp_ops_record> for BtSdpOpsRecord {
from(item: bindings::_bluetooth_sdp_ops_record) -> Self188     fn from(item: bindings::_bluetooth_sdp_ops_record) -> Self {
189         BtSdpOpsRecord {
190             hdr: BtSdpHeaderOverlay::from(item.hdr),
191             supported_formats_list_len: item.supported_formats_list_len,
192             supported_formats_list: item.supported_formats_list,
193         }
194     }
195 }
196 
197 #[derive(Clone, Debug)]
198 pub struct BtSdpSapRecord {
199     pub hdr: BtSdpHeaderOverlay,
200 }
201 
202 impl From<bindings::_bluetooth_sdp_sap_record> for BtSdpSapRecord {
from(item: bindings::_bluetooth_sdp_sap_record) -> Self203     fn from(item: bindings::_bluetooth_sdp_sap_record) -> Self {
204         BtSdpSapRecord { hdr: BtSdpHeaderOverlay::from(item.hdr) }
205     }
206 }
207 
208 #[derive(Clone, Debug)]
209 pub struct BtSdpDipRecord {
210     pub hdr: BtSdpHeaderOverlay,
211     pub spec_id: u16,
212     pub vendor: u16,
213     pub vendor_id_source: u16,
214     pub product: u16,
215     pub version: u16,
216     pub primary_record: bool,
217 }
218 
219 impl From<bindings::_bluetooth_sdp_dip_record> for BtSdpDipRecord {
from(item: bindings::_bluetooth_sdp_dip_record) -> Self220     fn from(item: bindings::_bluetooth_sdp_dip_record) -> Self {
221         BtSdpDipRecord {
222             hdr: BtSdpHeaderOverlay::from(item.hdr),
223             spec_id: item.spec_id,
224             vendor: item.vendor,
225             vendor_id_source: item.vendor_id_source,
226             product: item.product,
227             version: item.version,
228             primary_record: item.primary_record,
229         }
230     }
231 }
232 
233 pub type SupportedScenarios = [u8; 8usize];
234 pub type SupportedDependencies = [u8; 2usize];
235 
236 #[derive(Clone, Debug)]
237 pub struct BtSdpMpsRecord {
238     pub hdr: BtSdpHeaderOverlay,
239     pub supported_scenarios_mpsd: SupportedScenarios, // LibBluetooth expects big endian data
240     pub supported_scenarios_mpmd: SupportedScenarios, // LibBluetooth expects big endian data
241     pub supported_dependencies: SupportedDependencies, // LibBluetooth expects big endian data
242 }
243 
244 impl BtSdpMpsRecord {
default() -> Self245     pub fn default() -> Self {
246         let empty_uuid = Uuid::try_from(vec![0x0, 0x0]).unwrap();
247         BtSdpMpsRecord {
248             hdr: BtSdpHeaderOverlay {
249                 sdp_type: BtSdpType::Mps,
250                 uuid: empty_uuid,            // Not used
251                 service_name_length: 0,      // Not used
252                 service_name: String::new(), // Not used
253                 rfcomm_channel_number: 0,    // Not used
254                 l2cap_psm: 0,                // Not used
255                 profile_version: 0x0100,
256                 user1_len: 0,       // Not used
257                 user1_data: vec![], // Not used
258                 user2_len: 0,       // Not used
259                 user2_data: vec![], // Not used
260             },
261             // LibBluetooth accepts big endian data. CrOS supports:
262             // - 0 Answer Incoming Call during Audio Streaming (HFP-AG_A2DP-SRC)
263             // - 2 Outgoing Call during Audio Streaming (HFP-AG_A2DP-SRC)
264             // - 4 Reject/Ignore Incoming Call during Audio Streaming (HFP-AG_A2DP-SRC)
265             // - 6 HFP call termination during AVP connection (HFP-AG_A2DP-SRC)
266             // - 8 Press Play on Audio Player during active call (HFP-AG_A2DP-SRC)
267             // - 10 Start Audio Streaming after AVRCP Play Command (HFP-AG_A2DP-SRC)
268             // - 12 Suspend Audio Streaming after AVRCP Pause/Stop (HFP-AG_A2DP-SRC)
269             supported_scenarios_mpsd: [0, 0, 0, 0, 0, 0, 0b_1_0101, 0b_0101_0101],
270             supported_scenarios_mpmd: [0; 8],
271             // LibBluetooth accepts big endian data. CrOS supports:
272             // - 1 Sniff Mode During Streaming
273             // - 3 (Dis-)Connection Order / Behavior
274             supported_dependencies: [0, 0b_1010],
275         }
276     }
277 }
278 
279 impl From<bindings::_bluetooth_sdp_mps_record> for BtSdpMpsRecord {
from(item: bindings::_bluetooth_sdp_mps_record) -> Self280     fn from(item: bindings::_bluetooth_sdp_mps_record) -> Self {
281         BtSdpMpsRecord {
282             hdr: BtSdpHeaderOverlay::from(item.hdr),
283             supported_scenarios_mpsd: item.supported_scenarios_mpsd,
284             supported_scenarios_mpmd: item.supported_scenarios_mpmd,
285             supported_dependencies: item.supported_dependencies,
286         }
287     }
288 }
289 
290 #[derive(Clone, Debug)]
291 pub enum BtSdpRecord {
292     HeaderOverlay(BtSdpHeaderOverlay),
293     MapMas(BtSdpMasRecord),
294     MapMns(BtSdpMnsRecord),
295     PbapPse(BtSdpPseRecord),
296     PbapPce(BtSdpPceRecord),
297     OppServer(BtSdpOpsRecord),
298     SapServer(BtSdpSapRecord),
299     Dip(BtSdpDipRecord),
300     Mps(BtSdpMpsRecord),
301 }
302 
303 impl From<bindings::bluetooth_sdp_record> for BtSdpRecord {
from(item: bindings::bluetooth_sdp_record) -> Self304     fn from(item: bindings::bluetooth_sdp_record) -> Self {
305         let sdp_type = unsafe { BtSdpType::from(item.hdr.type_) };
306 
307         match sdp_type {
308             BtSdpType::Raw => unsafe {
309                 BtSdpRecord::HeaderOverlay(BtSdpHeaderOverlay::from(item.hdr))
310             },
311             BtSdpType::MapMas => unsafe { BtSdpRecord::MapMas(BtSdpMasRecord::from(item.mas)) },
312             BtSdpType::MapMns => unsafe { BtSdpRecord::MapMns(BtSdpMnsRecord::from(item.mns)) },
313             BtSdpType::PbapPse => unsafe { BtSdpRecord::PbapPse(BtSdpPseRecord::from(item.pse)) },
314             BtSdpType::PbapPce => unsafe { BtSdpRecord::PbapPce(BtSdpPceRecord::from(item.pce)) },
315             BtSdpType::OppServer => unsafe {
316                 BtSdpRecord::OppServer(BtSdpOpsRecord::from(item.ops))
317             },
318             BtSdpType::SapServer => unsafe {
319                 BtSdpRecord::SapServer(BtSdpSapRecord::from(item.sap))
320             },
321             BtSdpType::Dip => unsafe { BtSdpRecord::Dip(BtSdpDipRecord::from(item.dip)) },
322             BtSdpType::Mps => unsafe { BtSdpRecord::Mps(BtSdpMpsRecord::from(item.mps)) },
323         }
324     }
325 }
326 
327 impl BtSdpRecord {
convert_header<'a>(hdr: &'a mut BtSdpHeaderOverlay) -> bindings::bluetooth_sdp_hdr_overlay328     fn convert_header<'a>(hdr: &'a mut BtSdpHeaderOverlay) -> bindings::bluetooth_sdp_hdr_overlay {
329         let srv_name_ptr = LTCheckedPtrMut::from(&mut hdr.service_name);
330         let user1_ptr = LTCheckedPtr::from(&hdr.user1_data);
331         let user2_ptr = LTCheckedPtr::from(&hdr.user2_data);
332         bindings::bluetooth_sdp_hdr_overlay {
333             type_: hdr.sdp_type.to_u32().unwrap(),
334             uuid: hdr.uuid,
335             service_name_length: hdr.service_name_length,
336             service_name: srv_name_ptr.cast_into::<c_char>(),
337             rfcomm_channel_number: hdr.rfcomm_channel_number,
338             l2cap_psm: hdr.l2cap_psm,
339             profile_version: hdr.profile_version,
340             user1_ptr_len: hdr.user1_len,
341             user1_ptr: user1_ptr.into(),
342             user2_ptr_len: hdr.user2_len,
343             user2_ptr: user2_ptr.into(),
344         }
345     }
346 
347     // Get sdp record with lifetime tied to self
get_unsafe_record<'a>(&'a mut self) -> bindings::bluetooth_sdp_record348     fn get_unsafe_record<'a>(&'a mut self) -> bindings::bluetooth_sdp_record {
349         match self {
350             BtSdpRecord::HeaderOverlay(ref mut hdr) => {
351                 bindings::bluetooth_sdp_record { hdr: BtSdpRecord::convert_header(hdr) }
352             }
353             BtSdpRecord::MapMas(mas) => bindings::bluetooth_sdp_record {
354                 mas: bindings::_bluetooth_sdp_mas_record {
355                     hdr: BtSdpRecord::convert_header(&mut mas.hdr),
356                     mas_instance_id: mas.mas_instance_id,
357                     supported_features: mas.supported_features,
358                     supported_message_types: mas.supported_message_types,
359                 },
360             },
361             BtSdpRecord::MapMns(mns) => bindings::bluetooth_sdp_record {
362                 mns: bindings::_bluetooth_sdp_mns_record {
363                     hdr: BtSdpRecord::convert_header(&mut mns.hdr),
364                     supported_features: mns.supported_features,
365                 },
366             },
367             BtSdpRecord::PbapPse(pse) => bindings::bluetooth_sdp_record {
368                 pse: bindings::_bluetooth_sdp_pse_record {
369                     hdr: BtSdpRecord::convert_header(&mut pse.hdr),
370                     supported_features: pse.supported_features,
371                     supported_repositories: pse.supported_repositories,
372                 },
373             },
374             BtSdpRecord::PbapPce(pce) => bindings::bluetooth_sdp_record {
375                 pce: bindings::_bluetooth_sdp_pce_record {
376                     hdr: BtSdpRecord::convert_header(&mut pce.hdr),
377                 },
378             },
379             BtSdpRecord::OppServer(ops) => bindings::bluetooth_sdp_record {
380                 ops: bindings::_bluetooth_sdp_ops_record {
381                     hdr: BtSdpRecord::convert_header(&mut ops.hdr),
382                     supported_formats_list_len: ops.supported_formats_list_len,
383                     supported_formats_list: ops.supported_formats_list,
384                 },
385             },
386             BtSdpRecord::SapServer(sap) => bindings::bluetooth_sdp_record {
387                 sap: bindings::_bluetooth_sdp_sap_record {
388                     hdr: BtSdpRecord::convert_header(&mut sap.hdr),
389                 },
390             },
391             BtSdpRecord::Dip(dip) => bindings::bluetooth_sdp_record {
392                 dip: bindings::_bluetooth_sdp_dip_record {
393                     hdr: BtSdpRecord::convert_header(&mut dip.hdr),
394                     spec_id: dip.spec_id,
395                     vendor: dip.vendor,
396                     vendor_id_source: dip.vendor_id_source,
397                     product: dip.product,
398                     version: dip.version,
399                     primary_record: dip.primary_record,
400                 },
401             },
402             BtSdpRecord::Mps(mps) => bindings::bluetooth_sdp_record {
403                 mps: bindings::_bluetooth_sdp_mps_record {
404                     hdr: BtSdpRecord::convert_header(&mut mps.hdr),
405                     supported_scenarios_mpsd: mps.supported_scenarios_mpsd,
406                     supported_scenarios_mpmd: mps.supported_scenarios_mpmd,
407                     supported_dependencies: mps.supported_dependencies,
408                 },
409             },
410         }
411     }
412 }
413 
414 #[derive(Debug)]
415 pub enum SdpCallbacks {
416     SdpSearch(BtStatus, RawAddress, Uuid, i32, Vec<BtSdpRecord>),
417 }
418 
419 pub struct SdpCallbacksDispatcher {
420     pub dispatch: Box<dyn Fn(SdpCallbacks) + Send>,
421 }
422 
423 impl Debug for SdpCallbacksDispatcher {
fmt(&self, f: &mut Formatter<'_>) -> Result424     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
425         write!(f, "SdpCallbacksDispatcher {{}}")
426     }
427 }
428 
429 type SdpCb = Arc<Mutex<SdpCallbacksDispatcher>>;
430 
431 cb_variant!(SdpCb, sdp_search_cb -> SdpCallbacks::SdpSearch,
432 bindings::bt_status_t -> BtStatus,
433 *const RawAddress, *const Uuid, i32,
434 *mut bindings::bluetooth_sdp_record, {
435     let _1 = unsafe { *_1 };
436     let _2 = unsafe { *_2 };
437     let _4 = ptr_to_vec(_4, _3 as usize);
438 });
439 
440 struct RawSdpWrapper {
441     pub raw: *const bindings::btsdp_interface_t,
442 }
443 
444 unsafe impl Send for RawSdpWrapper {}
445 
446 pub struct Sdp {
447     internal: RawSdpWrapper,
448     is_init: bool,
449     callbacks: Option<Box<bindings::btsdp_callbacks_t>>,
450 }
451 
452 impl Sdp {
453     #[log_args]
new(intf: &BluetoothInterface) -> Sdp454     pub fn new(intf: &BluetoothInterface) -> Sdp {
455         let r = intf.get_profile_interface(SupportedProfiles::Sdp);
456         Sdp {
457             internal: RawSdpWrapper { raw: r as *const bindings::btsdp_interface_t },
458             is_init: false,
459             callbacks: None,
460         }
461     }
462 
463     #[log_args]
is_initialized(&self) -> bool464     pub fn is_initialized(&self) -> bool {
465         self.is_init
466     }
467 
468     #[log_args]
initialize(&mut self, callbacks: SdpCallbacksDispatcher) -> bool469     pub fn initialize(&mut self, callbacks: SdpCallbacksDispatcher) -> bool {
470         if get_dispatchers().lock().unwrap().set::<SdpCb>(Arc::new(Mutex::new(callbacks))) {
471             panic!("Tried to set dispatcher for SdpCallbacks but it already existed");
472         }
473 
474         let mut callbacks = Box::new(bindings::btsdp_callbacks_t {
475             size: 2 * 8,
476             sdp_search_cb: Some(sdp_search_cb),
477         });
478 
479         let cb_ptr = LTCheckedPtrMut::from(&mut callbacks);
480 
481         let init = ccall!(self, init, cb_ptr.into());
482         self.is_init = BtStatus::from(init) == BtStatus::Success;
483         self.callbacks = Some(callbacks);
484 
485         return self.is_init;
486     }
487 
488     #[log_args]
sdp_search(&self, address: &mut RawAddress, uuid: &Uuid) -> BtStatus489     pub fn sdp_search(&self, address: &mut RawAddress, uuid: &Uuid) -> BtStatus {
490         let addr_ptr = LTCheckedPtrMut::from_ref(address);
491         BtStatus::from(ccall!(self, sdp_search, addr_ptr.into(), uuid))
492     }
493 
494     #[log_args]
create_sdp_record(&self, record: &mut BtSdpRecord, handle: &mut i32) -> BtStatus495     pub fn create_sdp_record(&self, record: &mut BtSdpRecord, handle: &mut i32) -> BtStatus {
496         let mut converted = record.get_unsafe_record();
497         let record_ptr = LTCheckedPtrMut::from_ref(&mut converted);
498         let handle_ptr = LTCheckedPtrMut::from_ref(handle);
499         BtStatus::from(ccall!(self, create_sdp_record, record_ptr.into(), handle_ptr.into()))
500     }
501 
502     #[log_args]
remove_sdp_record(&self, handle: i32) -> BtStatus503     pub fn remove_sdp_record(&self, handle: i32) -> BtStatus {
504         BtStatus::from(ccall!(self, remove_sdp_record, handle))
505     }
506 }
507