Sfoglia il codice sorgente

packet assembler: simplify data structure and api.

Dario Nieuwenhuis 2 anni fa
parent
commit
af115a5769

+ 9 - 24
examples/client.rs

@@ -1,16 +1,9 @@
 mod utils;
 
 use log::debug;
-use std::collections::BTreeMap;
 use std::os::unix::io::AsRawFd;
 use std::str::{self, FromStr};
 
-#[cfg(any(
-    feature = "proto-sixlowpan-fragmentation",
-    feature = "proto-ipv4-fragmentation"
-))]
-use smoltcp::iface::ReassemblyBuffer;
-
 use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::tcp;
@@ -51,33 +44,25 @@ fn main() {
     routes.add_default_ipv4_route(default_v4_gw).unwrap();
 
     let medium = device.capabilities().medium;
-    let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
+    let builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
 
     #[cfg(feature = "proto-ipv4-fragmentation")]
     let mut ipv4_out_packet_cache = [0u8; 1280];
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    {
-        let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder
-            .ipv4_reassembly_buffer(ipv4_frag_cache)
-            .ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
-    }
+    let builder = builder.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
 
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     let mut sixlowpan_out_packet_cache = [0u8; 1280];
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    {
-        let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder
-            .sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
-            .sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
-    }
+    let builder = builder.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
 
-    if medium == Medium::Ethernet {
-        builder = builder
+    let builder = if medium == Medium::Ethernet {
+        builder
             .hardware_addr(ethernet_addr.into())
-            .neighbor_cache(neighbor_cache);
-    }
+            .neighbor_cache(neighbor_cache)
+    } else {
+        builder
+    };
     let mut iface = builder.finalize(&mut device);
 
     let mut sockets = SocketSet::new(vec![]);

+ 2 - 18
examples/server.rs

@@ -1,15 +1,9 @@
 mod utils;
 
 use log::debug;
-use std::collections::BTreeMap;
 use std::fmt::Write;
 use std::os::unix::io::AsRawFd;
 
-#[cfg(any(
-    feature = "proto-sixlowpan-fragmentation",
-    feature = "proto-ipv4-fragmentation"
-))]
-use smoltcp::iface::ReassemblyBuffer;
 use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::{tcp, udp};
