Loading floss/hcidoc/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -10,3 +10,4 @@ clap = "4.0" chrono = "0.4" num-derive = "0.3" num-traits = "0.2" lazy_static = "1.0" floss/hcidoc/src/groups/connections.rs +3 −0 Original line number Diff line number Diff line Loading @@ -804,6 +804,9 @@ impl Rule for OddDisconnectionsRule { // We don't do anything with RX packets yet. PacketChild::AclRx(_) => (), // End packet.inner match _ => (), } } Loading floss/hcidoc/src/groups/controllers.rs +91 −4 Original line number Diff line number Diff line ///! Rule group for tracking controller related issues. use chrono::NaiveDateTime; use lazy_static::lazy_static; use std::collections::HashSet; use std::convert::Into; use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{Packet, PacketChild}; use bt_packets::hci::EventChild; use crate::parser::{NewIndex, Packet, PacketChild}; use bt_packets::hci::{CommandCompleteChild, ErrorCode, EventChild, LocalVersionInformation}; enum ControllerSignal { HardwareError, // Controller reports HCI event: Hardware Error LikelyExternalController, // Controller is not in the known list. Likely to be an external controller. } impl Into<&'static str> for ControllerSignal { fn into(self) -> &'static str { match self { ControllerSignal::HardwareError => "HardwareError", ControllerSignal::LikelyExternalController => "LikelyExternalController", } } } lazy_static! { static ref KNOWN_CONTROLLER_NAMES: [String; 6] = [ String::from("Bluemoon Universal Bluetooth Host Controller"), // AC7625 String::from("MTK MT7961 #1"), // MT7921LE/MT7921LS String::from("MTK MT7922 #1"), // MT7922 String::from("RTK_BT_5.0"), // RTL8822CE String::from("RT_BT"), // RTL8852AE String::from(""), // AC9260/AC9560/AX200/AX201/AX203/AX211/MVL8897/QCA6174A3/QCA6174A5/QC_WCN6856 ]; } const KNOWN_CONTROLLER_MANUFACTURERS: [u16; 5] = [ 2, // Intel. 29, // Qualcomm 70, // MediaTek 72, // Marvell 93, // Realtek ]; struct ControllerRule { /// Pre-defined signals discovered in the logs. signals: Vec<Signal>, /// Interesting occurrences surfaced by this rule. reportable: Vec<(NaiveDateTime, String)>, /// All detected open_index. controllers: HashSet<String>, } impl ControllerRule { pub fn new() -> Self { ControllerRule { signals: vec![], reportable: vec![] } ControllerRule { signals: vec![], reportable: vec![], controllers: HashSet::new() } } pub fn report_hardware_error(&mut self, packet: &Packet) { Loading @@ -41,6 +66,48 @@ impl ControllerRule { self.reportable.push((packet.ts, format!("controller reported hardware error"))); } fn process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet) { let null_index = local_name.iter().position(|&b| b == 0).unwrap_or(local_name.len()); match String::from_utf8(local_name[..null_index].to_vec()) { Ok(name) => { if !KNOWN_CONTROLLER_NAMES.contains(&name) { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }) } } Err(_) => self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }), } } fn process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet) { if !KNOWN_CONTROLLER_MANUFACTURERS.contains(&version_info.manufacturer_name) { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }) } } fn process_new_index(&mut self, new_index: &NewIndex, packet: &Packet) { self.controllers.insert(new_index.get_addr_str()); if self.controllers.len() > 1 { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }); } } } impl Rule for ControllerRule { Loading @@ -50,9 +117,29 @@ impl Rule for ControllerRule { EventChild::HardwareError(_ev) => { self.report_hardware_error(&packet); } EventChild::CommandComplete(ev) => match ev.specialize() { CommandCompleteChild::ReadLocalNameComplete(ev) => { if ev.get_status() != ErrorCode::Success { return; } self.process_local_name(ev.get_local_name(), &packet); } CommandCompleteChild::ReadLocalVersionInformationComplete(ev) => { if ev.get_status() != ErrorCode::Success { return; } self.process_local_version(ev.get_local_version_information(), &packet); } _ => {} }, _ => {} }, PacketChild::NewIndex(ni) => { self.process_new_index(ni, &packet); } _ => {} } } Loading floss/hcidoc/src/groups/informational.rs +4 −1 Original line number Diff line number Diff line Loading @@ -931,7 +931,10 @@ impl Rule for InformationalRule { // PacketChild::AclRx(rx).specialize() _ => {} } } // packet.inner } // End packet.inner match _ => (), } } Loading floss/hcidoc/src/parser.rs +47 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,7 @@ pub enum PacketChild { HciEvent(Event), AclTx(Acl), AclRx(Acl), NewIndex(NewIndex), } impl<'a> TryFrom<&'a LinuxSnoopPacket> for PacketChild { Loading Loading @@ -314,6 +315,11 @@ impl<'a> TryFrom<&'a LinuxSnoopPacket> for PacketChild { Err(e) => Err(format!("Couldn't parse acl rx: {:?}", e)), }, LinuxSnoopOpcodes::NewIndex => match NewIndex::parse(item.data.as_slice()) { Ok(data) => Ok(PacketChild::NewIndex(data)), Err(e) => Err(format!("Couldn't parse new index: {:?}", e)), }, // TODO(b/262928525) - Add packet handlers for more packet types. _ => Err(format!("Unhandled packet opcode: {:?}", item.opcode())), } Loading Loading @@ -400,3 +406,44 @@ pub fn get_acl_content(acl: &Acl) -> AclContent { _ => AclContent::None, } } #[derive(Clone, Debug)] pub struct NewIndex { _hci_type: u8, _bus: u8, bdaddr: [u8; 6], _name: [u8; 8], } impl NewIndex { fn parse(data: &[u8]) -> Result<NewIndex, std::string::String> { if data.len() != std::mem::size_of::<NewIndex>() { return Err(format!("Invalid size for New Index packet: {}", data.len())); } let rest = data; let (hci_type, rest) = rest.split_at(std::mem::size_of::<u8>()); let (bus, rest) = rest.split_at(std::mem::size_of::<u8>()); let (bdaddr, rest) = rest.split_at(6 * std::mem::size_of::<u8>()); let (name, _rest) = rest.split_at(8 * std::mem::size_of::<u8>()); Ok(NewIndex { _hci_type: hci_type[0], _bus: bus[0], bdaddr: bdaddr.try_into().unwrap(), _name: name.try_into().unwrap(), }) } pub fn get_addr_str(&self) -> String { String::from(format!( "[{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}]", self.bdaddr[0], self.bdaddr[1], self.bdaddr[2], self.bdaddr[3], self.bdaddr[4], self.bdaddr[5] )) } } Loading
floss/hcidoc/Cargo.toml +1 −0 Original line number Diff line number Diff line Loading @@ -10,3 +10,4 @@ clap = "4.0" chrono = "0.4" num-derive = "0.3" num-traits = "0.2" lazy_static = "1.0"
floss/hcidoc/src/groups/connections.rs +3 −0 Original line number Diff line number Diff line Loading @@ -804,6 +804,9 @@ impl Rule for OddDisconnectionsRule { // We don't do anything with RX packets yet. PacketChild::AclRx(_) => (), // End packet.inner match _ => (), } } Loading
floss/hcidoc/src/groups/controllers.rs +91 −4 Original line number Diff line number Diff line ///! Rule group for tracking controller related issues. use chrono::NaiveDateTime; use lazy_static::lazy_static; use std::collections::HashSet; use std::convert::Into; use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{Packet, PacketChild}; use bt_packets::hci::EventChild; use crate::parser::{NewIndex, Packet, PacketChild}; use bt_packets::hci::{CommandCompleteChild, ErrorCode, EventChild, LocalVersionInformation}; enum ControllerSignal { HardwareError, // Controller reports HCI event: Hardware Error LikelyExternalController, // Controller is not in the known list. Likely to be an external controller. } impl Into<&'static str> for ControllerSignal { fn into(self) -> &'static str { match self { ControllerSignal::HardwareError => "HardwareError", ControllerSignal::LikelyExternalController => "LikelyExternalController", } } } lazy_static! { static ref KNOWN_CONTROLLER_NAMES: [String; 6] = [ String::from("Bluemoon Universal Bluetooth Host Controller"), // AC7625 String::from("MTK MT7961 #1"), // MT7921LE/MT7921LS String::from("MTK MT7922 #1"), // MT7922 String::from("RTK_BT_5.0"), // RTL8822CE String::from("RT_BT"), // RTL8852AE String::from(""), // AC9260/AC9560/AX200/AX201/AX203/AX211/MVL8897/QCA6174A3/QCA6174A5/QC_WCN6856 ]; } const KNOWN_CONTROLLER_MANUFACTURERS: [u16; 5] = [ 2, // Intel. 29, // Qualcomm 70, // MediaTek 72, // Marvell 93, // Realtek ]; struct ControllerRule { /// Pre-defined signals discovered in the logs. signals: Vec<Signal>, /// Interesting occurrences surfaced by this rule. reportable: Vec<(NaiveDateTime, String)>, /// All detected open_index. controllers: HashSet<String>, } impl ControllerRule { pub fn new() -> Self { ControllerRule { signals: vec![], reportable: vec![] } ControllerRule { signals: vec![], reportable: vec![], controllers: HashSet::new() } } pub fn report_hardware_error(&mut self, packet: &Packet) { Loading @@ -41,6 +66,48 @@ impl ControllerRule { self.reportable.push((packet.ts, format!("controller reported hardware error"))); } fn process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet) { let null_index = local_name.iter().position(|&b| b == 0).unwrap_or(local_name.len()); match String::from_utf8(local_name[..null_index].to_vec()) { Ok(name) => { if !KNOWN_CONTROLLER_NAMES.contains(&name) { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }) } } Err(_) => self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }), } } fn process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet) { if !KNOWN_CONTROLLER_MANUFACTURERS.contains(&version_info.manufacturer_name) { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }) } } fn process_new_index(&mut self, new_index: &NewIndex, packet: &Packet) { self.controllers.insert(new_index.get_addr_str()); if self.controllers.len() > 1 { self.signals.push(Signal { index: packet.index, ts: packet.ts, tag: ControllerSignal::LikelyExternalController.into(), }); } } } impl Rule for ControllerRule { Loading @@ -50,9 +117,29 @@ impl Rule for ControllerRule { EventChild::HardwareError(_ev) => { self.report_hardware_error(&packet); } EventChild::CommandComplete(ev) => match ev.specialize() { CommandCompleteChild::ReadLocalNameComplete(ev) => { if ev.get_status() != ErrorCode::Success { return; } self.process_local_name(ev.get_local_name(), &packet); } CommandCompleteChild::ReadLocalVersionInformationComplete(ev) => { if ev.get_status() != ErrorCode::Success { return; } self.process_local_version(ev.get_local_version_information(), &packet); } _ => {} }, _ => {} }, PacketChild::NewIndex(ni) => { self.process_new_index(ni, &packet); } _ => {} } } Loading
floss/hcidoc/src/groups/informational.rs +4 −1 Original line number Diff line number Diff line Loading @@ -931,7 +931,10 @@ impl Rule for InformationalRule { // PacketChild::AclRx(rx).specialize() _ => {} } } // packet.inner } // End packet.inner match _ => (), } } Loading
floss/hcidoc/src/parser.rs +47 −0 Original line number Diff line number Diff line Loading @@ -287,6 +287,7 @@ pub enum PacketChild { HciEvent(Event), AclTx(Acl), AclRx(Acl), NewIndex(NewIndex), } impl<'a> TryFrom<&'a LinuxSnoopPacket> for PacketChild { Loading Loading @@ -314,6 +315,11 @@ impl<'a> TryFrom<&'a LinuxSnoopPacket> for PacketChild { Err(e) => Err(format!("Couldn't parse acl rx: {:?}", e)), }, LinuxSnoopOpcodes::NewIndex => match NewIndex::parse(item.data.as_slice()) { Ok(data) => Ok(PacketChild::NewIndex(data)), Err(e) => Err(format!("Couldn't parse new index: {:?}", e)), }, // TODO(b/262928525) - Add packet handlers for more packet types. _ => Err(format!("Unhandled packet opcode: {:?}", item.opcode())), } Loading Loading @@ -400,3 +406,44 @@ pub fn get_acl_content(acl: &Acl) -> AclContent { _ => AclContent::None, } } #[derive(Clone, Debug)] pub struct NewIndex { _hci_type: u8, _bus: u8, bdaddr: [u8; 6], _name: [u8; 8], } impl NewIndex { fn parse(data: &[u8]) -> Result<NewIndex, std::string::String> { if data.len() != std::mem::size_of::<NewIndex>() { return Err(format!("Invalid size for New Index packet: {}", data.len())); } let rest = data; let (hci_type, rest) = rest.split_at(std::mem::size_of::<u8>()); let (bus, rest) = rest.split_at(std::mem::size_of::<u8>()); let (bdaddr, rest) = rest.split_at(6 * std::mem::size_of::<u8>()); let (name, _rest) = rest.split_at(8 * std::mem::size_of::<u8>()); Ok(NewIndex { _hci_type: hci_type[0], _bus: bus[0], bdaddr: bdaddr.try_into().unwrap(), _name: name.try_into().unwrap(), }) } pub fn get_addr_str(&self) -> String { String::from(format!( "[{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}]", self.bdaddr[0], self.bdaddr[1], self.bdaddr[2], self.bdaddr[3], self.bdaddr[4], self.bdaddr[5] )) } }