1 ///! Rule group for general information.
2 use chrono::NaiveDateTime;
3 use std::cmp::Ordering;
4 use std::collections::{HashMap, HashSet};
5 use std::convert::Into;
6 use std::fmt;
7 use std::hash::Hash;
8 use std::io::Write;
9 
10 use crate::engine::{Rule, RuleGroup, Signal};
11 use crate::parser::{get_acl_content, AclContent, Packet, PacketChild};
12 use hcidoc_packets::hci::{
13     AclCommandChild, Address, CommandChild, ConnectionManagementCommandChild, DisconnectReason,
14     ErrorCode, EventChild, GapData, GapDataType, LeMetaEventChild,
15 };
16 use hcidoc_packets::l2cap::{ConnectionResponseResult, ControlChild};
17 
18 /// Valid values are in the range 0x0000-0x0EFF.
19 type ConnectionHandle = u16;
20 
21 type Psm = u16;
22 type Cid = u16;
23 
24 const INVALID_TS: NaiveDateTime = NaiveDateTime::MAX;
25 
print_start_end_timestamps(start: NaiveDateTime, end: NaiveDateTime) -> String26 fn print_start_end_timestamps(start: NaiveDateTime, end: NaiveDateTime) -> String {
27     fn print_time(ts: NaiveDateTime) -> String {
28         if ts == INVALID_TS {
29             return "N/A".to_owned();
30         }
31         return format!("{}", ts.time());
32     }
33 
34     if start == end && start != INVALID_TS {
35         return format!("{} - Failed", start.time());
36     }
37     return format!("{} to {}", print_time(start), print_time(end));
38 }
39 
40 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
41 enum AddressType {
42     None,
43     BREDR,
44     LE,
45     Dual,
46 }
47 
48 impl fmt::Display for AddressType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result49     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50         let str = match self {
51             AddressType::None => "Unknown type",
52             AddressType::BREDR => "BR/EDR",
53             AddressType::LE => "LE",
54             AddressType::Dual => "Dual",
55         };
56         write!(f, "{}", str)
57     }
58 }
59 
60 impl AddressType {
update(&mut self, new_type: AddressType)61     fn update(&mut self, new_type: AddressType) {
62         *self = match self {
63             AddressType::None => new_type,
64             AddressType::Dual => AddressType::Dual,
65             AddressType::BREDR => match new_type {
66                 AddressType::Dual | AddressType::LE => AddressType::Dual,
67                 _ => AddressType::BREDR,
68             },
69             AddressType::LE => match new_type {
70                 AddressType::Dual | AddressType::BREDR => AddressType::Dual,
71                 _ => AddressType::LE,
72             },
73         }
74     }
75 }
76 
77 #[derive(PartialEq)]
78 enum InitiatorType {
79     Unknown,
80     Host,
81     Peer,
82 }
83 
84 impl fmt::Display for InitiatorType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result85     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86         let str = match self {
87             InitiatorType::Unknown => "Unknown initiator",
88             InitiatorType::Host => "Host initiated",
89             InitiatorType::Peer => "Peer initiated",
90         };
91         write!(f, "{}", str)
92     }
93 }
94 
95 #[derive(Copy, Clone)]
96 enum AclState {
97     None,
98     Initiating,
99     Accepting,
100     Connected,
101 }
102 
103 impl Into<InitiatorType> for AclState {
into(self) -> InitiatorType104     fn into(self) -> InitiatorType {
105         match self {
106             AclState::Initiating => InitiatorType::Host,
107             AclState::Accepting => InitiatorType::Peer,
108             _ => InitiatorType::Unknown,
109         }
110     }
111 }
112 
113 /// Information about a specific device address
114 struct DeviceInformation {
115     names: HashSet<String>,
116     address: Address,
117     address_type: AddressType,
118     acls: Vec<AclInformation>,
119     acl_state: AclState,
120 }
121 
122 impl DeviceInformation {
new(address: Address) -> Self123     pub fn new(address: Address) -> Self {
124         DeviceInformation {
125             names: HashSet::new(),
126             address: address,
127             address_type: AddressType::None,
128             acls: vec![],
129             acl_state: AclState::None,
130         }
131     }
132 
is_connection_active(&self) -> bool133     fn is_connection_active(&self) -> bool {
134         // not empty and last connection's end time is not set.
135         return !self.acls.is_empty() && self.acls.last().unwrap().end_time == INVALID_TS;
136     }
137 
get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation138     fn get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation {
139         if !self.is_connection_active() {
140             let acl = AclInformation::new(*handle);
141             self.acls.push(acl);
142         }
143         return self.acls.last_mut().unwrap();
144     }
145 
report_connection_start(&mut self, handle: ConnectionHandle, ts: NaiveDateTime)146     fn report_connection_start(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) {
147         let mut acl = AclInformation::new(handle);
148         let initiator = self.acl_state.into();
149         acl.report_start(initiator, ts);
150         self.acls.push(acl);
151         self.acl_state = AclState::Connected;
152     }
153 
report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime)154     fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) {
155         let acl = self.get_or_allocate_connection(&handle);
156         acl.report_end(ts);
157         self.acl_state = AclState::None;
158     }
159 
print_names(names: &HashSet<String>) -> String160     fn print_names(names: &HashSet<String>) -> String {
161         if names.len() > 1 {
162             format!("{:?}", names)
163         } else {
164             names.iter().next().unwrap_or(&String::from("<Unknown name>")).to_owned()
165         }
166     }
167 }
168 
169 impl fmt::Display for DeviceInformation {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result170     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171         let _ = writeln!(
172             f,
173             "{address} ({address_type}, {device_names}), {num_connections} connections",
174             address = self.address,
175             address_type = self.address_type,
176             device_names = DeviceInformation::print_names(&self.names),
177             num_connections = self.acls.len()
178         );
179         for acl in &self.acls {
180             let _ = write!(f, "{}", acl);
181         }
182 
183         Ok(())
184     }
185 }
186 
187 #[derive(Debug)]
188 enum CidState {
189     Pending(Psm),
190     Connected(Cid, Psm),
191 }
192 
193 /// Information for an ACL connection session
194 struct AclInformation {
195     start_time: NaiveDateTime,
196     end_time: NaiveDateTime,
197     handle: ConnectionHandle,
198     initiator: InitiatorType,
199     active_profiles: HashMap<ProfileId, ProfileInformation>,
200     inactive_profiles: Vec<ProfileInformation>,
201     host_cids: HashMap<Cid, CidState>,
202     peer_cids: HashMap<Cid, CidState>,
203 }
204 
205 impl AclInformation {
new(handle: ConnectionHandle) -> Self206     pub fn new(handle: ConnectionHandle) -> Self {
207         AclInformation {
208             start_time: INVALID_TS,
209             end_time: INVALID_TS,
210             handle: handle,
211             initiator: InitiatorType::Unknown,
212             active_profiles: HashMap::new(),
213             inactive_profiles: vec![],
214             host_cids: HashMap::new(),
215             peer_cids: HashMap::new(),
216         }
217     }
218 
report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime)219     fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) {
220         self.initiator = initiator;
221         self.start_time = ts;
222     }
223 
report_end(&mut self, ts: NaiveDateTime)224     fn report_end(&mut self, ts: NaiveDateTime) {
225         // disconnect the active profiles
226         for (_, mut profile) in self.active_profiles.drain() {
227             profile.report_end(ts);
228             self.inactive_profiles.push(profile);
229         }
230         self.end_time = ts;
231     }
232 
report_profile_start( &mut self, profile_type: ProfileType, profile_id: ProfileId, initiator: InitiatorType, ts: NaiveDateTime, )233     fn report_profile_start(
234         &mut self,
235         profile_type: ProfileType,
236         profile_id: ProfileId,
237         initiator: InitiatorType,
238         ts: NaiveDateTime,
239     ) {
240         let mut profile = ProfileInformation::new(profile_type);
241         profile.report_start(initiator, ts);
242         let old_profile = self.active_profiles.insert(profile_id, profile);
243         if let Some(profile) = old_profile {
244             self.inactive_profiles.push(profile);
245         }
246     }
247 
report_profile_end( &mut self, profile_type: ProfileType, profile_id: ProfileId, ts: NaiveDateTime, )248     fn report_profile_end(
249         &mut self,
250         profile_type: ProfileType,
251         profile_id: ProfileId,
252         ts: NaiveDateTime,
253     ) {
254         let mut profile = self
255             .active_profiles
256             .remove(&profile_id)
257             .unwrap_or(ProfileInformation::new(profile_type));
258         profile.report_end(ts);
259         self.inactive_profiles.push(profile);
260     }
261 
report_l2cap_conn_req( &mut self, psm: Psm, cid: Cid, initiator: InitiatorType, _ts: NaiveDateTime, )262     fn report_l2cap_conn_req(
263         &mut self,
264         psm: Psm,
265         cid: Cid,
266         initiator: InitiatorType,
267         _ts: NaiveDateTime,
268     ) {
269         if initiator == InitiatorType::Host {
270             self.host_cids.insert(cid, CidState::Pending(psm));
271         } else if initiator == InitiatorType::Peer {
272             self.peer_cids.insert(cid, CidState::Pending(psm));
273         }
274     }
275 
276     // For pending connections, we report whether the PSM successfully connected and
277     // store the profile as started at this time.
report_l2cap_conn_rsp( &mut self, status: ConnectionResponseResult, host_cid: Cid, peer_cid: Cid, initiator: InitiatorType, ts: NaiveDateTime, )278     fn report_l2cap_conn_rsp(
279         &mut self,
280         status: ConnectionResponseResult,
281         host_cid: Cid,
282         peer_cid: Cid,
283         initiator: InitiatorType,
284         ts: NaiveDateTime,
285     ) {
286         let cid_state_option = match initiator {
287             InitiatorType::Host => self.host_cids.get(&host_cid),
288             InitiatorType::Peer => self.peer_cids.get(&peer_cid),
289             _ => None,
290         };
291 
292         let psm_option = match cid_state_option {
293             Some(cid_state) => match cid_state {
294                 CidState::Pending(psm) => Some(*psm),
295                 _ => None,
296             },
297             None => None,
298         };
299 
300         if let Some(psm) = psm_option {
301             let profile_option = ProfileType::from_psm(psm);
302             let profile_id = ProfileId::L2capCid(host_cid);
303             if status == ConnectionResponseResult::Success {
304                 self.host_cids.insert(host_cid, CidState::Connected(peer_cid, psm));
305                 self.peer_cids.insert(peer_cid, CidState::Connected(host_cid, psm));
306                 if let Some(profile) = profile_option {
307                     self.report_profile_start(profile, profile_id, initiator, ts);
308                 }
309             } else {
310                 // On failure, report start and end on the same time.
311                 if let Some(profile) = profile_option {
312                     self.report_profile_start(profile, profile_id, initiator, ts);
313                     self.report_profile_end(profile, profile_id, ts);
314                 }
315             }
316         } // TODO: debug on the else case.
317     }
318 
319     // L2cap disconnected so report profile connection closed if we were tracking it.
report_l2cap_disconn_rsp( &mut self, host_cid: Cid, peer_cid: Cid, _initiator: InitiatorType, ts: NaiveDateTime, )320     fn report_l2cap_disconn_rsp(
321         &mut self,
322         host_cid: Cid,
323         peer_cid: Cid,
324         _initiator: InitiatorType,
325         ts: NaiveDateTime,
326     ) {
327         let host_cid_state_option = self.host_cids.remove(&host_cid);
328         let host_psm = match host_cid_state_option {
329             Some(cid_state) => match cid_state {
330                 // TODO: assert that the peer cids match.
331                 CidState::Connected(_peer_cid, psm) => Some(psm),
332                 _ => None, // TODO: assert that state is connected.
333             },
334             None => None,
335         };
336 
337         let peer_cid_state_option = self.peer_cids.remove(&peer_cid);
338         let peer_psm = match peer_cid_state_option {
339             Some(cid_state) => match cid_state {
340                 // TODO: assert that the host cids match.
341                 CidState::Connected(_host_cid, psm) => Some(psm),
342                 _ => None, // TODO: assert that state is connected.
343             },
344             None => None,
345         };
346 
347         if host_psm != peer_psm {
348             eprintln!(
349                 "psm for host and peer mismatches at l2cap disc for handle {} at {}",
350                 self.handle, ts
351             );
352         }
353         let psm = match host_psm.or(peer_psm) {
354             Some(psm) => psm,
355             None => return, // No recorded PSM, no need to report.
356         };
357 
358         let profile_option = ProfileType::from_psm(psm);
359         if let Some(profile) = profile_option {
360             let profile_id = ProfileId::L2capCid(host_cid);
361             self.report_profile_end(profile, profile_id, ts)
362         }
363     }
364 }
365 
366 impl fmt::Display for AclInformation {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result367     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368         let _ = writeln!(
369             f,
370             "  Handle: {handle}, {initiator}, {timestamp_info}",
371             handle = self.handle,
372             initiator = self.initiator,
373             timestamp_info = print_start_end_timestamps(self.start_time, self.end_time)
374         );
375 
376         for profile in self.inactive_profiles.iter() {
377             let _ = write!(f, "{}", profile);
378         }
379         for (_, profile) in self.active_profiles.iter() {
380             let _ = write!(f, "{}", profile);
381         }
382 
383         Ok(())
384     }
385 }
386 
387 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
388 enum ProfileType {
389     Att,
390     Avctp,
391     Avdtp,
392     Eatt,
393     Hfp,
394     HidCtrl,
395     HidIntr,
396     Rfcomm,
397     Sdp,
398 }
399 
400 impl fmt::Display for ProfileType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result401     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402         let str = match self {
403             ProfileType::Att => "ATT",
404             ProfileType::Avctp => "AVCTP",
405             ProfileType::Avdtp => "AVDTP",
406             ProfileType::Eatt => "EATT",
407             ProfileType::Hfp => "HFP",
408             ProfileType::HidCtrl => "HID CTRL",
409             ProfileType::HidIntr => "HID INTR",
410             ProfileType::Rfcomm => "RFCOMM",
411             ProfileType::Sdp => "SDP",
412         };
413         write!(f, "{}", str)
414     }
415 }
416 
417 impl ProfileType {
from_psm(psm: Psm) -> Option<Self>418     fn from_psm(psm: Psm) -> Option<Self> {
419         match psm {
420             1 => Some(ProfileType::Sdp),
421             3 => Some(ProfileType::Rfcomm),
422             17 => Some(ProfileType::HidCtrl),
423             19 => Some(ProfileType::HidIntr),
424             23 => Some(ProfileType::Avctp),
425             25 => Some(ProfileType::Avdtp),
426             31 => Some(ProfileType::Att),
427             39 => Some(ProfileType::Eatt),
428             _ => None,
429         }
430     }
431 }
432 
433 // Use to distinguish between the same profiles within one ACL connection.
434 // Later we can add RFCOMM's DLCI, for example.
435 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
436 enum ProfileId {
437     OnePerConnection(ProfileType),
438     L2capCid(Cid),
439 }
440 
441 struct ProfileInformation {
442     start_time: NaiveDateTime,
443     end_time: NaiveDateTime,
444     profile_type: ProfileType,
445     initiator: InitiatorType,
446 }
447 
448 impl ProfileInformation {
new(profile_type: ProfileType) -> Self449     pub fn new(profile_type: ProfileType) -> Self {
450         ProfileInformation {
451             start_time: INVALID_TS,
452             end_time: INVALID_TS,
453             profile_type: profile_type,
454             initiator: InitiatorType::Unknown,
455         }
456     }
457 
report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime)458     fn report_start(&mut self, initiator: InitiatorType, ts: NaiveDateTime) {
459         self.initiator = initiator;
460         self.start_time = ts;
461     }
462 
report_end(&mut self, ts: NaiveDateTime)463     fn report_end(&mut self, ts: NaiveDateTime) {
464         self.end_time = ts;
465     }
466 }
467 
468 impl fmt::Display for ProfileInformation {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result469     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470         writeln!(
471             f,
472             "    {profile}, {initiator}, {timestamp_info}",
473             profile = self.profile_type,
474             initiator = self.initiator,
475             timestamp_info = print_start_end_timestamps(self.start_time, self.end_time)
476         )
477     }
478 }
479 
480 /// This rule prints devices names and connection/disconnection time.
481 struct InformationalRule {
482     devices: HashMap<Address, DeviceInformation>,
483     handles: HashMap<ConnectionHandle, Address>,
484     sco_handles: HashMap<ConnectionHandle, ConnectionHandle>,
485     /// unknownConnections store connections which is initiated before btsnoop starts.
486     unknown_connections: HashMap<ConnectionHandle, AclInformation>,
487     /// When powering off, the controller might or might not reply disconnection request. Therefore
488     /// make this a special case.
489     pending_disconnect_due_to_host_power_off: HashSet<ConnectionHandle>,
490 }
491 
492 impl InformationalRule {
new() -> Self493     pub fn new() -> Self {
494         InformationalRule {
495             devices: HashMap::new(),
496             handles: HashMap::new(),
497             sco_handles: HashMap::new(),
498             unknown_connections: HashMap::new(),
499             pending_disconnect_due_to_host_power_off: HashSet::new(),
500         }
501     }
502 
get_or_allocate_device(&mut self, address: &Address) -> &mut DeviceInformation503     fn get_or_allocate_device(&mut self, address: &Address) -> &mut DeviceInformation {
504         if !self.devices.contains_key(address) {
505             self.devices.insert(*address, DeviceInformation::new(*address));
506         }
507         return self.devices.get_mut(address).unwrap();
508     }
509 
get_or_allocate_unknown_connection( &mut self, handle: &ConnectionHandle, ) -> &mut AclInformation510     fn get_or_allocate_unknown_connection(
511         &mut self,
512         handle: &ConnectionHandle,
513     ) -> &mut AclInformation {
514         if !self.unknown_connections.contains_key(handle) {
515             self.unknown_connections.insert(*handle, AclInformation::new(*handle));
516         }
517         return self.unknown_connections.get_mut(handle).unwrap();
518     }
519 
get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation520     fn get_or_allocate_connection(&mut self, handle: &ConnectionHandle) -> &mut AclInformation {
521         if !self.handles.contains_key(&handle) {
522             let conn = self.get_or_allocate_unknown_connection(&handle);
523             return conn;
524         }
525 
526         let address = &self.handles.get(handle).unwrap().clone();
527         let device = self.get_or_allocate_device(address);
528         return device.get_or_allocate_connection(handle);
529     }
530 
report_address_type(&mut self, address: &Address, address_type: AddressType)531     fn report_address_type(&mut self, address: &Address, address_type: AddressType) {
532         let device = self.get_or_allocate_device(address);
533         device.address_type.update(address_type);
534     }
535 
report_name(&mut self, address: &Address, name: &String)536     fn report_name(&mut self, address: &Address, name: &String) {
537         let device = self.get_or_allocate_device(address);
538         device.names.insert(name.into());
539     }
540 
report_acl_state(&mut self, address: &Address, state: AclState)541     fn report_acl_state(&mut self, address: &Address, state: AclState) {
542         let device = self.get_or_allocate_device(address);
543         device.acl_state = state;
544     }
545 
report_connection_start( &mut self, address: &Address, handle: ConnectionHandle, ts: NaiveDateTime, )546     fn report_connection_start(
547         &mut self,
548         address: &Address,
549         handle: ConnectionHandle,
550         ts: NaiveDateTime,
551     ) {
552         let device = self.get_or_allocate_device(address);
553         device.report_connection_start(handle, ts);
554         self.handles.insert(handle, *address);
555         self.pending_disconnect_due_to_host_power_off.remove(&handle);
556     }
557 
report_sco_connection_start( &mut self, address: &Address, handle: ConnectionHandle, ts: NaiveDateTime, )558     fn report_sco_connection_start(
559         &mut self,
560         address: &Address,
561         handle: ConnectionHandle,
562         ts: NaiveDateTime,
563     ) {
564         if !self.devices.contains_key(address) {
565             // To simplify things, let's not process unknown devices
566             return;
567         }
568 
569         let device = self.devices.get_mut(address).unwrap();
570         if !device.is_connection_active() {
571             // SCO is connected, but ACL is not. This is weird, but let's ignore for simplicity.
572             eprintln!("[{}] SCO is connected, but ACL is not.", address);
573             return;
574         }
575 
576         // Whatever handle value works here - we aren't allocating a new one.
577         let acl = device.get_or_allocate_connection(&0);
578         let acl_handle = acl.handle;
579         // We need to listen the HCI commands to determine the correct initiator.
580         // Here we just assume host for simplicity.
581         acl.report_profile_start(
582             ProfileType::Hfp,
583             ProfileId::OnePerConnection(ProfileType::Hfp),
584             InitiatorType::Host,
585             ts,
586         );
587 
588         self.sco_handles.insert(handle, acl_handle);
589     }
590 
report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime)591     fn report_connection_end(&mut self, handle: ConnectionHandle, ts: NaiveDateTime) {
592         // This might be a SCO disconnection event, so check that first
593         if self.sco_handles.contains_key(&handle) {
594             let acl_handle = self.sco_handles[&handle];
595             let conn = self.get_or_allocate_connection(&acl_handle);
596             conn.report_profile_end(
597                 ProfileType::Hfp,
598                 ProfileId::OnePerConnection(ProfileType::Hfp),
599                 ts,
600             );
601             return;
602         }
603 
604         // Not recognized as SCO, assume it's an ACL handle.
605         if let Some(address) = self.handles.get(&handle) {
606             // This device is known
607             let device = self.devices.get_mut(address).unwrap();
608             device.report_connection_end(handle, ts);
609             self.handles.remove(&handle);
610 
611             // remove the associated SCO handle, if any
612             self.sco_handles.retain(|_sco_handle, acl_handle| *acl_handle != handle);
613         } else {
614             // Unknown device.
615             let conn = self.get_or_allocate_unknown_connection(&handle);
616             conn.report_end(ts);
617         }
618     }
619 
report_reset(&mut self, ts: NaiveDateTime)620     fn report_reset(&mut self, ts: NaiveDateTime) {
621         // report_connection_end removes the entries from the map, so store all the keys first.
622         let handles: Vec<ConnectionHandle> = self.handles.keys().cloned().collect();
623         for handle in handles {
624             self.report_connection_end(handle, ts);
625         }
626         self.sco_handles.clear();
627         self.pending_disconnect_due_to_host_power_off.clear();
628     }
629 
process_gap_data(&mut self, address: &Address, data: &GapData)630     fn process_gap_data(&mut self, address: &Address, data: &GapData) {
631         match data.data_type {
632             GapDataType::CompleteLocalName | GapDataType::ShortenedLocalName => {
633                 let name = String::from_utf8_lossy(data.data.as_slice()).into_owned();
634                 self.report_name(address, &name);
635             }
636 
637             _ => {}
638         }
639     }
640 
process_raw_gap_data(&mut self, address: &Address, data: &[u8])641     fn process_raw_gap_data(&mut self, address: &Address, data: &[u8]) {
642         let mut offset = 0;
643         while offset < data.len() {
644             let chunk_size = usize::from(data[offset]);
645             let chunk_end = offset + chunk_size + 1;
646 
647             // Prevent out-of-bounds index
648             if chunk_end > data.len() {
649                 return;
650             }
651             match GapData::parse(&data[offset..chunk_end]) {
652                 Ok(gap_data) => self.process_gap_data(&address, &gap_data),
653                 Err(_err) => {}
654             }
655             offset = chunk_end;
656         }
657     }
658 
report_l2cap_conn_req( &mut self, handle: ConnectionHandle, psm: Psm, cid: Cid, initiator: InitiatorType, ts: NaiveDateTime, )659     fn report_l2cap_conn_req(
660         &mut self,
661         handle: ConnectionHandle,
662         psm: Psm,
663         cid: Cid,
664         initiator: InitiatorType,
665         ts: NaiveDateTime,
666     ) {
667         let conn = self.get_or_allocate_connection(&handle);
668         conn.report_l2cap_conn_req(psm, cid, initiator, ts);
669     }
670 
report_l2cap_conn_rsp( &mut self, handle: ConnectionHandle, status: ConnectionResponseResult, host_cid: Cid, peer_cid: Cid, initiator: InitiatorType, ts: NaiveDateTime, )671     fn report_l2cap_conn_rsp(
672         &mut self,
673         handle: ConnectionHandle,
674         status: ConnectionResponseResult,
675         host_cid: Cid,
676         peer_cid: Cid,
677         initiator: InitiatorType,
678         ts: NaiveDateTime,
679     ) {
680         if status == ConnectionResponseResult::Pending {
681             return;
682         }
683         let conn = self.get_or_allocate_connection(&handle);
684         conn.report_l2cap_conn_rsp(status, host_cid, peer_cid, initiator, ts);
685     }
686 
report_l2cap_disconn_rsp( &mut self, handle: ConnectionHandle, host_cid: Cid, peer_cid: Cid, initiator: InitiatorType, ts: NaiveDateTime, )687     fn report_l2cap_disconn_rsp(
688         &mut self,
689         handle: ConnectionHandle,
690         host_cid: Cid,
691         peer_cid: Cid,
692         initiator: InitiatorType,
693         ts: NaiveDateTime,
694     ) {
695         let conn = self.get_or_allocate_connection(&handle);
696         conn.report_l2cap_disconn_rsp(host_cid, peer_cid, initiator, ts);
697     }
698 }
699 
700 impl Rule for InformationalRule {
process(&mut self, packet: &Packet)701     fn process(&mut self, packet: &Packet) {
702         match &packet.inner {
703             PacketChild::HciEvent(ev) => match ev.specialize() {
704                 EventChild::ConnectionComplete(ev) => {
705                     self.report_connection_start(
706                         &ev.get_bd_addr(),
707                         ev.get_connection_handle(),
708                         packet.ts,
709                     );
710 
711                     // If failed, assume it's the end of connection.
712                     if ev.get_status() != ErrorCode::Success {
713                         self.report_connection_end(ev.get_connection_handle(), packet.ts);
714                     }
715                 }
716 
717                 EventChild::SynchronousConnectionComplete(ev) => {
718                     self.report_sco_connection_start(
719                         &ev.get_bd_addr(),
720                         ev.get_connection_handle(),
721                         packet.ts,
722                     );
723                     // If failed, assume it's the end of connection.
724                     if ev.get_status() != ErrorCode::Success {
725                         self.report_connection_end(ev.get_connection_handle(), packet.ts);
726                     }
727                 }
728 
729                 EventChild::DisconnectionComplete(ev) => {
730                     // If disconnected because host is powering off, the event has been processed.
731                     // We can't just query the reason here because it's different across vendors.
732                     if !self
733                         .pending_disconnect_due_to_host_power_off
734                         .remove(&ev.get_connection_handle())
735                     {
736                         self.report_connection_end(ev.get_connection_handle(), packet.ts);
737                     }
738                 }
739 
740                 EventChild::ExtendedInquiryResult(ev) => {
741                     for data in ev.get_extended_inquiry_response() {
742                         self.process_gap_data(&ev.get_address(), data);
743                     }
744                     self.report_address_type(&ev.get_address(), AddressType::BREDR);
745                 }
746 
747                 EventChild::RemoteNameRequestComplete(ev) => {
748                     if ev.get_status() != ErrorCode::Success {
749                         return;
750                     }
751                     let name = String::from_utf8_lossy(ev.get_remote_name());
752                     let name = name.trim_end_matches(char::from(0));
753                     self.report_name(&ev.get_bd_addr(), &name.to_owned());
754                     self.report_address_type(&ev.get_bd_addr(), AddressType::BREDR);
755                 }
756 
757                 EventChild::LeMetaEvent(ev) => match ev.specialize() {
758                     LeMetaEventChild::LeConnectionComplete(ev) => {
759                         if ev.get_status() != ErrorCode::Success {
760                             return;
761                         }
762 
763                         // Determining LE initiator is complex, for simplicity assume host inits.
764                         self.report_acl_state(&ev.get_peer_address(), AclState::Initiating);
765                         self.report_connection_start(
766                             &ev.get_peer_address(),
767                             ev.get_connection_handle(),
768                             packet.ts,
769                         );
770                         self.report_address_type(&ev.get_peer_address(), AddressType::LE);
771                     }
772 
773                     LeMetaEventChild::LeEnhancedConnectionComplete(ev) => {
774                         if ev.get_status() != ErrorCode::Success {
775                             return;
776                         }
777 
778                         // Determining LE initiator is complex, for simplicity assume host inits.
779                         self.report_acl_state(&ev.get_peer_address(), AclState::Initiating);
780                         self.report_connection_start(
781                             &ev.get_peer_address(),
782                             ev.get_connection_handle(),
783                             packet.ts,
784                         );
785                         self.report_address_type(&ev.get_peer_address(), AddressType::LE);
786                     }
787 
788                     // Use the Raw version because somehow LeAdvertisingReport doesn't work
789                     LeMetaEventChild::LeAdvertisingReportRaw(ev) => {
790                         for resp in ev.get_responses() {
791                             self.process_raw_gap_data(&resp.address, &resp.advertising_data);
792                             self.report_address_type(&resp.address, AddressType::LE);
793                         }
794                     }
795 
796                     // Use the Raw version because somehow LeExtendedAdvertisingReport doesn't work
797                     LeMetaEventChild::LeExtendedAdvertisingReportRaw(ev) => {
798                         for resp in ev.get_responses() {
799                             self.process_raw_gap_data(&resp.address, &resp.advertising_data);
800                             self.report_address_type(&resp.address, AddressType::LE);
801                         }
802                     }
803 
804                     // EventChild::LeMetaEvent(ev).specialize()
805                     _ => {}
806                 },
807 
808                 // PacketChild::HciEvent(ev) => match ev.specialize()
809                 _ => {}
810             },
811 
812             PacketChild::HciCommand(cmd) => match cmd.specialize() {
813                 CommandChild::Reset(_cmd) => {
814                     self.report_reset(packet.ts);
815                 }
816 
817                 CommandChild::AclCommand(cmd) => match cmd.specialize() {
818                     AclCommandChild::ConnectionManagementCommand(cmd) => match cmd.specialize() {
819                         ConnectionManagementCommandChild::CreateConnection(cmd) => {
820                             self.report_acl_state(&cmd.get_bd_addr(), AclState::Initiating);
821                             self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR);
822                         }
823 
824                         ConnectionManagementCommandChild::AcceptConnectionRequest(cmd) => {
825                             self.report_acl_state(&cmd.get_bd_addr(), AclState::Accepting);
826                             self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR);
827                         }
828 
829                         // AclCommandChild::ConnectionManagementCommand(cmd).specialize()
830                         _ => {}
831                     },
832 
833                     AclCommandChild::Disconnect(cmd) => {
834                         // If reason is power off, the host might not wait for connection complete event
835                         if cmd.get_reason()
836                             == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff
837                         {
838                             self.pending_disconnect_due_to_host_power_off
839                                 .insert(cmd.get_connection_handle());
840                             self.report_connection_end(cmd.get_connection_handle(), packet.ts);
841                         }
842                     }
843 
844                     // CommandChild::AclCommand(cmd).specialize()
845                     _ => {}
846                 },
847 
848                 // PacketChild::HciCommand(cmd).specialize()
849                 _ => {}
850             },
851 
852             PacketChild::AclTx(tx) => {
853                 let content = get_acl_content(tx);
854                 match content {
855                     AclContent::Control(control) => match control.specialize() {
856                         ControlChild::ConnectionRequest(creq) => {
857                             self.report_l2cap_conn_req(
858                                 tx.get_handle(),
859                                 creq.get_psm(),
860                                 creq.get_source_cid(),
861                                 InitiatorType::Host,
862                                 packet.ts,
863                             );
864                         }
865                         ControlChild::ConnectionResponse(crsp) => {
866                             self.report_l2cap_conn_rsp(
867                                 tx.get_handle(),
868                                 crsp.get_result(),
869                                 crsp.get_destination_cid(),
870                                 crsp.get_source_cid(),
871                                 InitiatorType::Peer,
872                                 packet.ts,
873                             );
874                         }
875                         ControlChild::DisconnectionResponse(drsp) => {
876                             self.report_l2cap_disconn_rsp(
877                                 tx.get_handle(),
878                                 drsp.get_destination_cid(),
879                                 drsp.get_source_cid(),
880                                 InitiatorType::Peer,
881                                 packet.ts,
882                             );
883                         }
884 
885                         // AclContent::Control.specialize()
886                         _ => {}
887                     },
888 
889                     // PacketChild::AclTx(tx).specialize()
890                     _ => {}
891                 }
892             }
893 
894             PacketChild::AclRx(rx) => {
895                 let content = get_acl_content(rx);
896                 match content {
897                     AclContent::Control(control) => match control.specialize() {
898                         ControlChild::ConnectionRequest(creq) => {
899                             self.report_l2cap_conn_req(
900                                 rx.get_handle(),
901                                 creq.get_psm(),
902                                 creq.get_source_cid(),
903                                 InitiatorType::Peer,
904                                 packet.ts,
905                             );
906                         }
907                         ControlChild::ConnectionResponse(crsp) => {
908                             self.report_l2cap_conn_rsp(
909                                 rx.get_handle(),
910                                 crsp.get_result(),
911                                 crsp.get_source_cid(),
912                                 crsp.get_destination_cid(),
913                                 InitiatorType::Host,
914                                 packet.ts,
915                             );
916                         }
917                         ControlChild::DisconnectionResponse(drsp) => {
918                             self.report_l2cap_disconn_rsp(
919                                 rx.get_handle(),
920                                 drsp.get_source_cid(),
921                                 drsp.get_destination_cid(),
922                                 InitiatorType::Host,
923                                 packet.ts,
924                             );
925                         }
926 
927                         // AclContent::Control.specialize()
928                         _ => {}
929                     },
930 
931                     // PacketChild::AclRx(rx).specialize()
932                     _ => {}
933                 }
934             }
935 
936             // End packet.inner match
937             _ => (),
938         }
939     }
940 
report(&self, writer: &mut dyn Write)941     fn report(&self, writer: &mut dyn Write) {
942         /* Sort when displaying the addresses, from the most to the least important:
943          * (1) Device with connections > Device without connections
944          * (2) Device with known name > Device with unknown name
945          * (3) BREDR > LE > Dual
946          * (4) Name, lexicographically (case sensitive)
947          * (5) Address, alphabetically
948          */
949         fn sort_addresses(a: &DeviceInformation, b: &DeviceInformation) -> Ordering {
950             let connection_order = a.acls.is_empty().cmp(&b.acls.is_empty());
951             if connection_order != Ordering::Equal {
952                 return connection_order;
953             }
954 
955             let known_name_order = a.names.is_empty().cmp(&b.names.is_empty());
956             if known_name_order != Ordering::Equal {
957                 return known_name_order;
958             }
959 
960             let address_type_order = a.address_type.cmp(&b.address_type);
961             if address_type_order != Ordering::Equal {
962                 return address_type_order;
963             }
964 
965             let a_name = format!("{}", DeviceInformation::print_names(&a.names));
966             let b_name = format!("{}", DeviceInformation::print_names(&b.names));
967             let name_order = a_name.cmp(&b_name);
968             if name_order != Ordering::Equal {
969                 return name_order;
970             }
971 
972             let a_address = <[u8; 6]>::from(a.address);
973             let b_address = <[u8; 6]>::from(b.address);
974             for i in (0..6).rev() {
975                 let address_order = a_address[i].cmp(&b_address[i]);
976                 if address_order != Ordering::Equal {
977                     return address_order;
978                 }
979             }
980             // This shouldn't be executed
981             return Ordering::Equal;
982         }
983 
984         if self.devices.is_empty() && self.unknown_connections.is_empty() {
985             return;
986         }
987 
988         let mut addresses: Vec<Address> = self.devices.keys().cloned().collect();
989         addresses.sort_unstable_by(|a, b| sort_addresses(&self.devices[a], &self.devices[b]));
990 
991         let _ = writeln!(writer, "InformationalRule report:");
992         if !self.unknown_connections.is_empty() {
993             let _ = writeln!(
994                 writer,
995                 "Connections initiated before snoop start, {} connections",
996                 self.unknown_connections.len()
997             );
998             for (_, acl) in &self.unknown_connections {
999                 let _ = write!(writer, "{}", acl);
1000             }
1001         }
1002         for address in addresses {
1003             let _ = write!(writer, "{}", self.devices[&address]);
1004         }
1005     }
1006 
report_signals(&self) -> &[Signal]1007     fn report_signals(&self) -> &[Signal] {
1008         &[]
1009     }
1010 }
1011 
1012 /// Get a rule group with collision rules.
get_informational_group() -> RuleGroup1013 pub fn get_informational_group() -> RuleGroup {
1014     let mut group = RuleGroup::new();
1015     group.add_rule(Box::new(InformationalRule::new()));
1016 
1017     group
1018 }
1019