123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- #![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<u8>;
- #[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<u8>)
- /// 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<K> {
- key: Option<K>,
- buffer: Buffer,
- assembler: Assembler,
- total_size: Option<usize>,
- expires_at: Instant,
- }
- impl<K> PacketAssembler<K> {
- /// 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<usize, AssemblerError>,
- ) -> 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<K: Eq + Copy> {
- assemblers: [PacketAssembler<K>; REASSEMBLY_BUFFER_COUNT],
- }
- impl<K: Eq + Copy> PacketAssemblerSet<K> {
- const NEW_PA: PacketAssembler<K> = 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<K>, 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<FragKey>,
- #[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::new(0, 0, 0, 0),
- dst_addr: Ipv4Address::new(0, 0, 0, 0),
- 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::new(0, 0, 0, 0),
- dst_addr: Ipv4Address::new(0, 0, 0, 0),
- 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::<Key>::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::<Key>::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::<Key>::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][..]));
- }
- }
|