mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-02 15:15:05 +00:00
Reassemble incomming IPv4 packets.
This commit is contained in:
parent
19a78bb577
commit
3065959c70
10
Cargo.toml
10
Cargo.toml
@ -43,10 +43,12 @@ verbose = []
|
|||||||
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
|
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
|
||||||
|
|
||||||
"proto-ipv4" = []
|
"proto-ipv4" = []
|
||||||
|
"proto-ipv4-fragmentation" = ["proto-ipv4"]
|
||||||
"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-dns" = []
|
"proto-dns" = []
|
||||||
|
|
||||||
"socket" = []
|
"socket" = []
|
||||||
@ -63,7 +65,8 @@ default = [
|
|||||||
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
||||||
"medium-ethernet", "medium-ip", "medium-ieee802154",
|
"medium-ethernet", "medium-ip", "medium-ieee802154",
|
||||||
"phy-raw_socket", "phy-tuntap_interface",
|
"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",
|
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4", "socket-dns",
|
||||||
"async"
|
"async"
|
||||||
]
|
]
|
||||||
@ -114,10 +117,11 @@ required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interfac
|
|||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "sixlowpan"
|
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]]
|
[[example]]
|
||||||
name = "sixlowpan_benchmark"
|
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]]
|
[[example]]
|
||||||
name = "dns"
|
name = "dns"
|
||||||
|
@ -5,6 +5,12 @@ use std::collections::BTreeMap;
|
|||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::str::{self, FromStr};
|
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::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
|
||||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||||
use smoltcp::socket::tcp;
|
use smoltcp::socket::tcp;
|
||||||
@ -31,8 +37,8 @@ fn main() {
|
|||||||
|
|
||||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||||
|
|
||||||
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
|
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||||
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 128]);
|
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||||
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||||
|
|
||||||
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
||||||
@ -44,6 +50,23 @@ fn main() {
|
|||||||
|
|
||||||
let medium = device.capabilities().medium;
|
let medium = device.capabilities().medium;
|
||||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
|
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 {
|
if medium == Medium::Ethernet {
|
||||||
builder = builder
|
builder = builder
|
||||||
.hardware_addr(ethernet_addr.into())
|
.hardware_addr(ethernet_addr.into())
|
||||||
|
@ -6,6 +6,11 @@ use std::fmt::Write;
|
|||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::str;
|
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::iface::{InterfaceBuilder, NeighborCache, SocketSet};
|
||||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||||
use smoltcp::socket::{tcp, udp};
|
use smoltcp::socket::{tcp, udp};
|
||||||
@ -27,8 +32,8 @@ fn main() {
|
|||||||
|
|
||||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||||
|
|
||||||
let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 64]);
|
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; 128]);
|
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 udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
|
||||||
|
|
||||||
let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
|
let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
|
||||||
@ -56,6 +61,23 @@ fn main() {
|
|||||||
|
|
||||||
let medium = device.capabilities().medium;
|
let medium = device.capabilities().medium;
|
||||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
|
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 {
|
if medium == Medium::Ethernet {
|
||||||
builder = builder
|
builder = builder
|
||||||
.hardware_addr(ethernet_addr.into())
|
.hardware_addr(ethernet_addr.into())
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
use managed::{ManagedMap, ManagedSlice};
|
use managed::{ManagedMap, ManagedSlice};
|
||||||
|
|
||||||
use crate::storage::Assembler;
|
use crate::storage::Assembler;
|
||||||
use crate::time::Instant;
|
use crate::time::{Duration, Instant};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
/// Holds different fragments of one packet, used for assembling fragmented packets.
|
/// Holds different fragments of one packet, used for assembling fragmented packets.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub struct PacketAssembler<'a> {
|
pub struct PacketAssembler<'a> {
|
||||||
buffer: ManagedSlice<'a, u8>,
|
buffer: ManagedSlice<'a, u8>,
|
||||||
assembler: AssemblerState,
|
assembler: AssemblerState,
|
||||||
@ -17,14 +16,12 @@ pub struct PacketAssembler<'a> {
|
|||||||
|
|
||||||
/// Holds the state of the assembling of one packet.
|
/// Holds the state of the assembling of one packet.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
enum AssemblerState {
|
enum AssemblerState {
|
||||||
NotInit,
|
NotInit,
|
||||||
Assembling {
|
Assembling {
|
||||||
assembler: Assembler,
|
assembler: Assembler,
|
||||||
total_size: usize,
|
total_size: Option<usize>,
|
||||||
last_updated: Instant,
|
expires_at: Instant,
|
||||||
started_on: Instant,
|
|
||||||
offset_correction: isize,
|
offset_correction: isize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -51,32 +48,71 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
/// fragments of a packet.
|
/// fragments of a packet.
|
||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
&mut self,
|
&mut self,
|
||||||
total_size: usize,
|
total_size: Option<usize>,
|
||||||
start_time: Instant,
|
expires_at: Instant,
|
||||||
offset_correction: isize,
|
offset_correction: isize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match &mut self.buffer {
|
match &mut self.buffer {
|
||||||
ManagedSlice::Borrowed(b) if b.len() < total_size => {
|
ManagedSlice::Borrowed(b) => {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
if let Some(total_size) = total_size {
|
||||||
|
if b.len() < total_size {
|
||||||
|
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ManagedSlice::Borrowed(_) => (),
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
ManagedSlice::Owned(b) => {
|
ManagedSlice::Owned(b) => {
|
||||||
b.resize(total_size, 0);
|
if let Some(total_size) = total_size {
|
||||||
|
b.resize(total_size, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assembler = AssemblerState::Assembling {
|
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,
|
total_size,
|
||||||
last_updated: start_time,
|
expires_at,
|
||||||
started_on: start_time,
|
|
||||||
offset_correction,
|
offset_correction,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
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.
|
/// Add a fragment into the packet that is being reassembled.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@ -86,21 +122,30 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
|
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
|
||||||
/// place.
|
/// place.
|
||||||
/// - Returns [`Error::PacketAssemblerOverlap`] when there was an overlap when adding data.
|
/// - 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 {
|
match self.assembler {
|
||||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||||
AssemblerState::Assembling {
|
AssemblerState::Assembling {
|
||||||
ref mut assembler,
|
ref mut assembler,
|
||||||
total_size,
|
total_size,
|
||||||
ref mut last_updated,
|
|
||||||
offset_correction,
|
offset_correction,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let offset = offset as isize + offset_correction;
|
let offset = offset as isize + offset_correction;
|
||||||
let offset = if offset <= 0 { 0 } else { offset as usize };
|
let offset = if offset <= 0 { 0 } else { offset as usize };
|
||||||
|
|
||||||
if offset + data.len() > total_size {
|
match &mut self.buffer {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
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();
|
let len = data.len();
|
||||||
@ -111,7 +156,6 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
if overlap {
|
if overlap {
|
||||||
net_debug!("packet was added, but there was an overlap.");
|
net_debug!("packet was added, but there was an overlap.");
|
||||||
}
|
}
|
||||||
*last_updated = now;
|
|
||||||
self.is_complete()
|
self.is_complete()
|
||||||
}
|
}
|
||||||
// NOTE(thvdveld): hopefully we wont get too many holes errors I guess?
|
// 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::NotInit => return Err(Error::PacketAssemblerNotInit),
|
||||||
AssemblerState::Assembling { total_size, .. } => {
|
AssemblerState::Assembling { total_size, .. } => {
|
||||||
if self.is_complete()? {
|
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];
|
let a = &self.buffer[..total_size];
|
||||||
self.assembler = AssemblerState::NotInit;
|
self.assembler = AssemblerState::NotInit;
|
||||||
a
|
a
|
||||||
@ -158,13 +204,10 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
assembler,
|
assembler,
|
||||||
total_size,
|
total_size,
|
||||||
..
|
..
|
||||||
} => {
|
} => match (total_size, assembler.peek_front()) {
|
||||||
if let Some(front) = assembler.peek_front() {
|
(Some(total_size), Some(front)) => Ok(front == *total_size),
|
||||||
Ok(front == *total_size)
|
_ => Ok(false),
|
||||||
} else {
|
},
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,40 +216,20 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
self.assembler == AssemblerState::NotInit
|
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`].
|
/// Mark this assembler as [`AssemblerState::NotInit`].
|
||||||
/// This is then cleaned up by the [`PacketAssemblerSet`].
|
/// This is then cleaned up by the [`PacketAssemblerSet`].
|
||||||
pub fn mark_discarded(&mut self) {
|
pub fn mark_discarded(&mut self) {
|
||||||
self.assembler = AssemblerState::NotInit;
|
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`].
|
/// Set holding multiple [`PacketAssembler`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub struct PacketAssemblerSet<'a, Key: Eq + Ord + Clone + Copy> {
|
pub struct PacketAssemblerSet<'a, Key: Eq + Ord + Clone + Copy> {
|
||||||
packet_buffer: ManagedSlice<'a, PacketAssembler<'a>>,
|
packet_buffer: ManagedSlice<'a, PacketAssembler<'a>>,
|
||||||
index_buffer: ManagedMap<'a, Key, usize>,
|
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 {
|
match &mut self.packet_buffer {
|
||||||
ManagedSlice::Borrowed(_) => (),
|
ManagedSlice::Borrowed(_) => (),
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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
|
self.packet_buffer
|
||||||
@ -341,7 +364,10 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
|
|||||||
loop {
|
loop {
|
||||||
let mut key = None;
|
let mut key = None;
|
||||||
for (k, i) in self.index_buffer.iter() {
|
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);
|
key = Some(*k);
|
||||||
break;
|
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)`.
|
/// Mark all [`PacketAssembler`]s as discarded for which `f` returns `Ok(true)`.
|
||||||
pub fn remove_when(
|
/// This does not remove them from the buffer.
|
||||||
&mut self,
|
pub fn mark_discarded_when<F>(&mut self, f: F) -> Result<()>
|
||||||
f: impl Fn(&mut PacketAssembler<'_>) -> Result<bool>,
|
where
|
||||||
) -> Result<()> {
|
F: Fn(&mut PacketAssembler<'_>) -> Result<bool>,
|
||||||
|
{
|
||||||
for (_, i) in &mut self.index_buffer.iter() {
|
for (_, i) in &mut self.index_buffer.iter() {
|
||||||
let frag = &mut self.packet_buffer[*i as usize];
|
let frag = &mut self.packet_buffer[*i as usize];
|
||||||
if f(frag)? {
|
if f(frag)? {
|
||||||
frag.mark_discarded();
|
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();
|
self.remove_discarded();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -386,7 +423,7 @@ mod tests {
|
|||||||
let mut p_assembler = PacketAssembler::new(vec![]);
|
let mut p_assembler = PacketAssembler::new(vec![]);
|
||||||
let data = b"Hello World!";
|
let data = b"Hello World!";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p_assembler.add(&data[..], data.len(), Instant::now()),
|
p_assembler.add(&data[..], data.len()),
|
||||||
Err(Error::PacketAssemblerNotInit)
|
Err(Error::PacketAssemblerNotInit)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -403,14 +440,14 @@ mod tests {
|
|||||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p_assembler.start(2, Instant::now(), 0),
|
p_assembler.start(Some(2), Instant::from_secs(0), 0),
|
||||||
Err(Error::PacketAssemblerBufferTooSmall)
|
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!";
|
let data = b"Hello World!";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p_assembler.add(&data[..], data.len(), Instant::now()),
|
p_assembler.add(&data[..], data.len()),
|
||||||
Err(Error::PacketAssemblerBufferTooSmall)
|
Err(Error::PacketAssemblerBufferTooSmall)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -420,12 +457,14 @@ mod tests {
|
|||||||
let mut storage = [0u8; 5];
|
let mut storage = [0u8; 5];
|
||||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
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";
|
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]
|
#[test]
|
||||||
@ -435,18 +474,40 @@ mod tests {
|
|||||||
|
|
||||||
let data = b"Hello World!";
|
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!(
|
assert_eq!(
|
||||||
p_assembler.assemble(),
|
p_assembler.assemble(),
|
||||||
Err(Error::PacketAssemblerIncomplete)
|
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
|
p_assembler
|
||||||
.add(b"World!", b"Hello ".len(), Instant::now())
|
.start(Some(data.len()), Instant::from_secs(0), 0)
|
||||||
.unwrap();
|
.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!"[..]));
|
assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +555,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now(), 0)
|
.start(Some(0), Instant::from_secs(0), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
|
|
||||||
@ -502,7 +563,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now(), 0)
|
.start(Some(0), Instant::from_secs(0), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
|
|
||||||
@ -510,7 +571,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now(), 0)
|
.start(Some(0), Instant::from_secs(0), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
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 fragmentation;
|
||||||
mod interface;
|
mod interface;
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[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 self::route::{Route, Routes};
|
||||||
pub use socket_set::{SocketHandle, SocketSet, SocketStorage};
|
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::fragmentation::{PacketAssembler, PacketAssemblerSet as FragmentsCache};
|
||||||
|
|
||||||
pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};
|
pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};
|
||||||
|
@ -21,6 +21,13 @@ pub use super::IpProtocol as Protocol;
|
|||||||
// accept a packet of the following size.
|
// accept a packet of the following size.
|
||||||
pub const MIN_MTU: usize = 576;
|
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.
|
/// A four-octet IPv4 address.
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
||||||
pub struct Address(pub [u8; 4]);
|
pub struct Address(pub [u8; 4]);
|
||||||
@ -443,6 +450,15 @@ impl<T: AsRef<[u8]>> Packet<T> {
|
|||||||
let data = self.buffer.as_ref();
|
let data = self.buffer.as_ref();
|
||||||
checksum::data(&data[..self.header_len() as usize]) == !0
|
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> {
|
impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
|
||||||
@ -617,15 +633,14 @@ impl Repr {
|
|||||||
if checksum_caps.ipv4.rx() && !packet.verify_checksum() {
|
if checksum_caps.ipv4.rx() && !packet.verify_checksum() {
|
||||||
return Err(Error);
|
return Err(Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
|
||||||
// We do not support fragmentation.
|
// We do not support fragmentation.
|
||||||
if packet.more_frags() || packet.frag_offset() != 0 {
|
if packet.more_frags() || packet.frag_offset() != 0 {
|
||||||
return Err(Error);
|
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;
|
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 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.
|
// All ECN values are acceptable, since ECN requires opt-in from both endpoints.
|
||||||
@ -634,7 +649,7 @@ impl Repr {
|
|||||||
src_addr: packet.src_addr(),
|
src_addr: packet.src_addr(),
|
||||||
dst_addr: packet.dst_addr(),
|
dst_addr: packet.dst_addr(),
|
||||||
next_header: packet.next_header(),
|
next_header: packet.next_header(),
|
||||||
payload_len: payload_len,
|
payload_len,
|
||||||
hop_limit: packet.hop_limit(),
|
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) {
|
Ok(ip_packet) => match Repr::parse(&ip_packet, &checksum_caps) {
|
||||||
Err(_) => return Ok(()),
|
Err(_) => return Ok(()),
|
||||||
Ok(ip_repr) => {
|
Ok(ip_repr) => {
|
||||||
write!(f, "{}{}", indent, ip_repr)?;
|
if ip_packet.more_frags() || ip_packet.frag_offset() != 0 {
|
||||||
format_checksum(f, ip_packet.verify_checksum())?;
|
write!(
|
||||||
(ip_repr, ip_packet.payload())
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -169,8 +169,8 @@ pub use self::ip::{
|
|||||||
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
pub use self::ipv4::{
|
pub use self::ipv4::{
|
||||||
Address as Ipv4Address, Cidr as Ipv4Cidr, Packet as Ipv4Packet, Repr as Ipv4Repr,
|
Address as Ipv4Address, Cidr as Ipv4Cidr, Key as Ipv4FragKey, Packet as Ipv4Packet,
|
||||||
HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
|
Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
@ -359,6 +359,7 @@ pub mod frag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Repr {
|
impl Repr {
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
pub(crate) fn set_offset(&mut self, value: u8) {
|
pub(crate) fn set_offset(&mut self, value: u8) {
|
||||||
match self {
|
match self {
|
||||||
Repr::FirstFragment { .. } => (),
|
Repr::FirstFragment { .. } => (),
|
||||||
@ -2105,15 +2106,15 @@ mod test {
|
|||||||
.reserve_with_key(&key)
|
.reserve_with_key(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(
|
.start(
|
||||||
frag.datagram_size() as usize - uncompressed + compressed,
|
Some(frag.datagram_size() as usize - uncompressed + compressed),
|
||||||
Instant::now(),
|
Instant::now() + crate::time::Duration::from_secs(60),
|
||||||
-((uncompressed - compressed) as isize),
|
-((uncompressed - compressed) as isize),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
frags_cache
|
frags_cache
|
||||||
.get_packet_assembler_mut(&key)
|
.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(frag.payload(), 0, Instant::now())
|
.add(frag.payload(), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let frame2: &[u8] = &[
|
let frame2: &[u8] = &[
|
||||||
@ -2149,11 +2150,7 @@ mod test {
|
|||||||
frags_cache
|
frags_cache
|
||||||
.get_packet_assembler_mut(&key)
|
.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(
|
.add(frag.payload(), frag.datagram_offset() as usize * 8)
|
||||||
frag.payload(),
|
|
||||||
frag.datagram_offset() as usize * 8,
|
|
||||||
Instant::now(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let frame3: &[u8] = &[
|
let frame3: &[u8] = &[
|
||||||
@ -2188,11 +2185,7 @@ mod test {
|
|||||||
frags_cache
|
frags_cache
|
||||||
.get_packet_assembler_mut(&key)
|
.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add(
|
.add(frag.payload(), frag.datagram_offset() as usize * 8)
|
||||||
frag.payload(),
|
|
||||||
frag.datagram_offset() as usize * 8,
|
|
||||||
Instant::now(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let assembled_packet = frags_cache.get_assembled_packet(&key).unwrap();
|
let assembled_packet = frags_cache.get_assembled_packet(&key).unwrap();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user