Browse Source

iface: unify ipv4/6lowpan packet assemblers.

If you enable both ipv4 and 6lowpan on the same binary, an Interface
had twice the needed reassembly buffers, one copy for ipv4 and another
for 6lowpan. Only one of both was used at a time.

Now interfaces have a single assembler used for either medium.
Dario Nieuwenhuis 2 years ago
parent
commit
12fd8161c7

+ 8 - 2
Cargo.toml

@@ -45,12 +45,12 @@ defmt = [ "dep:defmt", "heapless/defmt", "heapless/defmt-impl" ]
 "phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
 "phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
 
 
 "proto-ipv4" = []
 "proto-ipv4" = []
-"proto-ipv4-fragmentation" = ["proto-ipv4"]
+"proto-ipv4-fragmentation" = ["proto-ipv4", "_proto-fragmentation"]
 "proto-igmp" = ["proto-ipv4"]
 "proto-igmp" = ["proto-ipv4"]
 "proto-dhcpv4" = ["proto-ipv4"]
 "proto-dhcpv4" = ["proto-ipv4"]
 "proto-ipv6" = []
 "proto-ipv6" = []
 "proto-sixlowpan" = ["proto-ipv6"]
 "proto-sixlowpan" = ["proto-ipv6"]
-"proto-sixlowpan-fragmentation" = ["proto-sixlowpan"]
+"proto-sixlowpan-fragmentation" = ["proto-sixlowpan", "_proto-fragmentation"]
 "proto-dns" = []
 "proto-dns" = []
 
 
 "socket" = []
 "socket" = []
