diff options
-rw-r--r-- | floss/hcidoc/packets/build.rs | 2 | ||||
-rw-r--r-- | floss/hcidoc/packets/lib.rs | 42 | ||||
-rw-r--r-- | floss/hcidoc/src/groups/connections.rs | 232 | ||||
-rw-r--r-- | floss/hcidoc/src/groups/informational.rs | 86 |
4 files changed, 175 insertions, 187 deletions
diff --git a/floss/hcidoc/packets/build.rs b/floss/hcidoc/packets/build.rs index 7a08060feb..f9d0304a55 100644 --- a/floss/hcidoc/packets/build.rs +++ b/floss/hcidoc/packets/build.rs @@ -44,7 +44,7 @@ fn generate_packets() { ); let out_file = File::create(out_dir.join("hci_packets.rs")).unwrap(); - let in_file = PathBuf::from("../../../system/pdl/hci/hci_packets.pdl"); + let in_file = PathBuf::from("../../../tools/rootcanal/packets/hci_packets.pdl"); println!("cargo:rerun-if-changed={}", in_file.display()); let output = Command::new("pdlc") diff --git a/floss/hcidoc/packets/lib.rs b/floss/hcidoc/packets/lib.rs index af9d810145..4a71e58e13 100644 --- a/floss/hcidoc/packets/lib.rs +++ b/floss/hcidoc/packets/lib.rs @@ -36,4 +36,46 @@ pub mod hci { bytes[0..6].try_into().unwrap() } } + + pub struct GapData { + pub data_type: GapDataType, + pub data: Vec<u8>, + } + + impl GapData { + pub fn parse(bytes: &[u8]) -> std::result::Result<Self, String> { + // In case of parsing EIR, we can get normal data, or all zeroes. Normal data always + // have at least 2 bytes: one for the length, and another for the type. Therefore we + // can terminate early if the data has less than 2 bytes. + if (bytes.len() == 0) { + return Err("no data to parse".to_string()); + } else if (bytes.len() == 1) { + if (bytes[0] != 0) { + return Err(format!("can't parse 1 byte of data: {}", bytes[0])); + } + return Ok(GapData { data_type: GapDataType::Invalid, data: vec![] }); + } + + let mut data_size = bytes[0] as usize; + if (data_size == 0) { + // Data size already include the data_type, so size = 0 is possible only when + // parsing EIR, where all data are zeroes. Here we just assume that assumption is + // correct, and don't really check all the elements. + return Ok(GapData { data_type: GapDataType::Invalid, data: bytes[2..].to_vec() }); + } + + if (data_size > bytes.len() - 1) { + return Err(format!( + "size {} is bigger than remaining length {}", + data_size, + bytes.len() - 1 + )); + } + let data_type = match GapDataType::try_from(bytes[1]) { + Ok(data_type) => Ok(data_type), + Err(_) => Err(format!("can't parse data type {}", bytes[1])), + }?; + return Ok(GapData { data_type, data: bytes[2..(data_size + 1)].to_vec() }); + } + } } diff --git a/floss/hcidoc/src/groups/connections.rs b/floss/hcidoc/src/groups/connections.rs index 9c1526f1b7..0f22e73e5f 100644 --- a/floss/hcidoc/src/groups/connections.rs +++ b/floss/hcidoc/src/groups/connections.rs @@ -8,11 +8,9 @@ use std::slice::Iter; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{Packet, PacketChild}; use hcidoc_packets::hci::{ - Acl, AclCommandChild, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, - ConnectionManagementCommandChild, DisconnectReason, Enable, ErrorCode, EventChild, - InitiatorFilterPolicy, LeConnectionManagementCommandChild, LeMetaEventChild, - LeSecurityCommandChild, NumberOfCompletedPackets, OpCode, ScoConnectionCommandChild, - SecurityCommandChild, + Acl, Address, AuthenticatedPayloadTimeoutExpired, CommandChild, DisconnectReason, Enable, + ErrorCode, EventChild, InitiatorFilterPolicy, LeMetaEventChild, NumberOfCompletedPackets, + OpCode, }; enum ConnectionSignal { @@ -626,100 +624,77 @@ impl Rule for OddDisconnectionsRule { fn process(&mut self, packet: &Packet) { match &packet.inner { PacketChild::HciCommand(cmd) => match cmd.specialize() { - CommandChild::AclCommand(aclpkt) => match aclpkt.specialize() { - AclCommandChild::ConnectionManagementCommand(conn) => match conn.specialize() { - ConnectionManagementCommandChild::CreateConnection(cc) => { - self.process_classic_connection(cc.get_bd_addr(), packet); - } - ConnectionManagementCommandChild::AcceptConnectionRequest(ac) => { - self.process_classic_connection(ac.get_bd_addr(), packet); - } - ConnectionManagementCommandChild::ReadRemoteSupportedFeatures(rrsf) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Supported, - &rrsf.get_connection_handle(), - packet, - ); - } - ConnectionManagementCommandChild::ReadRemoteExtendedFeatures(rref) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Extended, - &rref.get_connection_handle(), - packet, - ); - } - // End ConnectionManagementCommand.specialize() - _ => {} - }, - AclCommandChild::ScoConnectionCommand(sco_con) => match sco_con.specialize() { - ScoConnectionCommandChild::SetupSynchronousConnection(ssc) => { - let address = - self.convert_sco_handle_to_address(ssc.get_connection_handle()); - self.process_sync_connection(address, packet); - } - ScoConnectionCommandChild::EnhancedSetupSynchronousConnection(esc) => { - let address = - self.convert_sco_handle_to_address(esc.get_connection_handle()); - self.process_sync_connection(address, packet); - } - ScoConnectionCommandChild::AcceptSynchronousConnection(asc) => { - self.process_sync_connection(asc.get_bd_addr(), packet); - } - ScoConnectionCommandChild::EnhancedAcceptSynchronousConnection(easc) => { - self.process_sync_connection(easc.get_bd_addr(), packet); - } - // End ScoConnectionCommand.specialize() - _ => {} - }, - AclCommandChild::LeConnectionManagementCommand(le_conn) => match le_conn - .specialize() - { - LeConnectionManagementCommandChild::LeCreateConnection(lcc) => { - self.process_le_create_connection( - lcc.get_peer_address(), - lcc.get_initiator_filter_policy(), - packet, - ); - } - LeConnectionManagementCommandChild::LeExtendedCreateConnection(lecc) => { - self.process_le_create_connection( - lecc.get_peer_address(), - lecc.get_initiator_filter_policy(), - packet, - ); - } - LeConnectionManagementCommandChild::LeAddDeviceToFilterAcceptList(laac) => { - self.process_add_accept_list(laac.get_address(), packet); - } - LeConnectionManagementCommandChild::LeRemoveDeviceFromFilterAcceptList( - lrac, - ) => { - self.process_remove_accept_list(lrac.get_address(), packet); - } - LeConnectionManagementCommandChild::LeClearFilterAcceptList(_lcac) => { - self.process_clear_accept_list(packet); - } - LeConnectionManagementCommandChild::LeReadRemoteFeatures(lrrf) => { - self.process_remote_feat_cmd( - PendingRemoteFeature::Le, - &lrrf.get_connection_handle(), - packet, - ); - } - // End LeConnectionManagementCommand.specialize() - _ => {} - }, - AclCommandChild::Disconnect(dc_conn) => { - self.process_disconnect_cmd( - dc_conn.get_reason(), - dc_conn.get_connection_handle(), - packet, - ); - } - - // End AclCommand.specialize() - _ => (), - }, + CommandChild::CreateConnection(cc) => { + self.process_classic_connection(cc.get_bd_addr(), packet); + } + CommandChild::AcceptConnectionRequest(ac) => { + self.process_classic_connection(ac.get_bd_addr(), packet); + } + CommandChild::ReadRemoteSupportedFeatures(rrsf) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Supported, + &rrsf.get_connection_handle(), + packet, + ); + } + CommandChild::ReadRemoteExtendedFeatures(rref) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Extended, + &rref.get_connection_handle(), + packet, + ); + } + CommandChild::SetupSynchronousConnection(ssc) => { + let address = self.convert_sco_handle_to_address(ssc.get_connection_handle()); + self.process_sync_connection(address, packet); + } + CommandChild::EnhancedSetupSynchronousConnection(esc) => { + let address = self.convert_sco_handle_to_address(esc.get_connection_handle()); + self.process_sync_connection(address, packet); + } + CommandChild::AcceptSynchronousConnection(asc) => { + self.process_sync_connection(asc.get_bd_addr(), packet); + } + CommandChild::EnhancedAcceptSynchronousConnection(easc) => { + self.process_sync_connection(easc.get_bd_addr(), packet); + } + CommandChild::LeCreateConnection(lcc) => { + self.process_le_create_connection( + lcc.get_peer_address(), + lcc.get_initiator_filter_policy(), + packet, + ); + } + CommandChild::LeExtendedCreateConnection(lecc) => { + self.process_le_create_connection( + lecc.get_peer_address(), + lecc.get_initiator_filter_policy(), + packet, + ); + } + CommandChild::LeAddDeviceToFilterAcceptList(laac) => { + self.process_add_accept_list(laac.get_address(), packet); + } + CommandChild::LeRemoveDeviceFromFilterAcceptList(lrac) => { + self.process_remove_accept_list(lrac.get_address(), packet); + } + CommandChild::LeClearFilterAcceptList(_lcac) => { + self.process_clear_accept_list(packet); + } + CommandChild::LeReadRemoteFeatures(lrrf) => { + self.process_remote_feat_cmd( + PendingRemoteFeature::Le, + &lrrf.get_connection_handle(), + packet, + ); + } + CommandChild::Disconnect(dc_conn) => { + self.process_disconnect_cmd( + dc_conn.get_reason(), + dc_conn.get_connection_handle(), + packet, + ); + } CommandChild::Reset(_) => { self.process_reset(); } @@ -754,6 +729,7 @@ impl Rule for OddDisconnectionsRule { EventChild::NumberOfCompletedPackets(nocp) => { self.process_nocp(&nocp, packet); } + EventChild::AuthenticatedPayloadTimeoutExpired(apte) => { self.process_apte(&apte, packet); } @@ -1008,44 +984,26 @@ impl Rule for LinkKeyMismatchRule { }, PacketChild::HciCommand(cmd) => match cmd.specialize() { - CommandChild::AclCommand(cmd) => match cmd.specialize() { - // Have an arm for Disconnect since sometimes we don't receive disconnect - // event when powering off. However, no need to actually match the reason - // since we just clean the handle in both cases. - AclCommandChild::Disconnect(cmd) => { - self.process_handle_auth( - ErrorCode::Success, - cmd.get_connection_handle(), - &packet, - ); - self.handles.remove(&cmd.get_connection_handle()); - } - - // CommandChild::AclCommand(cmd).specialize() - _ => {} - }, - - CommandChild::SecurityCommand(cmd) => match cmd.specialize() { - SecurityCommandChild::LinkKeyRequestReply(cmd) => { - self.process_reply_link_key(cmd.get_bd_addr(), true); - } - SecurityCommandChild::LinkKeyRequestNegativeReply(cmd) => { - self.process_reply_link_key(cmd.get_bd_addr(), false); - } - - // CommandChild::SecurityCommand(cmd).specialize() - _ => {} - }, - - CommandChild::LeSecurityCommand(cmd) => match cmd.specialize() { - LeSecurityCommandChild::LeStartEncryption(cmd) => { - self.pending_le_encrypt.insert(cmd.get_connection_handle()); - } - - // CommandChild::LeSecurityCommand(cmd).specialize() - _ => {} - }, - + // Have an arm for Disconnect since sometimes we don't receive disconnect + // event when powering off. However, no need to actually match the reason + // since we just clean the handle in both cases. + CommandChild::Disconnect(cmd) => { + self.process_handle_auth( + ErrorCode::Success, + cmd.get_connection_handle(), + &packet, + ); + self.handles.remove(&cmd.get_connection_handle()); + } + CommandChild::LinkKeyRequestReply(cmd) => { + self.process_reply_link_key(cmd.get_bd_addr(), true); + } + CommandChild::LinkKeyRequestNegativeReply(cmd) => { + self.process_reply_link_key(cmd.get_bd_addr(), false); + } + CommandChild::LeStartEncryption(cmd) => { + self.pending_le_encrypt.insert(cmd.get_connection_handle()); + } CommandChild::Reset(_) => { self.process_reset(); } diff --git a/floss/hcidoc/src/groups/informational.rs b/floss/hcidoc/src/groups/informational.rs index a8654e7434..dbaa6c8ae3 100644 --- a/floss/hcidoc/src/groups/informational.rs +++ b/floss/hcidoc/src/groups/informational.rs @@ -10,8 +10,8 @@ use std::io::Write; use crate::engine::{Rule, RuleGroup, Signal}; use crate::parser::{get_acl_content, AclContent, Packet, PacketChild}; use hcidoc_packets::hci::{ - AclCommandChild, Address, CommandChild, ConnectionManagementCommandChild, DisconnectReason, - ErrorCode, EventChild, GapData, GapDataType, LeMetaEventChild, + Address, CommandChild, DisconnectReason, ErrorCode, EventChild, GapData, GapDataType, + LeMetaEventChild, }; use hcidoc_packets::l2cap::{ConnectionResponseResult, ControlChild}; @@ -706,18 +706,20 @@ impl InformationalRule { fn process_raw_gap_data(&mut self, address: &Address, data: &[u8]) { let mut offset = 0; while offset < data.len() { - let chunk_size = usize::from(data[offset]); - let chunk_end = offset + chunk_size + 1; - - // Prevent out-of-bounds index - if chunk_end > data.len() { - return; + match GapData::parse(&data[offset..]) { + Ok(gap_data) => { + self.process_gap_data(&address, &gap_data); + // advance data len + 2 (size = 1, type = 1) + offset += gap_data.data.len() + 2; + } + Err(err) => { + eprintln!("[{}] GAP data is not parsed correctly: {}", address, err); + break; + } } - match GapData::parse(&data[offset..chunk_end]) { - Ok(gap_data) => self.process_gap_data(&address, &gap_data), - Err(_err) => {} + if offset >= data.len() { + break; } - offset = chunk_end; } } @@ -804,9 +806,10 @@ impl Rule for InformationalRule { } EventChild::ExtendedInquiryResult(ev) => { - for data in ev.get_extended_inquiry_response() { - self.process_gap_data(&ev.get_address(), data); - } + self.process_raw_gap_data( + &ev.get_address(), + ev.get_extended_inquiry_response(), + ); self.report_address_type(&ev.get_address(), AddressType::BREDR); } @@ -851,16 +854,14 @@ impl Rule for InformationalRule { self.report_address_type(&ev.get_peer_address(), AddressType::LE); } - // Use the Raw version because somehow LeAdvertisingReport doesn't work - LeMetaEventChild::LeAdvertisingReportRaw(ev) => { + LeMetaEventChild::LeAdvertisingReport(ev) => { for resp in ev.get_responses() { self.process_raw_gap_data(&resp.address, &resp.advertising_data); self.report_address_type(&resp.address, AddressType::LE); } } - // Use the Raw version because somehow LeExtendedAdvertisingReport doesn't work - LeMetaEventChild::LeExtendedAdvertisingReportRaw(ev) => { + LeMetaEventChild::LeExtendedAdvertisingReport(ev) => { for resp in ev.get_responses() { self.process_raw_gap_data(&resp.address, &resp.advertising_data); self.report_address_type(&resp.address, AddressType::LE); @@ -879,37 +880,24 @@ impl Rule for InformationalRule { CommandChild::Reset(_cmd) => { self.report_reset(packet.ts); } - - CommandChild::AclCommand(cmd) => match cmd.specialize() { - AclCommandChild::ConnectionManagementCommand(cmd) => match cmd.specialize() { - ConnectionManagementCommandChild::CreateConnection(cmd) => { - self.report_acl_state(&cmd.get_bd_addr(), AclState::Initiating); - self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); - } - - ConnectionManagementCommandChild::AcceptConnectionRequest(cmd) => { - self.report_acl_state(&cmd.get_bd_addr(), AclState::Accepting); - self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); - } - - // AclCommandChild::ConnectionManagementCommand(cmd).specialize() - _ => {} - }, - - AclCommandChild::Disconnect(cmd) => { - // If reason is power off, the host might not wait for connection complete event - let is_power_off = cmd.get_reason() - == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff; - let handle = cmd.get_connection_handle(); - self.pending_disconnections.insert(handle, is_power_off); - if is_power_off { - self.report_connection_end(handle, packet.ts); - } + CommandChild::CreateConnection(cmd) => { + self.report_acl_state(&cmd.get_bd_addr(), AclState::Initiating); + self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); + } + CommandChild::AcceptConnectionRequest(cmd) => { + self.report_acl_state(&cmd.get_bd_addr(), AclState::Accepting); + self.report_address_type(&cmd.get_bd_addr(), AddressType::BREDR); + } + CommandChild::Disconnect(cmd) => { + // If reason is power off, the host might not wait for connection complete event + let is_power_off = cmd.get_reason() + == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff; + let handle = cmd.get_connection_handle(); + self.pending_disconnections.insert(handle, is_power_off); + if is_power_off { + self.report_connection_end(handle, packet.ts); } - - // CommandChild::AclCommand(cmd).specialize() - _ => {} - }, + } // PacketChild::HciCommand(cmd).specialize() _ => {} |