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

Commit 47b1e39a authored by Archie Pusaka's avatar Archie Pusaka Committed by Gerrit Code Review
Browse files

Merge changes Ie77389cd,I6e61533a into main

* changes:
  Floss: hcidoc: Consider adapter off and suspend in rulesets
  Floss: hcidoc: add ignore-unknown and signals-only parameter
parents 9cfbe4ad 0f0d00d5
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()
                    _ => {}
                },
+40 −7
Original line number Diff line number Diff line
@@ -18,12 +18,25 @@ fn main() {
            Arg::new("filename")
                .help("Path to the snoop log. If omitted, read from stdin instead."),
        )
        .arg(
            Arg::new("ignore-unknown")
                .long("ignore-unknown")
                .action(ArgAction::SetTrue)
                .help("Don't print warning for unknown opcodes"),
        )
        .arg(
            Arg::new("signals")
                .short('s')
                .long("signals")
                .action(ArgAction::SetTrue)
                .help("Report signals from active rules."),
        )
        .arg(
            Arg::new("signals-only")
                .long("signals-only")
                .action(ArgAction::SetTrue)
                .help("Only print signals from active rules, don't print other events."),
        )
        .get_matches();

    let filename = match matches.get_one::<String>("filename") {
@@ -31,11 +44,25 @@ fn main() {
        None => "",
    };

    let report_signals = match matches.get_one::<bool>("signals") {
    let ignore_unknown_opcode = match matches.get_one::<bool>("ignore-unknown") {
        Some(v) => *v,
        None => false,
    };

    let mut report_signals = match matches.get_one::<bool>("signals") {
        Some(v) => *v,
        None => false,
    };

    let report_only_signals = match matches.get_one::<bool>("signals-only") {
        Some(v) => *v,
        None => false,
    };

    if report_only_signals {
        report_signals = true;
    }

    let mut parser = match LogParser::new(filename) {
        Ok(p) => p,
        Err(e) => {
@@ -70,16 +97,22 @@ fn main() {
        for (pos, v) in parser.get_snoop_iterator().expect("Not a linux snoop file").enumerate() {
            match Packet::try_from((pos, &v)) {
                Ok(p) => engine.process(p),
                Err(e) => match v.opcode() {
                Err(e) => {
                    if !ignore_unknown_opcode {
                        match v.opcode() {
                            LinuxSnoopOpcodes::Command | LinuxSnoopOpcodes::Event => {
                                eprintln!("#{}: {}", pos, e);
                            }
                            _ => (),
                },
                        }
                    }
                }
            }
        }

        if !report_only_signals {
            engine.report(&mut writer);
        }
        if report_signals {
            let _ = writeln!(&mut writer, "### Signals ###");
            engine.report_signals(&mut writer);