• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Shim for `bt_interface_t`, providing access to libbluetooth.
2 //!
3 //! This is a shim interface for calling the C++ bluetooth interface via Rust.
4 
5 use crate::bindings::root as bindings;
6 use crate::topstack::get_dispatchers;
7 use num_traits::cast::{FromPrimitive, ToPrimitive};
8 use std::cmp;
9 use std::fmt::{Debug, Formatter, Result};
10 use std::mem;
11 use std::os::raw::c_char;
12 use std::sync::{Arc, Mutex};
13 use std::vec::Vec;
14 use topshim_macros::cb_variant;
15 
16 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
17 #[repr(u32)]
18 pub enum BtState {
19     Off = 0,
20     On,
21 }
22 
23 impl From<bindings::bt_state_t> for BtState {
from(item: bindings::bt_state_t) -> Self24     fn from(item: bindings::bt_state_t) -> Self {
25         BtState::from_u32(item).unwrap_or_else(|| BtState::Off)
26     }
27 }
28 
29 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
30 #[repr(u32)]
31 pub enum BtTransport {
32     Auto = 0,
33     Bredr,
34     Le,
35 }
36 
37 impl From<i32> for BtTransport {
from(item: i32) -> Self38     fn from(item: i32) -> Self {
39         BtTransport::from_i32(item).unwrap_or_else(|| BtTransport::Auto)
40     }
41 }
42 
43 impl From<BtTransport> for i32 {
from(item: BtTransport) -> Self44     fn from(item: BtTransport) -> Self {
45         item.to_i32().unwrap_or_else(|| 0)
46     }
47 }
48 
49 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
50 #[repr(u32)]
51 pub enum BtSspVariant {
52     PasskeyConfirmation = 0,
53     PasskeyEntry,
54     Consent,
55     PasskeyNotification,
56 }
57 
58 impl From<bindings::bt_ssp_variant_t> for BtSspVariant {
from(item: bindings::bt_ssp_variant_t) -> Self59     fn from(item: bindings::bt_ssp_variant_t) -> Self {
60         BtSspVariant::from_u32(item).unwrap_or_else(|| BtSspVariant::PasskeyConfirmation)
61     }
62 }
63 
64 impl From<BtSspVariant> for bindings::bt_ssp_variant_t {
from(item: BtSspVariant) -> Self65     fn from(item: BtSspVariant) -> Self {
66         item.to_u32().unwrap_or_else(|| 0)
67     }
68 }
69 
70 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
71 #[repr(u32)]
72 pub enum BtBondState {
73     NotBonded = 0,
74     Bonding,
75     Bonded,
76 }
77 
78 impl From<bindings::bt_bond_state_t> for BtBondState {
from(item: bindings::bt_bond_state_t) -> Self79     fn from(item: bindings::bt_bond_state_t) -> Self {
80         BtBondState::from_u32(item).unwrap_or_else(|| BtBondState::NotBonded)
81     }
82 }
83 
84 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
85 #[repr(u32)]
86 pub enum BtConnectionState {
87     NotConnected = 0,
88     ConnectedOnly = 1,
89     EncryptedBredr = 3,
90     EncryptedLe = 5,
91 }
92 
93 impl From<i32> for BtConnectionState {
from(item: i32) -> Self94     fn from(item: i32) -> Self {
95         let fallback = if item > 0 {
96             BtConnectionState::ConnectedOnly
97         } else {
98             BtConnectionState::NotConnected
99         };
100 
101         BtConnectionState::from_i32(item).unwrap_or(fallback)
102     }
103 }
104 
105 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
106 #[repr(u32)]
107 pub enum BtAclState {
108     Connected = 0,
109     Disconnected,
110 }
111 
112 impl From<bindings::bt_acl_state_t> for BtAclState {
from(item: bindings::bt_acl_state_t) -> Self113     fn from(item: bindings::bt_acl_state_t) -> Self {
114         BtAclState::from_u32(item).unwrap_or_else(|| BtAclState::Disconnected)
115     }
116 }
117 
118 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
119 #[repr(u32)]
120 pub enum BtDeviceType {
121     Bredr,
122     Ble,
123     Dual,
124     Unknown,
125 }
126 
127 #[derive(Clone, Debug, Eq, Hash, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
128 #[repr(u32)]
129 pub enum BtPropertyType {
130     BdName = 0x1,
131     BdAddr,
132     Uuids,
133     ClassOfDevice,
134     TypeOfDevice,
135     ServiceRecord,
136     AdapterScanMode,
137     AdapterBondedDevices,
138     AdapterDiscoverableTimeout,
139     RemoteFriendlyName,
140     RemoteRssi,
141     RemoteVersionInfo,
142     LocalLeFeatures,
143     LocalIoCaps,
144     LocalIoCapsBle,
145     DynamicAudioBuffer,
146 
147     Unknown = 0xFE,
148     RemoteDeviceTimestamp = 0xFF,
149 }
150 
151 impl From<u32> for BtPropertyType {
from(item: u32) -> Self152     fn from(item: u32) -> Self {
153         BtPropertyType::from_u32(item).unwrap_or_else(|| BtPropertyType::Unknown)
154     }
155 }
156 
157 impl From<BtPropertyType> for u32 {
from(item: BtPropertyType) -> Self158     fn from(item: BtPropertyType) -> Self {
159         item.to_u32().unwrap_or_else(|| 0)
160     }
161 }
162 
163 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
164 #[repr(u32)]
165 pub enum BtDiscoveryState {
166     Stopped = 0x0,
167     Started,
168 }
169 
170 impl From<u32> for BtDiscoveryState {
from(item: u32) -> Self171     fn from(item: u32) -> Self {
172         BtDiscoveryState::from_u32(item).unwrap_or_else(|| BtDiscoveryState::Stopped)
173     }
174 }
175 
176 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
177 #[repr(u32)]
178 pub enum BtStatus {
179     Success = 0,
180     Fail,
181     NotReady,
182     NoMemory,
183     Busy,
184     Done,
185     Unsupported,
186     InvalidParam,
187     Unhandled,
188     AuthFailure,
189     RemoteDeviceDown,
190     AuthRejected,
191     JniEnvironmentError,
192     JniThreadAttachError,
193     WakeLockError,
194 
195     // Any statuses that couldn't be cleanly converted
196     Unknown = 0xff,
197 }
198 
ascii_to_string(data: &[u8], length: usize) -> String199 pub fn ascii_to_string(data: &[u8], length: usize) -> String {
200     // We need to reslice data because from_utf8 tries to interpret the
201     // whole slice and not just what is before the null terminated portion
202     let ascii = data
203         .iter()
204         .enumerate()
205         .take_while(|&(pos, &c)| c != 0 && pos < length)
206         .map(|(_pos, &x)| x.clone())
207         .collect::<Vec<u8>>();
208 
209     return String::from_utf8(ascii).unwrap_or_default();
210 }
211 
u32_from_bytes(item: &[u8]) -> u32212 fn u32_from_bytes(item: &[u8]) -> u32 {
213     let mut u: [u8; 4] = [0; 4];
214     let len = std::cmp::min(item.len(), 4);
215     u[0..len].copy_from_slice(&item);
216     u32::from_ne_bytes(u)
217 }
218 
219 impl From<bindings::bt_status_t> for BtStatus {
from(item: bindings::bt_status_t) -> Self220     fn from(item: bindings::bt_status_t) -> Self {
221         match BtStatus::from_u32(item) {
222             Some(x) => x,
223             _ => BtStatus::Unknown,
224         }
225     }
226 }
227 
228 impl From<bindings::bt_bdname_t> for String {
from(item: bindings::bt_bdname_t) -> Self229     fn from(item: bindings::bt_bdname_t) -> Self {
230         ascii_to_string(&item.name, item.name.len())
231     }
232 }
233 
234 #[derive(Debug, Clone)]
235 pub struct BtServiceRecord {
236     pub uuid: bindings::bluetooth::Uuid,
237     pub channel: u16,
238     pub name: String,
239 }
240 
241 impl From<bindings::bt_service_record_t> for BtServiceRecord {
from(item: bindings::bt_service_record_t) -> Self242     fn from(item: bindings::bt_service_record_t) -> Self {
243         let name = item.name.iter().map(|&x| x.clone() as u8).collect::<Vec<u8>>();
244 
245         BtServiceRecord {
246             uuid: item.uuid,
247             channel: item.channel,
248             name: ascii_to_string(name.as_slice(), name.len()),
249         }
250     }
251 }
252 
253 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
254 #[repr(u32)]
255 pub enum BtScanMode {
256     None_,
257     Connectable,
258     ConnectableDiscoverable,
259 }
260 
261 impl From<bindings::bt_scan_mode_t> for BtScanMode {
from(item: bindings::bt_scan_mode_t) -> Self262     fn from(item: bindings::bt_scan_mode_t) -> Self {
263         BtScanMode::from_u32(item).unwrap_or(BtScanMode::None_)
264     }
265 }
266 
267 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
268 #[repr(u32)]
269 pub enum BtIoCap {
270     Out,
271     InOut,
272     In,
273     None_,
274     KbDisp,
275     Max,
276     Unknown = 0xff,
277 }
278 
279 impl From<bindings::bt_io_cap_t> for BtIoCap {
from(item: bindings::bt_io_cap_t) -> Self280     fn from(item: bindings::bt_io_cap_t) -> Self {
281         BtIoCap::from_u32(item).unwrap_or(BtIoCap::Unknown)
282     }
283 }
284 
285 pub type BtHciErrorCode = u8;
286 pub type BtLocalLeFeatures = bindings::bt_local_le_features_t;
287 pub type BtPinCode = bindings::bt_pin_code_t;
288 pub type BtRemoteVersion = bindings::bt_remote_version_t;
289 pub type Uuid = bindings::bluetooth::Uuid;
290 pub type Uuid128Bit = bindings::bluetooth::Uuid_UUID128Bit;
291 
292 /// All supported Bluetooth properties after conversion.
293 #[derive(Debug, Clone)]
294 pub enum BluetoothProperty {
295     BdName(String),
296     BdAddr(RawAddress),
297     Uuids(Vec<Uuid>),
298     ClassOfDevice(u32),
299     TypeOfDevice(BtDeviceType),
300     ServiceRecord(BtServiceRecord),
301     AdapterScanMode(BtScanMode),
302     AdapterBondedDevices(Vec<RawAddress>),
303     AdapterDiscoverableTimeout(u32),
304     RemoteFriendlyName(String),
305     RemoteRssi(i8),
306     RemoteVersionInfo(BtRemoteVersion),
307     LocalLeFeatures(BtLocalLeFeatures),
308     LocalIoCaps(BtIoCap),
309     LocalIoCapsBle(BtIoCap),
310     DynamicAudioBuffer(),
311     RemoteDeviceTimestamp(),
312 
313     Unknown(),
314 }
315 
316 /// Wherever names are sent in bindings::bt_property_t, the size of the character
317 /// arrays are 256. Keep one extra byte for null termination.
318 const PROPERTY_NAME_MAX: usize = 255;
319 
320 impl BluetoothProperty {
get_type(&self) -> BtPropertyType321     pub fn get_type(&self) -> BtPropertyType {
322         match &*self {
323             BluetoothProperty::BdName(_) => BtPropertyType::BdName,
324             BluetoothProperty::BdAddr(_) => BtPropertyType::BdAddr,
325             BluetoothProperty::Uuids(_) => BtPropertyType::Uuids,
326             BluetoothProperty::ClassOfDevice(_) => BtPropertyType::ClassOfDevice,
327             BluetoothProperty::TypeOfDevice(_) => BtPropertyType::TypeOfDevice,
328             BluetoothProperty::ServiceRecord(_) => BtPropertyType::ServiceRecord,
329             BluetoothProperty::AdapterScanMode(_) => BtPropertyType::AdapterScanMode,
330             BluetoothProperty::AdapterBondedDevices(_) => BtPropertyType::AdapterBondedDevices,
331             BluetoothProperty::AdapterDiscoverableTimeout(_) => {
332                 BtPropertyType::AdapterDiscoverableTimeout
333             }
334             BluetoothProperty::RemoteFriendlyName(_) => BtPropertyType::RemoteFriendlyName,
335             BluetoothProperty::RemoteRssi(_) => BtPropertyType::RemoteRssi,
336             BluetoothProperty::RemoteVersionInfo(_) => BtPropertyType::RemoteVersionInfo,
337             BluetoothProperty::LocalLeFeatures(_) => BtPropertyType::LocalLeFeatures,
338             BluetoothProperty::LocalIoCaps(_) => BtPropertyType::LocalIoCaps,
339             BluetoothProperty::LocalIoCapsBle(_) => BtPropertyType::LocalIoCapsBle,
340             BluetoothProperty::DynamicAudioBuffer() => BtPropertyType::DynamicAudioBuffer,
341             BluetoothProperty::RemoteDeviceTimestamp() => BtPropertyType::RemoteDeviceTimestamp,
342             BluetoothProperty::Unknown() => BtPropertyType::Unknown,
343         }
344     }
345 
get_len(&self) -> usize346     fn get_len(&self) -> usize {
347         match &*self {
348             BluetoothProperty::BdName(name) => cmp::min(PROPERTY_NAME_MAX, name.len() + 1),
349             BluetoothProperty::BdAddr(addr) => addr.val.len(),
350             BluetoothProperty::Uuids(uulist) => uulist.len() * mem::size_of::<Uuid>(),
351             BluetoothProperty::ClassOfDevice(_) => mem::size_of::<u32>(),
352             BluetoothProperty::TypeOfDevice(_) => mem::size_of::<BtDeviceType>(),
353             BluetoothProperty::ServiceRecord(rec) => {
354                 mem::size_of::<BtServiceRecord>() + cmp::min(PROPERTY_NAME_MAX, rec.name.len() + 1)
355             }
356             BluetoothProperty::AdapterScanMode(_) => mem::size_of::<BtScanMode>(),
357             BluetoothProperty::AdapterBondedDevices(devlist) => {
358                 devlist.len() * mem::size_of::<RawAddress>()
359             }
360             BluetoothProperty::AdapterDiscoverableTimeout(_) => mem::size_of::<u32>(),
361             BluetoothProperty::RemoteFriendlyName(name) => {
362                 cmp::min(PROPERTY_NAME_MAX, name.len() + 1)
363             }
364             BluetoothProperty::RemoteRssi(_) => mem::size_of::<i8>(),
365             BluetoothProperty::RemoteVersionInfo(_) => mem::size_of::<BtRemoteVersion>(),
366             BluetoothProperty::LocalLeFeatures(_) => mem::size_of::<BtLocalLeFeatures>(),
367             BluetoothProperty::LocalIoCaps(_) => mem::size_of::<BtIoCap>(),
368             BluetoothProperty::LocalIoCapsBle(_) => mem::size_of::<BtIoCap>(),
369 
370             // TODO(abps) - Figure out sizes for these
371             BluetoothProperty::DynamicAudioBuffer() => 0,
372             BluetoothProperty::RemoteDeviceTimestamp() => 0,
373             BluetoothProperty::Unknown() => 0,
374         }
375     }
376 
377     /// Given a mutable array, this will copy the data to that array and return a
378     /// pointer to it.
379     ///
380     /// The lifetime of the returned pointer is tied to that of the slice given.
get_data_ptr<'a>(&'a self, data: &'a mut [u8]) -> *mut u8381     fn get_data_ptr<'a>(&'a self, data: &'a mut [u8]) -> *mut u8 {
382         let len = self.get_len();
383         match &*self {
384             BluetoothProperty::BdName(name) => {
385                 let copy_len = len - 1;
386                 data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
387                 data[copy_len] = 0;
388             }
389             BluetoothProperty::BdAddr(addr) => {
390                 data.copy_from_slice(&addr.val);
391             }
392             BluetoothProperty::Uuids(uulist) => {
393                 for (idx, &uuid) in uulist.iter().enumerate() {
394                     let start = idx * mem::size_of::<Uuid>();
395                     let end = start + mem::size_of::<Uuid>();
396                     data[start..end].copy_from_slice(&uuid.uu);
397                 }
398             }
399             BluetoothProperty::ClassOfDevice(cod) => {
400                 data.copy_from_slice(&cod.to_ne_bytes());
401             }
402             BluetoothProperty::TypeOfDevice(tod) => {
403                 data.copy_from_slice(&BtDeviceType::to_u32(tod).unwrap_or_default().to_ne_bytes());
404             }
405             BluetoothProperty::ServiceRecord(sr) => {
406                 // Do an unsafe cast to binding:: type and assign the values
407                 // The underlying memory location is provided by |data| which will
408                 // have enough space because it uses get_len()
409                 let mut record =
410                     unsafe { &mut *(data.as_mut_ptr() as *mut bindings::bt_service_record_t) };
411                 record.uuid = sr.uuid;
412                 record.channel = sr.channel;
413                 let name_len = len - mem::size_of::<BtServiceRecord>() - 1;
414                 record.name[0..name_len].copy_from_slice(
415                     &(sr.name.as_bytes().iter().map(|x| *x as c_char).collect::<Vec<c_char>>())
416                         [0..name_len],
417                 );
418                 record.name[name_len] = 0;
419             }
420             BluetoothProperty::AdapterScanMode(sm) => {
421                 data.copy_from_slice(&BtScanMode::to_u32(sm).unwrap_or_default().to_ne_bytes());
422             }
423             BluetoothProperty::AdapterBondedDevices(devlist) => {
424                 for (idx, &dev) in devlist.iter().enumerate() {
425                     let start = idx * mem::size_of::<RawAddress>();
426                     let end = idx + mem::size_of::<RawAddress>();
427                     data[start..end].copy_from_slice(&dev.val);
428                 }
429             }
430             BluetoothProperty::AdapterDiscoverableTimeout(timeout) => {
431                 data.copy_from_slice(&timeout.to_ne_bytes());
432             }
433             BluetoothProperty::RemoteFriendlyName(name) => {
434                 let copy_len = len - 1;
435                 data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
436                 data[copy_len] = 0;
437             }
438             BluetoothProperty::RemoteRssi(rssi) => {
439                 data[0] = *rssi as u8;
440             }
441             BluetoothProperty::RemoteVersionInfo(rvi) => {
442                 let ptr: *const BtRemoteVersion = rvi;
443                 let slice = unsafe {
444                     std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtRemoteVersion>())
445                 };
446                 data.copy_from_slice(&slice);
447             }
448             BluetoothProperty::LocalLeFeatures(llf) => {
449                 let ptr: *const BtLocalLeFeatures = llf;
450                 let slice = unsafe {
451                     std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtLocalLeFeatures>())
452                 };
453                 data.copy_from_slice(&slice);
454             }
455             BluetoothProperty::LocalIoCaps(iocap) => {
456                 data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
457             }
458             BluetoothProperty::LocalIoCapsBle(iocap) => {
459                 data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
460             }
461             BluetoothProperty::DynamicAudioBuffer() => (),
462             BluetoothProperty::RemoteDeviceTimestamp() => (),
463             BluetoothProperty::Unknown() => (),
464         };
465 
466         data.as_mut_ptr()
467     }
468 }
469 
470 // TODO(abps) - Check that sizes are correct when given a BtProperty
471 impl From<bindings::bt_property_t> for BluetoothProperty {
from(prop: bindings::bt_property_t) -> Self472     fn from(prop: bindings::bt_property_t) -> Self {
473         let slice: &[u8] =
474             unsafe { std::slice::from_raw_parts(prop.val as *mut u8, prop.len as usize) };
475         let len = prop.len as usize;
476 
477         match BtPropertyType::from(prop.type_) {
478             BtPropertyType::BdName => BluetoothProperty::BdName(ascii_to_string(slice, len)),
479             BtPropertyType::BdAddr => {
480                 BluetoothProperty::BdAddr(RawAddress::from_bytes(slice).unwrap_or_default())
481             }
482             BtPropertyType::Uuids => {
483                 let count = len / mem::size_of::<Uuid>();
484                 BluetoothProperty::Uuids(ptr_to_vec(prop.val as *mut Uuid, count))
485             }
486             BtPropertyType::ClassOfDevice => {
487                 BluetoothProperty::ClassOfDevice(u32_from_bytes(slice))
488             }
489             BtPropertyType::TypeOfDevice => BluetoothProperty::TypeOfDevice(
490                 BtDeviceType::from_u32(u32_from_bytes(slice)).unwrap_or(BtDeviceType::Bredr),
491             ),
492             BtPropertyType::ServiceRecord => {
493                 let v = unsafe { *(prop.val as *const bindings::bt_service_record_t) };
494                 BluetoothProperty::ServiceRecord(BtServiceRecord::from(v))
495             }
496             BtPropertyType::AdapterScanMode => BluetoothProperty::AdapterScanMode(
497                 BtScanMode::from_u32(u32_from_bytes(slice)).unwrap_or(BtScanMode::None_),
498             ),
499             BtPropertyType::AdapterBondedDevices => {
500                 let count = len / mem::size_of::<RawAddress>();
501                 BluetoothProperty::AdapterBondedDevices(ptr_to_vec(
502                     prop.val as *mut RawAddress,
503                     count,
504                 ))
505             }
506             BtPropertyType::AdapterDiscoverableTimeout => {
507                 BluetoothProperty::AdapterDiscoverableTimeout(u32_from_bytes(slice))
508             }
509             BtPropertyType::RemoteFriendlyName => {
510                 BluetoothProperty::RemoteFriendlyName(ascii_to_string(slice, len))
511             }
512             BtPropertyType::RemoteRssi => BluetoothProperty::RemoteRssi(slice[0] as i8),
513             BtPropertyType::RemoteVersionInfo => {
514                 let v = unsafe { *(prop.val as *const BtRemoteVersion) };
515                 BluetoothProperty::RemoteVersionInfo(v.clone())
516             }
517             BtPropertyType::LocalLeFeatures => {
518                 let v = unsafe { *(prop.val as *const BtLocalLeFeatures) };
519                 BluetoothProperty::LocalLeFeatures(v.clone())
520             }
521             BtPropertyType::LocalIoCaps => BluetoothProperty::LocalIoCaps(
522                 BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
523             ),
524             BtPropertyType::LocalIoCapsBle => BluetoothProperty::LocalIoCapsBle(
525                 BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
526             ),
527 
528             // TODO(abps) - Figure out if these values should actually have contents
529             BtPropertyType::DynamicAudioBuffer => BluetoothProperty::DynamicAudioBuffer(),
530             BtPropertyType::RemoteDeviceTimestamp => BluetoothProperty::RemoteDeviceTimestamp(),
531             _ => BluetoothProperty::Unknown(),
532         }
533     }
534 }
535 
536 impl From<BluetoothProperty> for (Box<[u8]>, bindings::bt_property_t) {
from(prop: BluetoothProperty) -> Self537     fn from(prop: BluetoothProperty) -> Self {
538         let dvec: Vec<u8> = vec![0; prop.get_len()];
539         let mut data: Box<[u8]> = dvec.into_boxed_slice();
540         let prop = bindings::bt_property_t {
541             type_: prop.get_type().into(),
542             len: prop.get_len() as i32,
543             val: prop.get_data_ptr(&mut data) as *mut std::os::raw::c_void,
544         };
545 
546         (data, prop)
547     }
548 }
549 
550 pub enum SupportedProfiles {
551     HidHost,
552     Hfp,
553     A2dp,
554     Gatt,
555     Sdp,
556 }
557 
558 impl From<SupportedProfiles> for Vec<u8> {
from(item: SupportedProfiles) -> Self559     fn from(item: SupportedProfiles) -> Self {
560         match item {
561             SupportedProfiles::HidHost => "hidhost",
562             SupportedProfiles::Hfp => "hfp",
563             SupportedProfiles::A2dp => "a2dp",
564             SupportedProfiles::Gatt => "gatt",
565             SupportedProfiles::Sdp => "sdp",
566         }
567         .bytes()
568         .chain("\0".bytes())
569         .collect::<Vec<u8>>()
570     }
571 }
572 
573 #[cxx::bridge(namespace = bluetooth::topshim::rust)]
574 mod ffi {
575     #[derive(Debug, Copy, Clone)]
576     pub struct RustRawAddress {
577         address: [u8; 6],
578     }
579 
580     unsafe extern "C++" {
581         include!("btif/btif_shim.h");
582 
583         // For converting init flags from Vec<String> to const char **
584         type InitFlags;
585 
586         // Convert flgas into an InitFlags object
ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>587         fn ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>;
GetFlagsPtr(self: &InitFlags) -> *mut *const c_char588         fn GetFlagsPtr(self: &InitFlags) -> *mut *const c_char;
589     }
590 }
591 
592 // Export the raw address type directly from the bindings
593 pub type FfiAddress = bindings::RawAddress;
594 
595 /// A shared address structure that has the same representation as
596 /// bindings::RawAddress. Macros `deref_ffi_address` and `cast_to_ffi_address`
597 /// are used for transforming between bindings::RawAddress at ffi boundaries.
598 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
599 #[repr(C)]
600 pub struct RawAddress {
601     pub val: [u8; 6],
602 }
603 
604 impl Debug for RawAddress {
fmt(&self, f: &mut Formatter<'_>) -> Result605     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
606         f.write_fmt(format_args!(
607             "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
608             self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
609         ))
610     }
611 }
612 
613 impl Default for RawAddress {
default() -> Self614     fn default() -> Self {
615         Self { val: [0; 6] }
616     }
617 }
618 
619 impl ToString for RawAddress {
to_string(&self) -> String620     fn to_string(&self) -> String {
621         String::from(format!(
622             "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
623             self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
624         ))
625     }
626 }
627 
628 impl RawAddress {
629     /// Constructs a RawAddress from a slice of 6 bytes.
from_bytes(raw_addr: &[u8]) -> Option<RawAddress>630     pub fn from_bytes(raw_addr: &[u8]) -> Option<RawAddress> {
631         if raw_addr.len() != 6 {
632             return None;
633         }
634         let mut raw: [u8; 6] = [0; 6];
635         raw.copy_from_slice(raw_addr);
636         return Some(RawAddress { val: raw });
637     }
638 
from_string<S: Into<String>>(addr: S) -> Option<RawAddress>639     pub fn from_string<S: Into<String>>(addr: S) -> Option<RawAddress> {
640         let addr: String = addr.into();
641         let s = addr.split(':').collect::<Vec<&str>>();
642 
643         if s.len() != 6 {
644             return None;
645         }
646 
647         let mut raw: [u8; 6] = [0; 6];
648         for i in 0..s.len() {
649             raw[i] = match u8::from_str_radix(s[i], 16) {
650                 Ok(res) => res,
651                 Err(_) => {
652                     return None;
653                 }
654             };
655         }
656 
657         Some(RawAddress { val: raw })
658     }
659 
to_byte_arr(&self) -> [u8; 6]660     pub fn to_byte_arr(&self) -> [u8; 6] {
661         self.val.clone()
662     }
663 }
664 
665 #[macro_export]
666 macro_rules! deref_ffi_address {
667     ($ffi_addr:ident) => {
668         *($ffi_addr as *mut RawAddress)
669     };
670 }
671 
672 #[macro_export]
673 macro_rules! deref_const_ffi_address {
674     ($ffi_addr:ident) => {
675         *($ffi_addr as *const RawAddress)
676     };
677 }
678 
679 #[macro_export]
680 macro_rules! cast_to_ffi_address {
681     ($raw_addr:expr) => {
682         $raw_addr as *mut FfiAddress
683     };
684 }
685 
686 #[macro_export]
687 macro_rules! cast_to_const_ffi_address {
688     ($raw_addr:expr) => {
689         $raw_addr as *const FfiAddress
690     };
691 }
692 
693 /// An enum representing `bt_callbacks_t` from btif.
694 #[derive(Clone, Debug)]
695 pub enum BaseCallbacks {
696     AdapterState(BtState),
697     AdapterProperties(BtStatus, i32, Vec<BluetoothProperty>),
698     RemoteDeviceProperties(BtStatus, RawAddress, i32, Vec<BluetoothProperty>),
699     DeviceFound(i32, Vec<BluetoothProperty>),
700     DiscoveryState(BtDiscoveryState),
701     PinRequest(RawAddress, String, u32, bool),
702     SspRequest(RawAddress, String, u32, BtSspVariant, u32),
703     BondState(BtStatus, RawAddress, BtBondState, i32),
704     AddressConsolidate(RawAddress, RawAddress),
705     LeAddressAssociate(RawAddress, RawAddress),
706     AclState(BtStatus, RawAddress, BtAclState, BtTransport, BtHciErrorCode),
707     // Unimplemented so far:
708     // thread_evt_cb
709     // dut_mode_recv_cb
710     // le_test_mode_cb
711     // energy_info_cb
712     // link_quality_report_cb
713     // generate_local_oob_data_cb
714     // switch_buffer_size_cb
715     // switch_codec_cb
716 }
717 
718 pub struct BaseCallbacksDispatcher {
719     pub dispatch: Box<dyn Fn(BaseCallbacks) + Send>,
720 }
721 
722 type BaseCb = Arc<Mutex<BaseCallbacksDispatcher>>;
723 
724 cb_variant!(BaseCb, adapter_state_cb -> BaseCallbacks::AdapterState, u32 -> BtState);
725 cb_variant!(BaseCb, adapter_properties_cb -> BaseCallbacks::AdapterProperties,
726 u32 -> BtStatus, i32, *mut bindings::bt_property_t, {
727     let _2 = ptr_to_vec(_2, _1 as usize);
728 });
729 cb_variant!(BaseCb, remote_device_properties_cb -> BaseCallbacks::RemoteDeviceProperties,
730 u32 -> BtStatus, *mut FfiAddress -> RawAddress, i32, *mut bindings::bt_property_t, {
731     let _1 = unsafe { *(_1 as *const RawAddress) };
732     let _3 = ptr_to_vec(_3, _2 as usize);
733 });
734 cb_variant!(BaseCb, device_found_cb -> BaseCallbacks::DeviceFound,
735 i32, *mut bindings::bt_property_t, {
736     let _1 = ptr_to_vec(_1, _0 as usize);
737 });
738 cb_variant!(BaseCb, discovery_state_cb -> BaseCallbacks::DiscoveryState,
739     bindings::bt_discovery_state_t -> BtDiscoveryState);
740 cb_variant!(BaseCb, pin_request_cb -> BaseCallbacks::PinRequest,
741 *mut FfiAddress, *mut bindings::bt_bdname_t, u32, bool, {
742     let _0 = unsafe { *(_0 as *const RawAddress)};
743     let _1 = String::from(unsafe{*_1});
744 });
745 cb_variant!(BaseCb, ssp_request_cb -> BaseCallbacks::SspRequest,
746 *mut FfiAddress, *mut bindings::bt_bdname_t, u32, bindings::bt_ssp_variant_t -> BtSspVariant, u32, {
747     let _0 = unsafe { *(_0 as *const RawAddress) };
748     let _1 = String::from(unsafe{*_1});
749 });
750 cb_variant!(BaseCb, bond_state_cb -> BaseCallbacks::BondState,
751 u32 -> BtStatus, *mut FfiAddress, bindings::bt_bond_state_t -> BtBondState, i32, {
752     let _1 = unsafe { *(_1 as *const RawAddress) };
753 });
754 
755 cb_variant!(BaseCb, address_consolidate_cb -> BaseCallbacks::AddressConsolidate,
756 *mut FfiAddress, *mut FfiAddress, {
757     let _0 = unsafe { *(_0 as *const RawAddress) };
758     let _1 = unsafe { *(_1 as *const RawAddress) };
759 });
760 
761 cb_variant!(BaseCb, le_address_associate_cb -> BaseCallbacks::LeAddressAssociate,
762 *mut FfiAddress, *mut FfiAddress, {
763     let _0 = unsafe { *(_0 as *const RawAddress) };
764     let _1 = unsafe { *(_1 as *const RawAddress) };
765 });
766 
767 cb_variant!(BaseCb, acl_state_cb -> BaseCallbacks::AclState,
768 u32 -> BtStatus, *mut FfiAddress, bindings::bt_acl_state_t -> BtAclState, i32 -> BtTransport, bindings::bt_hci_error_code_t -> BtHciErrorCode, {
769     let _1 = unsafe { *(_1 as *const RawAddress) };
770 });
771 
772 struct RawInterfaceWrapper {
773     pub raw: *const bindings::bt_interface_t,
774 }
775 
776 unsafe impl Send for RawInterfaceWrapper {}
777 
778 /// Macro to call functions via function pointers. Expects the self object to
779 /// have a raw interface wrapper at `self.internal`. The actual function call is
780 /// marked unsafe since it will need to dereference a C object. This can cause
781 /// segfaults if not validated beforehand.
782 ///
783 /// Example:
784 ///     ccall!(self, foobar, arg1, arg2)
785 ///     Expands to: unsafe {((*self.internal.raw).foobar.unwrap())(arg1, arg2)}
786 #[macro_export]
787 macro_rules! ccall {
788     ($self:ident,$fn_name:ident) => {
789         unsafe {
790             ((*$self.internal.raw).$fn_name.unwrap())()
791         }
792     };
793     ($self:ident,$fn_name:ident, $($args:expr),*) => {
794         unsafe {
795             ((*$self.internal.raw).$fn_name.unwrap())($($args),*)
796         }
797     };
798 }
799 
800 /// Macro to call const functions via cxx. Expects the self object to have the
801 /// cxx object to be called at `self.internal_cxx`.
802 ///
803 /// Example:
804 ///     cxxcall!(self, foobar, arg1, arg2)
805 ///     Expands to: self.internal_cxx.foobar(arg1, arg2)
806 #[macro_export]
807 macro_rules! cxxcall {
808     ($self:expr,$fn_name:ident) => {
809         $self.internal_cxx.$fn_name()
810     };
811     ($self:expr,$fn_name:ident, $($args:expr),*) => {
812         $self.internal_cxx.$fn_name($($args),*)
813     };
814 }
815 
816 /// Macro to call mutable functions via cxx. Mutable functions are always
817 /// required to be defined with `self: Pin<&mut Self>`. The self object must
818 /// have the cxx object at `self.internal_cxx`.
819 ///
820 /// Example:
821 ///     mutcxxcall!(self, foobar, arg1, arg2)
822 ///     Expands to: self.internal_cxx.pin_mut().foobar(arg1, arg2)
823 #[macro_export]
824 macro_rules! mutcxxcall {
825     ($self:expr,$fn_name:ident) => {
826         $self.internal_cxx.pin_mut().$fn_name()
827     };
828     ($self:expr,$fn_name:ident, $($args:expr),*) => {
829         $self.internal_cxx.pin_mut().$fn_name($($args),*)
830     };
831 }
832 
833 /// Rust wrapper around `bt_interface_t`.
834 pub struct BluetoothInterface {
835     internal: RawInterfaceWrapper,
836 
837     /// Set to true after `initialize` is called.
838     pub is_init: bool,
839 
840     // Need to take ownership of callbacks so it doesn't get freed after init
841     callbacks: Option<Box<bindings::bt_callbacks_t>>,
842 }
843 
844 impl BluetoothInterface {
is_initialized(&self) -> bool845     pub fn is_initialized(&self) -> bool {
846         self.is_init
847     }
848 
849     /// Initialize the Bluetooth interface by setting up the underlying interface.
850     ///
851     /// # Arguments
852     ///
853     /// * `callbacks` - Dispatcher struct that accepts [`BaseCallbacks`]
854     /// * `init_flags` - List of flags sent to libbluetooth for init.
initialize( &mut self, callbacks: BaseCallbacksDispatcher, init_flags: Vec<String>, ) -> bool855     pub fn initialize(
856         &mut self,
857         callbacks: BaseCallbacksDispatcher,
858         init_flags: Vec<String>,
859     ) -> bool {
860         // Init flags need to be converted from string to null terminated bytes
861         let converted: cxx::UniquePtr<ffi::InitFlags> = ffi::ConvertFlags(init_flags);
862         let flags = (*converted).GetFlagsPtr();
863 
864         if get_dispatchers().lock().unwrap().set::<BaseCb>(Arc::new(Mutex::new(callbacks))) {
865             panic!("Tried to set dispatcher for BaseCallbacks but it already existed");
866         }
867 
868         // Fill up callbacks struct to pass to init function (will be copied so
869         // no need to worry about ownership)
870         let mut callbacks = Box::new(bindings::bt_callbacks_t {
871             size: 16 * 8,
872             adapter_state_changed_cb: Some(adapter_state_cb),
873             adapter_properties_cb: Some(adapter_properties_cb),
874             remote_device_properties_cb: Some(remote_device_properties_cb),
875             device_found_cb: Some(device_found_cb),
876             discovery_state_changed_cb: Some(discovery_state_cb),
877             pin_request_cb: Some(pin_request_cb),
878             ssp_request_cb: Some(ssp_request_cb),
879             bond_state_changed_cb: Some(bond_state_cb),
880             address_consolidate_cb: Some(address_consolidate_cb),
881             le_address_associate_cb: Some(le_address_associate_cb),
882             acl_state_changed_cb: Some(acl_state_cb),
883             thread_evt_cb: None,
884             dut_mode_recv_cb: None,
885             le_test_mode_cb: None,
886             energy_info_cb: None,
887             link_quality_report_cb: None,
888             generate_local_oob_data_cb: None,
889             switch_buffer_size_cb: None,
890             switch_codec_cb: None,
891         });
892 
893         let rawcb: *mut bindings::bt_callbacks_t = &mut *callbacks;
894 
895         let (guest_mode, is_common_criteria_mode, config_compare_result, is_atv) =
896             (false, false, 0, false);
897 
898         let init = ccall!(
899             self,
900             init,
901             rawcb,
902             guest_mode,
903             is_common_criteria_mode,
904             config_compare_result,
905             flags,
906             is_atv,
907             std::ptr::null()
908         );
909 
910         self.is_init = init == 0;
911         self.callbacks = Some(callbacks);
912 
913         return self.is_init;
914     }
915 
cleanup(&self)916     pub fn cleanup(&self) {
917         ccall!(self, cleanup)
918     }
919 
enable(&self) -> i32920     pub fn enable(&self) -> i32 {
921         ccall!(self, enable)
922     }
923 
disable(&self) -> i32924     pub fn disable(&self) -> i32 {
925         ccall!(self, disable)
926     }
927 
get_adapter_properties(&self) -> i32928     pub fn get_adapter_properties(&self) -> i32 {
929         ccall!(self, get_adapter_properties)
930     }
931 
get_adapter_property(&self, prop: BtPropertyType) -> i32932     pub fn get_adapter_property(&self, prop: BtPropertyType) -> i32 {
933         let converted_type = bindings::bt_property_type_t::from(prop);
934         ccall!(self, get_adapter_property, converted_type)
935     }
936 
set_adapter_property(&self, prop: BluetoothProperty) -> i32937     pub fn set_adapter_property(&self, prop: BluetoothProperty) -> i32 {
938         let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
939         ccall!(self, set_adapter_property, &prop_pair.1)
940     }
941 
get_remote_device_properties(&self, addr: &mut RawAddress) -> i32942     pub fn get_remote_device_properties(&self, addr: &mut RawAddress) -> i32 {
943         let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
944         ccall!(self, get_remote_device_properties, ffi_addr)
945     }
946 
get_remote_device_property( &self, addr: &mut RawAddress, prop_type: BtPropertyType, ) -> i32947     pub fn get_remote_device_property(
948         &self,
949         addr: &mut RawAddress,
950         prop_type: BtPropertyType,
951     ) -> i32 {
952         let converted_type = bindings::bt_property_type_t::from(prop_type);
953         let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
954         ccall!(self, get_remote_device_property, ffi_addr, converted_type)
955     }
956 
set_remote_device_property( &self, addr: &mut RawAddress, prop: BluetoothProperty, ) -> i32957     pub fn set_remote_device_property(
958         &self,
959         addr: &mut RawAddress,
960         prop: BluetoothProperty,
961     ) -> i32 {
962         let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
963         let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
964         ccall!(self, set_remote_device_property, ffi_addr, &prop_pair.1)
965     }
966 
get_remote_services(&self, addr: &mut RawAddress, transport: BtTransport) -> i32967     pub fn get_remote_services(&self, addr: &mut RawAddress, transport: BtTransport) -> i32 {
968         let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
969         ccall!(self, get_remote_services, ffi_addr, transport.to_i32().unwrap())
970     }
971 
start_discovery(&self) -> i32972     pub fn start_discovery(&self) -> i32 {
973         ccall!(self, start_discovery)
974     }
975 
cancel_discovery(&self) -> i32976     pub fn cancel_discovery(&self) -> i32 {
977         ccall!(self, cancel_discovery)
978     }
979 
create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32980     pub fn create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32 {
981         let ctransport: i32 = transport.into();
982         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
983         ccall!(self, create_bond, ffi_addr, ctransport)
984     }
985 
remove_bond(&self, addr: &RawAddress) -> i32986     pub fn remove_bond(&self, addr: &RawAddress) -> i32 {
987         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
988         ccall!(self, remove_bond, ffi_addr)
989     }
990 
cancel_bond(&self, addr: &RawAddress) -> i32991     pub fn cancel_bond(&self, addr: &RawAddress) -> i32 {
992         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
993         ccall!(self, cancel_bond, ffi_addr)
994     }
995 
get_connection_state(&self, addr: &RawAddress) -> u32996     pub fn get_connection_state(&self, addr: &RawAddress) -> u32 {
997         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
998         ccall!(self, get_connection_state, ffi_addr).to_u32().unwrap()
999     }
1000 
pin_reply( &self, addr: &RawAddress, accept: u8, pin_len: u8, pin_code: &mut BtPinCode, ) -> i321001     pub fn pin_reply(
1002         &self,
1003         addr: &RawAddress,
1004         accept: u8,
1005         pin_len: u8,
1006         pin_code: &mut BtPinCode,
1007     ) -> i32 {
1008         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
1009         ccall!(self, pin_reply, ffi_addr, accept, pin_len, pin_code)
1010     }
1011 
ssp_reply( &self, addr: &RawAddress, variant: BtSspVariant, accept: u8, passkey: u32, ) -> i321012     pub fn ssp_reply(
1013         &self,
1014         addr: &RawAddress,
1015         variant: BtSspVariant,
1016         accept: u8,
1017         passkey: u32,
1018     ) -> i32 {
1019         let cvariant = bindings::bt_ssp_variant_t::from(variant);
1020         let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
1021         ccall!(self, ssp_reply, ffi_addr, cvariant, accept, passkey)
1022     }
1023 
clear_event_filter(&self) -> i321024     pub fn clear_event_filter(&self) -> i32 {
1025         ccall!(self, clear_event_filter)
1026     }
1027 
get_profile_interface( &self, profile: SupportedProfiles, ) -> *const std::os::raw::c_void1028     pub(crate) fn get_profile_interface(
1029         &self,
1030         profile: SupportedProfiles,
1031     ) -> *const std::os::raw::c_void {
1032         let cprofile = Vec::<u8>::from(profile);
1033         ccall!(
1034             self,
1035             get_profile_interface,
1036             cprofile.as_slice().as_ptr() as *const std::os::raw::c_char
1037         )
1038     }
1039 
as_raw_ptr(&self) -> *const u81040     pub(crate) fn as_raw_ptr(&self) -> *const u8 {
1041         self.internal.raw as *const u8
1042     }
1043 }
1044 
get_btinterface() -> Option<BluetoothInterface>1045 pub fn get_btinterface() -> Option<BluetoothInterface> {
1046     let mut ret: Option<BluetoothInterface> = None;
1047     let mut ifptr: *const bindings::bt_interface_t = std::ptr::null();
1048 
1049     unsafe {
1050         if bindings::hal_util_load_bt_library(&mut ifptr) == 0 {
1051             ret = Some(BluetoothInterface {
1052                 internal: RawInterfaceWrapper { raw: ifptr },
1053                 is_init: false,
1054                 callbacks: None,
1055             });
1056         }
1057     }
1058 
1059     ret
1060 }
1061 
1062 // Turns C-array T[] to Vec<U>.
ptr_to_vec<T: Copy, U: From<T>>(start: *const T, length: usize) -> Vec<U>1063 pub(crate) fn ptr_to_vec<T: Copy, U: From<T>>(start: *const T, length: usize) -> Vec<U> {
1064     unsafe { (0..length).map(|i| U::from(*start.offset(i as isize))).collect::<Vec<U>>() }
1065 }
1066 
1067 #[cfg(test)]
1068 mod tests {
1069     use super::*;
1070     use std::mem;
1071 
1072     #[test]
test_addr_size()1073     fn test_addr_size() {
1074         assert_eq!(mem::size_of::<RawAddress>(), mem::size_of::<FfiAddress>());
1075     }
1076 
1077     #[test]
test_offset()1078     fn test_offset() {
1079         let r = RawAddress { val: [1, 2, 3, 4, 5, 6] };
1080         let f = FfiAddress { address: [1, 2, 3, 4, 5, 6] };
1081         assert_eq!(
1082             &f as *const _ as usize - &f.address as *const _ as usize,
1083             &r as *const _ as usize - &r.val as *const _ as usize
1084         );
1085     }
1086 
1087     #[test]
test_alignment()1088     fn test_alignment() {
1089         assert_eq!(std::mem::align_of::<RawAddress>(), std::mem::align_of::<FfiAddress>());
1090     }
1091 
make_bdname_from_slice(slice: &[u8]) -> bindings::bt_bdname_t1092     fn make_bdname_from_slice(slice: &[u8]) -> bindings::bt_bdname_t {
1093         // Length of slice must be less than bd_name max
1094         assert!(slice.len() <= 249);
1095 
1096         let mut bdname = bindings::bt_bdname_t { name: [128; 249] };
1097 
1098         for (i, v) in slice.iter().enumerate() {
1099             bdname.name[i] = v.clone();
1100         }
1101 
1102         bdname
1103     }
1104 
1105     #[test]
test_bdname_conversions()1106     fn test_bdname_conversions() {
1107         let hello_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79, 0]);
1108         assert_eq!("HELLO".to_string(), String::from(hello_bdname));
1109 
1110         let empty_bdname = make_bdname_from_slice(&[0]);
1111         assert_eq!("".to_string(), String::from(empty_bdname));
1112 
1113         let no_nullterm_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79]);
1114         assert_eq!("".to_string(), String::from(no_nullterm_bdname));
1115 
1116         let invalid_bdname = make_bdname_from_slice(&[128; 249]);
1117         assert_eq!("".to_string(), String::from(invalid_bdname));
1118     }
1119 
1120     #[test]
test_ptr_to_vec()1121     fn test_ptr_to_vec() {
1122         let arr: [i32; 3] = [1, 2, 3];
1123         let vec: Vec<i32> = ptr_to_vec(arr.as_ptr(), arr.len());
1124         let expected: Vec<i32> = vec![1, 2, 3];
1125         assert_eq!(expected, vec);
1126     }
1127 
1128     #[test]
test_property_with_string_conversions()1129     fn test_property_with_string_conversions() {
1130         {
1131             let bdname = BluetoothProperty::BdName("FooBar".into());
1132             let prop_pair: (Box<[u8]>, bindings::bt_property_t) = bdname.into();
1133             let converted: BluetoothProperty = prop_pair.1.into();
1134             assert!(match converted {
1135                 BluetoothProperty::BdName(name) => "FooBar".to_string() == name,
1136                 _ => false,
1137             });
1138         }
1139 
1140         {
1141             let orig_record = BtServiceRecord {
1142                 uuid: Uuid { uu: [0; 16] },
1143                 channel: 3,
1144                 name: "FooBar".to_string(),
1145             };
1146             let service_record = BluetoothProperty::ServiceRecord(orig_record.clone());
1147             let prop_pair: (Box<[u8]>, bindings::bt_property_t) = service_record.into();
1148             let converted: BluetoothProperty = prop_pair.1.into();
1149             assert!(match converted {
1150                 BluetoothProperty::ServiceRecord(sr) => {
1151                     sr.uuid == orig_record.uuid
1152                         && sr.channel == orig_record.channel
1153                         && sr.name == orig_record.name
1154                 }
1155                 _ => false,
1156             });
1157         }
1158 
1159         {
1160             let rfname = BluetoothProperty::RemoteFriendlyName("FooBizz".into());
1161             let prop_pair: (Box<[u8]>, bindings::bt_property_t) = rfname.into();
1162             let converted: BluetoothProperty = prop_pair.1.into();
1163             assert!(match converted {
1164                 BluetoothProperty::RemoteFriendlyName(name) => "FooBizz".to_string() == name,
1165                 _ => false,
1166             });
1167         }
1168     }
1169 }
1170