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