Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f0d00d5 authored by Archie Pusaka's avatar Archie Pusaka
Browse files

Floss: hcidoc: Consider adapter off and suspend in rulesets

When adapter is going off or suspending, the host will send
disconnect request with reason Remote Device Power Off (0x15), and
might not wait for the reply from the peer device. We should treat
this accordingly in hcidoc to avoid wrong judgement because of
missing disconnect events.

Additionally, when controller is reset, we should also reset the
states of the rules, otherwise we might get bogus signals which is
based on the old state of the controller.

This CL adjust the states for the Informational Rule and Connection
Rule.

Bug: 290593784
Tag: #floss
Test: test with feedback report 91055564245 and 91061378476
Change-Id: Ie77389cdd301440d60912c51087994c82c59098f
parent 774ea19e
Loading
Loading
Loading
Loading
+68 −35
Original line number Diff line number Diff line
@@ -8,9 +8,9 @@ use crate::engine::{Rule, RuleGroup, Signal};
use crate::parser::{Packet, PacketChild};
use bt_packets::hci::{
    Acl, AclCommandChild, Address, CommandChild, CommandStatus, ConnectionManagementCommandChild,
    ErrorCode, Event, EventChild, LeConnectionManagementCommandChild, LeMetaEventChild,
    NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild, SecurityCommandChild,
    SubeventCode,
    DisconnectReason, ErrorCode, Event, EventChild, LeConnectionManagementCommandChild,
    LeMetaEventChild, NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild,
    SecurityCommandChild, SubeventCode,
};

