1 //! Loads info from the controller at startup
2 
3 use crate::{Address, CommandSender};
4 use bt_packets::hci::{
5     Enable, ErrorCode, LeMaximumDataLength, LeReadBufferSizeV1Builder, LeReadBufferSizeV2Builder,
6     LeReadConnectListSizeBuilder, LeReadLocalSupportedFeaturesBuilder,
7     LeReadMaximumAdvertisingDataLengthBuilder, LeReadMaximumDataLengthBuilder,
8     LeReadNumberOfSupportedAdvertisingSetsBuilder, LeReadPeriodicAdvertiserListSizeBuilder,
9     LeReadResolvingListSizeBuilder, LeReadSuggestedDefaultDataLengthBuilder,
10     LeReadSupportedStatesBuilder, LeSetEventMaskBuilder, LocalVersionInformation, OpCode,
11     OpCodeIndex, ReadBdAddrBuilder, ReadBufferSizeBuilder, ReadLocalExtendedFeaturesBuilder,
12     ReadLocalNameBuilder, ReadLocalSupportedCommandsBuilder, ReadLocalVersionInformationBuilder,
13     SetEventMaskBuilder, WriteLeHostSupportBuilder, WriteSimplePairingModeBuilder,
14 };
15 use gddi::{module, provides, Stoppable};
16 use num_traits::ToPrimitive;
17 use std::convert::TryFrom;
18 use std::sync::Arc;
19 
20 module! {
21     controller_module,
22     providers {
23         Arc<ControllerExports> => provide_controller,
24     },
25 }
26 
27 macro_rules! assert_success {
28     ($hci:ident.send($builder:expr)) => {{
29         let response = $hci.send($builder).await;
30         assert!(response.get_status() == ErrorCode::Success);
31 
32         response
33     }};
34 }
35 
36 #[provides]
provide_controller(mut hci: CommandSender) -> Arc<ControllerExports>37 async fn provide_controller(mut hci: CommandSender) -> Arc<ControllerExports> {
38     assert_success!(hci.send(LeSetEventMaskBuilder { le_event_mask: 0x0000000000021e7f }));
39     assert_success!(hci.send(SetEventMaskBuilder { event_mask: 0x3dbfffffffffffff }));
40     assert_success!(
41         hci.send(WriteSimplePairingModeBuilder { simple_pairing_mode: Enable::Enabled })
42     );
43     assert_success!(hci.send(WriteLeHostSupportBuilder {
44         le_supported_host: Enable::Enabled,
45         simultaneous_le_host: Enable::Enabled
46     }));
47 
48     let name = null_terminated_to_string(
49         assert_success!(hci.send(ReadLocalNameBuilder {})).get_local_name(),
50     );
51 
52     let version_info = assert_success!(hci.send(ReadLocalVersionInformationBuilder {}))
53         .get_local_version_information()
54         .clone();
55 
56     let commands = SupportedCommands {
57         supported: *assert_success!(hci.send(ReadLocalSupportedCommandsBuilder {}))
58             .get_supported_commands(),
59     };
60 
61     let features = read_features(&mut hci).await;
62 
63     let buffer_size = assert_success!(hci.send(ReadBufferSizeBuilder {}));
64     let acl_buffer_length = buffer_size.get_acl_data_packet_length();
65     let mut acl_buffers = buffer_size.get_total_num_acl_data_packets();
66 
67     let (mut le_buffer_length, mut le_buffers, iso_buffer_length, iso_buffers) =
68         if commands.is_supported(OpCode::LeReadBufferSizeV2) {
69             let response = assert_success!(hci.send(LeReadBufferSizeV2Builder {}));
70             (
71                 response.get_le_buffer_size().le_data_packet_length,
72                 response.get_le_buffer_size().total_num_le_packets,
73                 response.get_iso_buffer_size().le_data_packet_length,
74                 response.get_iso_buffer_size().total_num_le_packets,
75             )
76         } else {
77             let response = assert_success!(hci.send(LeReadBufferSizeV1Builder {}));
78             (
79                 response.get_le_buffer_size().le_data_packet_length,
80                 response.get_le_buffer_size().total_num_le_packets,
81                 0,
82                 0,
83             )
84         };
85 
86     // If the controller reports zero LE buffers, the ACL buffers are shared between classic & LE
87     if le_buffers == 0 {
88         le_buffers = (acl_buffers / 2) as u8;
89         acl_buffers -= le_buffers as u16;
90         le_buffer_length = acl_buffer_length;
91     }
92 
93     let le_features = SupportedLeFeatures::new(
94         assert_success!(hci.send(LeReadLocalSupportedFeaturesBuilder {})).get_le_features(),
95     );
96     let le_supported_states =
97         assert_success!(hci.send(LeReadSupportedStatesBuilder {})).get_le_states();
98     let le_connect_list_size =
99         assert_success!(hci.send(LeReadConnectListSizeBuilder {})).get_connect_list_size();
100     let le_resolving_list_size =
101         assert_success!(hci.send(LeReadResolvingListSizeBuilder {})).get_resolving_list_size();
102 
103     let le_max_data_length = if commands.is_supported(OpCode::LeReadMaximumDataLength) {
104         assert_success!(hci.send(LeReadMaximumDataLengthBuilder {}))
105             .get_le_maximum_data_length()
106             .clone()
107     } else {
108         LeMaximumDataLength {
109             supported_max_rx_octets: 0,
110             supported_max_rx_time: 0,
111             supported_max_tx_octets: 0,
112             supported_max_tx_time: 0,
113         }
114     };
115 
116     let le_suggested_default_data_length =
117         if commands.is_supported(OpCode::LeReadSuggestedDefaultDataLength) {
118             assert_success!(hci.send(LeReadSuggestedDefaultDataLengthBuilder {})).get_tx_octets()
119         } else {
120             0
121         };
122 
123     let le_max_advertising_data_length =
124         if commands.is_supported(OpCode::LeReadMaximumAdvertisingDataLength) {
125             assert_success!(hci.send(LeReadMaximumAdvertisingDataLengthBuilder {}))
126                 .get_maximum_advertising_data_length()
127         } else {
128             31
129         };
130     let le_supported_advertising_sets =
131         if commands.is_supported(OpCode::LeReadNumberOfSupportedAdvertisingSets) {
132             assert_success!(hci.send(LeReadNumberOfSupportedAdvertisingSetsBuilder {}))
133                 .get_number_supported_advertising_sets()
134         } else {
135             1
136         };
137     let le_periodic_advertiser_list_size =
138         if commands.is_supported(OpCode::LeReadPeriodicAdvertisingListSize) {
139             assert_success!(hci.send(LeReadPeriodicAdvertiserListSizeBuilder {}))
140                 .get_periodic_advertiser_list_size()
141         } else {
142             0
143         };
144 
145     let address = assert_success!(hci.send(ReadBdAddrBuilder {})).get_bd_addr();
146 
147     Arc::new(ControllerExports {
148         name,
149         address,
150         version_info,
151         commands,
152         features,
153         acl_buffer_length,
154         acl_buffers,
155         sco_buffer_length: buffer_size.get_synchronous_data_packet_length(),
156         sco_buffers: buffer_size.get_total_num_synchronous_data_packets(),
157         le_buffer_length,
158         le_buffers,
159         iso_buffer_length,
160         iso_buffers,
161         le_features,
162         le_supported_states,
163         le_connect_list_size,
164         le_resolving_list_size,
165         le_max_data_length,
166         le_suggested_default_data_length,
167         le_max_advertising_data_length,
168         le_supported_advertising_sets,
169         le_periodic_advertiser_list_size,
170     })
171 }
172 
read_features(hci: &mut CommandSender) -> SupportedFeatures173 async fn read_features(hci: &mut CommandSender) -> SupportedFeatures {
174     let mut features = Vec::new();
175     let mut page_number: u8 = 0;
176     let mut max_page_number: u8 = 1;
177     while page_number < max_page_number {
178         let response = assert_success!(hci.send(ReadLocalExtendedFeaturesBuilder { page_number }));
179         max_page_number = response.get_maximum_page_number();
180         features.push(response.get_extended_lmp_features());
181         page_number += 1;
182     }
183 
184     SupportedFeatures::new(features)
185 }
186 
187 /// Controller interface
188 #[derive(Clone, Stoppable)]
189 #[allow(missing_docs)]
190 pub struct ControllerExports {
191     pub name: String,
192     pub address: Address,
193     pub version_info: LocalVersionInformation,
194     pub commands: SupportedCommands,
195     pub features: SupportedFeatures,
196     pub acl_buffer_length: u16,
197     pub acl_buffers: u16,
198     pub sco_buffer_length: u8,
199     pub sco_buffers: u16,
200     pub le_buffer_length: u16,
201     pub le_buffers: u8,
202     pub iso_buffer_length: u16,
203     pub iso_buffers: u8,
204     pub le_features: SupportedLeFeatures,
205     pub le_supported_states: u64,
206     pub le_connect_list_size: u8,
207     pub le_resolving_list_size: u8,
208     pub le_max_data_length: LeMaximumDataLength,
209     pub le_suggested_default_data_length: u16,
210     pub le_max_advertising_data_length: u16,
211     pub le_supported_advertising_sets: u8,
212     pub le_periodic_advertiser_list_size: u8,
213 }
214 
215 /// Convenience struct for checking what commands are supported
216 #[derive(Clone)]
217 pub struct SupportedCommands {
218     supported: [u8; 64],
219 }
220 
221 impl SupportedCommands {
222     /// Check whether a given opcode is supported by the controller
is_supported(&self, opcode: OpCode) -> bool223     pub fn is_supported(&self, opcode: OpCode) -> bool {
224         let converted = OpCodeIndex::try_from(opcode);
225         if converted.is_err() {
226             return false;
227         }
228 
229         let index = converted.unwrap().to_usize().unwrap();
230 
231         // OpCodeIndex is encoded as octet * 10 + bit for readability
232         self.supported[index / 10] & (1 << (index % 10)) == 1
233     }
234 }
235 
236 macro_rules! supported_features {
237     ($($id:ident => $page:literal : $bit:literal),*) => {
238         /// Convenience struct for checking what features are supported
239         #[derive(Clone)]
240         #[allow(missing_docs)]
241         pub struct SupportedFeatures {
242             $(pub $id: bool,)*
243         }
244 
245         impl SupportedFeatures {
246             fn new(supported: Vec<u64>) -> Self {
247                 Self {
248                     $($id: *supported.get($page).unwrap_or(&0) & (1 << $bit) != 0,)*
249                 }
250             }
251         }
252     }
253 }
254 
255 supported_features! {
256     three_slot_packets => 0:0,
257     five_slot_packets => 0:1,
258     role_switch => 0:5,
259     hold_mode => 0:6,
260     sniff_mode => 0:7,
261     park_mode => 0:8,
262     sco => 0:11,
263     hv2_packets => 0:12,
264     hv3_packets => 0:13,
265     classic_2m_phy => 0:25,
266     classic_3m_phy => 0:26,
267     interlaced_inquiry_scan => 0:28,
268     rssi_with_inquiry_results => 0:30,
269     ev3_packets => 0:31,
270     ev4_packets => 0:32,
271     ev5_packets => 0:33,
272     ble => 0:38,
273     three_slot_edr_packets => 0:39,
274     five_slot_edr_packets => 0:40,
275     sniff_subrating => 0:41,
276     encryption_pause => 0:42,
277     esco_2m_phy => 0:45,
278     esco_3m_phy => 0:46,
279     three_slot_esco_edr_packets => 0:47,
280     extended_inquiry_response => 0:48,
281     simultaneous_le_bredr => 0:49,
282     simple_pairing => 0:51,
283     non_flushable_pb => 0:54,
284     secure_connections => 2:8
285 }
286 
287 macro_rules! supported_le_features {
288     ($($id:ident => $bit:literal),*) => {
289         /// Convenience struct for checking what features are supported
290         #[derive(Clone)]
291         #[allow(missing_docs)]
292         pub struct SupportedLeFeatures {
293             $(pub $id: bool,)*
294         }
295 
296         impl SupportedLeFeatures {
297             fn new(supported: u64) -> Self {
298                 Self {
299                     $($id: supported & (1 << $bit) != 0,)*
300                 }
301             }
302         }
303     }
304 }
305 
306 supported_le_features! {
307     connection_parameter_request => 1,
308     connection_parameters_request => 2,
309     peripheral_initiated_feature_exchange => 3,
310     packet_extension => 5,
311     privacy => 6,
312     ble_2m_phy => 8,
313     ble_coded_phy => 11,
314     extended_advertising => 12,
315     periodic_advertising => 13,
316     periodic_advertising_sync_transfer_sender => 24,
317     periodic_advertising_sync_transfer_recipient => 25,
318     connected_iso_stream_central => 28,
319     connected_iso_stream_peripheral => 29,
320     iso_broadcaster => 30,
321     synchronized_receiver => 31
322 }
323 
324 /// Convert a null terminated C string into a Rust String
null_terminated_to_string(slice: &[u8]) -> String325 pub fn null_terminated_to_string(slice: &[u8]) -> String {
326     let temp = std::str::from_utf8(slice).unwrap();
327     temp[0..temp.find('\0').unwrap()].to_string()
328 }
329