Kaynağa Gözat

Merge pull request #740 from smoltcp-rs/fragmentation-unify

iface: unify ipv4/6lowpan fragmentation.
Dario Nieuwenhuis 2 yıl önce
ebeveyn
işleme
3fbef82cbe

+ 8 - 2
Cargo.toml

@@ -45,12 +45,12 @@ defmt = [ "dep:defmt", "heapless/defmt", "heapless/defmt-impl" ]
 "phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
 
 "proto-ipv4" = []
-"proto-ipv4-fragmentation" = ["proto-ipv4"]
+"proto-ipv4-fragmentation" = ["proto-ipv4", "_proto-fragmentation"]
 "proto-igmp" = ["proto-ipv4"]
 "proto-dhcpv4" = ["proto-ipv4"]
 "proto-ipv6" = []
 "proto-sixlowpan" = ["proto-ipv6"]
-"proto-sixlowpan-fragmentation" = ["proto-sixlowpan"]
+"proto-sixlowpan-fragmentation" = ["proto-sixlowpan", "_proto-fragmentation"]
 "proto-dns" = []
 
 "socket" = []
@@ -74,6 +74,12 @@ default = [
   "async"
 ]
 
+# Private features
+# Features starting with "_" are considered private. They should not be enabled by 
+# other crates, and they are not considered semver-stable.
+
+"_proto-fragmentation" = []
+
 [[example]]
 name = "packet2pcap"
 path = "utils/packet2pcap.rs"

+ 3 - 12
src/iface/interface/ethernet.rs

@@ -15,7 +15,7 @@ impl InterfaceInner {
         &mut self,
         sockets: &mut SocketSet,
         frame: &'frame T,
-        _fragments: &'frame mut FragmentsBuffer,
+        fragments: &'frame mut FragmentsBuffer,
     ) -> Option<EthernetPacket<'frame>> {
         let eth_frame = check!(EthernetFrame::new_checked(frame));
 
