From 26437648070d71dc15d5e1db7927474a21854df9 Mon Sep 17 00:00:00 2001 From: SamClercky Date: Wed, 25 Sep 2024 11:35:13 +0200 Subject: [PATCH 1/2] feat: initial version of PAN IDs Implemented partial rejection rules of IEEE 802.15.4 - 2015 standard p101-102 --- dot15d4/build.rs | 2 + dot15d4/src/csma/constants.rs | 2 + dot15d4/src/csma/mod.rs | 110 ++++++++++++++++-- .../src/csma/user_configurable_constants.rs | 3 + dot15d4/src/phy/radio/mod.rs | 9 +- 5 files changed, 115 insertions(+), 11 deletions(-) diff --git a/dot15d4/build.rs b/dot15d4/build.rs index 54c3d3e..2d8a027 100644 --- a/dot15d4/build.rs +++ b/dot15d4/build.rs @@ -24,6 +24,8 @@ fn main() { ("MAC_AIFS_PERIOD", ("Duration", "Duration::from_us(1000)")), ("MAC_SIFS_PERIOD", ("Duration", "Duration::from_us(1000)")), ("MAC_LIFS_PERIOD", ("Duration", "Duration::from_us(10_000)")), + ("MAC_PAN_ID", ("u16", "0xffff")), + ("MAC_IMPLICIT_BROADCAST", ("bool", "false")), ]); // Make sure we get rerun if needed diff --git a/dot15d4/src/csma/constants.rs b/dot15d4/src/csma/constants.rs index f8c6db6..00c918b 100644 --- a/dot15d4/src/csma/constants.rs +++ b/dot15d4/src/csma/constants.rs @@ -9,6 +9,8 @@ pub const TURNAROUND_TIME: u32 = 12; /// The time required to perform CCA detection in symbol periods. pub const CCA_TIME: u32 = 8; +pub const BROADCAST_PAN_ID: u16 = 0xffff; + // /// The delay between the start of the SFD and the LEIP, as described in // /// 18.6. // const A_LEIP_DELAY_TIME: u32 = 0.815 ms diff --git a/dot15d4/src/csma/mod.rs b/dot15d4/src/csma/mod.rs index b3bf55e..a5a0852 100644 --- a/dot15d4/src/csma/mod.rs +++ b/dot15d4/src/csma/mod.rs @@ -27,7 +27,7 @@ use crate::{ }, time::Duration, }; -use dot15d4_frame::{Address, Frame, FrameBuilder, FrameType}; +use dot15d4_frame::{Address, AddressingFieldsRepr, Frame, FrameBuilder, FrameType, FrameVersion}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Clone, Copy)] @@ -55,6 +55,10 @@ pub struct CsmaConfig { pub ack_everything: bool, /// The channel on which to transmit/receive pub channel: config::Channel, + /// Overwrite all frames' destination PAN ID (default = false) + pub overwrite_dst_pan_id: bool, + /// Overwrite all frames' source PAN ID (default = true) + pub overwrite_src_pan_id: bool, } impl Default for CsmaConfig { @@ -65,6 +69,8 @@ impl Default for CsmaConfig { ignore_not_for_us: true, ack_everything: false, channel: config::Channel::_26, + overwrite_dst_pan_id: false, + overwrite_src_pan_id: true, } } } @@ -128,10 +134,32 @@ where /// Checks if the current frame is intended for us. For the hardware /// address, the full 64-bit address should be provided. fn is_package_for_us(hardware_address: &[u8; 8], frame: &Frame<&'_ [u8]>) -> bool { - let Some(addr) = frame.addressing().and_then(|fields| fields.dst_address()) else { + // Check if the type is known, otherwise drop + if matches!(frame.frame_control().frame_type(), FrameType::Unknown) { return false; + } + // Check if the Frame version is valid, otherwise drop + if matches!(frame.frame_control().frame_version(), FrameVersion::Unknown) { + return false; + } + + let addr = match frame.addressing().and_then(|fields| fields.dst_address()) { + Some(addr) => addr, + None if MAC_IMPLICIT_BROADCAST => Address::BROADCAST, + _ => return false, }; + // Check if dst_pan (in present) is provided + let dst_pan_id = frame + .addressing() + .and_then(|fields| fields.dst_pan_id()) + .unwrap_or(BROADCAST_PAN_ID); + if dst_pan_id != MAC_PAN_ID && dst_pan_id != BROADCAST_PAN_ID { + return false; + } + + // TODO: Check rules if frame comes from PAN coordinator and the same MAC_PAN_ID + // TODO: Implement `macGroupRxMode` check here match &addr { _ if addr.is_broadcast() => true, Address::Absent => false, @@ -318,6 +346,52 @@ where } } + fn overwrite_pan_id<'a, RadioFrame>( + &self, + buffer: &'a mut [u8], + ) -> Result<(), TransmissionTaskError> + where + RadioFrame: RadioFrameMut<&'a mut [u8]>, + { + let mut frame = + RadioFrame::new_checked(buffer).map_err(TransmissionTaskError::InvalidDeviceFrame)?; + let mut frame = + Frame::new(frame.data_mut()).map_err(|_err| TransmissionTaskError::InvalidIEEEFrame)?; + + let Some(mut addr) = frame + .addressing() + .map(|fields| AddressingFieldsRepr::parse(fields)) + else { + return Ok(()); + }; + + let mut changed = false; + if self.config.overwrite_src_pan_id + && addr + .src_pan_id + .map(|pan_id| pan_id != MAC_PAN_ID) + .unwrap_or(false) + { + addr.src_pan_id = Some(MAC_PAN_ID); + changed = true; + } + if self.config.overwrite_dst_pan_id + && addr + .dst_pan_id + .map(|pan_id| pan_id != MAC_PAN_ID) + .unwrap_or(false) + { + addr.dst_pan_id = Some(MAC_PAN_ID); + changed = true; + } + + if changed { + frame.set_addressing_fields(&addr); + } + + Ok(()) + } + async fn wait_for_valid_ack( radio: &mut R, channel: config::Channel, @@ -381,6 +455,22 @@ where .await; } } + match self.overwrite_pan_id::>(&mut tx.buffer) { + Ok(()) => (), + Err(TransmissionTaskError::InvalidIEEEFrame) => { + // Invalid IEEE frame encountered + #[cfg(feature = "defmt")] + defmt::trace!("INVALID frame TX incoming buffer IEEE"); + self.driver.error(driver::Error::InvalidIEEEStructure).await; + } + #[allow(unused_variables)] + Err(TransmissionTaskError::InvalidDeviceFrame(err)) => { + // Invalid device frame encountered + self.driver + .error(driver::Error::InvalidDeviceStructure) + .await; + } + } let mut radio_guard = None; 'ack: for i_ack in 1..MAC_MAX_FRAME_RETIES + 1 { @@ -640,8 +730,8 @@ pub mod tests { .set_sequence_number(sequence_number) .set_dst_address(Address::Extended(radio.ieee802154_address())) .set_src_address(Address::Extended([1, 2, 3, 4, 9, 8, 7, 6])) - .set_dst_pan_id(0xfff) - .set_src_pan_id(0xfff) + .set_dst_pan_id(MAC_PAN_ID) + .set_src_pan_id(MAC_PAN_ID) .finalize() .unwrap(); frame_repr.frame_control.ack_request = true; @@ -709,8 +799,8 @@ pub mod tests { .set_sequence_number(sequence_number) .set_dst_address(Address::Extended(radio.ieee802154_address())) .set_src_address(Address::Extended([1, 2, 3, 4, 9, 8, 7, 6])) - .set_dst_pan_id(0xfff) - .set_src_pan_id(0xfff) + .set_dst_pan_id(MAC_PAN_ID) + .set_src_pan_id(MAC_PAN_ID) .finalize() .unwrap(); frame_repr.frame_control.ack_request = false; @@ -759,8 +849,8 @@ pub mod tests { .set_sequence_number(sequence_number) .set_dst_address(Address::Extended([1, 2, 3, 4, 5, 6, 7, 8])) .set_src_address(Address::Extended([1, 2, 3, 4, 9, 8, 7, 6])) - .set_dst_pan_id(0xfff) - .set_src_pan_id(0xfff) + .set_dst_pan_id(MAC_PAN_ID) + .set_src_pan_id(MAC_PAN_ID) .finalize() .unwrap(); // Set ACK to false, such that we can test if it acks @@ -963,8 +1053,8 @@ pub mod tests { .set_sequence_number(sequence_number) .set_dst_address(Address::BROADCAST) .set_src_address(Address::Extended([1, 2, 3, 4, 9, 8, 7, 6])) - .set_dst_pan_id(0xfff) - .set_src_pan_id(0xfff) + .set_dst_pan_id(MAC_PAN_ID) + .set_src_pan_id(MAC_PAN_ID) .finalize() .unwrap(); frame_repr.frame_control.ack_request = true; // This should be ignored diff --git a/dot15d4/src/csma/user_configurable_constants.rs b/dot15d4/src/csma/user_configurable_constants.rs index 3539b8d..f7d9d7f 100644 --- a/dot15d4/src/csma/user_configurable_constants.rs +++ b/dot15d4/src/csma/user_configurable_constants.rs @@ -20,6 +20,9 @@ mod constants { pub const MAC_AIFS_PERIOD: Duration = Duration::from_us(1000); pub const MAC_SIFS_PERIOD: Duration = Duration::from_us(1000); // TODO: SIFS=XXX pub const MAC_LIFS_PERIOD: Duration = Duration::from_us(10_000); // TODO: LIFS=XXX + // PAN Id + pub const MAC_PAN_ID: u16 = 0xffff; + pub const MAC_IMPLICIT_BROADCAST: bool = false; } #[cfg(not(test))] diff --git a/dot15d4/src/phy/radio/mod.rs b/dot15d4/src/phy/radio/mod.rs index 8d1b7a9..71e49a3 100644 --- a/dot15d4/src/phy/radio/mod.rs +++ b/dot15d4/src/phy/radio/mod.rs @@ -91,6 +91,7 @@ pub trait TxToken { #[cfg(test)] pub mod tests { + use core::panic; use std::{ cell::RefCell, collections::VecDeque, @@ -178,6 +179,10 @@ pub mod tests { if let Some(waker) = inner.assert_waker.take() { waker.wake(); } + // Do not check if we are already panicking + if std::thread::panicking() { + return; + } if let Some(assert_nxt) = inner.assert_nxt.pop_front() { assert_eq!( assert_nxt, evnt, @@ -215,7 +220,9 @@ pub mod tests { match select::select(wait_for_events, StdDelay::default().delay_ms(5000)).await { crate::sync::Either::First(_) => {} crate::sync::Either::Second(_) => { - panic!("Waiting timedout for events -> there is a bug in the code") + if !std::thread::panicking() { + panic!("Waiting timedout for events -> there is a bug in the code") + } } } } From 4c539dd49334f461200d326619f2e9f868eb78f9 Mon Sep 17 00:00:00 2001 From: SamClercky Date: Wed, 25 Sep 2024 13:43:48 +0200 Subject: [PATCH 2/2] fix: type not correctly recovered for environment variables --- dot15d4/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dot15d4/build.rs b/dot15d4/build.rs index 2d8a027..c6c98a4 100644 --- a/dot15d4/build.rs +++ b/dot15d4/build.rs @@ -47,7 +47,7 @@ fn main() { for (var, value) in std::env::vars() { if let Some(name) = var.strip_prefix("DOT15D4_") { // discard from hashmap as a way of consuming the setting - let Some((ty, _)) = configs.remove_entry(name) else { + let Some((_, (ty, _))) = configs.remove_entry(name) else { panic!("Wrong configuration name {name}"); };