#![allow(unused)] use core::fmt; use managed::{ManagedMap, ManagedSlice}; use crate::config::{FRAGMENTATION_BUFFER_SIZE, REASSEMBLY_BUFFER_COUNT, REASSEMBLY_BUFFER_SIZE}; use crate::storage::Assembler; use crate::time::{Duration, Instant}; use crate::wire::*; use core::result::Result; #[cfg(feature = "alloc")] type Buffer = alloc::vec::Vec; #[cfg(not(feature = "alloc"))] type Buffer = [u8; REASSEMBLY_BUFFER_SIZE]; /// Problem when assembling: something was out of bounds. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct AssemblerError; impl fmt::Display for AssemblerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "AssemblerError") } } #[cfg(feature = "std")] impl std::error::Error for AssemblerError {} /// Packet assembler is full #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct AssemblerFullError; impl fmt::Display for AssemblerFullError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "AssemblerFullError") } } #[cfg(feature = "std")] impl std::error::Error for AssemblerFullError {} /// Holds different fragments of one packet, used for assembling fragmented packets. /// /// The buffer used for the `PacketAssembler` should either be dynamically sized (ex: Vec) /// or should be statically allocated based upon the MTU of the type of packet being /// assembled (ex: 1280 for a IPv6 frame). #[derive(Debug)] pub struct PacketAssembler { key: Option, buffer: Buffer, assembler: Assembler, total_size: Option, expires_at: Instant, } impl PacketAssembler { /// Create a new empty buffer for fragments. pub const fn new() -> Self { Self { key: None, #[cfg(feature = "alloc")] buffer: Buffer::new(), #[cfg(not(feature = "alloc"))] buffer: [0u8; REASSEMBLY_BUFFER_SIZE], assembler: Assembler::new(), total_size: None, expires_at: Instant::ZERO, } } pub(crate) fn reset(&mut self) { self.key = None; self.assembler.clear(); self.total_size = None; self.expires_at = Instant::ZERO; } /// Set the total size of the packet assembler. pub(crate) fn set_total_size(&mut self, size: usize) -> Result<(), AssemblerError> { if let Some(old_size) = self.total_size { if old_size != size { return Err(AssemblerError); } } #[cfg(not(feature = "alloc"))] if self.buffer.len() < size { return Err(AssemblerError); } #[cfg(feature = "alloc")] if self.buffer.len() < size { self.buffer.resize(size, 0); } self.total_size = Some(size); Ok(()) } /// Return the instant when the assembler expires. pub(crate) fn expires_at(&self) -> Instant { self.expires_at } pub(crate) fn add_with( &mut self, offset: usize, f: impl Fn(&mut [u8]) -> Result, ) -> Result<(), AssemblerError> { if self.buffer.len() < offset { return Err(AssemblerError); } let len = f(&mut self.buffer[offset..])?; assert!(offset + len <= self.buffer.len()); net_debug!( "frag assembler: receiving {} octets at offset {}", len, offset ); self.assembler.add(offset, len); Ok(()) } /// Add a fragment into the packet that is being reassembled. /// /// # Errors /// /// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing /// place. pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<(), AssemblerError> { #[cfg(not(feature = "alloc"))] if self.buffer.len() < offset + data.len() { return Err(AssemblerError); } #[cfg(feature = "alloc")] if self.buffer.len() < offset + data.len() { self.buffer.resize(offset + data.len(), 0); } let len = data.len(); self.buffer[offset..][..len].copy_from_slice(data); net_debug!( "frag assembler: receiving {} octets at offset {}", len, offset ); self.assembler.add(offset, data.len()); Ok(()) } /// Get an immutable slice of the underlying packet data, if reassembly complete. /// This will mark the assembler as empty, so that it can be reused. pub(crate) fn assemble(&mut self) -> Option<&'_ [u8]> { if !self.is_complete() { return None; } // NOTE: we can unwrap because `is_complete` already checks this. let total_size = self.total_size.unwrap(); self.reset(); Some(&self.buffer[..total_size]) } /// Returns `true` when all fragments have been received, otherwise `false`. pub(crate) fn is_complete(&self) -> bool { self.total_size == Some(self.assembler.peek_front()) } /// Returns `true` when the packet assembler is free to use. fn is_free(&self) -> bool { self.key.is_none() } } /// Set holding multiple [`PacketAssembler`]. #[derive(Debug)] pub struct PacketAssemblerSet { assemblers: [PacketAssembler; REASSEMBLY_BUFFER_COUNT], } impl PacketAssemblerSet { const NEW_PA: PacketAssembler = PacketAssembler::new(); /// Create a new set of packet assemblers. pub fn new() -> Self { Self { assemblers: [Self::NEW_PA; REASSEMBLY_BUFFER_COUNT], } } /// Get a [`PacketAssembler`] for a specific key. /// /// If it doesn't exist, it is created, with the `expires_at` timestamp. /// /// If the assembler set is full, in which case an error is returned. pub(crate) fn get( &mut self, key: &K, expires_at: Instant, ) -> Result<&mut PacketAssembler, AssemblerFullError> { let mut empty_slot = None; for slot in &mut self.assemblers { if slot.key.as_ref() == Some(key) { return Ok(slot); } if slot.is_free() { empty_slot = Some(slot) } } let slot = empty_slot.ok_or(AssemblerFullError)?; slot.key = Some(*key); slot.expires_at = expires_at; Ok(slot) } /// Remove all [`PacketAssembler`]s that are expired. pub fn remove_expired(&mut self, timestamp: Instant) { for frag in &mut self.assemblers { if !frag.is_free() && frag.expires_at < timestamp { frag.reset(); } } } } // Max len of non-fragmented packets after decompression (including ipv6 header and payload) // TODO: lower. Should be (6lowpan mtu) - (min 6lowpan header size) + (max ipv6 header size) pub(crate) const MAX_DECOMPRESSED_LEN: usize = 1500; #[cfg(feature = "_proto-fragmentation")] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) enum FragKey { #[cfg(feature = "proto-ipv4-fragmentation")] Ipv4(Ipv4FragKey), #[cfg(feature = "proto-sixlowpan-fragmentation")] Sixlowpan(SixlowpanFragKey), } pub(crate) struct FragmentsBuffer { #[cfg(feature = "proto-sixlowpan")] pub decompress_buf: [u8; MAX_DECOMPRESSED_LEN], #[cfg(feature = "_proto-fragmentation")] pub assembler: PacketAssemblerSet, #[cfg(feature = "_proto-fragmentation")] pub reassembly_timeout: Duration, } #[cfg(not(feature = "_proto-fragmentation"))] pub(crate) struct Fragmenter {} #[cfg(not(feature = "_proto-fragmentation"))] impl Fragmenter { pub(crate) fn new() -> Self { Self {} } } #[cfg(feature = "_proto-fragmentation")] pub(crate) struct Fragmenter { /// The buffer that holds the unfragmented 6LoWPAN packet. pub buffer: [u8; FRAGMENTATION_BUFFER_SIZE], /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers. pub packet_len: usize, /// The amount of bytes that already have been transmitted. pub sent_bytes: usize, #[cfg(feature = "proto-ipv4-fragmentation")] pub ipv4: Ipv4Fragmenter, #[cfg(feature = "proto-sixlowpan-fragmentation")] pub sixlowpan: SixlowpanFragmenter, } #[cfg(feature = "proto-ipv4-fragmentation")] pub(crate) struct Ipv4Fragmenter { /// The IPv4 representation. pub repr: Ipv4Repr, /// The destination hardware address. #[cfg(feature = "medium-ethernet")] pub dst_hardware_addr: EthernetAddress, /// The offset of the next fragment. pub frag_offset: u16, /// The identifier of the stream. pub ident: u16, } #[cfg(feature = "proto-sixlowpan-fragmentation")] pub(crate) struct SixlowpanFragmenter { /// The datagram size that is used for the fragmentation headers. pub datagram_size: u16, /// The datagram tag that is used for the fragmentation headers. pub datagram_tag: u16, pub datagram_offset: usize, /// The size of the FRAG_N packets. pub fragn_size: usize, /// The link layer IEEE802.15.4 source address. pub ll_dst_addr: Ieee802154Address, /// The link layer IEEE802.15.4 source address. pub ll_src_addr: Ieee802154Address, } #[cfg(feature = "_proto-fragmentation")] impl Fragmenter { pub(crate) fn new() -> Self { Self { buffer: [0u8; FRAGMENTATION_BUFFER_SIZE], packet_len: 0, sent_bytes: 0, #[cfg(feature = "proto-ipv4-fragmentation")] ipv4: Ipv4Fragmenter { repr: Ipv4Repr { src_addr: Ipv4Address::default(), dst_addr: Ipv4Address::default(), next_header: IpProtocol::Unknown(0), payload_len: 0, hop_limit: 0, }, #[cfg(feature = "medium-ethernet")] dst_hardware_addr: EthernetAddress::default(), frag_offset: 0, ident: 0, }, #[cfg(feature = "proto-sixlowpan-fragmentation")] sixlowpan: SixlowpanFragmenter { datagram_size: 0, datagram_tag: 0, datagram_offset: 0, fragn_size: 0, ll_dst_addr: Ieee802154Address::Absent, ll_src_addr: Ieee802154Address::Absent, }, } } /// Return `true` when everything is transmitted. #[inline] pub(crate) fn finished(&self) -> bool { self.packet_len == self.sent_bytes } /// Returns `true` when there is nothing to transmit. #[inline] pub(crate) fn is_empty(&self) -> bool { self.packet_len == 0 } // Reset the buffer. pub(crate) fn reset(&mut self) { self.packet_len = 0; self.sent_bytes = 0; #[cfg(feature = "proto-ipv4-fragmentation")] { self.ipv4.repr = Ipv4Repr { src_addr: Ipv4Address::default(), dst_addr: Ipv4Address::default(), next_header: IpProtocol::Unknown(0), payload_len: 0, hop_limit: 0, }; #[cfg(feature = "medium-ethernet")] { self.ipv4.dst_hardware_addr = EthernetAddress::default(); } } #[cfg(feature = "proto-sixlowpan-fragmentation")] { self.sixlowpan.datagram_size = 0; self.sixlowpan.datagram_tag = 0; self.sixlowpan.fragn_size = 0; self.sixlowpan.ll_dst_addr = Ieee802154Address::Absent; self.sixlowpan.ll_src_addr = Ieee802154Address::Absent; } } } #[cfg(test)] mod tests { use super::*; #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] struct Key { id: usize, } #[test] fn packet_assembler_overlap() { let mut p_assembler = PacketAssembler::::new(); p_assembler.set_total_size(5).unwrap(); let data = b"Rust"; p_assembler.add(&data[..], 0); p_assembler.add(&data[..], 1); assert_eq!(p_assembler.assemble(), Some(&b"RRust"[..])) } #[test] fn packet_assembler_assemble() { let mut p_assembler = PacketAssembler::::new(); let data = b"Hello World!"; p_assembler.set_total_size(data.len()).unwrap(); p_assembler.add(b"Hello ", 0).unwrap(); assert_eq!(p_assembler.assemble(), None); p_assembler.add(b"World!", b"Hello ".len()).unwrap(); assert_eq!(p_assembler.assemble(), Some(&b"Hello World!"[..])); } #[test] fn packet_assembler_out_of_order_assemble() { let mut p_assembler = PacketAssembler::::new(); let data = b"Hello World!"; p_assembler.set_total_size(data.len()).unwrap(); p_assembler.add(b"World!", b"Hello ".len()).unwrap(); assert_eq!(p_assembler.assemble(), None); p_assembler.add(b"Hello ", 0).unwrap(); assert_eq!(p_assembler.assemble(), Some(&b"Hello World!"[..])); } #[test] fn packet_assembler_set() { let key = Key { id: 1 }; let mut set = PacketAssemblerSet::new(); assert!(set.get(&key, Instant::ZERO).is_ok()); } #[test] fn packet_assembler_set_full() { let mut set = PacketAssemblerSet::new(); for i in 0..REASSEMBLY_BUFFER_COUNT { set.get(&Key { id: i }, Instant::ZERO).unwrap(); } assert!(set.get(&Key { id: 4 }, Instant::ZERO).is_err()); } #[test] fn packet_assembler_set_assembling_many() { let mut set = PacketAssemblerSet::new(); let key = Key { id: 0 }; let assr = set.get(&key, Instant::ZERO).unwrap(); assert_eq!(assr.assemble(), None); assr.set_total_size(0).unwrap(); assr.assemble().unwrap(); // Test that `.assemble()` effectively deletes it. let assr = set.get(&key, Instant::ZERO).unwrap(); assert_eq!(assr.assemble(), None); assr.set_total_size(0).unwrap(); assr.assemble().unwrap(); let key = Key { id: 1 }; let assr = set.get(&key, Instant::ZERO).unwrap(); assr.set_total_size(0).unwrap(); assr.assemble().unwrap(); let key = Key { id: 2 }; let assr = set.get(&key, Instant::ZERO).unwrap(); assr.set_total_size(0).unwrap(); assr.assemble().unwrap(); let key = Key { id: 2 }; let assr = set.get(&key, Instant::ZERO).unwrap(); assr.set_total_size(2).unwrap(); assr.add(&[0x00], 0).unwrap(); assert_eq!(assr.assemble(), None); let assr = set.get(&key, Instant::ZERO).unwrap(); assr.add(&[0x01], 1).unwrap(); assert_eq!(assr.assemble(), Some(&[0x00, 0x01][..])); } }