@@ -82,22 +76,12 @@ fn main() {
     #[cfg(feature = "proto-ipv4-fragmentation")]
     let mut ipv4_out_packet_cache = [0u8; 10_000];
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    {
-        let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder
-            .ipv4_reassembly_buffer(ipv4_frag_cache)
-            .ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
-    }
+    let builder = builder.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
 
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     let mut sixlowpan_out_packet_cache = [0u8; 1280];
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    {
-        let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder
-            .sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
-            .sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
-    }
+    let mut builder = builder.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
 
     if medium == Medium::Ethernet {
         builder = builder

+ 2 - 12
examples/sixlowpan.rs

@@ -43,11 +43,10 @@
 mod utils;
 
 use log::debug;
-use std::collections::BTreeMap;
 use std::os::unix::io::AsRawFd;
 use std::str;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, ReassemblyBuffer, SocketSet};
+use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
 use smoltcp::socket::tcp;
 use smoltcp::socket::udp;
@@ -96,20 +95,11 @@ fn main() {
         .hardware_addr(ieee802154_addr.into())
         .neighbor_cache(neighbor_cache);
 
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    {
-        let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder.ipv4_reassembly_buffer(ipv4_frag_cache);
-    }
-
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     let mut out_packet_buffer = [0u8; 1280];
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     {
-        let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-        builder = builder
-            .sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
-            .sixlowpan_fragmentation_buffer(&mut out_packet_buffer[..]);
+        builder = builder.sixlowpan_fragmentation_buffer(&mut out_packet_buffer[..]);
     }
 
     let mut iface = builder.finalize(&mut device);

+ 1 - 5
examples/sixlowpan_benchmark.rs

@@ -44,11 +44,10 @@
 mod utils;
 
 use log::debug;
-use std::collections::BTreeMap;
 use std::os::unix::io::AsRawFd;
 use std::str;
 
-use smoltcp::iface::{InterfaceBuilder, NeighborCache, ReassemblyBuffer, SocketSet};
+use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
 use smoltcp::socket::tcp;
 use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
@@ -169,15 +168,12 @@ fn main() {
         ))
         .unwrap();
 
-    let cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
-
     let mut builder = InterfaceBuilder::new()
         .ip_addrs(ip_addrs)
         .pan_id(Ieee802154Pan(0xbeef));
     builder = builder
         .hardware_addr(ieee802154_addr.into())
         .neighbor_cache(neighbor_cache)
-        .sixlowpan_reassembly_buffer(cache)
         .sixlowpan_fragmentation_buffer(vec![]);
     let mut iface = builder.finalize(&mut device);
 

+ 155 - 333
src/iface/fragmentation.rs

@@ -6,8 +6,24 @@ use managed::{ManagedMap, ManagedSlice};
 
 use crate::storage::Assembler;
 use crate::time::{Duration, Instant};
-use crate::Error;
-use crate::Result;
+
+// TODO: make configurable.
+const BUFFER_SIZE: usize = 1500;
+
+#[cfg(feature = "alloc")]
+type Buffer = alloc::vec::Vec<u8>;
+#[cfg(not(feature = "alloc"))]
+type Buffer = [u8; BUFFER_SIZE];
+
+const PACKET_ASSEMBLER_COUNT: usize = 4;
+
+/// Problem when assembling: something was out of bounds.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct AssemblerError;
+
+/// Packet assembler is full
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct AssemblerFullError;
 
 /// Holds different fragments of one packet, used for assembling fragmented packets.
 ///
@@ -15,8 +31,9 @@ use crate::Result;
 /// 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<'a> {
-    buffer: ManagedSlice<'a, u8>,
+pub struct PacketAssembler<K> {
+    key: Option<K>,
+    buffer: Buffer,
 
     assembler: Assembler,
     total_size: Option<usize>,
@@ -24,15 +41,16 @@ pub struct PacketAssembler<'a> {
     offset_correction: isize,
 }
 
-impl<'a> PacketAssembler<'a> {
+impl<K> PacketAssembler<K> {
     /// Create a new empty buffer for fragments.
-    pub fn new<S>(storage: S) -> Self
-    where
-        S: Into<ManagedSlice<'a, u8>>,
-    {
-        let s = storage.into();
-        PacketAssembler {
-            buffer: s,
+    pub fn new() -> Self {
+        Self {
+            key: None,
+
+            #[cfg(feature = "alloc")]
+            buffer: Buffer::new(),
+            #[cfg(not(feature = "alloc"))]
+            buffer: [0u8; BUFFER_SIZE],
 
             assembler: Assembler::new(),
             total_size: None,
@@ -42,50 +60,33 @@ impl<'a> PacketAssembler<'a> {
     }
 
     pub(crate) fn reset(&mut self) {
-        self.assembler = Assembler::new();
+        self.key = None;
+        self.assembler.clear();
         self.total_size = None;
         self.expires_at = Instant::ZERO;
         self.offset_correction = 0;
     }
 
-    /// Start with saving fragments.
-    /// We initialize the assembler with the total size of the final packet.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerBufferTooSmall`] when the buffer is too small for holding all the
-    /// fragments of a packet.
-    pub(crate) fn start(
-        &mut self,
-        total_size: Option<usize>,
-        expires_at: Instant,
-        offset_correction: isize,
-    ) -> Result<()> {
-        self.reset();
-        if let Some(total_size) = total_size {
-            self.set_total_size(total_size)?;
-        }
-        self.expires_at = expires_at;
-        self.offset_correction = offset_correction;
-        Ok(())
+    pub(crate) fn set_offset_correction(&mut self, correction: isize) {
+        self.offset_correction = correction;
     }
 
     /// Set the total size of the packet assembler.
-    pub(crate) fn set_total_size(&mut self, size: usize) -> Result<()> {
+    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(Error::Malformed);
+                return Err(AssemblerError);
             }
         }
 
-        match &mut self.buffer {
-            ManagedSlice::Borrowed(b) => {
-                if b.len() < size {
-                    return Err(Error::PacketAssemblerBufferTooSmall);
-                }
-            }
-            #[cfg(feature = "alloc")]
-            ManagedSlice::Owned(b) => b.resize(size, 0),
+        #[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);
@@ -93,8 +94,8 @@ impl<'a> PacketAssembler<'a> {
     }
 
     /// Return the instant when the assembler expires.
-    pub(crate) fn expires_at(&self) -> Result<Instant> {
-        Ok(self.expires_at)
+    pub(crate) fn expires_at(&self) -> Instant {
+        self.expires_at
     }
 
     /// Add a fragment into the packet that is being reassembled.
@@ -103,29 +104,25 @@ impl<'a> PacketAssembler<'a> {
     ///
     /// - 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<bool> {
+    pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<(), AssemblerError> {
         let offset = offset as isize + self.offset_correction;
         let offset = if offset <= 0 { 0 } else { offset as usize };
 
-        match &mut self.buffer {
-            ManagedSlice::Borrowed(b) => {
-                if offset + data.len() > b.len() {
-                    return Err(Error::PacketAssemblerBufferTooSmall);
-                }
-            }
-            #[cfg(feature = "alloc")]
-            ManagedSlice::Owned(b) => {
-                if offset + data.len() > b.len() {
-                    b.resize(offset + data.len(), 0);
-                }
-            }
+        #[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 {} octests at offset {}",
+            "frag assembler: receiving {} octets at offset {}",
             len,
             offset
         );
@@ -133,225 +130,92 @@ impl<'a> PacketAssembler<'a> {
         match self.assembler.add(offset, data.len()) {
             Ok(()) => {
                 net_debug!("assembler: {}", self.assembler);
-                self.is_complete()
+                Ok(())
+            }
+            Err(_) => {
+                net_debug!("packet assembler: too many holes, dropping.");
+                Err(AssemblerError)
             }
-            // NOTE(thvdveld): hopefully we wont get too many holes errors I guess?
-            Err(_) => Err(Error::PacketAssemblerTooManyHoles),
         }
     }
 
-    /// Get an immutable slice of the underlying packet data.
+    /// 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.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerIncomplete`] when not all the fragments have been collected.
-    pub(crate) fn assemble(&mut self) -> Result<&'_ [u8]> {
-        if !self.is_complete()? {
-            return Err(Error::PacketAssemblerIncomplete);
+    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();
-        let a = &self.buffer[..total_size];
-
-        Ok(a)
+        self.reset();
+        Some(&self.buffer[..total_size])
     }
 
     /// Returns `true` when all fragments have been received, otherwise `false`.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerNotInit`] when the assembler was not initialized (try initializing the
-    /// assembler with [`Self::start`]).
-    pub(crate) fn is_complete(&self) -> Result<bool> {
-        match (self.total_size, self.assembler.peek_front()) {
-            (Some(total_size), front) => Ok(front == total_size),
-            _ => Ok(false),
-        }
+    pub(crate) fn is_complete(&self) -> bool {
+        self.total_size == Some(self.assembler.peek_front())
     }
 
-    /// Returns `true` when the packet assembler is empty (free to use).
-    fn is_empty(&self) -> bool {
-        self.assembler.is_empty()
+    /// 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<'a, Key: Eq + Ord + Clone + Copy> {
-    packet_buffer: ManagedSlice<'a, PacketAssembler<'a>>,
-    index_buffer: ManagedMap<'a, Key, usize>,
+pub struct PacketAssemblerSet<K: Eq + Copy> {
+    assemblers: [PacketAssembler<K>; PACKET_ASSEMBLER_COUNT],
 }
 
-impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
+impl<K: Eq + Copy> PacketAssemblerSet<K> {
     /// Create a new set of packet assemblers.
-    ///
-    /// # Panics
-    ///
-    /// This will panic when:
-    ///   - The packet buffer and index buffer don't have the same size or are empty (when they are
-    ///   both borrowed).
-    ///   - The packet buffer is empty (when only the packet buffer is borrowed).
-    ///   - The index buffer is empty (when only the index buffer is borrowed).
-    pub fn new<FB, IB>(packet_buffer: FB, index_buffer: IB) -> Self
-    where
-        FB: Into<ManagedSlice<'a, PacketAssembler<'a>>>,
-        IB: Into<ManagedMap<'a, K, usize>>,
-    {
-        let packet_buffer = packet_buffer.into();
-        let index_buffer = index_buffer.into();
-
-        match (&packet_buffer, &index_buffer) {
-            (ManagedSlice::Borrowed(f), ManagedMap::Borrowed(i)) => {
-                if f.len() != i.len() {
-                    panic!("The amount of places in the index buffer must be the same as the amount of possible fragments assemblers.");
-                }
-            }
-            #[cfg(feature = "alloc")]
-            (ManagedSlice::Borrowed(f), ManagedMap::Owned(_)) => {
-                if f.is_empty() {
-                    panic!("The packet buffer cannot be empty.");
-                }
-            }
-            #[cfg(feature = "alloc")]
-            (ManagedSlice::Owned(_), ManagedMap::Borrowed(i)) => {
-                if i.is_empty() {
-                    panic!("The index buffer cannot be empty.");
-                }
-            }
-            #[cfg(feature = "alloc")]
-            (ManagedSlice::Owned(_), ManagedMap::Owned(_)) => (),
-        }
-
+    pub fn new() -> Self {
         Self {
-            packet_buffer,
-            index_buffer,
-        }
-    }
-
-    /// Reserve a [`PacketAssembler`], which is linked to a specific key.
-    /// Returns the reserved fragments assembler.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerSetFull`] when every [`PacketAssembler`] in the buffer is used (only
-    /// when the non allocating version of is used).
-    pub(crate) fn reserve_with_key(&mut self, key: &K) -> Result<&mut PacketAssembler<'a>> {
-        // Check how many WIP reassemblies we have.
-        // The limit is currently set to 255.
-        if self.index_buffer.len() == u8::MAX as usize {
-            return Err(Error::PacketAssemblerSetFull);
-        }
-
-        if self.packet_buffer.len() == self.index_buffer.len() {
-            match &mut self.packet_buffer {
-                ManagedSlice::Borrowed(_) => return Err(Error::PacketAssemblerSetFull),
-                #[cfg(feature = "alloc")]
-                ManagedSlice::Owned(b) => (),
-            }
-        }
-
-        let i = self
-            .get_free_packet_assembler()
-            .ok_or(Error::PacketAssemblerSetFull)?;
-
-        // NOTE(thvdveld): this should not fail because we already checked the available space.
-        match self.index_buffer.insert(*key, i) {
-            Ok(_) => Ok(&mut self.packet_buffer[i]),
-            Err(_) => unreachable!(),
-        }
-    }
-
-    /// Return the first free packet assembler available from the cache.
-    fn get_free_packet_assembler(&mut self) -> Option<usize> {
-        match &mut self.packet_buffer {
-            ManagedSlice::Borrowed(_) => (),
-            #[cfg(feature = "alloc")]
-            ManagedSlice::Owned(b) => b.push(PacketAssembler::new(alloc::vec![])),
+            // TODO: support any PACKET_ASSEMBLER_COUNT
+            assemblers: [
+                PacketAssembler::new(),
+                PacketAssembler::new(),
+                PacketAssembler::new(),
+                PacketAssembler::new(),
+            ],
         }
-
-        self.packet_buffer
-            .iter()
-            .enumerate()
-            .find(|(_, b)| b.is_empty())
-            .map(|(i, _)| i)
     }
 
-    /// Return a mutable slice to a packet assembler.
-    ///
-    /// # Errors
+    /// Get a [`PacketAssembler`] for a specific key.
     ///
-    /// - Returns [`Error::PacketAssemblerSetKeyNotFound`] when the key was not found in the set.
-    pub(crate) fn get_packet_assembler_mut(&mut self, key: &K) -> Result<&mut PacketAssembler<'a>> {
-        if let Some(i) = self.index_buffer.get(key) {
-            Ok(&mut self.packet_buffer[*i])
-        } else {
-            Err(Error::PacketAssemblerSetKeyNotFound)
-        }
-    }
-
-    /// Return the assembled packet from a packet assembler.
-    /// This also removes it from the set.
+    /// If it doesn't exist, it is created, with the `expires_at` timestamp.
     ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerSetKeyNotFound`] when the `key` was not found.
-    /// - Returns [`Error::PacketAssemblerIncomplete`] when the fragments assembler was empty or not fully assembled.
-    pub(crate) fn get_assembled_packet(&mut self, key: &K) -> Result<&[u8]> {
-        if let Some(i) = self.index_buffer.get(key) {
-            let p = self.packet_buffer[*i].assemble()?;
-            self.index_buffer.remove(key);
-            Ok(p)
-        } else {
-            Err(Error::PacketAssemblerSetKeyNotFound)
-        }
-    }
-
-    /// Remove all [`PacketAssembler`]s that are marked as discarded.
-    pub fn remove_discarded(&mut self) {
-        loop {
-            let mut key = None;
-            for (k, i) in self.index_buffer.iter() {
-                if self.packet_buffer[*i].is_empty() {
-                    key = Some(*k);
-                    break;
-                }
+    /// 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 let Some(k) = key {
-                self.index_buffer.remove(&k);
-            } else {
-                break;
+            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)
     }
 
-    /// Mark all [`PacketAssembler`]s as discarded for which `f` returns `Ok(true)`.
-    /// This does not remove them from the buffer.
-    pub fn mark_discarded_when<F>(&mut self, f: F) -> Result<()>
-    where
-        F: Fn(&mut PacketAssembler<'_>) -> Result<bool>,
-    {
-        for (_, i) in &mut self.index_buffer.iter() {
-            let frag = &mut self.packet_buffer[*i];
-            if f(frag)? {
+    /// 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();
             }
         }
-
-        Ok(())
-    }
-
-    /// Remove all [`PacketAssembler`]s for which `f` returns `Ok(true)`.
-    pub fn remove_when<F>(&mut self, f: F) -> Result<()>
-    where
-        F: Fn(&mut PacketAssembler<'_>) -> Result<bool>,
-    {
-        self.mark_discarded_when(f)?;
-        self.remove_discarded();
-
-        Ok(())
     }
 }
 
@@ -364,145 +228,103 @@ mod tests {
         id: usize,
     }
 
-    #[test]
-    fn packet_assembler_buffer_too_small() {
-        let mut storage = [0u8; 1];
-        let mut p_assembler = PacketAssembler::new(&mut storage[..]);
-
-        assert_eq!(
-            p_assembler.start(Some(2), Instant::from_secs(0), 0),
-            Err(Error::PacketAssemblerBufferTooSmall)
-        );
-        assert_eq!(p_assembler.start(Some(1), Instant::from_secs(0), 0), Ok(()));
-
-        let data = b"Hello World!";
-        assert_eq!(
-            p_assembler.add(&data[..], data.len()),
-            Err(Error::PacketAssemblerBufferTooSmall)
-        );
-    }
-
     #[test]
     fn packet_assembler_overlap() {
-        let mut storage = [0u8; 5];
-        let mut p_assembler = PacketAssembler::new(&mut storage[..]);
+        let mut p_assembler = PacketAssembler::<Key>::new();
 
-        p_assembler
-            .start(Some(5), Instant::from_secs(0), 0)
-            .unwrap();
-        let data = b"Rust";
+        p_assembler.set_total_size(5).unwrap();
 
-        p_assembler.add(&data[..], 0).unwrap();
+        let data = b"Rust";
+        p_assembler.add(&data[..], 0);
+        p_assembler.add(&data[..], 1);
 
-        assert_eq!(p_assembler.add(&data[..], 1), Ok(true));
+        assert_eq!(p_assembler.assemble(), Some(&b"RRust"[..]))
     }
 
     #[test]
     fn packet_assembler_assemble() {
-        let mut storage = [0u8; 12];
-        let mut p_assembler = PacketAssembler::new(&mut storage[..]);
+        let mut p_assembler = PacketAssembler::<Key>::new();
 
         let data = b"Hello World!";
 
-        p_assembler
-            .start(Some(data.len()), Instant::from_secs(0), 0)
-            .unwrap();
+        p_assembler.set_total_size(data.len()).unwrap();
 
         p_assembler.add(b"Hello ", 0).unwrap();
-        assert_eq!(
-            p_assembler.assemble(),
-            Err(Error::PacketAssemblerIncomplete)
-        );
+        assert_eq!(p_assembler.assemble(), None);
 
         p_assembler.add(b"World!", b"Hello ".len()).unwrap();
 
-        assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
+        assert_eq!(p_assembler.assemble(), Some(&b"Hello World!"[..]));
     }
 
     #[test]
     fn packet_assembler_out_of_order_assemble() {
-        let mut storage = [0u8; 12];
-        let mut p_assembler = PacketAssembler::new(&mut storage[..]);
+        let mut p_assembler = PacketAssembler::<Key>::new();
 
         let data = b"Hello World!";
 
-        p_assembler
-            .start(Some(data.len()), Instant::from_secs(0), 0)
-            .unwrap();
+        p_assembler.set_total_size(data.len()).unwrap();
 
         p_assembler.add(b"World!", b"Hello ".len()).unwrap();
-        assert_eq!(
-            p_assembler.assemble(),
-            Err(Error::PacketAssemblerIncomplete)
-        );
+        assert_eq!(p_assembler.assemble(), None);
 
         p_assembler.add(b"Hello ", 0).unwrap();
 
-        assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
+        assert_eq!(p_assembler.assemble(), Some(&b"Hello World!"[..]));
     }
 
     #[test]
     fn packet_assembler_set() {
         let key = Key { id: 1 };
 
-        let mut set = PacketAssemblerSet::<'_, _>::new(vec![], std::collections::BTreeMap::new());
-
-        if let Err(e) = set.get_packet_assembler_mut(&key) {
-            assert_eq!(e, Error::PacketAssemblerSetKeyNotFound);
-        }
+        let mut set = PacketAssemblerSet::new();
 
-        assert!(set.reserve_with_key(&key).is_ok());
+        assert!(set.get(&key, Instant::ZERO).is_ok());
     }
 
     #[test]
-    fn packet_assembler_set_borrowed() {
-        let mut buf = [0u8, 127];
-        let mut packet_assembler_cache = [PacketAssembler::<'_>::new(&mut buf[..])];
-        let mut packet_index_cache = [None];
-
-        let key = Key { id: 1 };
-
-        let mut set =
-            PacketAssemblerSet::new(&mut packet_assembler_cache[..], &mut packet_index_cache[..]);
-
-        if let Err(e) = set.get_packet_assembler_mut(&key) {
-            assert_eq!(e, Error::PacketAssemblerSetKeyNotFound);
-        }
-
-        assert!(set.reserve_with_key(&key).is_ok());
+    fn packet_assembler_set_full() {
+        let mut set = PacketAssemblerSet::new();
+        set.get(&Key { id: 0 }, Instant::ZERO).unwrap();
+        set.get(&Key { id: 1 }, Instant::ZERO).unwrap();
+        set.get(&Key { id: 2 }, Instant::ZERO).unwrap();
+        set.get(&Key { id: 3 }, Instant::ZERO).unwrap();
+        assert!(set.get(&Key { id: 4 }, Instant::ZERO).is_err());
     }
 
     #[test]
     fn packet_assembler_set_assembling_many() {
-        let mut buf = [0u8, 127];
-        let mut packet_assembler_cache = [PacketAssembler::new(&mut buf[..])];
-        let mut packet_index_cache = [None];
-
-        let mut set =
-            PacketAssemblerSet::new(&mut packet_assembler_cache[..], &mut packet_index_cache[..]);
+        let mut set = PacketAssemblerSet::new();
 
         let key = Key { id: 0 };
-        set.reserve_with_key(&key).unwrap();
-        set.get_packet_assembler_mut(&key)
-            .unwrap()
-            .start(Some(0), Instant::from_secs(0), 0)
-            .unwrap();
-        set.get_assembled_packet(&key).unwrap();
+        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 };
-        set.reserve_with_key(&key).unwrap();
-        set.get_packet_assembler_mut(&key)
-            .unwrap()
-            .start(Some(0), Instant::from_secs(0), 0)
-            .unwrap();
-        set.get_assembled_packet(&key).unwrap();
+        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 };
-        set.reserve_with_key(&key).unwrap();
-        set.get_packet_assembler_mut(&key)
-            .unwrap()
-            .start(Some(0), Instant::from_secs(0), 0)
-            .unwrap();
-        set.get_assembled_packet(&key).unwrap();
+        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][..]));
     }
 }

+ 1 - 1
src/iface/interface/ethernet.rs

@@ -15,7 +15,7 @@ impl<'i> InterfaceInner<'i> {
         &mut self,
         sockets: &mut SocketSet,
         frame: &'frame T,
-        _fragments: &'frame mut FragmentsBuffer<'i>,
+        _fragments: &'frame mut FragmentsBuffer,
     ) -> Option<EthernetPacket<'frame>> {
         let eth_frame = check!(EthernetFrame::new_checked(frame));
 

+ 15 - 28
src/iface/interface/ipv4.rs

@@ -28,7 +28,7 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         sockets: &mut SocketSet,
         ipv4_packet: &Ipv4Packet<&'payload T>,
-        _fragments: Option<&'output mut PacketAssemblerSet<'a, Ipv4FragKey>>,
+        _fragments: Option<&'output mut PacketAssemblerSet<Ipv4FragKey>>,
     ) -> Option<IpPacket<'output>> {
         let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
         if !self.is_unicast_v4(ipv4_repr.src_addr) {
@@ -46,21 +46,11 @@ impl<'a> InterfaceInner<'a> {
             if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
                 let key = ipv4_packet.get_key();
 
-                let f = match fragments.get_packet_assembler_mut(&key) {
+                let f = match fragments.get(&key, self.now + REASSEMBLY_TIMEOUT) {
                     Ok(f) => f,
                     Err(_) => {
-                        let p = match fragments.reserve_with_key(&key) {
-                            Ok(p) => p,
-                            Err(Error::PacketAssemblerSetFull) => {
-                                net_debug!("No available packet assembler for fragmented packet");
-                                return Default::default();
-                            }
-                            e => check!(e),
-                        };
-
-                        check!(p.start(None, self.now + REASSEMBLY_TIMEOUT, 0));
-
-                        check!(fragments.get_packet_assembler_mut(&key))
+                        net_debug!("No available packet assembler for fragmented packet");
+                        return None;
                     }
                 };
 
@@ -72,20 +62,17 @@ impl<'a> InterfaceInner<'a> {
                     ));
                 }
 
-                match f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
-                    Ok(true) => {
-                        // NOTE: according to the standard, the total length needs to be
-                        // recomputed, as well as the checksum. However, we don't really use
-                        // the IPv4 header after the packet is reassembled.
-                        check!(fragments.get_assembled_packet(&key))
-                    }
-                    Ok(false) => {
-                        return None;
-                    }
-                    Err(e) => {
-                        net_debug!("fragmentation error: {}", e);
-                        return None;
-                    }
+                if let Err(e) = f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
+                    net_debug!("fragmentation error: {:?}", e);
+                    return None;
+                }
+
+                // NOTE: according to the standard, the total length needs to be
+                // recomputed, as well as the checksum. However, we don't really use
+                // the IPv4 header after the packet is reassembled.
+                match f.assemble() {
+                    Some(payload) => payload,
+                    None => return None,
                 }
             } else {
                 ipv4_packet.payload()

+ 13 - 36
src/iface/interface/mod.rs

@@ -39,18 +39,13 @@ const MAX_IP_ADDR_COUNT: usize = 5;
 #[cfg(feature = "proto-igmp")]
 const MAX_IPV4_MULTICAST_GROUPS: usize = 4;
 
-pub(crate) struct FragmentsBuffer<'a> {
+pub(crate) struct FragmentsBuffer {
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    pub(crate) ipv4_fragments: PacketAssemblerSet<'a, Ipv4FragKey>,
+    pub(crate) ipv4_fragments: PacketAssemblerSet<Ipv4FragKey>,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_fragments: PacketAssemblerSet<'a, SixlowpanFragKey>,
+    sixlowpan_fragments: PacketAssemblerSet<SixlowpanFragKey>,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     sixlowpan_fragments_cache_timeout: Duration,
-    #[cfg(not(any(
-        feature = "proto-ipv4-fragmentation",
-        feature = "proto-sixlowpan-fragmentation"
-    )))]
-    _lifetime: core::marker::PhantomData<&'a ()>,
 }
 
 pub(crate) struct OutPackets<'a> {
@@ -245,7 +240,7 @@ use check;
 /// a `&mut [T]`, or `Vec<T>` if a heap is available.
 pub struct Interface<'a> {
     inner: InterfaceInner<'a>,
-    fragments: FragmentsBuffer<'a>,
+    fragments: FragmentsBuffer,
     out_packets: OutPackets<'a>,
 }
 
@@ -308,12 +303,12 @@ pub struct InterfaceBuilder<'a> {
     random_seed: u64,
 
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    ipv4_fragments: PacketAssemblerSet<'a, Ipv4FragKey>,
+    ipv4_fragments: PacketAssemblerSet<Ipv4FragKey>,
     #[cfg(feature = "proto-ipv4-fragmentation")]
     ipv4_out_buffer: ManagedSlice<'a, u8>,
 
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_fragments: PacketAssemblerSet<'a, SixlowpanFragKey>,
+    sixlowpan_fragments: PacketAssemblerSet<SixlowpanFragKey>,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     sixlowpan_reassembly_buffer_timeout: Duration,
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
@@ -345,9 +340,6 @@ let hw_addr = // ...
 # EthernetAddress::default();
 let neighbor_cache = // ...
 # NeighborCache::new();
-# #[cfg(feature = "proto-ipv4-fragmentation")]
-# let ipv4_frag_cache = // ...
-# ReassemblyBuffer::new(vec![], BTreeMap::new());
 let ip_addrs = // ...
 # heapless::Vec::<IpCidr, 5>::new();
 let builder = InterfaceBuilder::new()
@@ -355,11 +347,6 @@ let builder = InterfaceBuilder::new()
         .neighbor_cache(neighbor_cache)
         .ip_addrs(ip_addrs);
 
-# #[cfg(feature = "proto-ipv4-fragmentation")]
-let builder = builder
-    .ipv4_reassembly_buffer(ipv4_frag_cache)
-    .ipv4_fragmentation_buffer(vec![]);
-
 let iface = builder.finalize(&mut device);
 ```
     "##
@@ -386,12 +373,12 @@ let iface = builder.finalize(&mut device);
             random_seed: 0,
 
             #[cfg(feature = "proto-ipv4-fragmentation")]
-            ipv4_fragments: PacketAssemblerSet::new(&mut [][..], &mut [][..]),
+            ipv4_fragments: PacketAssemblerSet::new(),
             #[cfg(feature = "proto-ipv4-fragmentation")]
             ipv4_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
 
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
-            sixlowpan_fragments: PacketAssemblerSet::new(&mut [][..], &mut [][..]),
+            sixlowpan_fragments: PacketAssemblerSet::new(),
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
             sixlowpan_reassembly_buffer_timeout: Duration::from_secs(60),
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
@@ -512,7 +499,7 @@ let iface = builder.finalize(&mut device);
 
     /// Set the IPv4 reassembly buffer the interface will use.
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    pub fn ipv4_reassembly_buffer(mut self, storage: PacketAssemblerSet<'a, Ipv4FragKey>) -> Self {
+    pub fn ipv4_reassembly_buffer(mut self, storage: PacketAssemblerSet<Ipv4FragKey>) -> Self {
         self.ipv4_fragments = storage;
         self
     }
@@ -541,7 +528,7 @@ let iface = builder.finalize(&mut device);
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     pub fn sixlowpan_reassembly_buffer(
         mut self,
-        storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
+        storage: PacketAssemblerSet<SixlowpanFragKey>,
     ) -> Self {
         self.sixlowpan_fragments = storage;
         self
@@ -664,12 +651,6 @@ let iface = builder.finalize(&mut device);
                 sixlowpan_fragments: self.sixlowpan_fragments,
                 #[cfg(feature = "proto-sixlowpan-fragmentation")]
                 sixlowpan_fragments_cache_timeout: self.sixlowpan_reassembly_buffer_timeout,
-
-                #[cfg(not(any(
-                    feature = "proto-ipv4-fragmentation",
-                    feature = "proto-sixlowpan-fragmentation"
-                )))]
-                _lifetime: core::marker::PhantomData,
             },
             out_packets: OutPackets {
                 #[cfg(feature = "proto-ipv4-fragmentation")]
@@ -1070,14 +1051,10 @@ impl<'a> Interface<'a> {
         self.inner.now = timestamp;
 
         #[cfg(feature = "proto-ipv4-fragmentation")]
-        self.fragments
-            .ipv4_fragments
-            .remove_when(|frag| Ok(timestamp >= frag.expires_at()?))?;
+        self.fragments.ipv4_fragments.remove_expired(timestamp);
 
         #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        self.fragments
-            .sixlowpan_fragments
-            .remove_when(|frag| Ok(timestamp >= frag.expires_at()?))?;
+        self.fragments.sixlowpan_fragments.remove_expired(timestamp);
 
         #[cfg(feature = "proto-ipv4-fragmentation")]
         match self.ipv4_egress(device) {
@@ -1719,7 +1696,7 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         sockets: &mut SocketSet,
         ip_payload: &'frame T,
-        _fragments: &'frame mut FragmentsBuffer<'a>,
+        _fragments: &'frame mut FragmentsBuffer,
     ) -> Option<IpPacket<'frame>> {
         match IpVersion::of_packet(ip_payload.as_ref()) {
             #[cfg(feature = "proto-ipv4")]

+ 32 - 40
src/iface/interface/sixlowpan.rs

@@ -21,7 +21,7 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         sockets: &mut SocketSet,
         sixlowpan_payload: &'payload T,
-        _fragments: &'output mut FragmentsBuffer<'a>,
+        _fragments: &'output mut FragmentsBuffer,
     ) -> Option<IpPacket<'output>> {
         let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
         let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
@@ -73,10 +73,7 @@ impl<'a> InterfaceInner<'a> {
         sockets: &mut SocketSet,
         ieee802154_repr: &Ieee802154Repr,
         payload: &'payload T,
-        _fragments: Option<(
-            &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
-            Duration,
-        )>,
+        _fragments: Option<(&'output mut PacketAssemblerSet<SixlowpanFragKey>, Duration)>,
     ) -> Option<IpPacket<'output>> {
         let payload = match check!(SixlowpanPacket::dispatch(payload)) {
             #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
@@ -173,11 +170,10 @@ impl<'a> InterfaceInner<'a> {
         &mut self,
         ieee802154_repr: &Ieee802154Repr,
         payload: &'payload T,
-        fragments: Option<(
-            &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
-            Duration,
-        )>,
+        fragments: Option<(&'output mut PacketAssemblerSet<SixlowpanFragKey>, Duration)>,
     ) -> Option<&'output [u8]> {
+        use crate::iface::fragmentation::AssemblerFullError;
+
         let (fragments, timeout) = fragments.unwrap();
 
         // We have a fragment header, which means we cannot process the 6LoWPAN packet,
@@ -191,6 +187,19 @@ impl<'a> InterfaceInner<'a> {
         // The offset of this fragment in increments of 8 octets.
         let offset = frag.datagram_offset() as usize * 8;
 
+        // We reserve a spot in the packet assembler set and add the required
+        // information to the packet assembler.
+        // This information is the total size of the packet when it is fully assmbled.
+        // We also pass the header size, since this is needed when other fragments
+        // (other than the first one) are added.
+        let frag_slot = match fragments.get(&key, self.now + timeout) {
+            Ok(frag) => frag,
+            Err(AssemblerFullError) => {
+                net_debug!("No available packet assembler for fragmented packet");
+                return Default::default();
+            }
+        };
+
         if frag.is_first_fragment() {
             // The first fragment contains the total size of the IPv6 packet.
             // However, we received a packet that is compressed following the 6LoWPAN
@@ -234,45 +243,28 @@ impl<'a> InterfaceInner<'a> {
                 SixlowpanNextHeader::Uncompressed(_) => (),
             }
 
-            // We reserve a spot in the packet assembler set and add the required
-            // information to the packet assembler.
-            // This information is the total size of the packet when it is fully assmbled.
-            // We also pass the header size, since this is needed when other fragments
-            // (other than the first one) are added.
-            let frag_slot = match fragments.reserve_with_key(&key) {
-                Ok(frag) => frag,
-                Err(Error::PacketAssemblerSetFull) => {
-                    net_debug!("No available packet assembler for fragmented packet");
-                    return Default::default();
-                }
-                e => check!(e),
-            };
-
-            check!(frag_slot.start(
-                Some(
-                    frag.datagram_size() as usize - uncompressed_header_size
-                        + compressed_header_size
-                ),
-                self.now + timeout,
+            let total_size =
+                frag.datagram_size() as usize - uncompressed_header_size + compressed_header_size;
+            check!(frag_slot.set_total_size(total_size));
+            frag_slot.set_offset_correction(
                 -((uncompressed_header_size - compressed_header_size) as isize),
-            ));
+            );
         }
 
-        let frags = check!(fragments.get_packet_assembler_mut(&key));
-
         net_trace!("6LoWPAN: received packet fragment");
 
         // Add the fragment to the packet assembler.
-        match frags.add(frag.payload(), offset) {
-            Ok(true) => {
+        if let Err(e) = frag_slot.add(frag.payload(), offset) {
+            net_debug!("fragmentation error: {:?}", e);
+            return None;
+        }
+
+        match frag_slot.assemble() {
+            Some(payload) => {
                 net_trace!("6LoWPAN: fragmented packet now complete");
-                match fragments.get_assembled_packet(&key) {
-                    Ok(packet) => Some(packet),
-                    _ => unreachable!(),
-                }
+                Some(payload)
             }
-            Ok(false) => None,
-            Err(_) => None,
+            None => None,
         }
     }
 

+ 4 - 13
src/iface/interface/tests.rs

@@ -1,4 +1,3 @@
-use std::collections::BTreeMap;
 #[cfg(feature = "proto-igmp")]
 use std::vec::Vec;
 
@@ -59,9 +58,7 @@ fn create_ip<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
     let iface_builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
 
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    let iface_builder = iface_builder
-        .ipv4_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
-        .ipv4_fragmentation_buffer(vec![]);
+    let iface_builder = iface_builder.ipv4_fragmentation_buffer(vec![]);
 
     let iface = iface_builder.finalize(&mut device);
 
@@ -92,14 +89,10 @@ fn create_ethernet<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
         .ip_addrs(ip_addrs);
 
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let iface_builder = iface_builder
-        .sixlowpan_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
-        .sixlowpan_fragmentation_buffer(vec![]);
+    let iface_builder = iface_builder.sixlowpan_fragmentation_buffer(vec![]);
 
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    let iface_builder = iface_builder
-        .ipv4_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
-        .ipv4_fragmentation_buffer(vec![]);
+    let iface_builder = iface_builder.ipv4_fragmentation_buffer(vec![]);
 
     let iface = iface_builder.finalize(&mut device);
 
@@ -126,9 +119,7 @@ fn create_ieee802154<'a>() -> (Interface<'a>, SocketSet<'a>, Loopback) {
         .ip_addrs(ip_addrs);
 
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    let iface_builder = iface_builder
-        .sixlowpan_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
-        .sixlowpan_fragmentation_buffer(vec![]);
+    let iface_builder = iface_builder.sixlowpan_fragmentation_buffer(vec![]);
 
     let iface = iface_builder.finalize(&mut device);
 

+ 0 - 24
src/lib.rs

@@ -184,18 +184,6 @@ pub enum Error {
     /// An incoming fragment arrived too late.
     ReassemblyTimeout,
 
-    /// The buffer of the assembler is to small and thus the final packet wont fit into it.
-    PacketAssemblerBufferTooSmall,
-    /// The packet assembler did not receive all the fragments for assembling the final packet.
-    PacketAssemblerIncomplete,
-    /// There are too many holes in the packet assembler (should be fixed in the future?).
-    PacketAssemblerTooManyHoles,
-
-    /// The packet assembler set has no place for assembling a new stream of fragments.
-    PacketAssemblerSetFull,
-    /// The key was not found in the packet assembler set.
-    PacketAssemblerSetKeyNotFound,
-
     /// An incoming packet was recognized but some parts are not supported by smoltcp.
     /// E.g. some bit configuration in a packet header is not supported, but is defined in an RFC.
     NotSupported,
@@ -221,18 +209,6 @@ impl fmt::Display for Error {
             Error::Malformed => write!(f, "malformed packet"),
             Error::Dropped => write!(f, "dropped by socket"),
             Error::ReassemblyTimeout => write!(f, "incoming fragment arrived too late"),
-            Error::PacketAssemblerBufferTooSmall => {
-                write!(f, "packet assembler buffer too small for final packet")
-            }
-            Error::PacketAssemblerIncomplete => write!(f, "packet assembler incomplete"),
-            Error::PacketAssemblerTooManyHoles => write!(
-                f,
-                "packet assembler has too many holes (internal smoltcp error)"
-            ),
-            Error::PacketAssemblerSetFull => write!(f, "packet assembler set is full"),
-            Error::PacketAssemblerSetKeyNotFound => {
-                write!(f, "packet assembler set does not find key")
-            }
             Error::NotSupported => write!(f, "not supported by smoltcp"),
         }
     }

+ 4 - 0
src/storage/assembler.rs

@@ -114,6 +114,10 @@ impl Assembler {
         Assembler { contigs }
     }
 
+    pub fn clear(&mut self) {
+        self.contigs.fill(Contig::empty());
+    }
+
     fn front(&self) -> Contig {
         self.contigs[0]
     }

+ 16 - 23
src/wire/sixlowpan.rs

@@ -2140,6 +2140,7 @@ pub mod nhc {
 #[cfg(test)]
 mod test {
     use crate::phy::ChecksumCapabilities;
+    use crate::time::Duration;
 
     use super::*;
 
@@ -2182,9 +2183,8 @@ mod test {
         use crate::wire::ieee802154::Frame as Ieee802154Frame;
         use crate::wire::ieee802154::Repr as Ieee802154Repr;
         use crate::wire::Ieee802154Address;
-        use std::collections::BTreeMap;
 
-        let mut frags_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
+        let mut frags_cache = ReassemblyBuffer::new();
 
         let frame1: &[u8] = &[
             0x41, 0xcc, 0x92, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
@@ -2219,20 +2219,13 @@ mod test {
         let uncompressed = 40 + 8;
         let compressed = 5 + 7;
 
-        frags_cache
-            .reserve_with_key(&key)
-            .unwrap()
-            .start(
-                Some(frag.datagram_size() as usize - uncompressed + compressed),
-                Instant::now() + crate::time::Duration::from_secs(60),
-                -((uncompressed - compressed) as isize),
-            )
+        let assr = frags_cache
+            .get(&key, Instant::now() + Duration::from_secs(60))
             .unwrap();
-        frags_cache
-            .get_packet_assembler_mut(&key)
-            .unwrap()
-            .add(frag.payload(), 0)
+        assr.set_total_size(frag.datagram_size() as usize - uncompressed + compressed)
             .unwrap();
+        assr.set_offset_correction(-((uncompressed - compressed) as isize));
+        assr.add(frag.payload(), 0).unwrap();
 
         let frame2: &[u8] = &[
             0x41, 0xcc, 0x93, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
@@ -2264,10 +2257,10 @@ mod test {
 
         let key = frag.get_key(&ieee802154_repr);
 
-        frags_cache
-            .get_packet_assembler_mut(&key)
-            .unwrap()
-            .add(frag.payload(), frag.datagram_offset() as usize * 8)
+        let assr = frags_cache
+            .get(&key, Instant::now() + Duration::from_secs(60))
+            .unwrap();
+        assr.add(frag.payload(), frag.datagram_offset() as usize * 8)
             .unwrap();
 
         let frame3: &[u8] = &[
@@ -2299,13 +2292,13 @@ mod test {
 
         let key = frag.get_key(&ieee802154_repr);
 
-        frags_cache
-            .get_packet_assembler_mut(&key)
-            .unwrap()
-            .add(frag.payload(), frag.datagram_offset() as usize * 8)
+        let assr = frags_cache
+            .get(&key, Instant::now() + Duration::from_secs(60))
+            .unwrap();
+        assr.add(frag.payload(), frag.datagram_offset() as usize * 8)
             .unwrap();
 
-        let assembled_packet = frags_cache.get_assembled_packet(&key).unwrap();
+        let assembled_packet = assr.assemble().unwrap();
 
         let sixlowpan_frame = SixlowpanPacket::dispatch(assembled_packet).unwrap();