1 ///! Rule group for tracking controller related issues.
2 use chrono::NaiveDateTime;
3 use lazy_static::lazy_static;
4 use std::collections::HashSet;
5 use std::convert::Into;
6 use std::io::Write;
7
8 use crate::engine::{Rule, RuleGroup, Signal};
9 use crate::parser::{NewIndex, Packet, PacketChild};
10 use hcidoc_packets::hci::{CommandCompleteChild, ErrorCode, EventChild, LocalVersionInformation};
11
12 enum ControllerSignal {
13 HardwareError, // Controller reports HCI event: Hardware Error
14 LikelyExternalController, // Controller is not in the known list. Likely to be an external controller.
15 }
16
17 impl Into<&'static str> for ControllerSignal {
into(self) -> &'static str18 fn into(self) -> &'static str {
19 match self {
20 ControllerSignal::HardwareError => "HardwareError",
21 ControllerSignal::LikelyExternalController => "LikelyExternalController",
22 }
23 }
24 }
25
26 lazy_static! {
27 static ref KNOWN_CONTROLLER_NAMES: [String; 6] = [
28 String::from("Bluemoon Universal Bluetooth Host Controller"), // AC7625
29 String::from("MTK MT7961 #1"), // MT7921LE/MT7921LS
30 String::from("MTK MT7922 #1"), // MT7922
31 String::from("RTK_BT_5.0"), // RTL8822CE
32 String::from("RT_BT"), // RTL8852AE
33 String::from(""), // AC9260/AC9560/AX200/AX201/AX203/AX211/MVL8897/QCA6174A3/QCA6174A5/QC_WCN6856
34 ];
35 }
36 const KNOWN_CONTROLLER_MANUFACTURERS: [u16; 5] = [
37 2, // Intel.
38 29, // Qualcomm
39 70, // MediaTek
40 72, // Marvell
41 93, // Realtek
42 ];
43
44 struct ControllerRule {
45 /// Pre-defined signals discovered in the logs.
46 signals: Vec<Signal>,
47
48 /// Interesting occurrences surfaced by this rule.
49 reportable: Vec<(NaiveDateTime, String)>,
50
51 /// All detected open_index.
52 controllers: HashSet<String>,
53 }
54
55 impl ControllerRule {
new() -> Self56 pub fn new() -> Self {
57 ControllerRule { signals: vec![], reportable: vec![], controllers: HashSet::new() }
58 }
59
report_hardware_error(&mut self, packet: &Packet)60 pub fn report_hardware_error(&mut self, packet: &Packet) {
61 self.signals.push(Signal {
62 index: packet.index,
63 ts: packet.ts.clone(),
64 tag: ControllerSignal::HardwareError.into(),
65 });
66
67 self.reportable.push((packet.ts, format!("controller reported hardware error")));
68 }
69
process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet)70 fn process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet) {
71 let null_index = local_name.iter().position(|&b| b == 0).unwrap_or(local_name.len());
72 match String::from_utf8(local_name[..null_index].to_vec()) {
73 Ok(name) => {
74 if !KNOWN_CONTROLLER_NAMES.contains(&name) {
75 self.signals.push(Signal {
76 index: packet.index,
77 ts: packet.ts,
78 tag: ControllerSignal::LikelyExternalController.into(),
79 })
80 }
81 }
82 Err(_) => self.signals.push(Signal {
83 index: packet.index,
84 ts: packet.ts,
85 tag: ControllerSignal::LikelyExternalController.into(),
86 }),
87 }
88 }
89
process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet)90 fn process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet) {
91 if !KNOWN_CONTROLLER_MANUFACTURERS.contains(&version_info.manufacturer_name) {
92 self.signals.push(Signal {
93 index: packet.index,
94 ts: packet.ts,
95 tag: ControllerSignal::LikelyExternalController.into(),
96 })
97 }
98 }
99
process_new_index(&mut self, new_index: &NewIndex, packet: &Packet)100 fn process_new_index(&mut self, new_index: &NewIndex, packet: &Packet) {
101 self.controllers.insert(new_index.get_addr_str());
102
103 if self.controllers.len() > 1 {
104 self.signals.push(Signal {
105 index: packet.index,
106 ts: packet.ts,
107 tag: ControllerSignal::LikelyExternalController.into(),
108 });
109 }
110 }
111 }
112
113 impl Rule for ControllerRule {
process(&mut self, packet: &Packet)114 fn process(&mut self, packet: &Packet) {
115 match &packet.inner {
116 PacketChild::HciEvent(ev) => match ev.specialize() {
117 EventChild::HardwareError(_ev) => {
118 self.report_hardware_error(&packet);
119 }
120 EventChild::CommandComplete(ev) => match ev.specialize() {
121 CommandCompleteChild::ReadLocalNameComplete(ev) => {
122 if ev.get_status() != ErrorCode::Success {
123 return;
124 }
125
126 self.process_local_name(ev.get_local_name(), &packet);
127 }
128 CommandCompleteChild::ReadLocalVersionInformationComplete(ev) => {
129 if ev.get_status() != ErrorCode::Success {
130 return;
131 }
132
133 self.process_local_version(ev.get_local_version_information(), &packet);
134 }
135 _ => {}
136 },
137 _ => {}
138 },
139 PacketChild::NewIndex(ni) => {
140 self.process_new_index(ni, &packet);
141 }
142 _ => {}
143 }
144 }
145
report(&self, writer: &mut dyn Write)146 fn report(&self, writer: &mut dyn Write) {
147 if self.reportable.len() > 0 {
148 let _ = writeln!(writer, "Controller report:");
149 for (ts, message) in self.reportable.iter() {
150 let _ = writeln!(writer, "[{:?}] {}", ts, message);
151 }
152 }
153 }
154
report_signals(&self) -> &[Signal]155 fn report_signals(&self) -> &[Signal] {
156 self.signals.as_slice()
157 }
158 }
159
160 /// Get a rule group with connection rules.
get_controllers_group() -> RuleGroup161 pub fn get_controllers_group() -> RuleGroup {
162 let mut group = RuleGroup::new();
163 group.add_rule(Box::new(ControllerRule::new()));
164
165 group
166 }
167