瀏覽代碼

Merge #624

624: IPv4 packet reassembly r=Dirbaio a=thvdveld

This adds IPv4 packet reassembly. Replacement for #236.

Depends on the fragmentation work of #580. When #580 gets merged I will rebase on master.

Co-authored-by: Thibaut Vandervelden <thvdveld@vub.be>
bors[bot] 2 年之前
父節點
當前提交
d647e757c5
共有 9 個文件被更改,包括 639 次插入331 次删除
  1. 7 3
      Cargo.toml
  2. 25 2
      examples/client.rs
  3. 24 2
      examples/server.rs
  4. 133 72
      src/iface/fragmentation.rs
  5. 406 227
      src/iface/interface.rs
  6. 2 2
      src/iface/mod.rs
  7. 34 8
      src/wire/ipv4.rs
  8. 2 2
      src/wire/mod.rs
  9. 6 13
      src/wire/sixlowpan.rs

+ 7 - 3
Cargo.toml

@@ -43,10 +43,12 @@ verbose = []
 "phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
 
 "proto-ipv4" = []
+"proto-ipv4-fragmentation" = ["proto-ipv4"]
 "proto-igmp" = ["proto-ipv4"]
 "proto-dhcpv4" = ["proto-ipv4"]
 "proto-ipv6" = []
 "proto-sixlowpan" = ["proto-ipv6"]
+"proto-sixlowpan-fragmentation" = ["proto-sixlowpan"]
 "proto-dns" = []
 
 "socket" = []
@@ -63,7 +65,8 @@ default = [
   "std", "log", # needed for `cargo test --no-default-features --features default` :/
   "medium-ethernet", "medium-ip", "medium-ieee802154",
   "phy-raw_socket", "phy-tuntap_interface",
-  "proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-sixlowpan", "proto-dns",
+  "proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-dns",
+  "proto-ipv4-fragmentation", "proto-sixlowpan-fragmentation",
   "socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4", "socket-dns",
   "async"
 ]
@@ -114,10 +117,11 @@ required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interfac
 
 [[example]]
 name = "sixlowpan"
-required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]
+required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "proto-sixlowpan-fragmentation", "socket-udp"]
+
 [[example]]
 name = "sixlowpan_benchmark"
-required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]
+required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "proto-sixlowpan-fragmentation", "socket-udp"]
 
 [[example]]
 name = "dns"

+ 25 - 2
examples/client.rs

@@ -5,6 +5,12 @@ 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::FragmentsCache;
+
 use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::tcp;
@@ -31,8 +37,8 @@ fn main() {
 
     let neighbor_cache = NeighborCache::new(BTreeMap::new());
 
-    let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
-    let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 128]);
+    let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
+    let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
     let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
 
     let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
@@ -44,6 +50,23 @@ fn main() {
 
     let medium = device.capabilities().medium;
     let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
+
+    #[cfg(feature = "proto-ipv4-fragmentation")]
+    {
+        let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
+        builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
+    }
+
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    let mut out_packet_buffer = [0u8; 1280];
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    {
+        let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
+        builder = builder
+            .sixlowpan_fragments_cache(sixlowpan_frag_cache)
+            .sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
+    }
+
     if medium == Medium::Ethernet {
         builder = builder
             .hardware_addr(ethernet_addr.into())

+ 24 - 2
examples/server.rs

@@ -6,6 +6,11 @@ use std::fmt::Write;
 use std::os::unix::io::AsRawFd;
 use std::str;
 
+#[cfg(any(
+    feature = "proto-sixlowpan-fragmentation",
+    feature = "proto-ipv4-fragmentation"
+))]
+use smoltcp::iface::FragmentsCache;
 use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
 use smoltcp::phy::{wait as phy_wait, Device, Medium};
 use smoltcp::socket::{tcp, udp};
@@ -27,8 +32,8 @@ fn main() {
 
     let neighbor_cache = NeighborCache::new(BTreeMap::new());
 
-    let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 64]);
-    let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 128]);
+    let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 65535]);
+    let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 65535]);
     let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
 
     let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
