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