summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--floss/hcidoc/packets/build.rs2
-rw-r--r--floss/hcidoc/packets/lib.rs42
-rw-r--r--floss/hcidoc/src/groups/connections.rs232
-rw-r--r--floss/hcidoc/src/groups/informational.rs86
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()
_ => {}