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