1 //! Parsing of various Bluetooth packets.
2 use chrono::{DateTime, NaiveDateTime};
3 use num_derive::{FromPrimitive, ToPrimitive};
4 use num_traits::cast::FromPrimitive;
5 use std::convert::TryFrom;
6 use std::fs::File;
7 use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
8 
9 use hcidoc_packets::hci::{Acl, AclChild, Command, Event};
10 use hcidoc_packets::l2cap::{
11     BasicFrame, BasicFrameChild, Control, ControlFrameChild, GroupFrameChild, LeControl,
12     LeControlFrameChild,
13 };
14 
15 /// Snoop file header format.
16 #[derive(Debug)]
17 pub struct SnoopHeader {
18     _id: [u8; 8],
19     _version: u32,
20     datalink_type: SnoopDatalinkType,
21 }
22 
23 /// Identifier for a snoop file. In ASCII, this is 'btsnoop\0'.
24 const SNOOP_MAGIC: [u8; 8] = [0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00];
25 
26 /// Size of snoop header. 8 bytes for magic, 4 bytes for version, and 4 bytes for snoop type.
27 const SNOOP_HEADER_SIZE: usize = 16;
28 
29 #[derive(Debug, FromPrimitive, ToPrimitive)]
30 #[repr(u32)]
31 enum SnoopDatalinkType {
32     H4Uart = 1002,
33     LinuxMonitor = 2001,
34 }
35 
36 impl TryFrom<&[u8]> for SnoopHeader {
37     type Error = String;
38 
try_from(item: &[u8]) -> Result<Self, Self::Error>39     fn try_from(item: &[u8]) -> Result<Self, Self::Error> {
40         if item.len() != SNOOP_HEADER_SIZE {
41             return Err(format!("Invalid size for snoop header: {}", item.len()));
42         }
43 
44         let rest = item;
45         let (id_bytes, rest) = rest.split_at(8);
46         let (version_bytes, rest) = rest.split_at(std::mem::size_of::<u32>());
47         let (data_type_bytes, _rest) = rest.split_at(std::mem::size_of::<u32>());
48 
49         let id = id_bytes.try_into().unwrap();
50         let version = u32::from_be_bytes(version_bytes.try_into().unwrap());
51         let data_type = u32::from_be_bytes(data_type_bytes.try_into().unwrap());
52 
53         if id != SNOOP_MAGIC {
54             return Err(format!("Id is not 'btsnoop'."));
55         }
56 
57         if version != 1 {
58             return Err(format!("Version is not supported. Got {}.", version));
59         }
60 
61         let datalink_type = match SnoopDatalinkType::from_u32(data_type) {
62             Some(datalink_type) => datalink_type,
63             None => return Err(format!("Unsupported datalink type {}", data_type)),
64         };
65 
66         return Ok(SnoopHeader { _id: id, _version: version, datalink_type });
67     }
68 }
69 
70 /// Opcodes for snoop packets.
71 #[derive(Debug, FromPrimitive, ToPrimitive)]
72 #[repr(u16)]
73 pub enum SnoopOpcodes {
74     NewIndex = 0,
75     DeleteIndex,
76     Command,
77     Event,
78     AclTxPacket,
79     AclRxPacket,
80     ScoTxPacket,
81     ScoRxPacket,
82     OpenIndex,
83     CloseIndex,
84     IndexInfo,
85     VendorDiag,
86     SystemNote,
87     UserLogging,
88     CtrlOpen,
89     CtrlClose,
90     CtrlCommand,
91     CtrlEvent,
92     IsoTx,
93     IsoRx,
94 
95     Invalid = 0xffff,
96 }
97 
98 /// Size of packet preamble (everything except the data).
99 const SNOOP_PACKET_PREAMBLE_SIZE: usize = 24;
100 
101 /// Number of microseconds from btsnoop zero to Linux epoch.
102 const SNOOP_Y0_TO_Y1970_US: i64 = 62_168_256_000_000_000;
103 
104 /// Snoop file packet format.
105 #[derive(Debug, Clone)]
106 #[allow(dead_code)]
107 pub struct SnoopPacketPreamble {
108     /// The original length of the captured packet as received via a network.
109     pub original_length: u32,
110 
111     /// The length of the included data (can be smaller than original_length if
112     /// the received packet was truncated).
113     pub included_length: u32,
114     pub flags: u32,
115     pub drops: u32,
116     pub timestamp_us: u64,
117 }
118 
119 impl SnoopPacketPreamble {
from_fd<'a>(fd: &mut Box<dyn BufRead + 'a>) -> Option<SnoopPacketPreamble>120     fn from_fd<'a>(fd: &mut Box<dyn BufRead + 'a>) -> Option<SnoopPacketPreamble> {
121         let mut buf = [0u8; SNOOP_PACKET_PREAMBLE_SIZE];
122         match fd.read_exact(&mut buf) {
123             Ok(()) => {}
124             Err(e) => {
125                 // |UnexpectedEof| could be seen since we're trying to read more
126                 // data than is available (i.e. end of file).
127                 if e.kind() != ErrorKind::UnexpectedEof {
128                     eprintln!("Error reading preamble: {:?}", e);
129                 }
130                 return None;
131             }
132         };
133 
134         match SnoopPacketPreamble::try_from(&buf[0..SNOOP_PACKET_PREAMBLE_SIZE]) {
135             Ok(preamble) => Some(preamble),
136             Err(e) => {
137                 eprintln!("Error reading preamble: {}", e);
138                 None
139             }
140         }
141     }
142 }
143 
144 impl TryFrom<&[u8]> for SnoopPacketPreamble {
145     type Error = String;
146 
try_from(item: &[u8]) -> Result<Self, Self::Error>147     fn try_from(item: &[u8]) -> Result<Self, Self::Error> {
148         if item.len() != SNOOP_PACKET_PREAMBLE_SIZE {
149             return Err(format!("Wrong size for snoop packet preamble: {}", item.len()));
150         }
151 
152         let rest = item;
153         let (orig_len_bytes, rest) = rest.split_at(std::mem::size_of::<u32>());
154         let (included_len_bytes, rest) = rest.split_at(std::mem::size_of::<u32>());
155         let (flags_bytes, rest) = rest.split_at(std::mem::size_of::<u32>());
156         let (drops_bytes, rest) = rest.split_at(std::mem::size_of::<u32>());
157         let (ts_bytes, _rest) = rest.split_at(std::mem::size_of::<u64>());
158 
159         // Note that all bytes are in big-endian because they're network order.
160         let preamble = SnoopPacketPreamble {
161             original_length: u32::from_be_bytes(orig_len_bytes.try_into().unwrap()),
162             included_length: u32::from_be_bytes(included_len_bytes.try_into().unwrap()),
163             flags: u32::from_be_bytes(flags_bytes.try_into().unwrap()),
164             drops: u32::from_be_bytes(drops_bytes.try_into().unwrap()),
165             timestamp_us: u64::from_be_bytes(ts_bytes.try_into().unwrap()),
166         };
167 
168         Ok(preamble)
169     }
170 }
171 
172 pub trait GeneralSnoopPacket {
adapter_index(&self) -> u16173     fn adapter_index(&self) -> u16;
opcode(&self) -> SnoopOpcodes174     fn opcode(&self) -> SnoopOpcodes;
preamble(&self) -> &SnoopPacketPreamble175     fn preamble(&self) -> &SnoopPacketPreamble;
data(&self) -> &Vec<u8>176     fn data(&self) -> &Vec<u8>;
177 
get_timestamp(&self) -> Option<NaiveDateTime>178     fn get_timestamp(&self) -> Option<NaiveDateTime> {
179         let preamble = self.preamble();
180         let ts_i64 = i64::try_from(preamble.timestamp_us).unwrap_or(i64::MAX);
181 
182         // TODO: directly use Datetime::from_timestamp_micros() once chrono package is re-vendored
183         //       to v0.4.35. Below is the actual implementation of that function.
184         let from_timestamp_micros = |micros: i64| -> Option<DateTime<_>> {
185             let secs = micros.div_euclid(1_000_000);
186             let nsecs = micros.rem_euclid(1_000_000) as u32 * 1000;
187             DateTime::from_timestamp(secs, nsecs)
188         };
189         from_timestamp_micros(ts_i64 - SNOOP_Y0_TO_Y1970_US).map(|date| date.naive_utc())
190     }
191 }
192 
193 pub struct LinuxSnoopPacket {
194     pub preamble: SnoopPacketPreamble,
195     pub data: Vec<u8>,
196 }
197 
198 impl GeneralSnoopPacket for LinuxSnoopPacket {
adapter_index(&self) -> u16199     fn adapter_index(&self) -> u16 {
200         (self.preamble.flags >> 16).try_into().unwrap_or(0u16)
201     }
opcode(&self) -> SnoopOpcodes202     fn opcode(&self) -> SnoopOpcodes {
203         SnoopOpcodes::from_u32(self.preamble.flags & 0xffff).unwrap_or(SnoopOpcodes::Invalid)
204     }
preamble(&self) -> &SnoopPacketPreamble205     fn preamble(&self) -> &SnoopPacketPreamble {
206         &self.preamble
207     }
data(&self) -> &Vec<u8>208     fn data(&self) -> &Vec<u8> {
209         &self.data
210     }
211 }
212 
213 pub struct H4SnoopPacket {
214     pub preamble: SnoopPacketPreamble,
215     pub data: Vec<u8>,
216     pub pkt_type: u8,
217 }
218 
219 impl GeneralSnoopPacket for H4SnoopPacket {
adapter_index(&self) -> u16220     fn adapter_index(&self) -> u16 {
221         0
222     }
opcode(&self) -> SnoopOpcodes223     fn opcode(&self) -> SnoopOpcodes {
224         match self.pkt_type {
225             0x01 => SnoopOpcodes::Command,
226             0x02 => match self.preamble.flags & 0x01 {
227                 0x00 => SnoopOpcodes::AclTxPacket,
228                 _ => SnoopOpcodes::AclRxPacket,
229             },
230             0x03 => match self.preamble.flags & 0x01 {
231                 0x00 => SnoopOpcodes::ScoTxPacket,
232                 _ => SnoopOpcodes::ScoRxPacket,
233             },
234             0x04 => SnoopOpcodes::Event,
235             0x05 => match self.preamble.flags & 0x01 {
236                 0x00 => SnoopOpcodes::IsoTx,
237                 _ => SnoopOpcodes::IsoRx,
238             },
239             _ => SnoopOpcodes::Invalid,
240         }
241     }
preamble(&self) -> &SnoopPacketPreamble242     fn preamble(&self) -> &SnoopPacketPreamble {
243         &self.preamble
244     }
data(&self) -> &Vec<u8>245     fn data(&self) -> &Vec<u8> {
246         &self.data
247     }
248 }
249 
250 /// Maximum packet size for snoop is the max ACL size + 4 bytes.
251 const SNOOP_MAX_PACKET_SIZE: usize = 1486 + 4;
252 
253 /// Reader for Linux snoop files.
254 pub struct LinuxSnoopReader<'a> {
255     fd: Box<dyn BufRead + 'a>,
256 }
257 
258 impl<'a> LinuxSnoopReader<'a> {
new(fd: Box<dyn BufRead + 'a>) -> Self259     fn new(fd: Box<dyn BufRead + 'a>) -> Self {
260         LinuxSnoopReader { fd }
261     }
262 }
263 
264 impl<'a> Iterator for LinuxSnoopReader<'a> {
265     type Item = Box<dyn GeneralSnoopPacket>;
266 
next(&mut self) -> Option<Self::Item>267     fn next(&mut self) -> Option<Self::Item> {
268         let preamble = match SnoopPacketPreamble::from_fd(&mut self.fd) {
269             Some(preamble) => preamble,
270             None => {
271                 return None;
272             }
273         };
274 
275         if preamble.included_length > 0 {
276             let size: usize = (preamble.included_length).try_into().unwrap();
277             let mut rem_data = [0u8; SNOOP_MAX_PACKET_SIZE];
278 
279             match self.fd.read_exact(&mut rem_data[0..size]) {
280                 Ok(()) => {
281                     Some(Box::new(LinuxSnoopPacket { preamble, data: rem_data[0..size].to_vec() }))
282                 }
283                 Err(e) => {
284                     eprintln!("Couldn't read any packet data: {}", e);
285                     None
286                 }
287             }
288         } else {
289             Some(Box::new(LinuxSnoopPacket { preamble, data: vec![] }))
290         }
291     }
292 }
293 
294 /// Reader for H4/UART/Android snoop files.
295 pub struct H4SnoopReader<'a> {
296     fd: Box<dyn BufRead + 'a>,
297 }
298 
299 impl<'a> H4SnoopReader<'a> {
new(fd: Box<dyn BufRead + 'a>) -> Self300     fn new(fd: Box<dyn BufRead + 'a>) -> Self {
301         H4SnoopReader { fd }
302     }
303 }
304 
305 impl<'a> Iterator for H4SnoopReader<'a> {
306     type Item = Box<dyn GeneralSnoopPacket>;
307 
next(&mut self) -> Option<Self::Item>308     fn next(&mut self) -> Option<Self::Item> {
309         let preamble = match SnoopPacketPreamble::from_fd(&mut self.fd) {
310             Some(preamble) => preamble,
311             None => {
312                 return None;
313             }
314         };
315 
316         if preamble.included_length > 0 {
317             let size: usize = (preamble.included_length - 1).try_into().unwrap();
318             let mut type_buf = [0u8; 1];
319             match self.fd.read_exact(&mut type_buf) {
320                 Ok(()) => {}
321                 Err(e) => {
322                     eprintln!("Couldn't read any packet data: {}", e);
323                     return None;
324                 }
325             };
326 
327             let mut rem_data = [0u8; SNOOP_MAX_PACKET_SIZE];
328             match self.fd.read_exact(&mut rem_data[0..size]) {
329                 Ok(()) => Some(Box::new(H4SnoopPacket {
330                     preamble,
331                     data: rem_data[0..size].to_vec(),
332                     pkt_type: type_buf[0],
333                 })),
334                 Err(e) => {
335                     eprintln!("Couldn't read any packet data: {}", e);
336                     None
337                 }
338             }
339         } else {
340             eprintln!("Non-positive packet size: {}", preamble.included_length);
341             None
342         }
343     }
344 }
345 
346 pub struct LogParser {
347     fd: Box<dyn BufRead>,
348     log_type: SnoopDatalinkType,
349 }
350 
351 impl<'a> LogParser {
new(filepath: &str) -> std::io::Result<Self>352     pub fn new(filepath: &str) -> std::io::Result<Self> {
353         let mut fd: Box<dyn BufRead>;
354         if filepath.len() == 0 {
355             fd = Box::new(BufReader::new(std::io::stdin()));
356         } else {
357             fd = Box::new(BufReader::new(File::open(filepath)?));
358         }
359 
360         let mut buf = [0; SNOOP_HEADER_SIZE];
361         fd.read_exact(&mut buf)?;
362 
363         match SnoopHeader::try_from(&buf[0..SNOOP_HEADER_SIZE]) {
364             Ok(header) => Ok(Self { fd, log_type: header.datalink_type }),
365             Err(e) => Err(Error::new(ErrorKind::Other, e)),
366         }
367     }
368 
get_snoop_iterator(self) -> Box<dyn Iterator<Item = Box<dyn GeneralSnoopPacket>>>369     pub fn get_snoop_iterator(self) -> Box<dyn Iterator<Item = Box<dyn GeneralSnoopPacket>>> {
370         let reader = Box::new(BufReader::new(self.fd));
371         match self.log_type {
372             SnoopDatalinkType::H4Uart => Box::new(H4SnoopReader::new(reader)),
373             SnoopDatalinkType::LinuxMonitor => Box::new(LinuxSnoopReader::new(reader)),
374         }
375     }
376 }
377 
378 /// Data owned by a packet.
379 #[derive(Debug, Clone)]
380 pub enum PacketChild {
381     HciCommand(Command),
382     HciEvent(Event),
383     AclTx(Acl),
384     AclRx(Acl),
385     NewIndex(NewIndex),
386     SystemNote(String),
387 }
388 
389 impl<'a> TryFrom<&'a dyn GeneralSnoopPacket> for PacketChild {
390     type Error = String;
391 
try_from(item: &'a dyn GeneralSnoopPacket) -> Result<Self, Self::Error>392     fn try_from(item: &'a dyn GeneralSnoopPacket) -> Result<Self, Self::Error> {
393         match item.opcode() {
394             SnoopOpcodes::Command => match Command::parse(item.data().as_slice()) {
395                 Ok(command) => Ok(PacketChild::HciCommand(command)),
396                 Err(e) => Err(format!("Couldn't parse command: {:?}", e)),
397             },
398 
399             SnoopOpcodes::Event => match Event::parse(item.data().as_slice()) {
400                 Ok(event) => Ok(PacketChild::HciEvent(event)),
401                 Err(e) => Err(format!("Couldn't parse event: {:?}", e)),
402             },
403 
404             SnoopOpcodes::AclTxPacket => match Acl::parse(item.data().as_slice()) {
405                 Ok(data) => Ok(PacketChild::AclTx(data)),
406                 Err(e) => Err(format!("Couldn't parse acl tx: {:?}", e)),
407             },
408 
409             SnoopOpcodes::AclRxPacket => match Acl::parse(item.data().as_slice()) {
410                 Ok(data) => Ok(PacketChild::AclRx(data)),
411                 Err(e) => Err(format!("Couldn't parse acl rx: {:?}", e)),
412             },
413 
414             SnoopOpcodes::NewIndex => match NewIndex::parse(item.data().as_slice()) {
415                 Ok(data) => Ok(PacketChild::NewIndex(data)),
416                 Err(e) => Err(format!("Couldn't parse new index: {:?}", e)),
417             },
418 
419             SnoopOpcodes::SystemNote => match String::from_utf8(item.data().to_vec()) {
420                 Ok(data) => Ok(PacketChild::SystemNote(data)),
421                 Err(e) => Err(format!("Couldn't parse system note: {:?}", e)),
422             },
423 
424             // TODO(b/262928525) - Add packet handlers for more packet types.
425             _ => Err(format!("Unhandled packet opcode: {:?}", item.opcode())),
426         }
427     }
428 }
429 
430 /// A single processable packet of data.
431 #[derive(Debug, Clone)]
432 #[allow(dead_code)]
433 pub struct Packet {
434     /// Timestamp of this packet
435     pub ts: NaiveDateTime,
436 
437     /// Which adapter this packet is for. Unassociated packets should use 0xFFFE.
438     pub adapter_index: u16,
439 
440     /// Packet number in current stream.
441     pub index: usize,
442 
443     /// Inner data for this packet.
444     pub inner: PacketChild,
445 }
446 
447 impl<'a> TryFrom<(usize, &'a dyn GeneralSnoopPacket)> for Packet {
448     type Error = String;
449 
try_from(item: (usize, &'a dyn GeneralSnoopPacket)) -> Result<Self, Self::Error>450     fn try_from(item: (usize, &'a dyn GeneralSnoopPacket)) -> Result<Self, Self::Error> {
451         let (index, packet) = item;
452         match PacketChild::try_from(packet) {
453             Ok(inner) => {
454                 let ts = packet.get_timestamp().ok_or(format!(
455                     "timestamp conversion error: {}",
456                     packet.preamble().timestamp_us
457                 ))?;
458                 let adapter_index = packet.adapter_index();
459                 Ok(Packet { ts, adapter_index, index, inner })
460             }
461 
462             Err(e) => Err(e),
463         }
464     }
465 }
466 
467 #[allow(dead_code)]
468 pub enum AclContent {
469     Control(Control),
470     LeControl(LeControl),
471     ConnectionlessData(u16, Vec<u8>),
472     StandardData(Vec<u8>),
473     None,
474 }
475 
get_acl_content(acl: &Acl) -> AclContent476 pub fn get_acl_content(acl: &Acl) -> AclContent {
477     match acl.specialize() {
478         AclChild::Payload(bytes) => match BasicFrame::parse(bytes.as_ref()) {
479             Ok(bf) => match bf.specialize() {
480                 BasicFrameChild::ControlFrame(cf) => match cf.specialize() {
481                     ControlFrameChild::Payload(p) => match Control::parse(p.as_ref()) {
482                         Ok(control) => AclContent::Control(control),
483                         Err(_) => AclContent::None,
484                     },
485                     _ => AclContent::None,
486                 },
487                 BasicFrameChild::LeControlFrame(lcf) => match lcf.specialize() {
488                     LeControlFrameChild::Payload(p) => match LeControl::parse(p.as_ref()) {
489                         Ok(le_control) => AclContent::LeControl(le_control),
490                         Err(_) => AclContent::None,
491                     },
492                     _ => AclContent::None,
493                 },
494                 BasicFrameChild::GroupFrame(gf) => match gf.specialize() {
495                     GroupFrameChild::Payload(p) => {
496                         AclContent::ConnectionlessData(gf.get_psm(), p.to_vec())
497                     }
498                     _ => AclContent::None,
499                 },
500                 BasicFrameChild::Payload(p) => AclContent::StandardData(p.to_vec()),
501                 _ => AclContent::None,
502             },
503             Err(_) => AclContent::None,
504         },
505         _ => AclContent::None,
506     }
507 }
508 
509 #[derive(Clone, Debug)]
510 pub struct NewIndex {
511     _hci_type: u8,
512     _bus: u8,
513     bdaddr: [u8; 6],
514     _name: [u8; 8],
515 }
516 
517 impl NewIndex {
parse(data: &[u8]) -> Result<NewIndex, std::string::String>518     fn parse(data: &[u8]) -> Result<NewIndex, std::string::String> {
519         if data.len() != std::mem::size_of::<NewIndex>() {
520             return Err(format!("Invalid size for New Index packet: {}", data.len()));
521         }
522 
523         let rest = data;
524         let (hci_type, rest) = rest.split_at(std::mem::size_of::<u8>());
525         let (bus, rest) = rest.split_at(std::mem::size_of::<u8>());
526         let (bdaddr, rest) = rest.split_at(6 * std::mem::size_of::<u8>());
527         let (name, _rest) = rest.split_at(8 * std::mem::size_of::<u8>());
528 
529         Ok(NewIndex {
530             _hci_type: hci_type[0],
531             _bus: bus[0],
532             bdaddr: bdaddr.try_into().unwrap(),
533             _name: name.try_into().unwrap(),
534         })
535     }
536 
get_addr_str(&self) -> String537     pub fn get_addr_str(&self) -> String {
538         String::from(format!(
539             "[{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}]",
540             self.bdaddr[0],
541             self.bdaddr[1],
542             self.bdaddr[2],
543             self.bdaddr[3],
544             self.bdaddr[4],
545             self.bdaddr[5]
546         ))
547     }
548 }
549