enum ConnectionSignal {
@@ -56,9 +56,6 @@ impl NocpData {

/// Keeps track of connections and identifies odd disconnections.
struct OddDisconnectionsRule {
    /// Timestamp on first packet in current log.
    start_of_log: Option<NaiveDateTime>,

    /// Handles that had successful complete connections. The value has the timestamp of the
    /// connection completion and the address of the device.
    active_handles: HashMap<ConnectionHandle, (NaiveDateTime, Address)>,
@@ -86,7 +83,6 @@ struct OddDisconnectionsRule {
impl OddDisconnectionsRule {
    pub fn new() -> Self {
        OddDisconnectionsRule {
            start_of_log: None,
            active_handles: HashMap::new(),
            connection_attempt: HashMap::new(),
            last_connection_attempt: None,
@@ -100,7 +96,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_classic_connection(
    fn process_classic_connection(
        &mut self,
        conn: &ConnectionManagementCommandChild,
        packet: &Packet,
@@ -127,11 +123,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_sco_connection(
        &mut self,
        sco_conn: &ScoConnectionCommandChild,
        packet: &Packet,
    ) {
    fn process_sco_connection(&mut self, sco_conn: &ScoConnectionCommandChild, packet: &Packet) {
        let handle = match sco_conn {
            ScoConnectionCommandChild::SetupSynchronousConnection(ssc) => {
                ssc.get_connection_handle()
@@ -178,7 +170,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_le_conn_connection(
    fn process_le_conn_connection(
        &mut self,
        le_conn: &LeConnectionManagementCommandChild,
        packet: &Packet,
@@ -206,7 +198,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_command_status(&mut self, cs: &CommandStatus, packet: &Packet) {
    fn process_command_status(&mut self, cs: &CommandStatus, packet: &Packet) {
        // Clear last connection attempt since it was successful.
        let last_address = match cs.get_command_op_code() {
            OpCode::CreateConnection | OpCode::AcceptConnectionRequest => {
@@ -264,7 +256,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_event(&mut self, ev: &Event, packet: &Packet) {
    fn process_event(&mut self, ev: &Event, packet: &Packet) {
        match ev.specialize() {
            EventChild::ConnectionComplete(cc) => {
                match self.connection_attempt.remove(&cc.get_bd_addr()) {
@@ -322,16 +314,8 @@ impl OddDisconnectionsRule {
                        }
                    }

                    None => {
                        self.reportable.push((
                            packet.ts,
                            format!(
                                "DisconnectionComplete for unknown handle {} with status={:?}",
                                dsc.get_connection_handle(),
                                dsc.get_status()
                            ),
                        ));
                    }
                    // No issue if none, probably device is connected before snoop started.
                    None => (),
                }

                // Remove nocp information for handles that were removed.
@@ -413,7 +397,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_acl_tx(&mut self, acl_tx: &Acl, packet: &Packet) {
    fn process_acl_tx(&mut self, acl_tx: &Acl, packet: &Packet) {
        let handle = acl_tx.get_handle();

        // Insert empty Nocp data for handle if it doesn't exist.
@@ -426,7 +410,7 @@ impl OddDisconnectionsRule {
        }
    }

    pub fn process_nocp(&mut self, nocp: &NumberOfCompletedPackets, packet: &Packet) {
    fn process_nocp(&mut self, nocp: &NumberOfCompletedPackets, packet: &Packet) {
        let ts = &packet.ts;
        for completed_packet in nocp.get_completed_packets() {
            let handle = completed_packet.connection_handle;
@@ -456,28 +440,52 @@ impl OddDisconnectionsRule {
            }
        }
    }

    fn process_reset(&mut self) {
        self.active_handles.clear();
        self.connection_attempt.clear();
        self.last_connection_attempt = None;
        self.le_connection_attempt.clear();
        self.last_le_connection_attempt = None;
        self.sco_connection_attempt.clear();
        self.last_sco_connection_attempt = None;
        self.nocp_by_handle.clear();
    }
}

impl Rule for OddDisconnectionsRule {
    fn process(&mut self, packet: &Packet) {
        if self.start_of_log.is_none() {
            self.start_of_log = Some(packet.ts.clone());
        }

        match &packet.inner {
            PacketChild::HciCommand(cmd) => match cmd.specialize() {
                CommandChild::AclCommand(aclpkt) => match aclpkt.specialize() {
                    AclCommandChild::ConnectionManagementCommand(conn) => {
                        self.process_classic_connection(&conn.specialize(), packet)
                        self.process_classic_connection(&conn.specialize(), packet);
                    }
                    AclCommandChild::ScoConnectionCommand(sco_conn) => {
                        self.process_sco_connection(&sco_conn.specialize(), packet)
                        self.process_sco_connection(&sco_conn.specialize(), packet);
                    }
                    AclCommandChild::LeConnectionManagementCommand(le_conn) => {
                        self.process_le_conn_connection(&le_conn.specialize(), packet)
                        self.process_le_conn_connection(&le_conn.specialize(), packet);
                    }
                    AclCommandChild::Disconnect(dc_conn) => {
                        // If reason is power off, the host might not wait for connection complete event
                        if dc_conn.get_reason()
                            == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff
                        {
                            let handle = dc_conn.get_connection_handle();
                            self.active_handles.remove(&handle);
                            self.nocp_by_handle.remove(&handle);
                        }
                    }

                    // end acl pkt
                    _ => (),
                },
                CommandChild::Reset(_) => {
                    self.process_reset();
                }

                // end hci command
                _ => (),
            },

@@ -493,6 +501,8 @@ impl Rule for OddDisconnectionsRule {
                    | OpCode::LeExtendedCreateConnection => {
                        self.process_command_status(&cs, packet);
                    }

                    // end command status
                    _ => (),
                },

@@ -513,6 +523,7 @@ impl Rule for OddDisconnectionsRule {
                    self.process_nocp(&nocp, packet);
                }

                // end hci event
                _ => (),
            },

@@ -639,6 +650,23 @@ impl Rule for LinkKeyMismatchRule {
            },

            PacketChild::HciCommand(cmd) => match cmd.specialize() {
                CommandChild::AclCommand(cmd) => match cmd.specialize() {
                    AclCommandChild::Disconnect(cmd) => {
                        // If reason is power off, the host might not wait for connection complete event
                        if cmd.get_reason()
                            == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff
                        {
                            if let Some(address) = self.handles.remove(&cmd.get_connection_handle())
                            {
                                self.states.remove(&address);
                            }
                        }
                    }

                    // CommandChild::AclCommand(cmd).specialize()
                    _ => {}
                },

                CommandChild::SecurityCommand(cmd) => match cmd.specialize() {
                    SecurityCommandChild::LinkKeyRequestReply(cmd) => {
                        let address = cmd.get_bd_addr();
@@ -655,6 +683,11 @@ impl Rule for LinkKeyMismatchRule {
                    _ => {}
                },

                CommandChild::Reset(_) => {
                    self.states.clear();
                    self.handles.clear();
                }

                // PacketChild::HciCommand(cmd).specialize()
                _ => {}
            },
+23 −2
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@ use std::io::Write;
use crate::engine::{Rule, RuleGroup, Signal};
use crate::parser::{Packet, PacketChild};
use bt_packets::hci::{
    AclCommandChild, Address, CommandChild, ConnectionManagementCommandChild, ErrorCode,
    EventChild, GapData, GapDataType, LeMetaEventChild,
    AclCommandChild, Address, CommandChild, ConnectionManagementCommandChild, DisconnectReason,
    ErrorCode, EventChild, GapData, GapDataType, LeMetaEventChild,
};

/// Valid values are in the range 0x0000-0x0EFF.
@@ -241,6 +241,14 @@ impl InformationalRule {
        self.handles.remove(&handle);
    }

    fn report_reset(&mut self, ts: NaiveDateTime) {
        // report_connection_end removes the entries from the map, so store all the keys first.
        let handles: Vec<ConnectionHandle> = self.handles.keys().cloned().collect();
        for handle in handles {
            self.report_connection_end(handle, ts);
        }
    }

    fn process_gap_data(&mut self, address: &Address, data: &GapData) {
        match data.data_type {
            GapDataType::CompleteLocalName | GapDataType::ShortenedLocalName => {
@@ -365,6 +373,10 @@ impl Rule for InformationalRule {
            },

            PacketChild::HciCommand(cmd) => match cmd.specialize() {
                CommandChild::Reset(_cmd) => {
                    self.report_reset(packet.ts);
                }

                CommandChild::AclCommand(cmd) => match cmd.specialize() {
                    AclCommandChild::ConnectionManagementCommand(cmd) => match cmd.specialize() {
                        ConnectionManagementCommandChild::CreateConnection(cmd) => {
@@ -381,6 +393,15 @@ impl Rule for InformationalRule {
                        _ => {}
                    },

                    AclCommandChild::Disconnect(cmd) => {
                        // If reason is power off, the host might not wait for connection complete event
                        if cmd.get_reason()
                            == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff
                        {
                            self.report_connection_end(cmd.get_connection_handle(), packet.ts);
                        }
                    }

                    // CommandChild::AclCommand(cmd).specialize()
                    _ => {}
                },