1 ///! Rule group for tracking controller related issues.
2 use chrono::NaiveDateTime;
3 use std::collections::HashSet;
4 use std::convert::Into;
5 use std::io::Write;
6 use std::sync::LazyLock;
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 static KNOWN_CONTROLLER_NAMES: LazyLock<[String; 6]> = LazyLock::new(|| {
27     [
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 
37 const KNOWN_CONTROLLER_MANUFACTURERS: [u16; 5] = [
38     2,  // Intel.
39     29, // Qualcomm
40     70, // MediaTek
41     72, // Marvell
42     93, // Realtek
43 ];
44 
45 struct ControllerRule {
46     /// Pre-defined signals discovered in the logs.
47     signals: Vec<Signal>,
48 
49     /// Interesting occurrences surfaced by this rule.
50     reportable: Vec<(NaiveDateTime, String)>,
51 
52     /// All detected open_index.
53     controllers: HashSet<String>,
54 }
55 
56 impl ControllerRule {
new() -> Self57     pub fn new() -> Self {
58         ControllerRule { signals: vec![], reportable: vec![], controllers: HashSet::new() }
59     }
60 
report_hardware_error(&mut self, packet: &Packet)61     pub fn report_hardware_error(&mut self, packet: &Packet) {
62         self.signals.push(Signal {
63             index: packet.index,
64             ts: packet.ts.clone(),
65             tag: ControllerSignal::HardwareError.into(),
66         });
67 
68         self.reportable.push((packet.ts, format!("controller reported hardware error")));
69     }
70 
process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet)71     fn process_local_name(&mut self, local_name: &[u8; 248], packet: &Packet) {
72         let null_index = local_name.iter().position(|&b| b == 0).unwrap_or(local_name.len());
73         match String::from_utf8(local_name[..null_index].to_vec()) {
74             Ok(name) => {
75                 if !KNOWN_CONTROLLER_NAMES.contains(&name) {
76                     self.signals.push(Signal {
77                         index: packet.index,
78                         ts: packet.ts,
79                         tag: ControllerSignal::LikelyExternalController.into(),
80                     })
81                 }
82             }
83             Err(_) => self.signals.push(Signal {
84                 index: packet.index,
85                 ts: packet.ts,
86                 tag: ControllerSignal::LikelyExternalController.into(),
87             }),
88         }
89     }
90 
process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet)91     fn process_local_version(&mut self, version_info: &LocalVersionInformation, packet: &Packet) {
92         if !KNOWN_CONTROLLER_MANUFACTURERS.contains(&version_info.manufacturer_name) {
93             self.signals.push(Signal {
94                 index: packet.index,
95                 ts: packet.ts,
96                 tag: ControllerSignal::LikelyExternalController.into(),
97             })
98         }
99     }
100 
process_new_index(&mut self, new_index: &NewIndex, packet: &Packet)101     fn process_new_index(&mut self, new_index: &NewIndex, packet: &Packet) {
102         self.controllers.insert(new_index.get_addr_str());
103 
104         if self.controllers.len() > 1 {
105             self.signals.push(Signal {
106                 index: packet.index,
107                 ts: packet.ts,
108                 tag: ControllerSignal::LikelyExternalController.into(),
109             });
110         }
111     }
112 }
113 
114 impl Rule for ControllerRule {
process(&mut self, packet: &Packet)115     fn process(&mut self, packet: &Packet) {
116         match &packet.inner {
117             PacketChild::HciEvent(ev) => match ev.specialize() {
118                 EventChild::HardwareError(_ev) => {
119                     self.report_hardware_error(&packet);
120                 }
121                 EventChild::CommandComplete(ev) => match ev.specialize() {
122                     CommandCompleteChild::ReadLocalNameComplete(ev) => {
123                         if ev.get_status() != ErrorCode::Success {
124                             return;
125                         }
126 
127                         self.process_local_name(ev.get_local_name(), &packet);
128                     }
129                     CommandCompleteChild::ReadLocalVersionInformationComplete(ev) => {
130                         if ev.get_status() != ErrorCode::Success {
131                             return;
132                         }
133 
134                         self.process_local_version(ev.get_local_version_information(), &packet);
135                     }
136                     _ => {}
137                 },
138                 _ => {}
139             },
140             PacketChild::NewIndex(ni) => {
141                 self.process_new_index(ni, &packet);
142             }
143             _ => {}
144         }
145     }
146 
report(&self, writer: &mut dyn Write)147     fn report(&self, writer: &mut dyn Write) {
148         if self.reportable.len() > 0 {
149             let _ = writeln!(writer, "Controller report:");
150             for (ts, message) in self.reportable.iter() {
151                 let _ = writeln!(writer, "[{:?}] {}", ts, message);
152             }
153         }
154     }
155 
report_signals(&self) -> &[Signal]156     fn report_signals(&self) -> &[Signal] {
157         self.signals.as_slice()
158     }
159 }
160 
161 /// Get a rule group with connection rules.
get_controllers_group() -> RuleGroup162 pub fn get_controllers_group() -> RuleGroup {
163     let mut group = RuleGroup::new();
164     group.add_rule(Box::new(ControllerRule::new()));
165 
166     group
167 }
168