use core::fmt;
use crate::crypto::{self, Crypto};
use crate::error::Error;
use crate::fmt::Bytes;
use crate::utils::storage::{ParseBuf, WriteBuf};
use super::plain_hdr::PlainHdr;
use super::proto_hdr::{self, ProtoHdr};
#[derive(Debug, Default, Clone)]
pub struct PacketHdr {
pub plain: PlainHdr,
pub proto: ProtoHdr,
}
impl PacketHdr {
pub const HDR_RESERVE: usize = PlainHdr::MAX_LEN + ProtoHdr::MAX_LEN;
pub const TAIL_RESERVE: usize = crypto::AEAD_TAG_LEN;
#[inline(always)]
pub const fn new() -> Self {
Self {
plain: PlainHdr::new(),
proto: ProtoHdr::new(),
}
}
pub fn reset(&mut self) {
self.plain = Default::default();
self.proto = Default::default();
self.proto.set_reliable();
}
pub fn load(&mut self, packet: &PacketHdr) {
self.plain = packet.plain.clone();
self.proto = packet.proto.clone();
}
pub fn decode_plain_hdr(&mut self, pb: &mut ParseBuf) -> Result<(), Error> {
self.plain.decode(pb)
}
pub fn decode_remaining<C: Crypto>(
&mut self,
crypto: C,
dec_key: Option<crypto::CanonAeadKeyRef<'_>>,
peer_nodeid: u64,
pb: &mut ParseBuf,
) -> Result<(), Error> {
self.proto
.decrypt_and_decode(crypto, dec_key, peer_nodeid, &self.plain, pb)
}
pub fn encode<C: Crypto>(
&self,
crypto: C,
enc_key: Option<crypto::CanonAeadKeyRef<'_>>,
local_nodeid: u64,
wb: &mut WriteBuf,
) -> Result<(), Error> {
let mut tmp_buf = [0_u8; ProtoHdr::MAX_LEN];
let mut write_buf = WriteBuf::new(&mut tmp_buf);
self.proto.encode(&mut write_buf)?;
wb.prepend(write_buf.as_slice())?;
let mut tmp_buf = [0_u8; PlainHdr::MAX_LEN];
let mut write_buf = WriteBuf::new(&mut tmp_buf);
self.plain.encode(&mut write_buf)?;
let plain_hdr_bytes = write_buf.as_slice();
trace!("Unencrypted packet: {}", Bytes(wb.as_slice()));
let ctr = self.plain.ctr;
if let Some(enc_key) = enc_key {
proto_hdr::encrypt_in_place(
crypto,
enc_key,
self.plain.sec_flags.bits(),
ctr,
local_nodeid,
plain_hdr_bytes,
wb,
)?;
}
wb.prepend(plain_hdr_bytes)?;
trace!("Full encrypted packet: {}", Bytes(wb.as_slice()));
Ok(())
}
}
impl fmt::Display for PacketHdr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}][{}]", self.plain, self.proto)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for PacketHdr {
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "[{}][{}]", self.plain, self.proto)
}
}