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