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) => {
|
||||||
|
if let Some(total_size) = total_size {
|
||||||
|
if b.len() < total_size {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||||
}
|
}
|
||||||
ManagedSlice::Borrowed(_) => (),
|
}
|
||||||
|
}
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
ManagedSlice::Owned(b) => {
|
ManagedSlice::Owned(b) => {
|
||||||
|
if let Some(total_size) = total_size {
|
||||||
b.resize(total_size, 0);
|
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,22 +122,31 @@ 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 {
|
||||||
|
ManagedSlice::Borrowed(b) => {
|
||||||
|
if offset + data.len() > b.len() {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
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();
|
||||||
self.buffer[offset..][..len].copy_from_slice(data);
|
self.buffer[offset..][..len].copy_from_slice(data);
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
use managed::{ManagedMap, ManagedSlice};
|
use managed::{ManagedMap, ManagedSlice};
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
|
||||||
use super::fragmentation::PacketAssemblerSet;
|
use super::fragmentation::PacketAssemblerSet;
|
||||||
use super::socket_set::SocketSet;
|
use super::socket_set::SocketSet;
|
||||||
use crate::iface::Routes;
|
use crate::iface::Routes;
|
||||||
@ -23,19 +23,27 @@ use crate::wire::*;
|
|||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
|
|
||||||
pub(crate) struct FragmentsBuffer<'a> {
|
pub(crate) struct FragmentsBuffer<'a> {
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
ipv4_fragments: PacketAssemblerSet<'a, Ipv4FragKey>,
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_fragments: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
sixlowpan_fragments: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
|
||||||
|
#[cfg(not(any(
|
||||||
|
feature = "proto-ipv4-fragmentation",
|
||||||
|
feature = "proto-sixlowpan-fragmentation"
|
||||||
|
)))]
|
||||||
_lifetime: core::marker::PhantomData<&'a ()>,
|
_lifetime: core::marker::PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct OutPackets<'a> {
|
pub(crate) struct OutPackets<'a> {
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_out_packet: SixlowpanOutPacket<'a>,
|
sixlowpan_out_packet: SixlowpanOutPacket<'a>,
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
|
||||||
|
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||||
_lifetime: core::marker::PhantomData<&'a ()>,
|
_lifetime: core::marker::PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
pub(crate) struct SixlowpanOutPacket<'a> {
|
pub(crate) struct SixlowpanOutPacket<'a> {
|
||||||
/// The buffer that holds the unfragmented 6LoWPAN packet.
|
/// The buffer that holds the unfragmented 6LoWPAN packet.
|
||||||
@ -59,7 +67,7 @@ pub(crate) struct SixlowpanOutPacket<'a> {
|
|||||||
ll_src_addr: Ieee802154Address,
|
ll_src_addr: Ieee802154Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
impl<'a> SixlowpanOutPacket<'a> {
|
impl<'a> SixlowpanOutPacket<'a> {
|
||||||
pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
|
pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -121,7 +129,7 @@ pub struct InterfaceInner<'a> {
|
|||||||
sequence_no: u8,
|
sequence_no: u8,
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pan_id: Option<Ieee802154Pan>,
|
pan_id: Option<Ieee802154Pan>,
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
tag: u16,
|
tag: u16,
|
||||||
ip_addrs: ManagedSlice<'a, IpCidr>,
|
ip_addrs: ManagedSlice<'a, IpCidr>,
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
@ -151,9 +159,13 @@ pub struct InterfaceBuilder<'a> {
|
|||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
|
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
|
||||||
random_seed: u64,
|
random_seed: u64,
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
|
||||||
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
ipv4_fragments: Option<PacketAssemblerSet<'a, Ipv4FragKey>>,
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_fragments: Option<PacketAssemblerSet<'a, SixlowpanFragKey>>,
|
sixlowpan_fragments: Option<PacketAssemblerSet<'a, SixlowpanFragKey>>,
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_out_buffer: Option<ManagedSlice<'a, u8>>,
|
sixlowpan_out_buffer: Option<ManagedSlice<'a, u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +179,8 @@ impl<'a> InterfaceBuilder<'a> {
|
|||||||
|
|
||||||
```
|
```
|
||||||
# use std::collections::BTreeMap;
|
# use std::collections::BTreeMap;
|
||||||
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
use smoltcp::iface::FragmentsCache;
|
||||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache};
|
use smoltcp::iface::{InterfaceBuilder, NeighborCache};
|
||||||
# use smoltcp::phy::{Loopback, Medium};
|
# use smoltcp::phy::{Loopback, Medium};
|
||||||
use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
|
use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
|
||||||
@ -177,13 +191,20 @@ let hw_addr = // ...
|
|||||||
# EthernetAddress::default();
|
# EthernetAddress::default();
|
||||||
let neighbor_cache = // ...
|
let neighbor_cache = // ...
|
||||||
# NeighborCache::new(BTreeMap::new());
|
# NeighborCache::new(BTreeMap::new());
|
||||||
|
# #[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
# let ipv4_frag_cache = // ...
|
||||||
|
# FragmentsCache::new(vec![], BTreeMap::new());
|
||||||
let ip_addrs = // ...
|
let ip_addrs = // ...
|
||||||
# [];
|
# [];
|
||||||
let iface = InterfaceBuilder::new()
|
let builder = InterfaceBuilder::new()
|
||||||
.hardware_addr(hw_addr.into())
|
.hardware_addr(hw_addr.into())
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs);
|
||||||
.finalize(&mut device);
|
|
||||||
|
# #[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
let builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||||
|
|
||||||
|
let iface = builder.finalize(&mut device);
|
||||||
```
|
```
|
||||||
"##
|
"##
|
||||||
)]
|
)]
|
||||||
@ -206,9 +227,12 @@ let iface = InterfaceBuilder::new()
|
|||||||
ipv4_multicast_groups: ManagedMap::Borrowed(&mut []),
|
ipv4_multicast_groups: ManagedMap::Borrowed(&mut []),
|
||||||
random_seed: 0,
|
random_seed: 0,
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
ipv4_fragments: None,
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_fragments: None,
|
sixlowpan_fragments: None,
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_out_buffer: None,
|
sixlowpan_out_buffer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,7 +345,13 @@ let iface = InterfaceBuilder::new()
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
pub fn ipv4_fragments_cache(mut self, storage: PacketAssemblerSet<'a, Ipv4FragKey>) -> Self {
|
||||||
|
self.ipv4_fragments = Some(storage);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
pub fn sixlowpan_fragments_cache(
|
pub fn sixlowpan_fragments_cache(
|
||||||
mut self,
|
mut self,
|
||||||
storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||||
@ -330,7 +360,7 @@ let iface = InterfaceBuilder::new()
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
pub fn sixlowpan_out_packet_cache<T>(mut self, storage: T) -> Self
|
pub fn sixlowpan_out_packet_cache<T>(mut self, storage: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<ManagedSlice<'a, u8>>,
|
T: Into<ManagedSlice<'a, u8>>,
|
||||||
@ -422,22 +452,29 @@ let iface = InterfaceBuilder::new()
|
|||||||
|
|
||||||
Interface {
|
Interface {
|
||||||
fragments: FragmentsBuffer {
|
fragments: FragmentsBuffer {
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
ipv4_fragments: self
|
||||||
|
.ipv4_fragments
|
||||||
|
.expect("Cache for incoming IPv4 fragments is required"),
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_fragments: self
|
sixlowpan_fragments: self
|
||||||
.sixlowpan_fragments
|
.sixlowpan_fragments
|
||||||
.expect("Cache for incoming 6LoWPAN fragments is required"),
|
.expect("Cache for incoming 6LoWPAN fragments is required"),
|
||||||
|
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
#[cfg(not(any(
|
||||||
|
feature = "proto-ipv4-fragmentation",
|
||||||
|
feature = "proto-sixlowpan-fragmentation"
|
||||||
|
)))]
|
||||||
_lifetime: core::marker::PhantomData,
|
_lifetime: core::marker::PhantomData,
|
||||||
},
|
},
|
||||||
out_packets: OutPackets {
|
out_packets: OutPackets {
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
sixlowpan_out_packet: SixlowpanOutPacket::new(
|
sixlowpan_out_packet: SixlowpanOutPacket::new(
|
||||||
self.sixlowpan_out_buffer
|
self.sixlowpan_out_buffer
|
||||||
.expect("Cache for outgoing fragments is required"),
|
.expect("Cache for outgoing 6LoWPAN fragments is required"),
|
||||||
),
|
),
|
||||||
|
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||||
_lifetime: core::marker::PhantomData,
|
_lifetime: core::marker::PhantomData,
|
||||||
},
|
},
|
||||||
inner: InterfaceInner {
|
inner: InterfaceInner {
|
||||||
@ -459,7 +496,7 @@ let iface = InterfaceBuilder::new()
|
|||||||
sequence_no,
|
sequence_no,
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pan_id: self.pan_id,
|
pan_id: self.pan_id,
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
tag,
|
tag,
|
||||||
rand,
|
rand,
|
||||||
},
|
},
|
||||||
@ -760,12 +797,11 @@ impl<'a> Interface<'a> {
|
|||||||
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
||||||
self.ip_addrs()
|
self.ip_addrs()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|cidr| match cidr.address() {
|
.find_map(|cidr| match cidr.address() {
|
||||||
IpAddress::Ipv4(addr) => Some(addr),
|
IpAddress::Ipv4(addr) => Some(addr),
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the IP addresses of the interface.
|
/// Update the IP addresses of the interface.
|
||||||
@ -825,35 +861,33 @@ impl<'a> Interface<'a> {
|
|||||||
{
|
{
|
||||||
self.inner.now = timestamp;
|
self.inner.now = timestamp;
|
||||||
|
|
||||||
let mut readiness_may_have_changed = false;
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
if let Err(e) = self
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
.fragments
|
||||||
|
.ipv4_fragments
|
||||||
|
.remove_when(|frag| Ok(timestamp >= frag.expires_at()?))
|
||||||
{
|
{
|
||||||
let SixlowpanOutPacket {
|
return Err(e);
|
||||||
packet_len,
|
|
||||||
sent_bytes,
|
|
||||||
..
|
|
||||||
} = &self.out_packets.sixlowpan_out_packet;
|
|
||||||
|
|
||||||
if *packet_len > *sent_bytes {
|
|
||||||
match device.transmit().ok_or(Error::Exhausted) {
|
|
||||||
Ok(tx_token) => {
|
|
||||||
if let Err(e) = self.inner.dispatch_ieee802154_out_packet(
|
|
||||||
tx_token,
|
|
||||||
&mut self.out_packets.sixlowpan_out_packet,
|
|
||||||
) {
|
|
||||||
net_debug!("failed to transmit: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
net_debug!("failed to transmit: {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(true);
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
|
if let Err(e) = self
|
||||||
|
.fragments
|
||||||
|
.sixlowpan_fragments
|
||||||
|
.remove_when(|frag| Ok(timestamp >= frag.expires_at()?))
|
||||||
|
{
|
||||||
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
|
match self.sixlowpan_egress(device) {
|
||||||
|
Ok(true) => return Ok(true),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut readiness_may_have_changed = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let processed_any = self.socket_ingress(device, sockets);
|
let processed_any = self.socket_ingress(device, sockets);
|
||||||
let emitted_any = self.socket_egress(device, sockets);
|
let emitted_any = self.socket_egress(device, sockets);
|
||||||
@ -923,15 +957,16 @@ impl<'a> Interface<'a> {
|
|||||||
let mut processed_any = false;
|
let mut processed_any = false;
|
||||||
let Self {
|
let Self {
|
||||||
inner,
|
inner,
|
||||||
fragments: _fragments,
|
fragments: ref mut _fragments,
|
||||||
out_packets: _out_packets,
|
out_packets: _out_packets,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
while let Some((rx_token, tx_token)) = device.receive() {
|
while let Some((rx_token, tx_token)) = device.receive() {
|
||||||
let res = rx_token.consume(inner.now, |frame| {
|
let res = rx_token.consume(inner.now, |frame| {
|
||||||
match inner.caps.medium {
|
match inner.caps.medium {
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
Medium::Ethernet => {
|
Medium::Ethernet => {
|
||||||
if let Some(packet) = inner.process_ethernet(sockets, &frame) {
|
if let Some(packet) = inner.process_ethernet(sockets, &frame, _fragments) {
|
||||||
if let Err(err) = inner.dispatch(tx_token, packet) {
|
if let Err(err) = inner.dispatch(tx_token, packet) {
|
||||||
net_debug!("Failed to send response: {}", err);
|
net_debug!("Failed to send response: {}", err);
|
||||||
}
|
}
|
||||||
@ -939,7 +974,7 @@ impl<'a> Interface<'a> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ip")]
|
#[cfg(feature = "medium-ip")]
|
||||||
Medium::Ip => {
|
Medium::Ip => {
|
||||||
if let Some(packet) = inner.process_ip(sockets, &frame) {
|
if let Some(packet) = inner.process_ip(sockets, &frame, _fragments) {
|
||||||
if let Err(err) = inner.dispatch_ip(tx_token, packet, None) {
|
if let Err(err) = inner.dispatch_ip(tx_token, packet, None) {
|
||||||
net_debug!("Failed to send response: {}", err);
|
net_debug!("Failed to send response: {}", err);
|
||||||
}
|
}
|
||||||
@ -947,11 +982,8 @@ impl<'a> Interface<'a> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
Medium::Ieee802154 => {
|
Medium::Ieee802154 => {
|
||||||
if let Some(packet) = inner.process_ieee802154(
|
if let Some(packet) = inner.process_ieee802154(sockets, &frame, _fragments)
|
||||||
sockets,
|
{
|
||||||
&frame,
|
|
||||||
&mut _fragments.sixlowpan_fragments,
|
|
||||||
) {
|
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
inner.dispatch_ip(tx_token, packet, Some(_out_packets))
|
inner.dispatch_ip(tx_token, packet, Some(_out_packets))
|
||||||
{
|
{
|
||||||
@ -996,14 +1028,14 @@ impl<'a> Interface<'a> {
|
|||||||
let mut respond = |inner: &mut InterfaceInner, response: IpPacket| {
|
let mut respond = |inner: &mut InterfaceInner, response: IpPacket| {
|
||||||
neighbor_addr = Some(response.ip_repr().dst_addr());
|
neighbor_addr = Some(response.ip_repr().dst_addr());
|
||||||
match device.transmit().ok_or(Error::Exhausted) {
|
match device.transmit().ok_or(Error::Exhausted) {
|
||||||
Ok(t) => {
|
Ok(_t) => {
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
if let Err(_e) = inner.dispatch_ip(t, response, Some(_out_packets)) {
|
if let Err(_e) = inner.dispatch_ip(_t, response, Some(_out_packets)) {
|
||||||
net_debug!("failed to dispatch IP: {}", _e);
|
net_debug!("failed to dispatch IP: {}", _e);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||||
if let Err(_e) = inner.dispatch_ip(t, response, None) {
|
if let Err(_e) = inner.dispatch_ip(_t, response, None) {
|
||||||
net_debug!("failed to dispatch IP: {}", _e);
|
net_debug!("failed to dispatch IP: {}", _e);
|
||||||
}
|
}
|
||||||
emitted_any = true;
|
emitted_any = true;
|
||||||
@ -1140,6 +1172,41 @@ impl<'a> Interface<'a> {
|
|||||||
_ => Ok(false),
|
_ => Ok(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
|
fn sixlowpan_egress<D>(&mut self, device: &mut D) -> Result<bool>
|
||||||
|
where
|
||||||
|
D: for<'d> Device<'d>,
|
||||||
|
{
|
||||||
|
let SixlowpanOutPacket {
|
||||||
|
packet_len,
|
||||||
|
sent_bytes,
|
||||||
|
..
|
||||||
|
} = &self.out_packets.sixlowpan_out_packet;
|
||||||
|
|
||||||
|
if *packet_len == 0 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *packet_len >= *sent_bytes {
|
||||||
|
match device.transmit().ok_or(Error::Exhausted) {
|
||||||
|
Ok(tx_token) => {
|
||||||
|
if let Err(e) = self.inner.dispatch_ieee802154_out_packet(
|
||||||
|
tx_token,
|
||||||
|
&mut self.out_packets.sixlowpan_out_packet,
|
||||||
|
) {
|
||||||
|
net_debug!("failed to transmit: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
net_debug!("failed to transmit: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InterfaceInner<'a> {
|
impl<'a> InterfaceInner<'a> {
|
||||||
@ -1256,7 +1323,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
sequence_no: 1,
|
sequence_no: 1,
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
tag: 1,
|
tag: 1,
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
@ -1301,7 +1368,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
no
|
no
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
|
fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
|
||||||
let tag = self.tag;
|
let tag = self.tag;
|
||||||
self.tag = self.tag.wrapping_add(1);
|
self.tag = self.tag.wrapping_add(1);
|
||||||
@ -1336,14 +1403,11 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
/// Get the first IPv4 address of the interface.
|
/// Get the first IPv4 address of the interface.
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
pub fn ipv4_address(&self) -> Option<Ipv4Address> {
|
pub fn ipv4_address(&self) -> Option<Ipv4Address> {
|
||||||
self.ip_addrs
|
self.ip_addrs.iter().find_map(|addr| match *addr {
|
||||||
.iter()
|
|
||||||
.filter_map(|addr| match *addr {
|
|
||||||
IpCidr::Ipv4(cidr) => Some(cidr.address()),
|
IpCidr::Ipv4(cidr) => Some(cidr.address()),
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
IpCidr::Ipv6(_) => None,
|
IpCidr::Ipv6(_) => None,
|
||||||
})
|
})
|
||||||
.next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the interface listens to given destination multicast IP address.
|
/// Check whether the interface listens to given destination multicast IP address.
|
||||||
@ -1367,6 +1431,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
frame: &'frame T,
|
frame: &'frame T,
|
||||||
|
_fragments: &'frame mut FragmentsBuffer<'a>,
|
||||||
) -> Option<EthernetPacket<'frame>> {
|
) -> Option<EthernetPacket<'frame>> {
|
||||||
let eth_frame = check!(EthernetFrame::new_checked(frame));
|
let eth_frame = check!(EthernetFrame::new_checked(frame));
|
||||||
|
|
||||||
@ -1384,8 +1449,14 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
EthernetProtocol::Ipv4 => {
|
EthernetProtocol::Ipv4 => {
|
||||||
let ipv4_packet = check!(Ipv4Packet::new_checked(eth_frame.payload()));
|
let ipv4_packet = check!(Ipv4Packet::new_checked(eth_frame.payload()));
|
||||||
self.process_ipv4(sockets, &ipv4_packet)
|
|
||||||
.map(EthernetPacket::Ip)
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "proto-ipv4-fragmentation")] {
|
||||||
|
self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
|
||||||
|
.map(EthernetPacket::Ip) } else {
|
||||||
|
self.process_ipv4(sockets, &ipv4_packet, None).map(EthernetPacket::Ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
EthernetProtocol::Ipv6 => {
|
EthernetProtocol::Ipv6 => {
|
||||||
@ -1403,12 +1474,20 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
ip_payload: &'frame T,
|
ip_payload: &'frame T,
|
||||||
|
_fragments: &'frame mut FragmentsBuffer<'a>,
|
||||||
) -> 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));
|
||||||
self.process_ipv4(sockets, &ipv4_packet)
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "proto-ipv4-fragmentation")] {
|
||||||
|
self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
|
||||||
|
} else {
|
||||||
|
self.process_ipv4(sockets, &ipv4_packet, None)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
Ok(IpVersion::Ipv6) => {
|
Ok(IpVersion::Ipv6) => {
|
||||||
@ -1425,7 +1504,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
sixlowpan_payload: &'payload T,
|
sixlowpan_payload: &'payload T,
|
||||||
fragments: &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
|
_fragments: &'output mut FragmentsBuffer<'a>,
|
||||||
) -> Option<IpPacket<'output>> {
|
) -> Option<IpPacket<'output>> {
|
||||||
let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
|
let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
|
||||||
let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
|
let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
|
||||||
@ -1449,7 +1528,15 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match ieee802154_frame.payload() {
|
match ieee802154_frame.payload() {
|
||||||
Some(payload) => self.process_sixlowpan(sockets, &ieee802154_repr, payload, fragments),
|
Some(payload) => {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "proto-sixlowpan-fragmentation")] {
|
||||||
|
self.process_sixlowpan(sockets, &ieee802154_repr, payload, Some(&mut _fragments.sixlowpan_fragments))
|
||||||
|
} else {
|
||||||
|
self.process_sixlowpan(sockets, &ieee802154_repr, payload, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1460,15 +1547,18 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
ieee802154_repr: &Ieee802154Repr,
|
ieee802154_repr: &Ieee802154Repr,
|
||||||
payload: &'payload T,
|
payload: &'payload T,
|
||||||
fragments: &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
|
_fragments: Option<&'output mut PacketAssemblerSet<'a, SixlowpanFragKey>>,
|
||||||
) -> Option<IpPacket<'output>> {
|
) -> Option<IpPacket<'output>> {
|
||||||
check!(fragments.remove_when(|frag| Ok(
|
|
||||||
self.now - frag.start_time().unwrap() > Duration::from_secs(60)
|
|
||||||
)));
|
|
||||||
fragments.remove_discarded();
|
|
||||||
|
|
||||||
let payload = match check!(SixlowpanPacket::dispatch(payload)) {
|
let payload = match check!(SixlowpanPacket::dispatch(payload)) {
|
||||||
|
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||||
SixlowpanPacket::FragmentHeader => {
|
SixlowpanPacket::FragmentHeader => {
|
||||||
|
net_debug!("Fragmentation is not supported, use the `proto-sixlowpan-fragmentation` feature to add support.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
|
SixlowpanPacket::FragmentHeader => {
|
||||||
|
let fragments = _fragments.unwrap();
|
||||||
|
|
||||||
// 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.
|
||||||
let frag = check!(SixlowpanFragPacket::new_checked(payload));
|
let frag = check!(SixlowpanFragPacket::new_checked(payload));
|
||||||
@ -1528,25 +1618,21 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
// 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.
|
||||||
check!(check!(fragments.reserve_with_key(&key)).start(
|
check!(check!(fragments.reserve_with_key(&key)).start(
|
||||||
|
Some(
|
||||||
frag.datagram_size() as usize - uncompressed_header_size
|
frag.datagram_size() as usize - uncompressed_header_size
|
||||||
+ compressed_header_size,
|
+ compressed_header_size
|
||||||
self.now,
|
),
|
||||||
|
self.now + Duration::from_secs(60),
|
||||||
-((uncompressed_header_size - compressed_header_size) as isize),
|
-((uncompressed_header_size - compressed_header_size) as isize),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let frags = check!(fragments.get_packet_assembler_mut(&key));
|
let frags = check!(fragments.get_packet_assembler_mut(&key));
|
||||||
|
|
||||||
// Check if 60 seconds have passed since the start of the first fragment.
|
|
||||||
if self.now - frags.start_time().unwrap() > Duration::from_secs(60) {
|
|
||||||
frags.mark_discarded();
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_trace!("6LoWPAN: received packet fragment");
|
net_trace!("6LoWPAN: received packet fragment");
|
||||||
|
|
||||||
// Add the fragment to the packet assembler.
|
// Add the fragment to the packet assembler.
|
||||||
match frags.add(frag.payload(), offset, self.now) {
|
match frags.add(frag.payload(), offset) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
net_trace!("6LoWPAN: fragmented packet now complete");
|
net_trace!("6LoWPAN: fragmented packet now complete");
|
||||||
check!(fragments.get_assembled_packet(&key))
|
check!(fragments.get_assembled_packet(&key))
|
||||||
@ -1830,22 +1916,76 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
fn process_ipv4<'frame, T: AsRef<[u8]> + ?Sized>(
|
fn process_ipv4<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
ipv4_packet: &Ipv4Packet<&'frame T>,
|
ipv4_packet: &Ipv4Packet<&'payload T>,
|
||||||
) -> Option<IpPacket<'frame>> {
|
_fragments: Option<&'output mut PacketAssemblerSet<'a, Ipv4FragKey>>,
|
||||||
|
) -> Option<IpPacket<'output>> {
|
||||||
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.
|
||||||
net_debug!("non-unicast source address");
|
net_debug!("non-unicast source address");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
let ip_payload = {
|
||||||
|
const REASSEMBLY_TIMEOUT: u64 = 90;
|
||||||
|
|
||||||
|
let fragments = _fragments.unwrap();
|
||||||
|
|
||||||
|
if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
|
||||||
|
let key = ipv4_packet.get_key();
|
||||||
|
|
||||||
|
let f = match fragments.get_packet_assembler_mut(&key) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(_) => {
|
||||||
|
check!(check!(fragments.reserve_with_key(&key)).start(
|
||||||
|
None,
|
||||||
|
self.now + Duration::from_secs(REASSEMBLY_TIMEOUT),
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
check!(fragments.get_packet_assembler_mut(&key))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !ipv4_packet.more_frags() {
|
||||||
|
// This is the last fragment, so we know the total size
|
||||||
|
check!(f.set_total_size(
|
||||||
|
ipv4_packet.total_len() as usize - ipv4_packet.header_len() as usize
|
||||||
|
+ ipv4_packet.frag_offset() as usize,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
match f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
|
||||||
|
Ok(true) => {
|
||||||
|
// NOTE: according to the standard, the total length needs to be
|
||||||
|
// recomputed, as well as the checksum. However, we don't really use
|
||||||
|
// the IPv4 header after the packet is reassembled.
|
||||||
|
check!(fragments.get_assembled_packet(&key))
|
||||||
|
}
|
||||||
|
Ok(false) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Err(Error::PacketAssemblerOverlap) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
net_debug!("fragmentation error: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ipv4_packet.payload()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
|
||||||
let ip_payload = ipv4_packet.payload();
|
let ip_payload = ipv4_packet.payload();
|
||||||
|
|
||||||
|
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
||||||
|
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
|
let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
|
||||||
#[cfg(not(feature = "socket-raw"))]
|
#[cfg(not(feature = "socket-raw"))]
|
||||||
@ -1862,8 +2002,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
{
|
{
|
||||||
if let Some(dhcp_socket) = sockets
|
if let Some(dhcp_socket) = sockets
|
||||||
.items_mut()
|
.items_mut()
|
||||||
.filter_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
|
.find_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
|
||||||
.next()
|
|
||||||
{
|
{
|
||||||
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
||||||
let udp_repr = check!(UdpRepr::parse(
|
let udp_repr = check!(UdpRepr::parse(
|
||||||
@ -2732,14 +2871,14 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(all(feature = "medium-ieee802154", feature = "proto-sixlowpan"))]
|
||||||
fn dispatch_ieee802154<Tx: TxToken>(
|
fn dispatch_ieee802154<Tx: TxToken>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ll_dst_a: Ieee802154Address,
|
ll_dst_a: Ieee802154Address,
|
||||||
ip_repr: &IpRepr,
|
ip_repr: &IpRepr,
|
||||||
tx_token: Tx,
|
tx_token: Tx,
|
||||||
packet: IpPacket,
|
packet: IpPacket,
|
||||||
out_packet: Option<&mut OutPackets>,
|
_out_packet: Option<&mut OutPackets>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// We first need to convert the IPv6 packet to a 6LoWPAN compressed packet.
|
// 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
|
// Whenever this packet is to big to fit in the IEEE802.15.4 packet, then we need to
|
||||||
@ -2798,14 +2937,14 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
// We need to know this, such that we know when to do the fragmentation.
|
// We need to know this, such that we know when to do the fragmentation.
|
||||||
let mut total_size = 0;
|
let mut total_size = 0;
|
||||||
total_size += iphc_repr.buffer_len();
|
total_size += iphc_repr.buffer_len();
|
||||||
let mut compressed_headers_len = iphc_repr.buffer_len();
|
let mut _compressed_headers_len = iphc_repr.buffer_len();
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
match packet {
|
match packet {
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
IpPacket::Udp((_, udpv6_repr, payload)) => {
|
IpPacket::Udp((_, udpv6_repr, payload)) => {
|
||||||
let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
|
let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
|
||||||
compressed_headers_len += udp_repr.header_len();
|
_compressed_headers_len += udp_repr.header_len();
|
||||||
total_size += udp_repr.header_len() + payload.len();
|
total_size += udp_repr.header_len() + payload.len();
|
||||||
}
|
}
|
||||||
#[cfg(feature = "socket-tcp")]
|
#[cfg(feature = "socket-tcp")]
|
||||||
@ -2822,6 +2961,8 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
let ieee_len = ieee_repr.buffer_len();
|
let ieee_len = ieee_repr.buffer_len();
|
||||||
|
|
||||||
if total_size + ieee_len > 125 {
|
if total_size + ieee_len > 125 {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(feature = "proto-sixlowpan-fragmentation")] {
|
||||||
// The packet does not fit in one Ieee802154 frame, so we need 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 `out_packet.buffer` from the interface.
|
||||||
// After emitting everything into that buffer, we send the first fragment heere.
|
// After emitting everything into that buffer, we send the first fragment heere.
|
||||||
@ -2840,7 +2981,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
ll_dst_addr,
|
ll_dst_addr,
|
||||||
ll_src_addr,
|
ll_src_addr,
|
||||||
..
|
..
|
||||||
} = &mut out_packet.unwrap().sixlowpan_out_packet;
|
} = &mut _out_packet.unwrap().sixlowpan_out_packet;
|
||||||
|
|
||||||
*ll_dst_addr = ll_dst_a;
|
*ll_dst_addr = ll_dst_a;
|
||||||
*ll_src_addr = ll_src_a;
|
*ll_src_addr = ll_src_a;
|
||||||
@ -2869,7 +3010,8 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "socket-tcp")]
|
#[cfg(feature = "socket-tcp")]
|
||||||
IpPacket::Tcp((_, tcp_repr)) => {
|
IpPacket::Tcp((_, tcp_repr)) => {
|
||||||
let mut tcp_packet = TcpPacket::new_unchecked(&mut b[..tcp_repr.buffer_len()]);
|
let mut tcp_packet =
|
||||||
|
TcpPacket::new_unchecked(&mut b[..tcp_repr.buffer_len()]);
|
||||||
tcp_repr.emit(
|
tcp_repr.emit(
|
||||||
&mut tcp_packet,
|
&mut tcp_packet,
|
||||||
&iphc_repr.src_addr.into(),
|
&iphc_repr.src_addr.into(),
|
||||||
@ -2919,9 +3061,9 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
// in multiples of 8 octets. This is explained in [RFC 4944 § 5.3].
|
// in multiples of 8 octets. This is explained in [RFC 4944 § 5.3].
|
||||||
//
|
//
|
||||||
// [RFC 4944 § 5.3]: https://datatracker.ietf.org/doc/html/rfc4944#section-5.3
|
// [RFC 4944 § 5.3]: https://datatracker.ietf.org/doc/html/rfc4944#section-5.3
|
||||||
let frag1_size = ((125 - ieee_len - frag1.buffer_len() - compressed_headers_len)
|
let frag1_size = ((125 - ieee_len - frag1.buffer_len() - _compressed_headers_len)
|
||||||
& 0xffff_fff8)
|
& 0xffff_fff8)
|
||||||
+ compressed_headers_len;
|
+ _compressed_headers_len;
|
||||||
*fragn_size = (125 - ieee_len - fragn.buffer_len()) & 0xffff_fff8;
|
*fragn_size = (125 - ieee_len - fragn.buffer_len()) & 0xffff_fff8;
|
||||||
|
|
||||||
*sent_bytes = frag1_size;
|
*sent_bytes = frag1_size;
|
||||||
@ -2931,7 +3073,8 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
ieee_len + frag1.buffer_len() + frag1_size,
|
ieee_len + frag1.buffer_len() + frag1_size,
|
||||||
|mut tx_buf| {
|
|mut tx_buf| {
|
||||||
// Add the IEEE header.
|
// Add the IEEE header.
|
||||||
let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
|
let mut ieee_packet =
|
||||||
|
Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
|
||||||
ieee_repr.emit(&mut ieee_packet);
|
ieee_repr.emit(&mut ieee_packet);
|
||||||
tx_buf = &mut tx_buf[ieee_len..];
|
tx_buf = &mut tx_buf[ieee_len..];
|
||||||
|
|
||||||
@ -2946,6 +3089,11 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
net_debug!("Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// We don't need fragmentation, so we emit everything to the TX token.
|
// We don't need fragmentation, so we emit everything to the TX token.
|
||||||
tx_token.consume(self.now, total_size + ieee_len, |mut tx_buf| {
|
tx_token.consume(self.now, total_size + ieee_len, |mut tx_buf| {
|
||||||
@ -3003,7 +3151,10 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(all(
|
||||||
|
feature = "medium-ieee802154",
|
||||||
|
feature = "proto-sixlowpan-fragmentation"
|
||||||
|
))]
|
||||||
fn dispatch_ieee802154_out_packet<Tx: TxToken>(
|
fn dispatch_ieee802154_out_packet<Tx: TxToken>(
|
||||||
&mut self,
|
&mut self,
|
||||||
tx_token: Tx,
|
tx_token: Tx,
|
||||||
@ -3162,6 +3313,11 @@ mod test {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let iface_builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
|
let iface_builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
let iface_builder =
|
||||||
|
iface_builder.ipv4_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()));
|
||||||
|
|
||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||||
let iface = iface_builder.finalize(&mut device);
|
let iface = iface_builder.finalize(&mut device);
|
||||||
@ -3182,19 +3338,19 @@ mod test {
|
|||||||
IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64),
|
IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64),
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
|
||||||
let iface_builder = InterfaceBuilder::new()
|
let iface_builder = InterfaceBuilder::new()
|
||||||
.hardware_addr(EthernetAddress::default().into())
|
.hardware_addr(EthernetAddress::default().into())
|
||||||
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
||||||
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
|
||||||
.sixlowpan_out_packet_cache(vec![])
|
|
||||||
.ip_addrs(ip_addrs);
|
.ip_addrs(ip_addrs);
|
||||||
|
|
||||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||||
let iface_builder = InterfaceBuilder::new()
|
let iface_builder = iface_builder
|
||||||
.hardware_addr(EthernetAddress::default().into())
|
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||||
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
.sixlowpan_out_packet_cache(vec![]);
|
||||||
.ip_addrs(ip_addrs);
|
|
||||||
|
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||||
|
let iface_builder =
|
||||||
|
iface_builder.ipv4_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()));
|
||||||
|
|
||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||||
@ -3262,7 +3418,18 @@ mod test {
|
|||||||
// Ensure that the unknown protocol frame does not trigger an
|
// Ensure that the unknown protocol frame does not trigger an
|
||||||
// ICMP error response when the destination address is a
|
// ICMP error response when the destination address is a
|
||||||
// broadcast address
|
// broadcast address
|
||||||
assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame), None);
|
|
||||||
|
#[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)
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -3339,8 +3506,20 @@ mod test {
|
|||||||
|
|
||||||
// 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!(
|
assert_eq!(
|
||||||
iface.inner.process_ipv4(&mut sockets, &frame),
|
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)
|
||||||
|
),
|
||||||
Some(expected_repr)
|
Some(expected_repr)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3632,8 +3811,19 @@ mod test {
|
|||||||
};
|
};
|
||||||
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!(
|
assert_eq!(
|
||||||
iface.inner.process_ipv4(&mut sockets, &frame),
|
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)
|
||||||
|
),
|
||||||
Some(expected_packet)
|
Some(expected_packet)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3682,8 +3872,8 @@ mod test {
|
|||||||
);
|
);
|
||||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||||
let ip_repr = Ipv4Repr {
|
let ip_repr = Ipv4Repr {
|
||||||
src_addr: src_addr,
|
src_addr,
|
||||||
dst_addr: dst_addr,
|
dst_addr,
|
||||||
next_header: IpProtocol::Udp,
|
next_header: IpProtocol::Udp,
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
|
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
|
||||||
@ -3788,7 +3978,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
iface
|
iface
|
||||||
.inner
|
.inner
|
||||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||||
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
||||||
operation: ArpOperation::Reply,
|
operation: ArpOperation::Reply,
|
||||||
source_hardware_addr: local_hw_addr,
|
source_hardware_addr: local_hw_addr,
|
||||||
@ -3863,7 +4053,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
iface
|
iface
|
||||||
.inner
|
.inner
|
||||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||||
Some(EthernetPacket::Ip(IpPacket::Icmpv6((
|
Some(EthernetPacket::Ip(IpPacket::Icmpv6((
|
||||||
ipv6_expected,
|
ipv6_expected,
|
||||||
icmpv6_expected
|
icmpv6_expected
|
||||||
@ -3910,7 +4100,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
iface
|
iface
|
||||||
.inner
|
.inner
|
||||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3962,7 +4152,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
iface
|
iface
|
||||||
.inner
|
.inner
|
||||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||||
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
||||||
operation: ArpOperation::Reply,
|
operation: ArpOperation::Reply,
|
||||||
source_hardware_addr: local_hw_addr,
|
source_hardware_addr: local_hw_addr,
|
||||||
@ -4289,8 +4479,8 @@ mod test {
|
|||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
);
|
);
|
||||||
let ipv4_repr = Ipv4Repr {
|
let ipv4_repr = Ipv4Repr {
|
||||||
src_addr: src_addr,
|
src_addr,
|
||||||
dst_addr: dst_addr,
|
dst_addr,
|
||||||
next_header: IpProtocol::Udp,
|
next_header: IpProtocol::Udp,
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
payload_len: udp_repr.header_len() + PAYLOAD_LEN,
|
payload_len: udp_repr.header_len() + PAYLOAD_LEN,
|
||||||
@ -4314,7 +4504,17 @@ mod test {
|
|||||||
Ipv4Packet::new_unchecked(&bytes)
|
Ipv4Packet::new_unchecked(&bytes)
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame), None);
|
#[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)
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -4370,8 +4570,8 @@ mod test {
|
|||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
);
|
);
|
||||||
let ipv4_repr = Ipv4Repr {
|
let ipv4_repr = Ipv4Repr {
|
||||||
src_addr: src_addr,
|
src_addr,
|
||||||
dst_addr: dst_addr,
|
dst_addr,
|
||||||
next_header: IpProtocol::Udp,
|
next_header: IpProtocol::Udp,
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
|
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
|
||||||
@ -4396,7 +4596,17 @@ mod test {
|
|||||||
Ipv4Packet::new_unchecked(&bytes)
|
Ipv4Packet::new_unchecked(&bytes)
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(iface.inner.process_ipv4(&mut sockets, &frame), None);
|
#[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)
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
// Make sure the UDP socket can still receive in presence of a Raw socket that handles UDP
|
// Make sure the UDP socket can still receive in presence of a Raw socket that handles UDP
|
||||||
let socket = sockets.get_mut::<udp::Socket>(udp_socket_handle);
|
let socket = sockets.get_mut::<udp::Socket>(udp_socket_handle);
|
||||||
|
@ -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,10 +764,21 @@ 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) => {
|
||||||
|
if ip_packet.more_frags() || ip_packet.frag_offset() != 0 {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}IPv4 Fragment more_frags={} offset={}",
|
||||||
|
indent,
|
||||||
|
ip_packet.more_frags(),
|
||||||
|
ip_packet.frag_offset()
|
||||||
|
)?;
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
write!(f, "{}{}", indent, ip_repr)?;
|
write!(f, "{}{}", indent, ip_repr)?;
|
||||||
format_checksum(f, ip_packet.verify_checksum())?;
|
format_checksum(f, ip_packet.verify_checksum())?;
|
||||||
(ip_repr, ip_packet.payload())
|
(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