@@ -74,6 +74,12 @@ default = [
   "async"
   "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]]
 [[example]]
 name = "packet2pcap"
 name = "packet2pcap"
 path = "utils/packet2pcap.rs"
 path = "utils/packet2pcap.rs"

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

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

+ 7 - 20
src/iface/interface/ipv4.rs

@@ -1,15 +1,4 @@
-use super::check;
+use super::*;
-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;
 
 
 #[cfg(feature = "socket-dhcpv4")]
 #[cfg(feature = "socket-dhcpv4")]
 use crate::socket::dhcpv4;
 use crate::socket::dhcpv4;
@@ -22,12 +11,12 @@ use crate::time::{Duration, Instant};
 use crate::wire::*;
 use crate::wire::*;
 
 
 impl InterfaceInner {
 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,
         &mut self,
         sockets: &mut SocketSet,
         sockets: &mut SocketSet,
-        ipv4_packet: &Ipv4Packet<&'payload T>,
+        ipv4_packet: &Ipv4Packet<&'a T>,
-        _fragments: Option<&'output mut PacketAssemblerSet<Ipv4FragKey>>,
+        #[cfg(feature = "proto-ipv4-fragmentation")] assembler: &'a mut PacketAssemblerSet<FragKey>,
-    ) -> Option<IpPacket<'output>> {
+    ) -> Option<IpPacket<'a>> {
         let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
         let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
         if !self.is_unicast_v4(ipv4_repr.src_addr) {
         if !self.is_unicast_v4(ipv4_repr.src_addr) {
             // Discard packets with non-unicast source addresses.
             // Discard packets with non-unicast source addresses.
@@ -39,12 +28,10 @@ impl InterfaceInner {
         let ip_payload = {
         let ip_payload = {
             const REASSEMBLY_TIMEOUT: Duration = Duration::from_secs(90);
             const REASSEMBLY_TIMEOUT: Duration = Duration::from_secs(90);
 
 
-            let fragments = _fragments.unwrap();
-
             if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
             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 assembler.get(&key, self.now + REASSEMBLY_TIMEOUT) {
                     Ok(f) => f,
                     Ok(f) => f,
                     Err(_) => {
                     Err(_) => {
                         net_debug!("No available packet assembler for fragmented packet");
                         net_debug!("No available packet assembler for fragmented packet");

+ 25 - 23
src/iface/interface/mod.rs

@@ -43,13 +43,23 @@ const FRAGMENTATION_BUFFER_SIZE: usize = 1500;
 #[cfg(feature = "proto-sixlowpan")]
 #[cfg(feature = "proto-sixlowpan")]
 const SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
 const SIXLOWPAN_ADDRESS_CONTEXT_COUNT: usize = 4;
 
 
+#[cfg(feature = "_proto-fragmentation")]
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub(crate) enum FragKey {
+    #[cfg(feature = "proto-ipv4-fragmentation")]
+    Ipv4(Ipv4FragKey),
+    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    Sixlowpan(SixlowpanFragKey),
+}
+
 pub(crate) struct FragmentsBuffer {
 pub(crate) struct FragmentsBuffer {
     #[cfg(feature = "proto-sixlowpan")]
     #[cfg(feature = "proto-sixlowpan")]
     decompress_buf: [u8; sixlowpan::MAX_DECOMPRESSED_LEN],
     decompress_buf: [u8; sixlowpan::MAX_DECOMPRESSED_LEN],
-    #[cfg(feature = "proto-ipv4-fragmentation")]
+
-    pub(crate) ipv4_fragments: PacketAssemblerSet<Ipv4FragKey>,
+    #[cfg(feature = "_proto-fragmentation")]
-    #[cfg(feature = "proto-sixlowpan-fragmentation")]
+    pub(crate) assembler: PacketAssemblerSet<FragKey>,
-    sixlowpan_fragments: PacketAssemblerSet<SixlowpanFragKey>,
+
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     sixlowpan_reassembly_timeout: Duration,
     sixlowpan_reassembly_timeout: Duration,
 }
 }
@@ -558,10 +568,8 @@ impl Interface {
                 #[cfg(feature = "proto-sixlowpan")]
                 #[cfg(feature = "proto-sixlowpan")]
                 decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
                 decompress_buf: [0u8; sixlowpan::MAX_DECOMPRESSED_LEN],
 
 
-                #[cfg(feature = "proto-ipv4-fragmentation")]
+                #[cfg(feature = "_proto-fragmentation")]
-                ipv4_fragments: PacketAssemblerSet::new(),
+                assembler: PacketAssemblerSet::new(),
-                #[cfg(feature = "proto-sixlowpan-fragmentation")]
-                sixlowpan_fragments: PacketAssemblerSet::new(),
                 #[cfg(feature = "proto-sixlowpan-fragmentation")]
                 #[cfg(feature = "proto-sixlowpan-fragmentation")]
                 sixlowpan_reassembly_timeout: Duration::from_secs(60),
                 sixlowpan_reassembly_timeout: Duration::from_secs(60),
             },
             },
@@ -767,11 +775,8 @@ impl Interface {
     {
     {
         self.inner.now = timestamp;
         self.inner.now = timestamp;
 
 
-        #[cfg(feature = "proto-ipv4-fragmentation")]
+        #[cfg(feature = "_proto-fragmentation")]
-        self.fragments.ipv4_fragments.remove_expired(timestamp);
+        self.fragments.assembler.remove_expired(timestamp);
-
-        #[cfg(feature = "proto-sixlowpan-fragmentation")]
-        self.fragments.sixlowpan_fragments.remove_expired(timestamp);
 
 
         #[cfg(feature = "proto-ipv4-fragmentation")]
         #[cfg(feature = "proto-ipv4-fragmentation")]
         if self.ipv4_egress(device) {
         if self.ipv4_egress(device) {
@@ -1328,22 +1333,19 @@ impl InterfaceInner {
         &mut self,
         &mut self,
         sockets: &mut SocketSet,
         sockets: &mut SocketSet,
         ip_payload: &'frame T,
         ip_payload: &'frame T,
-        _fragments: &'frame mut FragmentsBuffer,
+        fragments: &'frame mut FragmentsBuffer,
     ) -> Option<IpPacket<'frame>> {
     ) -> Option<IpPacket<'frame>> {
         match IpVersion::of_packet(ip_payload.as_ref()) {
         match IpVersion::of_packet(ip_payload.as_ref()) {
             #[cfg(feature = "proto-ipv4")]
             #[cfg(feature = "proto-ipv4")]
             Ok(IpVersion::Ipv4) => {
             Ok(IpVersion::Ipv4) => {
                 let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
                 let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
 
 
-                #[cfg(feature = "proto-ipv4-fragmentation")]
+                self.process_ipv4(
-                {
+                    sockets,
-                    self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
+                    &ipv4_packet,
-                }
+                    #[cfg(feature = "proto-ipv4-fragmentation")]
-
+                    &mut fragments.assembler,
-                #[cfg(not(feature = "proto-ipv4-fragmentation"))]
+                )
-                {
-                    self.process_ipv4(sockets, &ipv4_packet, None)
-                }
             }
             }
             #[cfg(feature = "proto-ipv6")]
             #[cfg(feature = "proto-ipv6")]
             Ok(IpVersion::Ipv6) => {
             Ok(IpVersion::Ipv6) => {

+ 3 - 2
src/iface/interface/sixlowpan.rs

@@ -98,6 +98,7 @@ impl InterfaceInner {
         f: &'output mut FragmentsBuffer,
         f: &'output mut FragmentsBuffer,
     ) -> Option<&'output [u8]> {
     ) -> Option<&'output [u8]> {
         use crate::iface::fragmentation::{AssemblerError, AssemblerFullError};
         use crate::iface::fragmentation::{AssemblerError, AssemblerFullError};
+        use crate::iface::interface::FragKey;
 
 
         // We have a fragment header, which means we cannot process the 6LoWPAN packet,
         // We have a fragment header, which means we cannot process the 6LoWPAN packet,
         // unless we have a complete one after processing this fragment.
         // unless we have a complete one after processing this fragment.
@@ -105,7 +106,7 @@ impl InterfaceInner {
 
 
         // The key specifies to which 6LoWPAN fragment it belongs too.
         // The key specifies to which 6LoWPAN fragment it belongs too.
         // It is based on the link layer addresses, the tag and the size.
         // 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.
         // The offset of this fragment in increments of 8 octets.
         let offset = frag.datagram_offset() as usize * 8;
         let offset = frag.datagram_offset() as usize * 8;
@@ -116,7 +117,7 @@ impl InterfaceInner {
         // We also pass the header size, since this is needed when other fragments
         // We also pass the header size, since this is needed when other fragments
         // (other than the first one) are added.
         // (other than the first one) are added.
         let frag_slot = match f
         let frag_slot = match f
-            .sixlowpan_fragments
+            .assembler
             .get(&key, self.now + f.sixlowpan_reassembly_timeout)
             .get(&key, self.now + f.sixlowpan_reassembly_timeout)
         {
         {
             Ok(frag) => frag,
             Ok(frag) => frag,

+ 10 - 28
src/iface/interface/tests.rs

@@ -167,14 +167,12 @@ fn test_no_icmp_no_unicast_ipv4() {
     // ICMP error response when the destination address is a
     // ICMP error response when the destination address is a
     // broadcast address
     // 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!(
     assert_eq!(
         iface.inner.process_ipv4(
         iface.inner.process_ipv4(
             &mut sockets,
             &mut sockets,
             &frame,
             &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            &mut iface.fragments.assembler
         ),
         ),
         None
         None
     );
     );
@@ -255,18 +253,12 @@ fn test_icmp_error_no_payload() {
     // Ensure that the unknown protocol triggers an error response.
     // Ensure that the unknown protocol triggers an error response.
     // And we correctly handle no payload.
     // 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!(
     assert_eq!(
         iface.inner.process_ipv4(
         iface.inner.process_ipv4(
             &mut sockets,
             &mut sockets,
             &frame,
             &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            &mut iface.fragments.assembler
         ),
         ),
         Some(expected_repr)
         Some(expected_repr)
     );
     );
@@ -571,18 +563,12 @@ fn test_handle_ipv4_broadcast() {
     };
     };
     let expected_packet = IpPacket::Icmpv4((expected_ipv4_repr, expected_icmpv4_repr));
     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!(
     assert_eq!(
         iface.inner.process_ipv4(
         iface.inner.process_ipv4(
             &mut sockets,
             &mut sockets,
             &frame,
             &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            &mut iface.fragments.assembler
         ),
         ),
         Some(expected_packet)
         Some(expected_packet)
     );
     );
@@ -1277,14 +1263,12 @@ fn test_raw_socket_no_reply() {
         Ipv4Packet::new_unchecked(&bytes)
         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!(
     assert_eq!(
         iface.inner.process_ipv4(
         iface.inner.process_ipv4(
             &mut sockets,
             &mut sockets,
             &frame,
             &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            &mut iface.fragments.assembler
         ),
         ),
         None
         None
     );
     );
@@ -1368,14 +1352,12 @@ fn test_raw_socket_with_udp_socket() {
         Ipv4Packet::new_unchecked(&bytes)
         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!(
     assert_eq!(
         iface.inner.process_ipv4(
         iface.inner.process_ipv4(
             &mut sockets,
             &mut sockets,
             &frame,
             &frame,
-            Some(&mut iface.fragments.ipv4_fragments)
+            #[cfg(feature = "proto-ipv4-fragmentation")]
+            &mut iface.fragments.assembler
         ),
         ),
         None
         None
     );
     );

+ 1 - 0
src/wire/ipv4.rs

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