@@ -56,6 +61,23 @@ fn main() {
 
     let medium = device.capabilities().medium;
     let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
+
+    #[cfg(feature = "proto-ipv4-fragmentation")]
+    {
+        let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
+        builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
+    }
+
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    let mut out_packet_buffer = [0u8; 1280];
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    {
+        let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
+        builder = builder
+            .sixlowpan_fragments_cache(sixlowpan_frag_cache)
+            .sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
+    }
+
     if medium == Medium::Ethernet {
         builder = builder
             .hardware_addr(ethernet_addr.into())

+ 133 - 72
src/iface/fragmentation.rs

@@ -3,13 +3,12 @@
 use managed::{ManagedMap, ManagedSlice};
 
 use crate::storage::Assembler;
-use crate::time::Instant;
+use crate::time::{Duration, Instant};
 use crate::Error;
 use crate::Result;
 
 /// Holds different fragments of one packet, used for assembling fragmented packets.
 #[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct PacketAssembler<'a> {
     buffer: ManagedSlice<'a, u8>,
     assembler: AssemblerState,
@@ -17,14 +16,12 @@ pub struct PacketAssembler<'a> {
 
 /// Holds the state of the assembling of one packet.
 #[derive(Debug, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 enum AssemblerState {
     NotInit,
     Assembling {
         assembler: Assembler,
-        total_size: usize,
-        last_updated: Instant,
-        started_on: Instant,
+        total_size: Option<usize>,
+        expires_at: Instant,
         offset_correction: isize,
     },
 }
@@ -51,32 +48,71 @@ impl<'a> PacketAssembler<'a> {
     /// fragments of a packet.
     pub(crate) fn start(
         &mut self,
-        total_size: usize,
-        start_time: Instant,
+        total_size: Option<usize>,
+        expires_at: Instant,
         offset_correction: isize,
     ) -> Result<()> {
         match &mut self.buffer {
-            ManagedSlice::Borrowed(b) if b.len() < total_size => {
-                return Err(Error::PacketAssemblerBufferTooSmall);
+            ManagedSlice::Borrowed(b) => {
+                if let Some(total_size) = total_size {
+                    if b.len() < total_size {
+                        return Err(Error::PacketAssemblerBufferTooSmall);
+                    }
+                }
             }
-            ManagedSlice::Borrowed(_) => (),
             #[cfg(any(feature = "std", feature = "alloc"))]
             ManagedSlice::Owned(b) => {
-                b.resize(total_size, 0);
+                if let Some(total_size) = total_size {
+                    b.resize(total_size, 0);
+                }
             }
         }
 
         self.assembler = AssemblerState::Assembling {
-            assembler: Assembler::new(total_size),
+            assembler: Assembler::new(if let Some(total_size) = total_size {
+                total_size
+            } else {
+                usize::MAX
+            }),
             total_size,
-            last_updated: start_time,
-            started_on: start_time,
+            expires_at,
             offset_correction,
         };
 
         Ok(())
     }
 
+    /// Set the total size of the packet assembler.
+    ///
+    /// # Errors
+    ///
+    /// - Returns [`Error::PacketAssemblerNotInit`] when the assembler was not initialized (try initializing the
+    /// assembler with [Self::start]).
+    pub(crate) fn set_total_size(&mut self, size: usize) -> Result<()> {
+        match self.assembler {
+            AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
+            AssemblerState::Assembling {
+                ref mut total_size, ..
+            } => {
+                *total_size = Some(size);
+                Ok(())
+            }
+        }
+    }
+
+    /// Return the instant when the assembler expires.
+    ///
+    /// # Errors
+    ///
+    /// - Returns [`Error::PacketAssemblerNotInit`] when the assembler was not initialized (try initializing the
+    /// assembler with [Self::start]).
+    pub(crate) fn expires_at(&self) -> Result<Instant> {
+        match self.assembler {
+            AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
+            AssemblerState::Assembling { expires_at, .. } => Ok(expires_at),
+        }
+    }
+
     /// Add a fragment into the packet that is being reassembled.
     ///
     /// # Errors
@@ -86,21 +122,30 @@ impl<'a> PacketAssembler<'a> {
     /// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
     /// place.
     /// - Returns [`Error::PacketAssemblerOverlap`] when there was an overlap when adding data.
-    pub(crate) fn add(&mut self, data: &[u8], offset: usize, now: Instant) -> Result<bool> {
+    pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<bool> {
         match self.assembler {
             AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
             AssemblerState::Assembling {
                 ref mut assembler,
                 total_size,
-                ref mut last_updated,
                 offset_correction,
                 ..
             } => {
                 let offset = offset as isize + offset_correction;
                 let offset = if offset <= 0 { 0 } else { offset as usize };
 
-                if offset + data.len() > total_size {
-                    return Err(Error::PacketAssemblerBufferTooSmall);
+                match &mut self.buffer {
+                    ManagedSlice::Borrowed(b) => {
+                        if offset + data.len() > b.len() {
+                            return Err(Error::PacketAssemblerBufferTooSmall);
+                        }
+                    }
+                    #[cfg(any(feature = "std", feature = "alloc"))]
+                    ManagedSlice::Owned(b) => {
+                        if offset + data.len() > b.len() {
+                            b.resize(offset + data.len(), 0);
+                        }
+                    }
                 }
 
                 let len = data.len();
@@ -111,7 +156,6 @@ impl<'a> PacketAssembler<'a> {
                         if overlap {
                             net_debug!("packet was added, but there was an overlap.");
                         }
-                        *last_updated = now;
                         self.is_complete()
                     }
                     // NOTE(thvdveld): hopefully we wont get too many holes errors I guess?
@@ -134,6 +178,8 @@ impl<'a> PacketAssembler<'a> {
             AssemblerState::NotInit => return Err(Error::PacketAssemblerNotInit),
             AssemblerState::Assembling { total_size, .. } => {
                 if self.is_complete()? {
+                    // NOTE: we can unwrap because `is_complete` already checks this.
+                    let total_size = total_size.unwrap();
                     let a = &self.buffer[..total_size];
                     self.assembler = AssemblerState::NotInit;
                     a
@@ -158,13 +204,10 @@ impl<'a> PacketAssembler<'a> {
                 assembler,
                 total_size,
                 ..
-            } => {
-                if let Some(front) = assembler.peek_front() {
-                    Ok(front == *total_size)
-                } else {
-                    Ok(false)
-                }
-            }
+            } => match (total_size, assembler.peek_front()) {
+                (Some(total_size), Some(front)) => Ok(front == *total_size),
+                _ => Ok(false),
+            },
         }
     }
 
@@ -173,40 +216,20 @@ impl<'a> PacketAssembler<'a> {
         self.assembler == AssemblerState::NotInit
     }
 
-    /// Returns the [`Instant`] when the packet assembler was started.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerNotInit`] when the packet assembler was not initialized.
-    pub fn start_time(&self) -> Result<Instant> {
-        match self.assembler {
-            AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
-            AssemblerState::Assembling { started_on, .. } => Ok(started_on),
-        }
-    }
-
-    /// Returns the [`Instant`] when the packet assembler was last updated.
-    ///
-    /// # Errors
-    ///
-    /// - Returns [`Error::PacketAssemblerNotInit`] when the packet assembler was not initialized.
-    pub fn last_update_time(&self) -> Result<Instant> {
-        match self.assembler {
-            AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
-            AssemblerState::Assembling { last_updated, .. } => Ok(last_updated),
-        }
-    }
-
     /// Mark this assembler as [`AssemblerState::NotInit`].
     /// This is then cleaned up by the [`PacketAssemblerSet`].
     pub fn mark_discarded(&mut self) {
         self.assembler = AssemblerState::NotInit;
     }
+
+    /// Returns `true` when the [`AssemblerState`] is discarded.
+    pub fn is_discarded(&self) -> bool {
+        matches!(self.assembler, AssemblerState::NotInit)
+    }
 }
 
 /// Set holding multiple [`PacketAssembler`].
 #[derive(Debug)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct PacketAssemblerSet<'a, Key: Eq + Ord + Clone + Copy> {
     packet_buffer: ManagedSlice<'a, PacketAssembler<'a>>,
     index_buffer: ManagedMap<'a, Key, usize>,
@@ -296,7 +319,7 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
         match &mut self.packet_buffer {
             ManagedSlice::Borrowed(_) => (),
             #[cfg(any(feature = "std", feature = "alloc"))]
-            ManagedSlice::Owned(b) => b.push(PacketAssembler::new(vec![])),
+            ManagedSlice::Owned(b) => b.push(PacketAssembler::new(alloc::vec![])),
         }
 
         self.packet_buffer
@@ -341,7 +364,10 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
         loop {
             let mut key = None;
             for (k, i) in self.index_buffer.iter() {
-                if self.packet_buffer[*i as usize].assembler == AssemblerState::NotInit {
+                if matches!(
+                    self.packet_buffer[*i as usize].assembler,
+                    AssemblerState::NotInit
+                ) {
                     key = Some(*k);
                     break;
                 }
@@ -355,17 +381,28 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
         }
     }
 
-    /// Remove all [`PacketAssembler`]s for which `f` returns `Ok(true)`.
-    pub fn remove_when(
-        &mut self,
-        f: impl Fn(&mut PacketAssembler<'_>) -> Result<bool>,
-    ) -> Result<()> {
+    /// 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 as usize];
             if f(frag)? {
                 frag.mark_discarded();
             }
         }
+
+        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(())
@@ -386,7 +423,7 @@ mod tests {
         let mut p_assembler = PacketAssembler::new(vec![]);
         let data = b"Hello World!";
         assert_eq!(
-            p_assembler.add(&data[..], data.len(), Instant::now()),
+            p_assembler.add(&data[..], data.len()),
             Err(Error::PacketAssemblerNotInit)
         );
 
@@ -403,14 +440,14 @@ mod tests {
         let mut p_assembler = PacketAssembler::new(&mut storage[..]);
 
         assert_eq!(
-            p_assembler.start(2, Instant::now(), 0),
+            p_assembler.start(Some(2), Instant::from_secs(0), 0),
             Err(Error::PacketAssemblerBufferTooSmall)
         );
-        assert_eq!(p_assembler.start(1, Instant::now(), 0), Ok(()));
+        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(), Instant::now()),
+            p_assembler.add(&data[..], data.len()),
             Err(Error::PacketAssemblerBufferTooSmall)
         );
     }
@@ -420,12 +457,14 @@ mod tests {
         let mut storage = [0u8; 5];
         let mut p_assembler = PacketAssembler::new(&mut storage[..]);
 
-        p_assembler.start(5, Instant::now(), 0).unwrap();
+        p_assembler
+            .start(Some(5), Instant::from_secs(0), 0)
+            .unwrap();
         let data = b"Rust";
 
-        p_assembler.add(&data[..], 0, Instant::now()).unwrap();
+        p_assembler.add(&data[..], 0).unwrap();
 
-        assert_eq!(p_assembler.add(&data[..], 1, Instant::now()), Ok(true));
+        assert_eq!(p_assembler.add(&data[..], 1), Ok(true));
     }
 
     #[test]
@@ -435,18 +474,40 @@ mod tests {
 
         let data = b"Hello World!";
 
-        p_assembler.start(data.len(), Instant::now(), 0).unwrap();
+        p_assembler
+            .start(Some(data.len()), Instant::from_secs(0), 0)
+            .unwrap();
 
-        p_assembler.add(b"Hello ", 0, Instant::now()).unwrap();
+        p_assembler.add(b"Hello ", 0).unwrap();
         assert_eq!(
             p_assembler.assemble(),
             Err(Error::PacketAssemblerIncomplete)
         );
 
+        p_assembler.add(b"World!", b"Hello ".len()).unwrap();
+
+        assert_eq!(p_assembler.assemble(), Ok(&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 data = b"Hello World!";
+
         p_assembler
-            .add(b"World!", b"Hello ".len(), Instant::now())
+            .start(Some(data.len()), Instant::from_secs(0), 0)
             .unwrap();
 
+        p_assembler.add(b"World!", b"Hello ".len()).unwrap();
+        assert_eq!(
+            p_assembler.assemble(),
+            Err(Error::PacketAssemblerIncomplete)
+        );
+
+        p_assembler.add(b"Hello ", 0).unwrap();
+
         assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
     }
 
@@ -494,7 +555,7 @@ mod tests {
         set.reserve_with_key(&key).unwrap();
         set.get_packet_assembler_mut(&key)
             .unwrap()
-            .start(0, Instant::now(), 0)
+            .start(Some(0), Instant::from_secs(0), 0)
             .unwrap();
         set.get_assembled_packet(&key).unwrap();
 
@@ -502,7 +563,7 @@ mod tests {
         set.reserve_with_key(&key).unwrap();
         set.get_packet_assembler_mut(&key)
             .unwrap()
-            .start(0, Instant::now(), 0)
+            .start(Some(0), Instant::from_secs(0), 0)
             .unwrap();
         set.get_assembled_packet(&key).unwrap();
 
@@ -510,7 +571,7 @@ mod tests {
         set.reserve_with_key(&key).unwrap();
         set.get_packet_assembler_mut(&key)
             .unwrap()
-            .start(0, Instant::now(), 0)
+            .start(Some(0), Instant::from_secs(0), 0)
             .unwrap();
         set.get_assembled_packet(&key).unwrap();
     }

文件差異過大導致無法顯示
+ 406 - 227
src/iface/interface.rs


+ 2 - 2
src/iface/mod.rs

@@ -4,7 +4,7 @@ The `iface` module deals with the *network interfaces*. It filters incoming fram
 provides lookup and caching of hardware addresses, and handles management packets.
 */
 
-#[cfg(feature = "proto-sixlowpan")]
+#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
 mod fragmentation;
 mod interface;
 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
@@ -22,7 +22,7 @@ pub use self::neighbor::Neighbor;
 pub use self::route::{Route, Routes};
 pub use socket_set::{SocketHandle, SocketSet, SocketStorage};
 
-#[cfg(feature = "proto-sixlowpan")]
+#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
 pub use self::fragmentation::{PacketAssembler, PacketAssemblerSet as FragmentsCache};
 
 pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};

+ 34 - 8
src/wire/ipv4.rs

@@ -21,6 +21,13 @@ pub use super::IpProtocol as Protocol;
 // accept a packet of the following size.
 pub const MIN_MTU: usize = 576;
 
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+pub struct Key {
+    id: u16,
+    src_addr: Address,
+    dst_addr: Address,
+}
+
 /// A four-octet IPv4 address.
 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
 pub struct Address(pub [u8; 4]);
@@ -443,6 +450,15 @@ impl<T: AsRef<[u8]>> Packet<T> {
         let data = self.buffer.as_ref();
         checksum::data(&data[..self.header_len() as usize]) == !0
     }
+
+    /// Returns the key for identifying the packet.
+    pub fn get_key(&self) -> Key {
+        Key {
+            id: self.ident(),
+            src_addr: self.src_addr(),
+            dst_addr: self.dst_addr(),
+        }
+    }
 }
 
 impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
@@ -617,15 +633,14 @@ impl Repr {
         if checksum_caps.ipv4.rx() && !packet.verify_checksum() {
             return Err(Error);
         }
+
+        #[cfg(not(feature = "proto-ipv4-fragmentation"))]
         // We do not support fragmentation.
         if packet.more_frags() || packet.frag_offset() != 0 {
             return Err(Error);
         }
-        // Since the packet is not fragmented, it must include the entire payload.
+
         let payload_len = packet.total_len() as usize - packet.header_len() as usize;
-        if packet.payload().len() < payload_len {
-            return Err(Error);
-        }
 
         // All DSCP values are acceptable, since they are of no concern to receiving endpoint.
         // All ECN values are acceptable, since ECN requires opt-in from both endpoints.
@@ -634,7 +649,7 @@ impl Repr {
             src_addr: packet.src_addr(),
             dst_addr: packet.dst_addr(),
             next_header: packet.next_header(),
-            payload_len: payload_len,
+            payload_len,
             hop_limit: packet.hop_limit(),
         })
     }
@@ -749,9 +764,20 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
             Ok(ip_packet) => match Repr::parse(&ip_packet, &checksum_caps) {
                 Err(_) => return Ok(()),
                 Ok(ip_repr) => {
-                    write!(f, "{}{}", indent, ip_repr)?;
-                    format_checksum(f, ip_packet.verify_checksum())?;
-                    (ip_repr, ip_packet.payload())
+                    if ip_packet.more_frags() || ip_packet.frag_offset() != 0 {
+                        write!(
+                            f,
+                            "{}IPv4 Fragment more_frags={} offset={}",
+                            indent,
+                            ip_packet.more_frags(),
+                            ip_packet.frag_offset()
+                        )?;
+                        return Ok(());
+                    } else {
+                        write!(f, "{}{}", indent, ip_repr)?;
+                        format_checksum(f, ip_packet.verify_checksum())?;
+                        (ip_repr, ip_packet.payload())
+                    }
                 }
             },
         };

+ 2 - 2
src/wire/mod.rs

@@ -169,8 +169,8 @@ pub use self::ip::{
 
 #[cfg(feature = "proto-ipv4")]
 pub use self::ipv4::{
-    Address as Ipv4Address, Cidr as Ipv4Cidr, Packet as Ipv4Packet, Repr as Ipv4Repr,
-    HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
+    Address as Ipv4Address, Cidr as Ipv4Cidr, Key as Ipv4FragKey, Packet as Ipv4Packet,
+    Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
 };
 
 #[cfg(feature = "proto-ipv6")]

+ 6 - 13
src/wire/sixlowpan.rs

@@ -359,6 +359,7 @@ pub mod frag {
     }
 
     impl Repr {
+        #[cfg(feature = "proto-sixlowpan-fragmentation")]
         pub(crate) fn set_offset(&mut self, value: u8) {
             match self {
                 Repr::FirstFragment { .. } => (),
@@ -2105,15 +2106,15 @@ mod test {
             .reserve_with_key(&key)
             .unwrap()
             .start(
-                frag.datagram_size() as usize - uncompressed + compressed,
-                Instant::now(),
+                Some(frag.datagram_size() as usize - uncompressed + compressed),
+                Instant::now() + crate::time::Duration::from_secs(60),
                 -((uncompressed - compressed) as isize),
             )
             .unwrap();
         frags_cache
             .get_packet_assembler_mut(&key)
             .unwrap()
-            .add(frag.payload(), 0, Instant::now())
+            .add(frag.payload(), 0)
             .unwrap();
 
         let frame2: &[u8] = &[
@@ -2149,11 +2150,7 @@ mod test {
         frags_cache
             .get_packet_assembler_mut(&key)
             .unwrap()
-            .add(
-                frag.payload(),
-                frag.datagram_offset() as usize * 8,
-                Instant::now(),
-            )
+            .add(frag.payload(), frag.datagram_offset() as usize * 8)
             .unwrap();
 
         let frame3: &[u8] = &[
@@ -2188,11 +2185,7 @@ mod test {
         frags_cache
             .get_packet_assembler_mut(&key)
             .unwrap()
-            .add(
-                frag.payload(),
-                frag.datagram_offset() as usize * 8,
-                Instant::now(),
-            )
+            .add(frag.payload(), frag.datagram_offset() as usize * 8)
             .unwrap();
 
         let assembled_packet = frags_cache.get_assembled_packet(&key).unwrap();

部分文件因文件數量過多而無法顯示