diff --git a/floss/hcidoc/src/groups/connections.rs b/floss/hcidoc/src/groups/connections.rs index 7d600b3191521231cf52916f10c7af52ed614d2c..13a398c91901476449d3f5f6bea4cb1da8fa8d6a 100644 --- a/floss/hcidoc/src/groups/connections.rs +++ b/floss/hcidoc/src/groups/connections.rs @@ -7,16 +7,17 @@ use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{Packet, PacketChild}; use bt_packets::hci::{ - Acl, AclCommandChild, Address, CommandChild, CommandStatus, ConnectionManagementCommandChild, - DisconnectReason, ErrorCode, Event, EventChild, LeConnectionManagementCommandChild, - LeMetaEventChild, NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild, - SecurityCommandChild, SubeventCode, + Acl, AclCommandChild, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, CommandStatus, + ConnectionManagementCommandChild, DisconnectReason, ErrorCode, Event, EventChild, + LeConnectionManagementCommandChild, LeMetaEventChild, NumberOfCompletedPackets, OpCode, + ScoConnectionCommandChild, SecurityCommandChild, SubeventCode, }; enum ConnectionSignal { LinkKeyMismatch, // Peer forgets the link key or it mismatches ours NocpDisconnect, // Peer is disconnected when NOCP packet isn't yet received NocpTimeout, // Host doesn't receive NOCP packet 5 seconds after ACL is sent + ApteDisconnect, // Host doesn't receive a packet with valid MIC for a while. } impl Into<&'static str> for ConnectionSignal { @@ -25,6 +26,7 @@ impl Into<&'static str> for ConnectionSignal { ConnectionSignal::LinkKeyMismatch => "LinkKeyMismatch", ConnectionSignal::NocpDisconnect => "Nocp", ConnectionSignal::NocpTimeout => "Nocp", + ConnectionSignal::ApteDisconnect => "AuthenticatedPayloadTimeoutExpired", } } } @@ -73,6 +75,9 @@ struct OddDisconnectionsRule { /// identify bursts. nocp_by_handle: HashMap<ConnectionHandle, NocpData>, + /// Number of |Authenticated Payload Timeout Expired| events hapened. + apte_by_handle: HashMap<ConnectionHandle, u32>, + /// Pre-defined signals discovered in the logs. signals: Vec<Signal>, @@ -91,6 +96,7 @@ impl OddDisconnectionsRule { sco_connection_attempt: HashMap::new(), last_sco_connection_attempt: None, nocp_by_handle: HashMap::new(), + apte_by_handle: HashMap::new(), signals: vec![], reportable: vec![], } @@ -315,6 +321,26 @@ impl OddDisconnectionsRule { // Remove nocp information for handles that were removed. self.nocp_by_handle.remove(&handle); + + // Check if auth payload timeout happened. + match self.apte_by_handle.get_mut(&handle) { + Some(apte_count) => { + self.signals.push(Signal { + index: packet.index, + ts: packet.ts.clone(), + tag: ConnectionSignal::ApteDisconnect.into(), + }); + + self.reportable.push(( + packet.ts, + format!("DisconnectionComplete with {} Authenticated Payload Timeout Expired (handle={})", + apte_count, handle))); + } + None => (), + } + + // Remove apte information for handles that were removed. + self.apte_by_handle.remove(&handle); } EventChild::SynchronousConnectionComplete(scc) => { @@ -436,6 +462,11 @@ impl OddDisconnectionsRule { } } + fn process_apte(&mut self, apte: &AuthenticatedPayloadTimeoutExpired, _packet: &Packet) { + let handle = apte.get_connection_handle(); + *self.apte_by_handle.entry(handle).or_insert(0) += 1; + } + fn process_reset(&mut self) { self.active_handles.clear(); self.connection_attempt.clear(); @@ -445,6 +476,7 @@ impl OddDisconnectionsRule { self.sco_connection_attempt.clear(); self.last_sco_connection_attempt = None; self.nocp_by_handle.clear(); + self.apte_by_handle.clear(); } } @@ -518,6 +550,10 @@ impl Rule for OddDisconnectionsRule { self.process_nocp(&nocp, packet); } + EventChild::AuthenticatedPayloadTimeoutExpired(apte) => { + self.process_apte(&apte, packet); + } + // end hci event _ => (), }, diff --git a/system/main/shim/hci_layer.cc b/system/main/shim/hci_layer.cc index 424c21de5ff56034bb4568531a3230a7c94384ee..d3ed495ce36424872f61434289a8cfea5eb57ae5 100644 --- a/system/main/shim/hci_layer.cc +++ b/system/main/shim/hci_layer.cc @@ -113,6 +113,7 @@ bool is_valid_event_code(bluetooth::hci::EventCode event_code) { return true; case bluetooth::hci::EventCode::VENDOR_SPECIFIC: case bluetooth::hci::EventCode::LE_META_EVENT: // Private to hci + case bluetooth::hci::EventCode::AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED: return false; } return false; diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl index f75bbe58d8c9bd3c4c3efd53eaa761cb5a02612b..d4b278bddb15902d31c18b397aa65b9939cfa317 100644 --- a/system/pdl/hci/hci_packets.pdl +++ b/system/pdl/hci/hci_packets.pdl @@ -831,6 +831,7 @@ enum EventCode : 8 { REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D, LE_META_EVENT = 0x3e, NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48, + AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED = 0x57, VENDOR_SPECIFIC = 0xFF, } @@ -5803,6 +5804,11 @@ packet NumberOfCompletedDataBlocks : Event (event_code = NUMBER_OF_COMPLETED_DAT _payload_, // placeholder (unimplemented) } +packet AuthenticatedPayloadTimeoutExpired : Event (event_code = AUTHENTICATED_PAYLOAD_TIMEOUT_EXPIRED) { + connection_handle : 12, + _reserved_ : 4, +} + // LE Events packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) { status : ErrorCode,