1 ///! Rule group for tracking connection related issues.
2 use chrono::NaiveDateTime;
3 use std::collections::{HashMap, HashSet, VecDeque};
4 use std::convert::Into;
5 use std::io::Write;
6 use std::slice::Iter;
7
8 use crate::engine::{Rule, RuleGroup, Signal};
9 use crate::parser::{Packet, PacketChild};
10 use hcidoc_packets::hci::{
11 Acl, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, DisconnectReason, Enable,
12 ErrorCode, EventChild, InitiatorFilterPolicy, LeMetaEventChild, NumberOfCompletedPackets,
13 OpCode,
14 };
15
16 enum ConnectionSignal {
17 LinkKeyMismatch, // Peer forgets the link key or it mismatches ours. (b/284802375)
18 LongTermKeyMismatch, // Like LinkKeyMismatch but for LE cases. (b/303600602)
19 NocpDisconnect, // Peer is disconnected when NOCP packet isn't yet received. (b/249295604)
20 NocpTimeout, // Host doesn't receive NOCP packet 5 seconds after ACL is sent. (b/249295604)
21 ApteDisconnect, // Host doesn't receive a packet with valid MIC for a while. (b/299850738)
22 RemoteFeatureNoReply, // Host doesn't receive a response for a remote feature request. (b/300851411)
23 RemoteFeatureError, // Controller replies error for remote feature request. (b/292116133)
24 SecurityMode3, // Peer uses the unsupported legacy security mode 3. (b/260625799)
25 }
26
27 impl Into<&'static str> for ConnectionSignal {
into(self) -> &'static str28 fn into(self) -> &'static str {
29 match self {
30 ConnectionSignal::LinkKeyMismatch => "LinkKeyMismatch",
31 ConnectionSignal::LongTermKeyMismatch => "LongTermKeyMismatch",
32 ConnectionSignal::NocpDisconnect => "Nocp",
33 ConnectionSignal::NocpTimeout => "Nocp",
34 ConnectionSignal::ApteDisconnect => "AuthenticatedPayloadTimeoutExpired",
35 ConnectionSignal::RemoteFeatureError => "RemoteFeatureError",
36 ConnectionSignal::RemoteFeatureNoReply => "RemoteFeatureNoReply",
37 ConnectionSignal::SecurityMode3 => "UnsupportedSecurityMode3",
38 }
39 }
40 }
41
42 /// Valid values are in the range 0x0000-0x0EFF.
43 pub type ConnectionHandle = u16;
44
45 /// When we attempt to create a sco connection on an unknown handle, use this address as
46 /// a placeholder.
47 pub const UNKNOWN_SCO_ADDRESS: [u8; 6] = [0xdeu8, 0xad, 0xbe, 0xef, 0x00, 0x00];
48
49 /// The tolerance duration of not receiving an expected reply. If 5s elapsed and timeout occurs,
50 /// we blame the pending event for causing timeout. This is used to detect NOCP and others.
51 pub const TIMEOUT_TOLERANCE_TIME_MS: i64 = 5000;
52
53 pub(crate) struct NocpData {
54 /// Number of in-flight packets without a corresponding NOCP.
55 pub inflight_acl_ts: VecDeque<NaiveDateTime>,
56 }
57
58 impl NocpData {
new() -> Self59 fn new() -> Self {
60 Self { inflight_acl_ts: VecDeque::new() }
61 }
62 }
63
64 #[derive(Debug, Eq, PartialEq, Hash)]
65 enum PendingRemoteFeature {
66 Supported,
67 Extended,
68 Le,
69 }
70
71 impl PendingRemoteFeature {
iterate_all() -> Iter<'static, PendingRemoteFeature>72 fn iterate_all() -> Iter<'static, PendingRemoteFeature> {
73 static FEATS: [PendingRemoteFeature; 3] = [
74 PendingRemoteFeature::Supported,
75 PendingRemoteFeature::Extended,
76 PendingRemoteFeature::Le,
77 ];
78 FEATS.iter()
79 }
80 }
81
82 /// Keeps track of connections and identifies odd disconnections.
83 struct OddDisconnectionsRule {
84 /// Handles that had successful complete connections. The value has the timestamp of the
85 /// connection completion and the address of the device.
86 active_handles: HashMap<ConnectionHandle, (NaiveDateTime, Address)>,
87
88 connection_attempt: HashMap<Address, Packet>,
89 last_connection_attempt: Option<Address>,
90
91 le_connection_attempt: HashMap<Address, Packet>,
92 last_le_connection_attempt: Option<Address>,
93 last_le_connection_filter_policy: Option<InitiatorFilterPolicy>,
94
95 sco_connection_attempt: HashMap<Address, Packet>,
96 last_sco_connection_attempt: Option<Address>,
97
98 accept_list: HashSet<Address>,
99
100 /// Keep track of some number of |Number of Completed Packets| and filter to
101 /// identify bursts.
102 nocp_by_handle: HashMap<ConnectionHandle, NocpData>,
103
104 /// Number of |Authenticated Payload Timeout Expired| events hapened.
105 apte_by_handle: HashMap<ConnectionHandle, u32>,
106
107 /// Pending handles for read remote features.
108 pending_supported_feat: HashMap<ConnectionHandle, NaiveDateTime>,
109 pending_extended_feat: HashMap<ConnectionHandle, NaiveDateTime>,
110 pending_le_feat: HashMap<ConnectionHandle, NaiveDateTime>,
111 last_feat_handle: HashMap<PendingRemoteFeature, ConnectionHandle>,
112
113 /// When powering off, the controller might or might not reply disconnection request. Therefore
114 /// make this a special case.
115 pending_disconnect_due_to_host_power_off: HashSet<ConnectionHandle>,
116
117 /// Pre-defined signals discovered in the logs.
118 signals: Vec<Signal>,
119
120 /// Interesting occurrences surfaced by this rule.
121 reportable: Vec<(NaiveDateTime, String)>,
122 }
123
124 impl OddDisconnectionsRule {
new() -> Self125 pub fn new() -> Self {
126 OddDisconnectionsRule {
127 active_handles: HashMap::new(),
128 connection_attempt: HashMap::new(),
129 last_connection_attempt: None,
130 le_connection_attempt: HashMap::new(),
131 last_le_connection_attempt: None,
132 last_le_connection_filter_policy: None,
133 sco_connection_attempt: HashMap::new(),
134 last_sco_connection_attempt: None,
135 accept_list: HashSet::new(),
136 nocp_by_handle: HashMap::new(),
137 apte_by_handle: HashMap::new(),
138 pending_supported_feat: HashMap::new(),
139 pending_extended_feat: HashMap::new(),
140 pending_le_feat: HashMap::new(),
141 last_feat_handle: HashMap::new(),
142 pending_disconnect_due_to_host_power_off: HashSet::new(),
143 signals: vec![],
144 reportable: vec![],
145 }
146 }
147
process_classic_connection(&mut self, address: Address, packet: &Packet)148 fn process_classic_connection(&mut self, address: Address, packet: &Packet) {
149 self.last_connection_attempt = Some(address);
150 if let Some(p) = self.connection_attempt.insert(address, packet.clone()) {
151 self.reportable.push((
152 p.ts,
153 format!("Dangling connection attempt at {:?} replaced with {:?}", p, packet),
154 ));
155 }
156 }
157
convert_sco_handle_to_address(&self, handle: ConnectionHandle) -> Address158 fn convert_sco_handle_to_address(&self, handle: ConnectionHandle) -> Address {
159 match self.active_handles.get(&handle).as_ref() {
160 Some((_ts, address)) => address.clone(),
161 None => Address::from(&UNKNOWN_SCO_ADDRESS),
162 }
163 }
164
process_sync_connection(&mut self, address: Address, packet: &Packet)165 fn process_sync_connection(&mut self, address: Address, packet: &Packet) {
166 self.last_sco_connection_attempt = Some(address);
167 if let Some(p) = self.sco_connection_attempt.insert(address, packet.clone()) {
168 self.reportable.push((
169 p.ts,
170 format!("Dangling sco connection attempt at {:?} replaced with {:?}", p, packet),
171 ));
172 }
173 }
174
process_le_create_connection( &mut self, address: Address, policy: InitiatorFilterPolicy, packet: &Packet, )175 fn process_le_create_connection(
176 &mut self,
177 address: Address,
178 policy: InitiatorFilterPolicy,
179 packet: &Packet,
180 ) {
181 self.last_le_connection_attempt = Some(address);
182 self.last_le_connection_filter_policy = Some(policy);
183 if let Some(p) = self.le_connection_attempt.insert(address, packet.clone()) {
184 self.reportable.push((
185 p.ts,
186 format!("Dangling LE connection attempt at {:?} replaced with {:?}", p, packet),
187 ));
188 }
189 }
190
process_add_accept_list(&mut self, address: Address, _packet: &Packet)191 fn process_add_accept_list(&mut self, address: Address, _packet: &Packet) {
192 self.accept_list.insert(address);
193 }
194
process_remove_accept_list(&mut self, address: Address, _packet: &Packet)195 fn process_remove_accept_list(&mut self, address: Address, _packet: &Packet) {
196 self.accept_list.remove(&address);
197 }
198
process_clear_accept_list(&mut self, _packet: &Packet)199 fn process_clear_accept_list(&mut self, _packet: &Packet) {
200 self.accept_list.clear();
201 }
202
get_feature_pending_map( &mut self, pending_type: &PendingRemoteFeature, ) -> &mut HashMap<ConnectionHandle, NaiveDateTime>203 fn get_feature_pending_map(
204 &mut self,
205 pending_type: &PendingRemoteFeature,
206 ) -> &mut HashMap<ConnectionHandle, NaiveDateTime> {
207 match pending_type {
208 PendingRemoteFeature::Supported => &mut self.pending_supported_feat,
209 PendingRemoteFeature::Extended => &mut self.pending_extended_feat,
210 PendingRemoteFeature::Le => &mut self.pending_le_feat,
211 }
212 }
213
process_remote_feat_cmd( &mut self, feat_type: PendingRemoteFeature, handle: &ConnectionHandle, packet: &Packet, )214 fn process_remote_feat_cmd(
215 &mut self,
216 feat_type: PendingRemoteFeature,
217 handle: &ConnectionHandle,
218 packet: &Packet,
219 ) {
220 self.get_feature_pending_map(&feat_type).insert(*handle, packet.ts);
221 self.last_feat_handle.insert(feat_type, *handle);
222 }
223
process_disconnect_cmd( &mut self, reason: DisconnectReason, handle: ConnectionHandle, packet: &Packet, )224 fn process_disconnect_cmd(
225 &mut self,
226 reason: DisconnectReason,
227 handle: ConnectionHandle,
228 packet: &Packet,
229 ) {
230 // If reason is power off, the host might not wait for connection complete event
231 if reason == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff {
232 self.process_disconn_complete_ev(handle, packet);
233 self.pending_disconnect_due_to_host_power_off.insert(handle);
234 }
235 }
236
process_command_status(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet)237 fn process_command_status(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet) {
238 match opcode {
239 OpCode::CreateConnection
240 | OpCode::AcceptConnectionRequest
241 | OpCode::SetupSynchronousConnection
242 | OpCode::AcceptSynchronousConnection
243 | OpCode::EnhancedSetupSynchronousConnection
244 | OpCode::EnhancedAcceptSynchronousConnection
245 | OpCode::LeCreateConnection
246 | OpCode::LeExtendedCreateConnection => {
247 self.process_command_status_conn(status, opcode, packet);
248 }
249
250 OpCode::ReadRemoteSupportedFeatures
251 | OpCode::ReadRemoteExtendedFeatures
252 | OpCode::LeReadRemoteFeatures => {
253 self.process_command_status_feat(status, opcode, packet);
254 }
255
256 _ => {}
257 }
258 }
259
process_command_status_conn(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet)260 fn process_command_status_conn(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet) {
261 // Clear last connection attempt since it was successful.
262 let last_address = match opcode {
263 OpCode::CreateConnection | OpCode::AcceptConnectionRequest => {
264 self.last_connection_attempt.take()
265 }
266
267 OpCode::SetupSynchronousConnection
268 | OpCode::AcceptSynchronousConnection
269 | OpCode::EnhancedSetupSynchronousConnection
270 | OpCode::EnhancedAcceptSynchronousConnection => {
271 self.last_sco_connection_attempt.take()
272 }
273
274 OpCode::LeCreateConnection | OpCode::LeExtendedCreateConnection => {
275 self.last_le_connection_attempt.take()
276 }
277
278 _ => return,
279 };
280
281 if let Some(address) = last_address {
282 if status != ErrorCode::Success {
283 self.reportable.push((
284 packet.ts,
285 format!("Failing command status on [{}]: {:?}", address, opcode),
286 ));
287
288 // Also remove the connection attempt.
289 match opcode {
290 OpCode::CreateConnection | OpCode::AcceptConnectionRequest => {
291 self.connection_attempt.remove(&address);
292 }
293
294 OpCode::SetupSynchronousConnection
295 | OpCode::AcceptSynchronousConnection
296 | OpCode::EnhancedSetupSynchronousConnection
297 | OpCode::EnhancedAcceptSynchronousConnection => {
298 self.sco_connection_attempt.remove(&address);
299 }
300
301 OpCode::LeCreateConnection | OpCode::LeExtendedCreateConnection => {
302 self.le_connection_attempt.remove(&address);
303 self.last_le_connection_filter_policy = None;
304 }
305
306 _ => (),
307 }
308 }
309 } else {
310 if status != ErrorCode::Success {
311 self.reportable.push((
312 packet.ts,
313 format!("Failing command status on unknown address: {:?}", opcode),
314 ));
315 }
316 }
317 }
318
process_command_status_feat(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet)319 fn process_command_status_feat(&mut self, status: ErrorCode, opcode: OpCode, packet: &Packet) {
320 let feat_type = match opcode {
321 OpCode::ReadRemoteSupportedFeatures => PendingRemoteFeature::Supported,
322 OpCode::ReadRemoteExtendedFeatures => PendingRemoteFeature::Extended,
323 OpCode::LeReadRemoteFeatures => PendingRemoteFeature::Le,
324 _ => return,
325 };
326
327 // If handle is not known, probably the request comes before btsnoop starts. In any case,
328 // the command complete event will still complain. So let's just return here.
329 let handle = match self.last_feat_handle.remove(&feat_type) {
330 Some(handle) => handle,
331 None => return,
332 };
333
334 // If failed, there won't be a following command complete event. So treat this as the
335 // command complete.
336 if status != ErrorCode::Success {
337 self.process_remote_feat_ev(feat_type, status, handle, packet);
338 }
339 }
340
process_conn_complete_ev( &mut self, status: ErrorCode, handle: ConnectionHandle, address: Address, packet: &Packet, )341 fn process_conn_complete_ev(
342 &mut self,
343 status: ErrorCode,
344 handle: ConnectionHandle,
345 address: Address,
346 packet: &Packet,
347 ) {
348 if let Some(_) = self.connection_attempt.remove(&address) {
349 if status == ErrorCode::Success {
350 self.active_handles.insert(handle, (packet.ts, address));
351 self.pending_disconnect_due_to_host_power_off.remove(&handle);
352 } else {
353 self.reportable.push((
354 packet.ts,
355 format!(
356 "ConnectionComplete error {:?} for addr {} (handle={})",
357 status, address, handle
358 ),
359 ));
360 }
361 } else {
362 self.reportable.push((
363 packet.ts,
364 format!(
365 "ConnectionComplete with status {:?} for unknown addr {} (handle={})",
366 status, address, handle
367 ),
368 ));
369 }
370 }
371
process_disconn_complete_ev(&mut self, handle: ConnectionHandle, packet: &Packet)372 fn process_disconn_complete_ev(&mut self, handle: ConnectionHandle, packet: &Packet) {
373 // If previously host send disconnect with power off reason, disconnection has been handled.
374 if self.pending_disconnect_due_to_host_power_off.remove(&handle) {
375 return;
376 }
377
378 self.active_handles.remove(&handle);
379
380 // Check if this is a NOCP type disconnection and flag it.
381 if let Some(nocp_data) = self.nocp_by_handle.get_mut(&handle) {
382 if let Some(acl_front_ts) = nocp_data.inflight_acl_ts.pop_front() {
383 let duration_since_acl = packet.ts.signed_duration_since(acl_front_ts);
384 if duration_since_acl.num_milliseconds() > TIMEOUT_TOLERANCE_TIME_MS {
385 self.signals.push(Signal {
386 index: packet.index,
387 ts: packet.ts,
388 tag: ConnectionSignal::NocpDisconnect.into(),
389 });
390
391 self.reportable.push((
392 packet.ts,
393 format!("DisconnectionComplete for handle({}) showed incomplete in-flight ACL at {}",
394 handle, acl_front_ts)));
395 }
396 }
397 }
398 // Remove nocp information for handles that were removed.
399 self.nocp_by_handle.remove(&handle);
400
401 // Check if auth payload timeout happened.
402 if let Some(apte_count) = self.apte_by_handle.remove(&handle) {
403 self.signals.push(Signal {
404 index: packet.index,
405 ts: packet.ts,
406 tag: ConnectionSignal::ApteDisconnect.into(),
407 });
408
409 self.reportable.push((
410 packet.ts,
411 format!("DisconnectionComplete with {} Authenticated Payload Timeout Expired (handle={})",
412 apte_count, handle))
413 );
414 }
415
416 // Check if remote feature request is pending
417 for feat_type in PendingRemoteFeature::iterate_all() {
418 if let Some(ts) = self.get_feature_pending_map(feat_type).remove(&handle) {
419 let elapsed_time_ms = packet.ts.signed_duration_since(ts).num_milliseconds();
420 if elapsed_time_ms > TIMEOUT_TOLERANCE_TIME_MS {
421 self.signals.push(Signal {
422 index: packet.index,
423 ts: packet.ts,
424 tag: ConnectionSignal::RemoteFeatureNoReply.into(),
425 });
426
427 self.reportable.push((
428 packet.ts,
429 format!(
430 "Handle {} doesn't respond to {:?} feature request at {}.",
431 handle,
432 feat_type,
433 ts.time()
434 ),
435 ));
436 }
437 }
438 }
439 }
440
process_sync_conn_complete_ev( &mut self, status: ErrorCode, handle: ConnectionHandle, address: Address, packet: &Packet, )441 fn process_sync_conn_complete_ev(
442 &mut self,
443 status: ErrorCode,
444 handle: ConnectionHandle,
445 address: Address,
446 packet: &Packet,
447 ) {
448 if let Some(_) = self.sco_connection_attempt.remove(&address) {
449 if status == ErrorCode::Success {
450 self.active_handles.insert(handle, (packet.ts, address));
451 self.pending_disconnect_due_to_host_power_off.remove(&handle);
452 } else {
453 self.reportable.push((
454 packet.ts,
455 format!(
456 "SynchronousConnectionComplete error {:?} for addr {} (handle={})",
457 status, address, handle
458 ),
459 ));
460 }
461 } else {
462 self.reportable.push((
463 packet.ts,
464 format!(
465 "SynchronousConnectionComplete with status {:?} for unknown addr {} (handle={})",
466 status,
467 address,
468 handle
469 ),
470 ));
471 }
472 }
473
process_le_conn_complete_ev( &mut self, status: ErrorCode, handle: ConnectionHandle, address: Address, packet: &Packet, )474 fn process_le_conn_complete_ev(
475 &mut self,
476 status: ErrorCode,
477 handle: ConnectionHandle,
478 address: Address,
479 packet: &Packet,
480 ) {
481 let use_accept_list = self
482 .last_le_connection_filter_policy
483 .map_or(false, |policy| policy == InitiatorFilterPolicy::UseFilterAcceptList);
484 let addr_to_remove =
485 if use_accept_list { hcidoc_packets::hci::EMPTY_ADDRESS } else { address };
486
487 if let Some(_) = self.le_connection_attempt.remove(&addr_to_remove) {
488 if status == ErrorCode::Success {
489 self.active_handles.insert(handle, (packet.ts, address));
490 self.pending_disconnect_due_to_host_power_off.remove(&handle);
491 } else {
492 let message = if use_accept_list {
493 format!("LeConnectionComplete error {:?} for accept list", status)
494 } else {
495 format!(
496 "LeConnectionComplete error {:?} for addr {} (handle={})",
497 status, address, handle
498 )
499 };
500 self.reportable.push((packet.ts, message));
501 }
502 } else {
503 self.reportable.push((
504 packet.ts,
505 format!(
506 "LeConnectionComplete with status {:?} for unknown addr {} (handle={})",
507 status, address, handle
508 ),
509 ));
510 }
511 }
512
process_acl_tx(&mut self, acl_tx: &Acl, packet: &Packet)513 fn process_acl_tx(&mut self, acl_tx: &Acl, packet: &Packet) {
514 let handle = acl_tx.get_handle();
515
516 // Insert empty Nocp data for handle if it doesn't exist.
517 if !self.nocp_by_handle.contains_key(&handle) {
518 self.nocp_by_handle.insert(handle, NocpData::new());
519 }
520
521 if let Some(nocp_data) = self.nocp_by_handle.get_mut(&handle) {
522 nocp_data.inflight_acl_ts.push_back(packet.ts);
523 }
524 }
525
process_nocp(&mut self, nocp: &NumberOfCompletedPackets, packet: &Packet)526 fn process_nocp(&mut self, nocp: &NumberOfCompletedPackets, packet: &Packet) {
527 let ts = &packet.ts;
528 for completed_packet in nocp.get_completed_packets() {
529 let handle = completed_packet.connection_handle;
530 let num = completed_packet.host_num_of_completed_packets;
531 if !self.nocp_by_handle.contains_key(&handle) {
532 self.nocp_by_handle.insert(handle, NocpData::new());
533 }
534
535 if let Some(nocp_data) = self.nocp_by_handle.get_mut(&handle) {
536 for _i in 0..num {
537 if let Some(acl_front_ts) = nocp_data.inflight_acl_ts.pop_front() {
538 let duration_since_acl = ts.signed_duration_since(acl_front_ts);
539 if duration_since_acl.num_milliseconds() > TIMEOUT_TOLERANCE_TIME_MS {
540 self.signals.push(Signal {
541 index: packet.index,
542 ts: packet.ts,
543 tag: ConnectionSignal::NocpTimeout.into(),
544 });
545 self.reportable.push((
546 packet.ts,
547 format!(
548 "Nocp sent {} ms after ACL on handle({}).",
549 duration_since_acl.num_milliseconds(),
550 handle
551 ),
552 ));
553 }
554 }
555 }
556 }
557 }
558 }
559
process_apte(&mut self, apte: &AuthenticatedPayloadTimeoutExpired, _packet: &Packet)560 fn process_apte(&mut self, apte: &AuthenticatedPayloadTimeoutExpired, _packet: &Packet) {
561 let handle = apte.get_connection_handle();
562 *self.apte_by_handle.entry(handle).or_insert(0) += 1;
563 }
564
process_remote_feat_ev( &mut self, feat_type: PendingRemoteFeature, status: ErrorCode, handle: ConnectionHandle, packet: &Packet, )565 fn process_remote_feat_ev(
566 &mut self,
567 feat_type: PendingRemoteFeature,
568 status: ErrorCode,
569 handle: ConnectionHandle,
570 packet: &Packet,
571 ) {
572 let feat_map = self.get_feature_pending_map(&feat_type);
573
574 if feat_map.remove(&handle) == None {
575 self.reportable.push((
576 packet.ts,
577 format!("Got remote {:?} for unknown handle {}", feat_type, handle),
578 ));
579 }
580
581 if status != ErrorCode::Success {
582 self.signals.push(Signal {
583 index: packet.index,
584 ts: packet.ts,
585 tag: ConnectionSignal::RemoteFeatureError.into(),
586 });
587
588 self.reportable.push((
589 packet.ts,
590 format!("Got {:?} for remote {:?} feature, handle {}", status, feat_type, handle),
591 ));
592 }
593 }
594
process_reset(&mut self)595 fn process_reset(&mut self) {
596 self.active_handles.clear();
597 self.connection_attempt.clear();
598 self.last_connection_attempt = None;
599 self.le_connection_attempt.clear();
600 self.last_le_connection_attempt = None;
601 self.last_le_connection_filter_policy = None;
602 self.sco_connection_attempt.clear();
603 self.last_sco_connection_attempt = None;
604 self.accept_list.clear();
605 self.nocp_by_handle.clear();
606 self.apte_by_handle.clear();
607 self.pending_supported_feat.clear();
608 self.pending_extended_feat.clear();
609 self.pending_le_feat.clear();
610 self.last_feat_handle.clear();
611 self.pending_disconnect_due_to_host_power_off.clear();
612 }
613
process_system_note(&mut self, note: &String)614 fn process_system_note(&mut self, note: &String) {
615 // Carryover section doesn't contain the NOCP from the controller.
616 // The note may contain zero bytes, so don't check for exact string.
617 if note.contains("END OF CARRYOVER SECTION") {
618 self.nocp_by_handle.clear();
619 }
620 }
621 }
622
623 impl Rule for OddDisconnectionsRule {
process(&mut self, packet: &Packet)624 fn process(&mut self, packet: &Packet) {
625 match &packet.inner {
626 PacketChild::HciCommand(cmd) => match cmd.specialize() {
627 CommandChild::CreateConnection(cc) => {
628 self.process_classic_connection(cc.get_bd_addr(), packet);
629 }
630 CommandChild::AcceptConnectionRequest(ac) => {
631 self.process_classic_connection(ac.get_bd_addr(), packet);
632 }
633 CommandChild::ReadRemoteSupportedFeatures(rrsf) => {
634 self.process_remote_feat_cmd(
635 PendingRemoteFeature::Supported,
636 &rrsf.get_connection_handle(),
637 packet,
638 );
639 }
640 CommandChild::ReadRemoteExtendedFeatures(rref) => {
641 self.process_remote_feat_cmd(
642 PendingRemoteFeature::Extended,
643 &rref.get_connection_handle(),
644 packet,
645 );
646 }
647 CommandChild::SetupSynchronousConnection(ssc) => {
648 let address = self.convert_sco_handle_to_address(ssc.get_connection_handle());
649 self.process_sync_connection(address, packet);
650 }
651 CommandChild::EnhancedSetupSynchronousConnection(esc) => {
652 let address = self.convert_sco_handle_to_address(esc.get_connection_handle());
653 self.process_sync_connection(address, packet);
654 }
655 CommandChild::AcceptSynchronousConnection(asc) => {
656 self.process_sync_connection(asc.get_bd_addr(), packet);
657 }
658 CommandChild::EnhancedAcceptSynchronousConnection(easc) => {
659 self.process_sync_connection(easc.get_bd_addr(), packet);
660 }
661 CommandChild::LeCreateConnection(lcc) => {
662 self.process_le_create_connection(
663 lcc.get_peer_address(),
664 lcc.get_initiator_filter_policy(),
665 packet,
666 );
667 }
668 CommandChild::LeExtendedCreateConnection(lecc) => {
669 self.process_le_create_connection(
670 lecc.get_peer_address(),
671 lecc.get_initiator_filter_policy(),
672 packet,
673 );
674 }
675 CommandChild::LeAddDeviceToFilterAcceptList(laac) => {
676 self.process_add_accept_list(laac.get_address(), packet);
677 }
678 CommandChild::LeRemoveDeviceFromFilterAcceptList(lrac) => {
679 self.process_remove_accept_list(lrac.get_address(), packet);
680 }
681 CommandChild::LeClearFilterAcceptList(_lcac) => {
682 self.process_clear_accept_list(packet);
683 }
684 CommandChild::LeReadRemoteFeatures(lrrf) => {
685 self.process_remote_feat_cmd(
686 PendingRemoteFeature::Le,
687 &lrrf.get_connection_handle(),
688 packet,
689 );
690 }
691 CommandChild::Disconnect(dc_conn) => {
692 self.process_disconnect_cmd(
693 dc_conn.get_reason(),
694 dc_conn.get_connection_handle(),
695 packet,
696 );
697 }
698 CommandChild::Reset(_) => {
699 self.process_reset();
700 }
701
702 // End HciCommand.specialize()
703 _ => (),
704 },
705
706 PacketChild::HciEvent(ev) => match ev.specialize() {
707 EventChild::CommandStatus(cs) => {
708 self.process_command_status(cs.get_status(), cs.get_command_op_code(), packet);
709 }
710 EventChild::ConnectionComplete(cc) => {
711 self.process_conn_complete_ev(
712 cc.get_status(),
713 cc.get_connection_handle(),
714 cc.get_bd_addr(),
715 packet,
716 );
717 }
718 EventChild::DisconnectionComplete(dsc) => {
719 self.process_disconn_complete_ev(dsc.get_connection_handle(), packet);
720 }
721 EventChild::SynchronousConnectionComplete(scc) => {
722 self.process_sync_conn_complete_ev(
723 scc.get_status(),
724 scc.get_connection_handle(),
725 scc.get_bd_addr(),
726 packet,
727 );
728 }
729 EventChild::NumberOfCompletedPackets(nocp) => {
730 self.process_nocp(&nocp, packet);
731 }
732
733 EventChild::AuthenticatedPayloadTimeoutExpired(apte) => {
734 self.process_apte(&apte, packet);
735 }
736 EventChild::ReadRemoteSupportedFeaturesComplete(rsfc) => {
737 self.process_remote_feat_ev(
738 PendingRemoteFeature::Supported,
739 rsfc.get_status(),
740 rsfc.get_connection_handle(),
741 packet,
742 );
743 }
744 EventChild::ReadRemoteExtendedFeaturesComplete(refc) => {
745 self.process_remote_feat_ev(
746 PendingRemoteFeature::Extended,
747 refc.get_status(),
748 refc.get_connection_handle(),
749 packet,
750 );
751 }
752 EventChild::LeMetaEvent(lme) => match lme.specialize() {
753 LeMetaEventChild::LeConnectionComplete(lcc) => {
754 self.process_le_conn_complete_ev(
755 lcc.get_status(),
756 lcc.get_connection_handle(),
757 lcc.get_peer_address(),
758 packet,
759 );
760 }
761 LeMetaEventChild::LeEnhancedConnectionComplete(lecc) => {
762 self.process_le_conn_complete_ev(
763 lecc.get_status(),
764 lecc.get_connection_handle(),
765 lecc.get_peer_address(),
766 packet,
767 );
768 }
769 LeMetaEventChild::LeReadRemoteFeaturesComplete(lrrfc) => {
770 self.process_remote_feat_ev(
771 PendingRemoteFeature::Le,
772 lrrfc.get_status(),
773 lrrfc.get_connection_handle(),
774 packet,
775 );
776 }
777 // End LeMetaEvent.specialize()
778 _ => {}
779 },
780
781 // End HciEvent.specialize()
782 _ => (),
783 },
784
785 // Use tx packets for nocp tracking.
786 PacketChild::AclTx(tx) => {
787 self.process_acl_tx(&tx, packet);
788 }
789
790 // We don't do anything with RX packets yet.
791 PacketChild::AclRx(_) => (),
792
793 PacketChild::SystemNote(note) => {
794 self.process_system_note(note);
795 }
796
797 // End packet.inner match
798 _ => (),
799 }
800 }
801
report(&self, writer: &mut dyn Write)802 fn report(&self, writer: &mut dyn Write) {
803 if self.reportable.len() > 0 {
804 let _ = writeln!(writer, "OddDisconnectionsRule report:");
805 for (ts, message) in self.reportable.iter() {
806 let _ = writeln!(writer, "[{:?}] {}", ts, message);
807 }
808 }
809 }
810
report_signals(&self) -> &[Signal]811 fn report_signals(&self) -> &[Signal] {
812 self.signals.as_slice()
813 }
814 }
815
816 // What state are we in for the LinkKeyMismatchRule state?
817 #[derive(Debug, PartialEq)]
818 enum LinkKeyMismatchState {
819 Requested, // Controller requested link key to the host
820 Replied, // Host replied the link key
821 }
822
823 /// Identifies instances when the peer forgets the link key or it mismatches with ours.
824 /// For classic connections, first the controller asks for the link key via Link Key Request, then
825 /// the host replies with Link Key Request Reply, finally the controller will report the result,
826 /// usually via AuthenticationComplete.
827 /// For LE connections, the host passes the Long Term Key (LTK) via LE Start Encryption, then the
828 /// controller reports the result via Encryption Change event. There are also LE Long Term Key
829 /// Requests from the controller, but that is only used when the device is a peripheral.
830 struct LinkKeyMismatchRule {
831 /// Addresses in authenticating process
832 states: HashMap<Address, LinkKeyMismatchState>,
833
834 /// Active handles
835 handles: HashMap<ConnectionHandle, Address>,
836
837 /// Handles pending for LE encryption
838 pending_le_encrypt: HashSet<ConnectionHandle>,
839
840 /// Pre-defined signals discovered in the logs.
841 signals: Vec<Signal>,
842
843 /// Interesting occurrences surfaced by this rule.
844 reportable: Vec<(NaiveDateTime, String)>,
845 }
846
847 impl LinkKeyMismatchRule {
new() -> Self848 pub fn new() -> Self {
849 LinkKeyMismatchRule {
850 states: HashMap::new(),
851 handles: HashMap::new(),
852 pending_le_encrypt: HashSet::new(),
853 signals: vec![],
854 reportable: vec![],
855 }
856 }
857
process_address_auth(&mut self, status: ErrorCode, address: Address, packet: &Packet)858 fn process_address_auth(&mut self, status: ErrorCode, address: Address, packet: &Packet) {
859 if status == ErrorCode::AuthenticationFailure {
860 if let Some(LinkKeyMismatchState::Replied) = self.states.get(&address) {
861 self.signals.push(Signal {
862 index: packet.index,
863 ts: packet.ts,
864 tag: ConnectionSignal::LinkKeyMismatch.into(),
865 });
866
867 self.reportable.push((
868 packet.ts,
869 format!("Peer {} forgets the link key, or it mismatches with ours.", address),
870 ));
871 }
872 }
873 self.states.remove(&address);
874 }
875
process_handle_auth( &mut self, status: ErrorCode, handle: ConnectionHandle, packet: &Packet, )876 fn process_handle_auth(
877 &mut self,
878 status: ErrorCode,
879 handle: ConnectionHandle,
880 packet: &Packet,
881 ) {
882 if let Some(address) = self.handles.get(&handle) {
883 self.process_address_auth(status, *address, packet);
884 }
885 }
886
process_request_link_key(&mut self, address: Address)887 fn process_request_link_key(&mut self, address: Address) {
888 self.states.insert(address, LinkKeyMismatchState::Requested);
889 }
890
process_reply_link_key(&mut self, address: Address, key_exist: bool)891 fn process_reply_link_key(&mut self, address: Address, key_exist: bool) {
892 if !key_exist {
893 self.states.remove(&address);
894 return;
895 }
896
897 if let Some(LinkKeyMismatchState::Requested) = self.states.get(&address) {
898 self.states.insert(address, LinkKeyMismatchState::Replied);
899 }
900 }
901
process_encryption_change( &mut self, status: ErrorCode, handle: ConnectionHandle, packet: &Packet, )902 fn process_encryption_change(
903 &mut self,
904 status: ErrorCode,
905 handle: ConnectionHandle,
906 packet: &Packet,
907 ) {
908 if status != ErrorCode::Success {
909 let address_format = self
910 .handles
911 .get(&handle)
912 .map_or(format!("handle {}", handle), |addr| format!("{}", addr));
913 self.reportable.push((
914 packet.ts,
915 format!("Encryption failure with {:?} for {}", status, address_format),
916 ));
917
918 if self.pending_le_encrypt.contains(&handle) {
919 self.signals.push(Signal {
920 index: packet.index,
921 ts: packet.ts,
922 tag: ConnectionSignal::LongTermKeyMismatch.into(),
923 });
924 }
925 }
926
927 self.pending_le_encrypt.remove(&handle);
928 }
929
process_reset(&mut self)930 fn process_reset(&mut self) {
931 self.states.clear();
932 self.handles.clear();
933 self.pending_le_encrypt.clear();
934 }
935 }
936
937 impl Rule for LinkKeyMismatchRule {
process(&mut self, packet: &Packet)938 fn process(&mut self, packet: &Packet) {
939 match &packet.inner {
940 PacketChild::HciEvent(ev) => match ev.specialize() {
941 EventChild::ConnectionComplete(ev) => {
942 if ev.get_status() == ErrorCode::Success {
943 self.handles.insert(ev.get_connection_handle(), ev.get_bd_addr());
944 }
945 }
946 EventChild::LinkKeyRequest(ev) => {
947 self.process_request_link_key(ev.get_bd_addr());
948 }
949 EventChild::SimplePairingComplete(ev) => {
950 self.process_address_auth(ev.get_status(), ev.get_bd_addr(), &packet);
951 }
952 EventChild::AuthenticationComplete(ev) => {
953 self.process_handle_auth(ev.get_status(), ev.get_connection_handle(), &packet);
954 }
955 EventChild::DisconnectionComplete(ev) => {
956 self.process_handle_auth(ev.get_status(), ev.get_connection_handle(), &packet);
957 self.handles.remove(&ev.get_connection_handle());
958 }
959 EventChild::EncryptionChange(ev) => {
960 self.process_encryption_change(
961 ev.get_status(),
962 ev.get_connection_handle(),
963 &packet,
964 );
965 }
966 EventChild::LeMetaEvent(ev) => match ev.specialize() {
967 LeMetaEventChild::LeConnectionComplete(ev) => {
968 if ev.get_status() == ErrorCode::Success {
969 self.handles.insert(ev.get_connection_handle(), ev.get_peer_address());
970 }
971 }
972 LeMetaEventChild::LeEnhancedConnectionComplete(ev) => {
973 if ev.get_status() == ErrorCode::Success {
974 self.handles.insert(ev.get_connection_handle(), ev.get_peer_address());
975 }
976 }
977
978 // EventChild::LeMetaEvent(ev).specialize()
979 _ => {}
980 },
981
982 // PacketChild::HciEvent(ev).specialize()
983 _ => {}
984 },
985
986 PacketChild::HciCommand(cmd) => match cmd.specialize() {
987 // Have an arm for Disconnect since sometimes we don't receive disconnect
988 // event when powering off. However, no need to actually match the reason
989 // since we just clean the handle in both cases.
990 CommandChild::Disconnect(cmd) => {
991 self.process_handle_auth(
992 ErrorCode::Success,
993 cmd.get_connection_handle(),
994 &packet,
995 );
996 self.handles.remove(&cmd.get_connection_handle());
997 }
998 CommandChild::LinkKeyRequestReply(cmd) => {
999 self.process_reply_link_key(cmd.get_bd_addr(), true);
1000 }
1001 CommandChild::LinkKeyRequestNegativeReply(cmd) => {
1002 self.process_reply_link_key(cmd.get_bd_addr(), false);
1003 }
1004 CommandChild::LeStartEncryption(cmd) => {
1005 self.pending_le_encrypt.insert(cmd.get_connection_handle());
1006 }
1007 CommandChild::Reset(_) => {
1008 self.process_reset();
1009 }
1010
1011 // PacketChild::HciCommand(cmd).specialize()
1012 _ => {}
1013 },
1014
1015 // packet.inner
1016 _ => {}
1017 }
1018 }
1019
report(&self, writer: &mut dyn Write)1020 fn report(&self, writer: &mut dyn Write) {
1021 if self.reportable.len() > 0 {
1022 let _ = writeln!(writer, "LinkKeyMismatchRule report:");
1023 for (ts, message) in self.reportable.iter() {
1024 let _ = writeln!(writer, "[{:?}] {}", ts, message);
1025 }
1026 }
1027 }
1028
report_signals(&self) -> &[Signal]1029 fn report_signals(&self) -> &[Signal] {
1030 self.signals.as_slice()
1031 }
1032 }
1033
1034 struct SecurityMode3Rule {
1035 /// Pre-defined signals discovered in the logs.
1036 signals: Vec<Signal>,
1037
1038 /// Interesting occurrences surfaced by this rule.
1039 reportable: Vec<(NaiveDateTime, String)>,
1040 }
1041
1042 impl SecurityMode3Rule {
new() -> Self1043 pub fn new() -> Self {
1044 SecurityMode3Rule { signals: vec![], reportable: vec![] }
1045 }
1046
process_connect_complete( &mut self, status: ErrorCode, address: Address, encryption_enabled: Enable, packet: &Packet, )1047 fn process_connect_complete(
1048 &mut self,
1049 status: ErrorCode,
1050 address: Address,
1051 encryption_enabled: Enable,
1052 packet: &Packet,
1053 ) {
1054 // See figure 5.2 and 5.3 in BT spec v5.4 Vol 3 Part C 5.2 for security mode 3 explanation.
1055 // It is indicated by encryption before the link setup is complete.
1056 // Therefore we just need to observe the encryption_enabled parameter in conn complete evt.
1057 if status == ErrorCode::Success && encryption_enabled == Enable::Enabled {
1058 self.signals.push(Signal {
1059 index: packet.index,
1060 ts: packet.ts,
1061 tag: ConnectionSignal::SecurityMode3.into(),
1062 });
1063
1064 self.reportable.push((
1065 packet.ts,
1066 format!("Device {} uses unsupported legacy security mode 3 (b/260625799)", address),
1067 ));
1068 }
1069 }
1070 }
1071
1072 impl Rule for SecurityMode3Rule {
process(&mut self, packet: &Packet)1073 fn process(&mut self, packet: &Packet) {
1074 match &packet.inner {
1075 PacketChild::HciEvent(ev) => match ev.specialize() {
1076 EventChild::ConnectionComplete(ev) => {
1077 self.process_connect_complete(
1078 ev.get_status(),
1079 ev.get_bd_addr(),
1080 ev.get_encryption_enabled(),
1081 packet,
1082 );
1083 }
1084 _ => {}
1085 },
1086 _ => {}
1087 }
1088 }
1089
report(&self, writer: &mut dyn Write)1090 fn report(&self, writer: &mut dyn Write) {
1091 if self.reportable.len() > 0 {
1092 let _ = writeln!(writer, "SecurityMode3Rule report:");
1093 for (ts, message) in self.reportable.iter() {
1094 let _ = writeln!(writer, "[{:?}] {}", ts, message);
1095 }
1096 }
1097 }
1098
report_signals(&self) -> &[Signal]1099 fn report_signals(&self) -> &[Signal] {
1100 self.signals.as_slice()
1101 }
1102 }
1103
1104 /// Get a rule group with connection rules.
get_connections_group() -> RuleGroup1105 pub fn get_connections_group() -> RuleGroup {
1106 let mut group = RuleGroup::new();
1107 group.add_rule(Box::new(LinkKeyMismatchRule::new()));
1108 group.add_rule(Box::new(OddDisconnectionsRule::new()));
1109 group.add_rule(Box::new(SecurityMode3Rule::new()));
1110
1111 group
1112 }
1113