use byte::{check_len, BytesExt, TryRead, TryWrite, LE};
use cipher::{consts::U16, BlockCipher, NewBlockCipher};
use hash32_derive::Hash32;
pub use super::frame_control::{AddressMode, FrameType, FrameVersion};
use super::DecodeError;
use super::{
frame_control::{mask, offset},
security::{KeyDescriptorLookup, SecurityContext},
};
use super::{security::AuxiliarySecurityHeader, EncodeError};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Header {
pub frame_type: FrameType,
pub frame_pending: bool,
pub ack_request: bool,
pub pan_id_compress: bool,
pub seq_no_suppress: bool,
pub ie_present: bool,
pub version: FrameVersion,
pub seq: u8,
pub destination: Option<Address>,
pub source: Option<Address>,
pub auxiliary_security_header: Option<AuxiliarySecurityHeader>,
}
impl Header {
pub fn get_octet_size(&self) -> usize {
let mut len = 3;
for i in [self.destination, self.source].iter() {
match i {
Some(addr) => {
len += 2;
match addr {
Address::Short(..) => len += 2,
Address::Extended(..) => len += 8,
}
}
_ => {}
}
}
len
}
pub fn has_security(&self) -> bool {
self.auxiliary_security_header.is_some()
}
}
impl TryRead<'_> for Header {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
check_len(&bytes, 3)?;
let bits: u16 = bytes.read_with(offset, LE)?;
let frame_type =
((bits & mask::FRAME_TYPE) >> offset::FRAME_TYPE) as u8;
let security = ((bits & mask::SECURITY) >> offset::SECURITY) as u8;
let frame_pending = ((bits & mask::PENDING) >> offset::PENDING) as u8;
let ack_request = ((bits & mask::ACK) >> offset::ACK) as u8;
let pan_id_compress =
((bits & mask::PAN_ID_COMPRESS) >> offset::PAN_ID_COMPRESS) as u8;
let seq_no_suppress =
((bits & mask::SEQ_NO_SUPPRESS) >> offset::SEQ_NO_SUPPRESS) as u8;
let ie_present =
((bits & mask::IE_PRESENT) >> offset::IE_PRESENT) as u8;
let dest_addr_mode =
((bits & mask::DEST_ADDR_MODE) >> offset::DEST_ADDR_MODE) as u8;
let version = ((bits & mask::VERSION) >> offset::VERSION) as u8;
let src_addr_mode =
((bits & mask::SRC_ADDR_MODE) >> offset::SRC_ADDR_MODE) as u8;
let version = FrameVersion::from_bits(version)
.ok_or(DecodeError::InvalidFrameVersion(version))?;
let frame_type = FrameType::from_bits(frame_type)
.ok_or(DecodeError::InvalidFrameType(frame_type))?;
let dest_addr_mode = AddressMode::from_bits(dest_addr_mode)?;
let src_addr_mode = AddressMode::from_bits(src_addr_mode)?;
let security = security > 0;
let frame_pending = frame_pending > 0;
let ack_request = ack_request > 0;
let pan_id_compress = pan_id_compress > 0;
let seq_no_suppress = seq_no_suppress > 0;
let ie_present = ie_present > 0;
let seq = bytes.read(offset)?;
let destination = match dest_addr_mode {
AddressMode::None => None,
AddressMode::Short => {
Some(Address::Short(bytes.read(offset)?, bytes.read(offset)?))
}
AddressMode::Extended => Some(Address::Extended(
bytes.read(offset)?,
bytes.read(offset)?,
)),
};
if pan_id_compress {
destination.ok_or(byte::Error::BadInput {
err: "InvalidAddressMode",
})?;
}
let source = match src_addr_mode {
AddressMode::None => None,
AddressMode::Short => {
if pan_id_compress {
Some(Address::Short(
destination.unwrap().pan_id(),
bytes.read(offset)?,
))
} else {
Some(Address::Short(
bytes.read(offset)?,
bytes.read(offset)?,
))
}
}
AddressMode::Extended => {
if pan_id_compress {
Some(Address::Extended(
destination.unwrap().pan_id(),
bytes.read(offset)?,
))
} else {
Some(Address::Extended(
bytes.read(offset)?,
bytes.read(offset)?,
))
}
}
};
let auxiliary_security_header = match security {
true => Some(bytes.read(offset)?),
false => None,
};
let header = Header {
frame_type,
frame_pending,
ack_request,
pan_id_compress,
seq_no_suppress,
ie_present,
version,
seq,
destination,
source,
auxiliary_security_header,
};
Ok((header, *offset))
}
}
impl<AEADBLKCIPH, KEYDESCLO>
TryWrite<&Option<&mut SecurityContext<AEADBLKCIPH, KEYDESCLO>>> for Header
where
AEADBLKCIPH: NewBlockCipher + BlockCipher<BlockSize = U16>,
KEYDESCLO: KeyDescriptorLookup<AEADBLKCIPH::KeySize>,
{
fn try_write(
self,
bytes: &mut [u8],
sec_ctx: &Option<&mut SecurityContext<AEADBLKCIPH, KEYDESCLO>>,
) -> byte::Result<usize> {
let offset = &mut 0;
let dest_addr_mode = AddressMode::from(self.destination);
let src_addr_mode = AddressMode::from(self.source);
let security = self.auxiliary_security_header.is_some();
let frame_control_raw = (self.frame_type as u16) << offset::FRAME_TYPE
| (security as u16) << offset::SECURITY
| (self.frame_pending as u16) << offset::PENDING
| (self.ack_request as u16) << offset::ACK
| (self.pan_id_compress as u16) << offset::PAN_ID_COMPRESS
| (dest_addr_mode as u16) << offset::DEST_ADDR_MODE
| (self.version as u16) << offset::VERSION
| (src_addr_mode as u16) << offset::SRC_ADDR_MODE;
bytes.write_with(offset, frame_control_raw, LE)?;
bytes.write(offset, self.seq)?;
if (self.destination.is_none() || self.source.is_none())
&& self.pan_id_compress
{
return Err(EncodeError::DisallowedPanIdCompress)?;
}
if let Some(destination) = self.destination {
bytes.write_with(offset, destination, AddressEncoding::Normal)?;
}
match (self.source, self.pan_id_compress) {
(Some(source), true) => {
bytes.write_with(
offset,
source,
AddressEncoding::Compressed,
)?;
}
(Some(source), false) => {
bytes.write_with(offset, source, AddressEncoding::Normal)?;
}
(None, true) => {
panic!("frame control request compress source address without contain this address")
}
(None, false) => (),
}
if security && sec_ctx.is_none() {
return Err(EncodeError::MissingSecurityCtx)?;
} else if security {
match self.auxiliary_security_header {
Some(aux_sec_head) => match sec_ctx {
Some(sec_ctx) => {
bytes.write_with(offset, aux_sec_head, sec_ctx)?;
}
None => return Err(EncodeError::UnknownError)?,
},
None => return Err(EncodeError::UnknownError)?,
}
}
Ok(*offset)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PanId(pub u16);
impl PanId {
pub fn broadcast() -> Self {
Self(0xffff)
}
}
impl TryWrite for PanId {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
bytes.write_with(offset, self.0, LE)?;
Ok(*offset)
}
}
impl TryRead<'_> for PanId {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
Ok((Self(bytes.read_with(offset, LE)?), *offset))
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ShortAddress(pub u16);
impl ShortAddress {
pub const BROADCAST: Self = ShortAddress(0xffff);
pub fn broadcast() -> Self {
ShortAddress(0xffff)
}
}
impl TryWrite for ShortAddress {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
bytes.write_with(offset, self.0, LE)?;
Ok(*offset)
}
}
impl TryRead<'_> for ShortAddress {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
Ok((Self(bytes.read_with(offset, LE)?), *offset))
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Hash32, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ExtendedAddress(pub u64);
impl ExtendedAddress {
pub const BROADCAST: Self = ExtendedAddress(0xffffffffffffffffu64);
pub fn broadcast() -> Self {
ExtendedAddress(0xffffffffffffffffu64)
}
}
impl TryWrite for ExtendedAddress {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
bytes.write_with(offset, self.0, LE)?;
Ok(*offset)
}
}
impl TryRead<'_> for ExtendedAddress {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
Ok((Self(bytes.read_with(offset, LE)?), *offset))
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Address {
Short(PanId, ShortAddress),
Extended(PanId, ExtendedAddress),
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum AddressEncoding {
Normal,
Compressed,
}
impl TryWrite<AddressEncoding> for Address {
fn try_write(
self,
bytes: &mut [u8],
enc: AddressEncoding,
) -> byte::Result<usize> {
let offset = &mut 0;
match (self, enc) {
(Address::Short(pan_id, addr), AddressEncoding::Normal) => {
bytes.write(offset, pan_id)?;
bytes.write(offset, addr)?;
}
(Address::Short(_pan_id, addr), AddressEncoding::Compressed) => {
bytes.write(offset, addr)?;
}
(Address::Extended(pan_id, addr), AddressEncoding::Normal) => {
bytes.write(offset, pan_id)?;
bytes.write(offset, addr)?;
}
(Address::Extended(_pan_id, addr), AddressEncoding::Compressed) => {
bytes.write(offset, addr)?;
}
}
Ok(*offset)
}
}
impl Address {
pub fn broadcast(mode: &AddressMode) -> Option<Self> {
match mode {
AddressMode::None => None,
AddressMode::Short => Some(Address::Short(
PanId::broadcast(),
ShortAddress::broadcast(),
)),
AddressMode::Extended => Some(Address::Extended(
PanId::broadcast(),
ExtendedAddress::broadcast(),
)),
}
}
pub fn pan_id(&self) -> PanId {
match *self {
Address::Short(pan_id, _) => pan_id,
Address::Extended(pan_id, _) => pan_id,
}
}
}