@@ -34,17 +34,8 @@ impl InterfaceInner {
             EthernetProtocol::Ipv4 => {
                 let ipv4_packet = check!(Ipv4Packet::new_checked(eth_frame.payload()));
 
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                {
-                    self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
-                        .map(EthernetPacket::Ip)
-                }
-
-                #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-                {
-                    self.process_ipv4(sockets, &ipv4_packet, None)
-                        .map(EthernetPacket::Ip)
-                }
+                self.process_ipv4(sockets, &ipv4_packet, fragments)
+                    .map(EthernetPacket::Ip)
             }
             #[cfg(feature = "proto-ipv6")]
             EthernetProtocol::Ipv6 => {

+ 12 - 4
src/iface/interface/igmp.rs

@@ -51,7 +51,9 @@ impl Interface {
                         .ok_or(MulticastError::Exhausted)?;
 
                     // NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
-                    self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
+                    self.inner
+                        .dispatch_ip(tx_token, pkt, &mut self.fragmenter)
+                        .unwrap();
 
                     Ok(true)
                 } else {
@@ -91,7 +93,9 @@ impl Interface {
                         .ok_or(MulticastError::Exhausted)?;
 
                     // NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
-                    self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
+                    self.inner
+                        .dispatch_ip(tx_token, pkt, &mut self.fragmenter)
+                        .unwrap();
 
                     Ok(true)
                 } else {
@@ -125,7 +129,9 @@ impl Interface {
                     // Send initial membership report
                     if let Some(tx_token) = device.transmit(self.inner.now) {
                         // NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
-                        self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
+                        self.inner
+                            .dispatch_ip(tx_token, pkt, &mut self.fragmenter)
+                            .unwrap();
                     } else {
                         return false;
                     }
@@ -153,7 +159,9 @@ impl Interface {
                             // Send initial membership report
                             if let Some(tx_token) = device.transmit(self.inner.now) {
                                 // NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
-                                self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
+                                self.inner
+                                    .dispatch_ip(tx_token, pkt, &mut self.fragmenter)
+                                    .unwrap();
                             } else {
                                 return false;
                             }

+ 25 - 42
src/iface/interface/ipv4.rs

@@ -1,15 +1,4 @@
-use super::check;
-use super::icmp_reply_payload_len;
-use super::InterfaceInner;
-use super::IpPacket;
-use super::PacketAssemblerSet;
-use super::SocketSet;
-
-#[cfg(feature = "medium-ethernet")]
-use super::EthernetPacket;
-
-#[cfg(feature = "proto-ipv4-fragmentation")]
-use super::Ipv4OutPacket;
+use super::*;
 
 #[cfg(feature = "socket-dhcpv4")]
 use crate::socket::dhcpv4;
@@ -18,16 +7,16 @@ use crate::socket::icmp;
 use crate::socket::AnySocket;
 
 use crate::phy::{Medium, TxToken};
-use crate::time::{Duration, Instant};
+use crate::time::Instant;
 use crate::wire::*;
 
 impl InterfaceInner {
-    pub(super) fn process_ipv4<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
+    pub(super) fn process_ipv4<'a, T: AsRef<[u8]> + ?Sized>(
         &mut self,
         sockets: &mut SocketSet,
-        ipv4_packet: &Ipv4Packet<&'payload T>,
-        _fragments: Option<&'output mut PacketAssemblerSet<Ipv4FragKey>>,
-    ) -> Option<IpPacket<'output>> {
+        ipv4_packet: &Ipv4Packet<&'a T>,
+        frag: &'a mut FragmentsBuffer,
+    ) -> Option<IpPacket<'a>> {
         let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
         if !self.is_unicast_v4(ipv4_repr.src_addr) {
             // Discard packets with non-unicast source addresses.
@@ -37,14 +26,10 @@ impl InterfaceInner {
 
         #[cfg(feature = "proto-ipv4-fragmentation")]
         let ip_payload = {
-            const REASSEMBLY_TIMEOUT: Duration = Duration::from_secs(90);
-
-            let fragments = _fragments.unwrap();
-
             if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
-                let key = ipv4_packet.get_key();
+                let key = FragKey::Ipv4(ipv4_packet.get_key());
 
-                let f = match fragments.get(&key, self.now + REASSEMBLY_TIMEOUT) {
+                let f = match frag.assembler.get(&key, self.now + frag.reassembly_timeout) {
                     Ok(f) => f,
                     Err(_) => {
                         net_debug!("No available packet assembler for fragmented packet");
@@ -345,20 +330,16 @@ impl InterfaceInner {
     }
 
     #[cfg(feature = "proto-ipv4-fragmentation")]
-    pub(super) fn dispatch_ipv4_out_packet<Tx: TxToken>(
-        &mut self,
-        tx_token: Tx,
-        pkt: &mut Ipv4OutPacket,
-    ) {
+    pub(super) fn dispatch_ipv4_frag<Tx: TxToken>(&mut self, tx_token: Tx, frag: &mut Fragmenter) {
         let caps = self.caps.clone();
 
         let mtu_max = self.ip_mtu();
-        let ip_len = (pkt.packet_len - pkt.sent_bytes + pkt.repr.buffer_len()).min(mtu_max);
-        let payload_len = ip_len - pkt.repr.buffer_len();
+        let ip_len = (frag.packet_len - frag.sent_bytes + frag.ipv4.repr.buffer_len()).min(mtu_max);
+        let payload_len = ip_len - frag.ipv4.repr.buffer_len();
 
-        let more_frags = (pkt.packet_len - pkt.sent_bytes) != payload_len;
-        pkt.repr.payload_len = payload_len;
-        pkt.sent_bytes += payload_len;
+        let more_frags = (frag.packet_len - frag.sent_bytes) != payload_len;
+        frag.ipv4.repr.payload_len = payload_len;
+        frag.sent_bytes += payload_len;
 
         let mut tx_len = ip_len;
         #[cfg(feature = "medium-ethernet")]
@@ -373,7 +354,7 @@ impl InterfaceInner {
 
             let src_addr = self.hardware_addr.unwrap().ethernet_or_panic();
             frame.set_src_addr(src_addr);
-            frame.set_dst_addr(pkt.dst_hardware_addr);
+            frame.set_dst_addr(frag.ipv4.dst_hardware_addr);
 
             match repr.version() {
                 #[cfg(feature = "proto-ipv4")]
@@ -386,27 +367,29 @@ impl InterfaceInner {
         tx_token.consume(tx_len, |mut tx_buffer| {
             #[cfg(feature = "medium-ethernet")]
             if matches!(self.caps.medium, Medium::Ethernet) {
-                emit_ethernet(&IpRepr::Ipv4(pkt.repr), tx_buffer);
+                emit_ethernet(&IpRepr::Ipv4(frag.ipv4.repr), tx_buffer);
                 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
             }
 
-            let mut packet = Ipv4Packet::new_unchecked(&mut tx_buffer[..pkt.repr.buffer_len()]);
-            pkt.repr.emit(&mut packet, &caps.checksum);
-            packet.set_ident(pkt.ident);
+            let mut packet =
+                Ipv4Packet::new_unchecked(&mut tx_buffer[..frag.ipv4.repr.buffer_len()]);
+            frag.ipv4.repr.emit(&mut packet, &caps.checksum);
+            packet.set_ident(frag.ipv4.ident);
             packet.set_more_frags(more_frags);
             packet.set_dont_frag(false);
-            packet.set_frag_offset(pkt.frag_offset);
+            packet.set_frag_offset(frag.ipv4.frag_offset);
 
             if caps.checksum.ipv4.tx() {
                 packet.fill_checksum();
             }
 
-            tx_buffer[pkt.repr.buffer_len()..][..payload_len].copy_from_slice(
-                &pkt.buffer[pkt.frag_offset as usize + pkt.repr.buffer_len()..][..payload_len],
+            tx_buffer[frag.ipv4.repr.buffer_len()..][..payload_len].copy_from_slice(
+                &frag.buffer[frag.ipv4.frag_offset as usize + frag.ipv4.repr.buffer_len()..]
+                    [..payload_len],
             );
 
             // Update the frag offset for the next fragment.
-            pkt.frag_offset += payload_len as u16;
+            frag.ipv4.frag_offset += payload_len as u16;
         })
     }
 

+ 161 - 209
src/iface/interface/mod.rs

@@ -43,48 +43,39 @@ const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
 #[cfg(feature = "proto-sixlowpan")]
 const SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
 
-pub(crate) struct FragmentsBuffer {
-    #[cfg(feature = "proto-sixlowpan")]
-    decompress_buf: [u8; sixlowpan::MAX_DECOMPRESSED_LEN],
+#[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")]
-    pub(crate) ipv4_fragments: PacketAssemblerSet<Ipv4FragKey>,
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_fragments: PacketAssemblerSet<SixlowpanFragKey>,
+    Ipv4(Ipv4FragKey),
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_fragments_cache_timeout: Duration,
+    Sixlowpan(SixlowpanFragKey),
 }
 
-pub(crate) struct OutPackets {
-    #[cfg(feature = "proto-ipv4-fragmentation")]
-    ipv4_out_packet: Ipv4OutPacket,
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
-    sixlowpan_out_packet: SixlowpanOutPacket,
-}
+pub(crate) struct FragmentsBuffer {
+    #[cfg(feature = "proto-sixlowpan")]
+    decompress_buf: [u8; sixlowpan::MAX_DECOMPRESSED_LEN],
 
-impl OutPackets {
-    #[cfg(any(
-        feature = "proto-ipv4-fragmentation",
-        feature = "proto-sixlowpan-fragmentation"
-    ))]
-    /// Returns `true` when all the data of the outgoing buffers are transmitted.
-    fn all_transmitted(&self) -> bool {
-        #[cfg(feature = "proto-ipv4-fragmentation")]
-        if !self.ipv4_out_packet.is_empty() {
-            return false;
-        }
+    #[cfg(feature = "_proto-fragmentation")]
+    pub(crate) assembler: PacketAssemblerSet<FragKey>,
 
-        #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        if !self.sixlowpan_out_packet.is_empty() {
-            return false;
-        }
+    #[cfg(feature = "_proto-fragmentation")]
+    reassembly_timeout: Duration,
+}
+
+#[cfg(not(feature = "_proto-fragmentation"))]
+pub(crate) struct Fragmenter {}
 
-        true
+#[cfg(not(feature = "_proto-fragmentation"))]
+impl Fragmenter {
+    pub(crate) fn new() -> Self {
+        Self {}
     }
 }
 
-#[allow(unused)]
-#[cfg(feature = "proto-ipv4-fragmentation")]
-pub(crate) struct Ipv4OutPacket {
+#[cfg(feature = "_proto-fragmentation")]
+pub(crate) struct Fragmenter {
     /// The buffer that holds the unfragmented 6LoWPAN packet.
     buffer: [u8; FRAGMENTATION_BUFFER_SIZE],
     /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
@@ -92,6 +83,14 @@ pub(crate) struct Ipv4OutPacket {
     /// The amount of bytes that already have been transmitted.
     sent_bytes: usize,
 
+    #[cfg(feature = "proto-ipv4-fragmentation")]
+    ipv4: Ipv4Fragmenter,
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    sixlowpan: SixlowpanFragmenter,
+}
+
+#[cfg(feature = "proto-ipv4-fragmentation")]
+pub(crate) struct Ipv4Fragmenter {
     /// The IPv4 representation.
     repr: Ipv4Repr,
     /// The destination hardware address.
@@ -103,67 +102,8 @@ pub(crate) struct Ipv4OutPacket {
     ident: u16,
 }
 
-#[cfg(feature = "proto-ipv4-fragmentation")]
-impl Ipv4OutPacket {
-    pub(crate) fn new() -> Self {
-        Self {
-            buffer: [0u8; FRAGMENTATION_BUFFER_SIZE],
-            packet_len: 0,
-            sent_bytes: 0,
-            repr: Ipv4Repr {
-                src_addr: Ipv4Address::default(),
-                dst_addr: Ipv4Address::default(),
-                next_header: IpProtocol::Unknown(0),
-                payload_len: 0,
-                hop_limit: 0,
-            },
-            #[cfg(feature = "medium-ethernet")]
-            dst_hardware_addr: EthernetAddress::default(),
-            frag_offset: 0,
-            ident: 0,
-        }
-    }
-
-    /// Return `true` when everything is transmitted.
-    #[inline]
-    fn finished(&self) -> bool {
-        self.packet_len == self.sent_bytes
-    }
-
-    /// Returns `true` when there is nothing to transmit.
-    #[inline]
-    fn is_empty(&self) -> bool {
-        self.packet_len == 0
-    }
-
-    // Reset the buffer.
-    fn reset(&mut self) {
-        self.packet_len = 0;
-        self.sent_bytes = 0;
-        self.repr = Ipv4Repr {
-            src_addr: Ipv4Address::default(),
-            dst_addr: Ipv4Address::default(),
-            next_header: IpProtocol::Unknown(0),
-            payload_len: 0,
-            hop_limit: 0,
-        };
-        #[cfg(feature = "medium-ethernet")]
-        {
-            self.dst_hardware_addr = EthernetAddress::default();
-        }
-    }
-}
-
-#[allow(unused)]
-#[cfg(feature = "proto-sixlowpan")]
-pub(crate) struct SixlowpanOutPacket {
-    /// The buffer that holds the unfragmented 6LoWPAN packet.
-    buffer: [u8; FRAGMENTATION_BUFFER_SIZE],
-    /// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
-    packet_len: usize,
-    /// The amount of bytes that already have been transmitted.
-    sent_bytes: usize,
-
+#[cfg(feature = "proto-sixlowpan-fragmentation")]
+pub(crate) struct SixlowpanFragmenter {
     /// The datagram size that is used for the fragmentation headers.
     datagram_size: u16,
     /// The datagram tag that is used for the fragmentation headers.
@@ -179,19 +119,38 @@ pub(crate) struct SixlowpanOutPacket {
     ll_src_addr: Ieee802154Address,
 }
 
-#[cfg(feature = "proto-sixlowpan-fragmentation")]
-impl SixlowpanOutPacket {
+#[cfg(feature = "_proto-fragmentation")]
+impl Fragmenter {
     pub(crate) fn new() -> Self {
         Self {
             buffer: [0u8; FRAGMENTATION_BUFFER_SIZE],
             packet_len: 0,
-            datagram_size: 0,
-            datagram_tag: 0,
-            datagram_offset: 0,
             sent_bytes: 0,
-            fragn_size: 0,
-            ll_dst_addr: Ieee802154Address::Absent,
-            ll_src_addr: Ieee802154Address::Absent,
+
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            ipv4: Ipv4Fragmenter {
+                repr: Ipv4Repr {
+                    src_addr: Ipv4Address::default(),
+                    dst_addr: Ipv4Address::default(),
+                    next_header: IpProtocol::Unknown(0),
+                    payload_len: 0,
+                    hop_limit: 0,
+                },
+                #[cfg(feature = "medium-ethernet")]
+                dst_hardware_addr: EthernetAddress::default(),
+                frag_offset: 0,
+                ident: 0,
+            },
+
+            #[cfg(feature = "proto-sixlowpan-fragmentation")]
+            sixlowpan: SixlowpanFragmenter {
+                datagram_size: 0,
+                datagram_tag: 0,
+                datagram_offset: 0,
+                fragn_size: 0,
+                ll_dst_addr: Ieee802154Address::Absent,
+                ll_src_addr: Ieee802154Address::Absent,
+            },
         }
     }
 
@@ -210,12 +169,31 @@ impl SixlowpanOutPacket {
     // Reset the buffer.
     fn reset(&mut self) {
         self.packet_len = 0;
-        self.datagram_size = 0;
-        self.datagram_tag = 0;
         self.sent_bytes = 0;
-        self.fragn_size = 0;
-        self.ll_dst_addr = Ieee802154Address::Absent;
-        self.ll_src_addr = Ieee802154Address::Absent;
+
+        #[cfg(feature = "proto-ipv4-fragmentation")]
+        {
+            self.ipv4.repr = Ipv4Repr {
+                src_addr: Ipv4Address::default(),
+                dst_addr: Ipv4Address::default(),
+                next_header: IpProtocol::Unknown(0),
+                payload_len: 0,
+                hop_limit: 0,
+            };
+            #[cfg(feature = "medium-ethernet")]
+            {
+                self.ipv4.dst_hardware_addr = EthernetAddress::default();
+            }
+        }
+
+        #[cfg(feature = "proto-sixlowpan-fragmentation")]
+        {
+            self.sixlowpan.datagram_size = 0;
+            self.sixlowpan.datagram_tag = 0;
+            self.sixlowpan.fragn_size = 0;
+            self.sixlowpan.ll_dst_addr = Ieee802154Address::Absent;
+            self.sixlowpan.ll_src_addr = Ieee802154Address::Absent;
+        }
     }
 }
 
@@ -244,7 +222,7 @@ use check;
 pub struct Interface {
     inner: InterfaceInner,
     fragments: FragmentsBuffer,
-    out_packets: OutPackets,
+    fragmenter: Fragmenter,
 }
 
 /// The device independent part of an Ethernet network interface.
@@ -558,19 +536,12 @@ impl Interface {
                 #[cfg(feature = "proto-sixlowpan")]
                 decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
 
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                ipv4_fragments: PacketAssemblerSet::new(),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments: PacketAssemblerSet::new(),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments_cache_timeout: Duration::from_secs(60),
-            },
-            out_packets: OutPackets {
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                ipv4_out_packet: Ipv4OutPacket::new(),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_out_packet: SixlowpanOutPacket::new(),
+                #[cfg(feature = "_proto-fragmentation")]
+                assembler: PacketAssemblerSet::new(),
+                #[cfg(feature = "_proto-fragmentation")]
+                reassembly_timeout: Duration::from_secs(60),
             },
+            fragmenter: Fragmenter::new(),
             inner: InterfaceInner {
                 now: Instant::from_secs(0),
                 caps,
@@ -732,22 +703,18 @@ impl Interface {
     }
 
     /// Get the packet reassembly timeout.
-    ///
-    /// Currently used only for 6LoWPAN, will be used for IPv4 in the future as well.
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    #[cfg(feature = "_proto-fragmentation")]
     pub fn reassembly_timeout(&self) -> Duration {
-        self.fragments.sixlowpan_fragments_cache_timeout
+        self.fragments.reassembly_timeout
     }
 
     /// Set the packet reassembly timeout.
-    ///
-    /// Currently used only for 6LoWPAN, will be used for IPv4 in the future as well.
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    #[cfg(feature = "_proto-fragmentation")]
     pub fn set_reassembly_timeout(&mut self, timeout: Duration) {
         if timeout > Duration::from_secs(60) {
             net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
         }
-        self.fragments.sixlowpan_fragments_cache_timeout = timeout;
+        self.fragments.reassembly_timeout = timeout;
     }
 
     /// Transmit packets queued in the given sockets, and receive packets queued
@@ -767,20 +734,26 @@ impl Interface {
     {
         self.inner.now = timestamp;
 
-        #[cfg(feature = "proto-ipv4-fragmentation")]
-        self.fragments.ipv4_fragments.remove_expired(timestamp);
+        #[cfg(feature = "_proto-fragmentation")]
+        self.fragments.assembler.remove_expired(timestamp);
 
-        #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        self.fragments.sixlowpan_fragments.remove_expired(timestamp);
-
-        #[cfg(feature = "proto-ipv4-fragmentation")]
-        if self.ipv4_egress(device) {
-            return true;
-        }
-
-        #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        if self.sixlowpan_egress(device) {
-            return true;
+        match self.inner.caps.medium {
+            #[cfg(feature = "medium-ieee802154")]
+            Medium::Ieee802154 =>
+            {
+                #[cfg(feature = "proto-sixlowpan-fragmentation")]
+                if self.sixlowpan_egress(device) {
+                    return true;
+                }
+            }
+            #[cfg(any(feature = "medium-ethernet", feature = "medium-ip"))]
+            _ =>
+            {
+                #[cfg(feature = "proto-ipv4-fragmentation")]
+                if self.ipv4_egress(device) {
+                    return true;
+                }
+            }
         }
 
         let mut readiness_may_have_changed = false;
@@ -816,8 +789,8 @@ impl Interface {
     pub fn poll_at(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option<Instant> {
         self.inner.now = timestamp;
 
-        #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        if !self.out_packets.all_transmitted() {
+        #[cfg(feature = "_proto-fragmentation")]
+        if !self.fragmenter.is_empty() {
             return Some(Instant::from_millis(0));
         }
 
@@ -871,8 +844,7 @@ impl Interface {
                                 .process_ethernet(sockets, &frame, &mut self.fragments)
                         {
                             if let Err(err) =
-                                self.inner
-                                    .dispatch(tx_token, packet, Some(&mut self.out_packets))
+                                self.inner.dispatch(tx_token, packet, &mut self.fragmenter)
                             {
                                 net_debug!("Failed to send response: {:?}", err);
                             }
@@ -883,11 +855,10 @@ impl Interface {
                         if let Some(packet) =
                             self.inner.process_ip(sockets, &frame, &mut self.fragments)
                         {
-                            if let Err(err) = self.inner.dispatch_ip(
-                                tx_token,
-                                packet,
-                                Some(&mut self.out_packets),
-                            ) {
+                            if let Err(err) =
+                                self.inner
+                                    .dispatch_ip(tx_token, packet, &mut self.fragmenter)
+                            {
                                 net_debug!("Failed to send response: {:?}", err);
                             }
                         }
@@ -898,11 +869,10 @@ impl Interface {
                             self.inner
                                 .process_ieee802154(sockets, &frame, &mut self.fragments)
                         {
-                            if let Err(err) = self.inner.dispatch_ip(
-                                tx_token,
-                                packet,
-                                Some(&mut self.out_packets),
-                            ) {
+                            if let Err(err) =
+                                self.inner
+                                    .dispatch_ip(tx_token, packet, &mut self.fragmenter)
+                            {
                                 net_debug!("Failed to send response: {:?}", err);
                             }
                         }
@@ -943,20 +913,8 @@ impl Interface {
                     EgressError::Exhausted
                 })?;
 
-                #[cfg(any(
-                    feature = "proto-ipv4-fragmentation",
-                    feature = "proto-sixlowpan-fragmentation"
-                ))]
                 inner
-                    .dispatch_ip(t, response, Some(&mut self.out_packets))
-                    .map_err(EgressError::Dispatch)?;
-
-                #[cfg(not(any(
-                    feature = "proto-ipv4-fragmentation",
-                    feature = "proto-sixlowpan-fragmentation"
-                )))]
-                inner
-                    .dispatch_ip(t, response, None)
+                    .dispatch_ip(t, response, &mut self.fragmenter)
                     .map_err(EgressError::Dispatch)?;
 
                 emitted_any = true;
@@ -1031,19 +989,19 @@ impl Interface {
         D: Device + ?Sized,
     {
         // Reset the buffer when we transmitted everything.
-        if self.out_packets.ipv4_out_packet.finished() {
-            self.out_packets.ipv4_out_packet.reset();
+        if self.fragmenter.finished() {
+            self.fragmenter.reset();
         }
 
-        if self.out_packets.ipv4_out_packet.is_empty() {
+        if self.fragmenter.is_empty() {
             return false;
         }
 
-        let pkt = &self.out_packets.ipv4_out_packet;
+        let pkt = &self.fragmenter;
         if pkt.packet_len > pkt.sent_bytes {
             if let Some(tx_token) = device.transmit(self.inner.now) {
                 self.inner
-                    .dispatch_ipv4_out_packet(tx_token, &mut self.out_packets.ipv4_out_packet);
+                    .dispatch_ipv4_frag(tx_token, &mut self.fragmenter);
                 return true;
             }
         }
@@ -1061,21 +1019,19 @@ impl Interface {
         D: Device + ?Sized,
     {
         // Reset the buffer when we transmitted everything.
-        if self.out_packets.sixlowpan_out_packet.finished() {
-            self.out_packets.sixlowpan_out_packet.reset();
+        if self.fragmenter.finished() {
+            self.fragmenter.reset();
         }
 
-        if self.out_packets.sixlowpan_out_packet.is_empty() {
+        if self.fragmenter.is_empty() {
             return false;
         }
 
-        let pkt = &self.out_packets.sixlowpan_out_packet;
+        let pkt = &self.fragmenter;
         if pkt.packet_len > pkt.sent_bytes {
             if let Some(tx_token) = device.transmit(self.inner.now) {
-                self.inner.dispatch_ieee802154_out_packet(
-                    tx_token,
-                    &mut self.out_packets.sixlowpan_out_packet,
-                );
+                self.inner
+                    .dispatch_ieee802154_frag(tx_token, &mut self.fragmenter);
                 return true;
             }
         }
@@ -1328,22 +1284,14 @@ impl InterfaceInner {
         &mut self,
         sockets: &mut SocketSet,
         ip_payload: &'frame T,
-        _fragments: &'frame mut FragmentsBuffer,
+        frag: &'frame mut FragmentsBuffer,
     ) -> Option<IpPacket<'frame>> {
         match IpVersion::of_packet(ip_payload.as_ref()) {
             #[cfg(feature = "proto-ipv4")]
             Ok(IpVersion::Ipv4) => {
                 let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
 
-                #[cfg(feature = "proto-ipv4-fragmentation")]
-                {
-                    self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
-                }
-
-                #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-                {
-                    self.process_ipv4(sockets, &ipv4_packet, None)
-                }
+                self.process_ipv4(sockets, &ipv4_packet, frag)
             }
             #[cfg(feature = "proto-ipv6")]
             Ok(IpVersion::Ipv6) => {
@@ -1507,7 +1455,7 @@ impl InterfaceInner {
         &mut self,
         tx_token: Tx,
         packet: EthernetPacket,
-        _out_packet: Option<&mut OutPackets>,
+        frag: &mut Fragmenter,
     ) -> Result<(), DispatchError>
     where
         Tx: TxToken,
@@ -1530,7 +1478,7 @@ impl InterfaceInner {
                     arp_repr.emit(&mut packet);
                 })
             }
-            EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, _out_packet),
+            EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, frag),
         }
     }
 
@@ -1578,6 +1526,7 @@ impl InterfaceInner {
         tx_token: Tx,
         src_addr: &IpAddress,
         dst_addr: &IpAddress,
+        fragmenter: &mut Fragmenter,
     ) -> Result<(HardwareAddress, Tx), DispatchError>
     where
         Tx: TxToken,
@@ -1696,7 +1645,7 @@ impl InterfaceInner {
                     solicit,
                 ));
 
-                if let Err(e) = self.dispatch_ip(tx_token, packet, None) {
+                if let Err(e) = self.dispatch_ip(tx_token, packet, fragmenter) {
                     net_debug!("Failed to dispatch NDISC solicit: {:?}", e);
                     return Err(DispatchError::NeighborPending);
                 }
@@ -1722,7 +1671,7 @@ impl InterfaceInner {
         &mut self,
         tx_token: Tx,
         packet: IpPacket,
-        _out_packet: Option<&mut OutPackets>,
+        frag: &mut Fragmenter,
     ) -> Result<(), DispatchError> {
         let ip_repr = packet.ip_repr();
         assert!(!ip_repr.dst_addr().is_unspecified());
@@ -1731,11 +1680,15 @@ impl InterfaceInner {
 
         #[cfg(feature = "medium-ieee802154")]
         if matches!(self.caps.medium, Medium::Ieee802154) {
-            let (addr, tx_token) =
-                self.lookup_hardware_addr(tx_token, &ip_repr.src_addr(), &ip_repr.dst_addr())?;
+            let (addr, tx_token) = self.lookup_hardware_addr(
+                tx_token,
+                &ip_repr.src_addr(),
+                &ip_repr.dst_addr(),
+                frag,
+            )?;
             let addr = addr.ieee802154_or_panic();
 
-            self.dispatch_ieee802154(addr, tx_token, packet, _out_packet);
+            self.dispatch_ieee802154(addr, tx_token, packet, frag);
             return Ok(());
         }
 
@@ -1763,6 +1716,7 @@ impl InterfaceInner {
                     tx_token,
                     &ip_repr.src_addr(),
                     &ip_repr.dst_addr(),
+                    frag,
                 )? {
                     (HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token),
                     #[cfg(feature = "medium-ieee802154")]
@@ -1810,15 +1764,13 @@ impl InterfaceInner {
                     {
                         net_debug!("start fragmentation");
 
-                        let pkt = &mut _out_packet.unwrap().ipv4_out_packet;
-
                         // Calculate how much we will send now (including the Ethernet header).
                         let tx_len = self.caps.max_transmission_unit;
 
                         let ip_header_len = repr.buffer_len();
                         let first_frag_ip_len = self.caps.ip_mtu();
 
-                        if pkt.buffer.len() < first_frag_ip_len {
+                        if frag.buffer.len() < first_frag_ip_len {
                             net_debug!(
                                 "Fragmentation buffer is too small, at least {} needed. Dropping",
                                 first_frag_ip_len
@@ -1828,26 +1780,26 @@ impl InterfaceInner {
 
                         #[cfg(feature = "medium-ethernet")]
                         {
-                            pkt.dst_hardware_addr = dst_hardware_addr;
+                            frag.ipv4.dst_hardware_addr = dst_hardware_addr;
                         }
 
                         // Save the total packet len (without the Ethernet header, but with the first
                         // IP header).
-                        pkt.packet_len = total_ip_len;
+                        frag.packet_len = total_ip_len;
 
                         // Save the IP header for other fragments.
-                        pkt.repr = repr;
+                        frag.ipv4.repr = repr;
 
                         // Save how much bytes we will send now.
-                        pkt.sent_bytes = first_frag_ip_len;
+                        frag.sent_bytes = first_frag_ip_len;
 
                         // Modify the IP header
                         repr.payload_len = first_frag_ip_len - repr.buffer_len();
 
                         // Emit the IP header to the buffer.
-                        emit_ip(&ip_repr, &mut pkt.buffer);
-                        let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut pkt.buffer[..]);
-                        pkt.ident = ipv4_id;
+                        emit_ip(&ip_repr, &mut frag.buffer);
+                        let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut frag.buffer[..]);
+                        frag.ipv4.ident = ipv4_id;
                         ipv4_packet.set_ident(ipv4_id);
                         ipv4_packet.set_more_frags(true);
                         ipv4_packet.set_dont_frag(false);
@@ -1866,11 +1818,11 @@ impl InterfaceInner {
                             }
 
                             // Change the offset for the next packet.
-                            pkt.frag_offset = (first_frag_ip_len - ip_header_len) as u16;
+                            frag.ipv4.frag_offset = (first_frag_ip_len - ip_header_len) as u16;
 
                             // Copy the IP header and the payload.
                             tx_buffer[..first_frag_ip_len]
-                                .copy_from_slice(&pkt.buffer[..first_frag_ip_len]);
+                                .copy_from_slice(&frag.buffer[..first_frag_ip_len]);
 
                             Ok(())
                         })

+ 28 - 39
src/iface/interface/sixlowpan.rs

@@ -1,12 +1,4 @@
-use super::check;
-use super::FragmentsBuffer;
-use super::InterfaceInner;
-use super::IpPacket;
-use super::OutPackets;
-use super::SocketSet;
-
-#[cfg(feature = "proto-sixlowpan-fragmentation")]
-use super::SixlowpanOutPacket;
+use super::*;
 
 use crate::phy::ChecksumCapabilities;
 use crate::phy::TxToken;
@@ -105,7 +97,7 @@ impl InterfaceInner {
 
         // The key specifies to which 6LoWPAN fragment it belongs too.
         // It is based on the link layer addresses, the tag and the size.
-        let key = frag.get_key(ieee802154_repr);
+        let key = FragKey::Sixlowpan(frag.get_key(ieee802154_repr));
 
         // The offset of this fragment in increments of 8 octets.
         let offset = frag.datagram_offset() as usize * 8;
@@ -115,10 +107,7 @@ impl InterfaceInner {
         // 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 f
-            .sixlowpan_fragments
-            .get(&key, self.now + f.sixlowpan_fragments_cache_timeout)
-        {
+        let frag_slot = match f.assembler.get(&key, self.now + f.reassembly_timeout) {
             Ok(frag) => frag,
             Err(AssemblerFullError) => {
                 net_debug!("No available packet assembler for fragmented packet");
@@ -274,7 +263,7 @@ impl InterfaceInner {
         ll_dst_a: Ieee802154Address,
         tx_token: Tx,
         packet: IpPacket,
-        _out_packet: Option<&mut OutPackets>,
+        frag: &mut Fragmenter,
     ) {
         // We first need to convert the IPv6 packet to a 6LoWPAN compressed packet.
         // Whenever this packet is to big to fit in the IEEE802.15.4 packet, then we need to
@@ -364,14 +353,14 @@ impl InterfaceInner {
             #[cfg(feature = "proto-sixlowpan-fragmentation")]
             {
                 // The packet does not fit in one Ieee802154 frame, so we need fragmentation.
-                // We do this by emitting everything in the `out_packet.buffer` from the interface.
+                // We do this by emitting everything in the `frag.buffer` from the interface.
                 // After emitting everything into that buffer, we send the first fragment heere.
-                // When `poll` is called again, we check if out_packet was fully sent, otherwise we
-                // call `dispatch_ieee802154_out_packet`, which will transmit the other fragments.
+                // When `poll` is called again, we check if frag was fully sent, otherwise we
+                // call `dispatch_ieee802154_frag`, which will transmit the other fragments.
 
-                // `dispatch_ieee802154_out_packet` requires some information about the total packet size,
+                // `dispatch_ieee802154_frag` requires some information about the total packet size,
                 // the link local source and destination address...
-                let pkt = &mut _out_packet.unwrap().sixlowpan_out_packet;
+                let pkt = frag;
 
                 if pkt.buffer.len() < total_size {
                     net_debug!(
@@ -381,8 +370,8 @@ impl InterfaceInner {
                     return;
                 }
 
-                pkt.ll_dst_addr = ll_dst_a;
-                pkt.ll_src_addr = ll_src_a;
+                pkt.sixlowpan.ll_dst_addr = ll_dst_a;
+                pkt.sixlowpan.ll_src_addr = ll_src_a;
 
                 let mut iphc_packet =
                     SixlowpanIphcPacket::new_unchecked(&mut pkt.buffer[..iphc_repr.buffer_len()]);
@@ -435,20 +424,20 @@ impl InterfaceInner {
 
                 // The datagram size that we need to set in the first fragment header is equal to the
                 // IPv6 payload length + 40.
-                pkt.datagram_size = (packet.ip_repr().payload_len() + 40) as u16;
+                pkt.sixlowpan.datagram_size = (packet.ip_repr().payload_len() + 40) as u16;
 
                 // We generate a random tag.
                 let tag = self.get_sixlowpan_fragment_tag();
                 // We save the tag for the other fragments that will be created when calling `poll`
                 // multiple times.
-                pkt.datagram_tag = tag;
+                pkt.sixlowpan.datagram_tag = tag;
 
                 let frag1 = SixlowpanFragRepr::FirstFragment {
-                    size: pkt.datagram_size,
+                    size: pkt.sixlowpan.datagram_size,
                     tag,
                 };
                 let fragn = SixlowpanFragRepr::Fragment {
-                    size: pkt.datagram_size,
+                    size: pkt.sixlowpan.datagram_size,
                     tag,
                     offset: 0,
                 };
@@ -464,10 +453,10 @@ impl InterfaceInner {
                 let frag1_size =
                     (125 - ieee_len - frag1.buffer_len() + header_diff) / 8 * 8 - (header_diff);
 
-                pkt.fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
+                pkt.sixlowpan.fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
 
                 pkt.sent_bytes = frag1_size;
-                pkt.datagram_offset = frag1_size + header_diff;
+                pkt.sixlowpan.datagram_offset = frag1_size + header_diff;
 
                 tx_token.consume(ieee_len + frag1.buffer_len() + frag1_size, |mut tx_buf| {
                     // Add the IEEE header.
@@ -552,10 +541,10 @@ impl InterfaceInner {
         feature = "medium-ieee802154",
         feature = "proto-sixlowpan-fragmentation"
     ))]
-    pub(super) fn dispatch_ieee802154_out_packet<Tx: TxToken>(
+    pub(super) fn dispatch_ieee802154_frag<Tx: TxToken>(
         &mut self,
         tx_token: Tx,
-        pkt: &mut SixlowpanOutPacket,
+        frag: &mut Fragmenter,
     ) {
         // Create the IEEE802.15.4 header.
         let ieee_repr = Ieee802154Repr {
@@ -567,20 +556,20 @@ impl InterfaceInner {
             pan_id_compression: true,
             frame_version: Ieee802154FrameVersion::Ieee802154_2003,
             dst_pan_id: self.pan_id,
-            dst_addr: Some(pkt.ll_dst_addr),
+            dst_addr: Some(frag.sixlowpan.ll_dst_addr),
             src_pan_id: self.pan_id,
-            src_addr: Some(pkt.ll_src_addr),
+            src_addr: Some(frag.sixlowpan.ll_src_addr),
         };
 
         // Create the FRAG_N header.
         let fragn = SixlowpanFragRepr::Fragment {
-            size: pkt.datagram_size,
-            tag: pkt.datagram_tag,
-            offset: (pkt.datagram_offset / 8) as u8,
+            size: frag.sixlowpan.datagram_size,
+            tag: frag.sixlowpan.datagram_tag,
+            offset: (frag.sixlowpan.datagram_offset / 8) as u8,
         };
 
         let ieee_len = ieee_repr.buffer_len();
-        let frag_size = (pkt.packet_len - pkt.sent_bytes).min(pkt.fragn_size);
+        let frag_size = (frag.packet_len - frag.sent_bytes).min(frag.sixlowpan.fragn_size);
 
         tx_token.consume(
             ieee_repr.buffer_len() + fragn.buffer_len() + frag_size,
@@ -595,10 +584,10 @@ impl InterfaceInner {
                 tx_buf = &mut tx_buf[fragn.buffer_len()..];
 
                 // Add the buffer part
-                tx_buf[..frag_size].copy_from_slice(&pkt.buffer[pkt.sent_bytes..][..frag_size]);
+                tx_buf[..frag_size].copy_from_slice(&frag.buffer[frag.sent_bytes..][..frag_size]);
 
-                pkt.sent_bytes += frag_size;
-                pkt.datagram_offset += frag_size;
+                frag.sent_bytes += frag_size;
+                frag.sixlowpan.datagram_offset += frag_size;
             },
         );
     }

+ 25 - 54
src/iface/interface/tests.rs

@@ -167,15 +167,10 @@ fn test_no_icmp_no_unicast_ipv4() {
     // ICMP error response when the destination address is a
     // broadcast address
 
-    #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-    assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame, None), None);
-    #[cfg(feature = "proto-ipv4-fragmentation")]
     assert_eq!(
-        iface.inner.process_ipv4(
-            &mut sockets,
-            &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
-        ),
+        iface
+            .inner
+            .process_ipv4(&mut sockets, &frame, &mut iface.fragments),
         None
     );
 }
@@ -255,19 +250,10 @@ fn test_icmp_error_no_payload() {
     // Ensure that the unknown protocol triggers an error response.
     // And we correctly handle no payload.
 
-    #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-    assert_eq!(
-        iface.inner.process_ipv4(&mut sockets, &frame, None),
-        Some(expected_repr)
-    );
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
     assert_eq!(
-        iface.inner.process_ipv4(
-            &mut sockets,
-            &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
-        ),
+        iface
+            .inner
+            .process_ipv4(&mut sockets, &frame, &mut iface.fragments),
         Some(expected_repr)
     );
 }
@@ -571,19 +557,10 @@ fn test_handle_ipv4_broadcast() {
     };
     let expected_packet = IpPacket::Icmpv4((expected_ipv4_repr, expected_icmpv4_repr));
 
-    #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-    assert_eq!(
-        iface.inner.process_ipv4(&mut sockets, &frame, None),
-        Some(expected_packet)
-    );
-
-    #[cfg(feature = "proto-ipv4-fragmentation")]
     assert_eq!(
-        iface.inner.process_ipv4(
-            &mut sockets,
-            &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
-        ),
+        iface
+            .inner
+            .process_ipv4(&mut sockets, &frame, &mut iface.fragments),
         Some(expected_packet)
     );
 }
@@ -763,7 +740,8 @@ fn test_handle_valid_arp_request() {
         iface.inner.lookup_hardware_addr(
             MockTxToken,
             &IpAddress::Ipv4(local_ip_addr),
-            &IpAddress::Ipv4(remote_ip_addr)
+            &IpAddress::Ipv4(remote_ip_addr),
+            &mut iface.fragmenter,
         ),
         Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
     );
@@ -835,7 +813,8 @@ fn test_handle_valid_ndisc_request() {
         iface.inner.lookup_hardware_addr(
             MockTxToken,
             &IpAddress::Ipv6(local_ip_addr),
-            &IpAddress::Ipv6(remote_ip_addr)
+            &IpAddress::Ipv6(remote_ip_addr),
+            &mut iface.fragmenter,
         ),
         Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
     );
@@ -879,7 +858,8 @@ fn test_handle_other_arp_request() {
         iface.inner.lookup_hardware_addr(
             MockTxToken,
             &IpAddress::Ipv4(Ipv4Address([0x7f, 0x00, 0x00, 0x01])),
-            &IpAddress::Ipv4(remote_ip_addr)
+            &IpAddress::Ipv4(remote_ip_addr),
+            &mut iface.fragmenter,
         ),
         Err(DispatchError::NeighborPending)
     );
@@ -937,7 +917,8 @@ fn test_arp_flush_after_update_ip() {
         iface.inner.lookup_hardware_addr(
             MockTxToken,
             &IpAddress::Ipv4(local_ip_addr),
-            &IpAddress::Ipv4(remote_ip_addr)
+            &IpAddress::Ipv4(remote_ip_addr),
+            &mut iface.fragmenter,
         ),
         Ok((HardwareAddress::Ethernet(remote_hw_addr), MockTxToken))
     );
@@ -1277,15 +1258,10 @@ fn test_raw_socket_no_reply() {
         Ipv4Packet::new_unchecked(&bytes)
     };
 
-    #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-    assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame, None), None);
-    #[cfg(feature = "proto-ipv4-fragmentation")]
     assert_eq!(
-        iface.inner.process_ipv4(
-            &mut sockets,
-            &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
-        ),
+        iface
+            .inner
+            .process_ipv4(&mut sockets, &frame, &mut iface.fragments),
         None
     );
 }
@@ -1368,15 +1344,10 @@ fn test_raw_socket_with_udp_socket() {
         Ipv4Packet::new_unchecked(&bytes)
     };
 
-    #[cfg(not(feature = "proto-ipv4-fragmentation"))]
-    assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame, None), None);
-    #[cfg(feature = "proto-ipv4-fragmentation")]
     assert_eq!(
-        iface.inner.process_ipv4(
-            &mut sockets,
-            &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
-        ),
+        iface
+            .inner
+            .process_ipv4(&mut sockets, &frame, &mut iface.fragments),
         None
     );
 
@@ -1545,7 +1516,7 @@ fn test_echo_request_sixlowpan_128_bytes() {
         Ieee802154Address::default(),
         tx_token,
         result.unwrap(),
-        Some(&mut iface.out_packets),
+        &mut iface.fragmenter,
     );
 
     assert_eq!(
@@ -1695,7 +1666,7 @@ fn test_sixlowpan_udp_with_fragmentation() {
             },
             udp_data,
         )),
-        Some(&mut iface.out_packets),
+        &mut iface.fragmenter,
     );
 
     iface.poll(Instant::now(), &mut device, &mut sockets);

+ 1 - 0
src/wire/ipv4.rs

@@ -27,6 +27,7 @@ pub const MIN_MTU: usize = 576;
 pub const ADDR_SIZE: usize = 4;
 
 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 pub struct Key {
     id: u16,
     src_addr: Address,