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"]
|
||||
|
||||
"proto-ipv4" = []
|
||||
"proto-ipv4-fragmentation" = ["proto-ipv4"]
|
||||
"proto-igmp" = ["proto-ipv4"]
|
||||
"proto-dhcpv4" = ["proto-ipv4"]
|
||||
"proto-ipv6" = []
|
||||
"proto-sixlowpan" = ["proto-ipv6"]
|
||||
"proto-sixlowpan-fragmentation" = ["proto-sixlowpan"]
|
||||
"proto-dns" = []
|
||||
|
||||
"socket" = []
|
||||
@ -63,7 +65,8 @@ default = [
|
||||
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
||||
"medium-ethernet", "medium-ip", "medium-ieee802154",
|
||||
"phy-raw_socket", "phy-tuntap_interface",
|
||||
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-sixlowpan", "proto-dns",
|
||||
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6", "proto-dns",
|
||||
"proto-ipv4-fragmentation", "proto-sixlowpan-fragmentation",
|
||||
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp", "socket-dhcpv4", "socket-dns",
|
||||
"async"
|
||||
]
|
||||
@ -114,10 +117,11 @@ required-features = ["std", "medium-ethernet", "medium-ip", "phy-tuntap_interfac
|
||||
|
||||
[[example]]
|
||||
name = "sixlowpan"
|
||||
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]
|
||||
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "proto-sixlowpan-fragmentation", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "sixlowpan_benchmark"
|
||||
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "socket-udp"]
|
||||
required-features = ["std", "medium-ieee802154", "phy-raw_socket", "proto-sixlowpan", "proto-sixlowpan-fragmentation", "socket-udp"]
|
||||
|
||||
[[example]]
|
||||
name = "dns"
|
||||
|
@ -5,6 +5,12 @@ use std::collections::BTreeMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::str::{self, FromStr};
|
||||
|
||||
#[cfg(any(
|
||||
feature = "proto-sixlowpan-fragmentation",
|
||||
feature = "proto-ipv4-fragmentation"
|
||||
))]
|
||||
use smoltcp::iface::FragmentsCache;
|
||||
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||
use smoltcp::socket::tcp;
|
||||
@ -31,8 +37,8 @@ fn main() {
|
||||
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
|
||||
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
|
||||
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 128]);
|
||||
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 1500]);
|
||||
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||
|
||||
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
||||
@ -44,6 +50,23 @@ fn main() {
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
{
|
||||
let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let mut out_packet_buffer = [0u8; 1280];
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
{
|
||||
let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.sixlowpan_fragments_cache(sixlowpan_frag_cache)
|
||||
.sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
|
||||
}
|
||||
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.hardware_addr(ethernet_addr.into())
|
||||
|
@ -6,6 +6,11 @@ use std::fmt::Write;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::str;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "proto-sixlowpan-fragmentation",
|
||||
feature = "proto-ipv4-fragmentation"
|
||||
))]
|
||||
use smoltcp::iface::FragmentsCache;
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||
use smoltcp::socket::{tcp, udp};
|
||||
@ -27,8 +32,8 @@ fn main() {
|
||||
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
|
||||
let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 64]);
|
||||
let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 128]);
|
||||
let udp_rx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 65535]);
|
||||
let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 65535]);
|
||||
let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
|
||||
|
||||
let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 64]);
|
||||
@ -56,6 +61,23 @@ fn main() {
|
||||
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
{
|
||||
let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let mut out_packet_buffer = [0u8; 1280];
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
{
|
||||
let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.sixlowpan_fragments_cache(sixlowpan_frag_cache)
|
||||
.sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
|
||||
}
|
||||
|
||||
if medium == Medium::Ethernet {
|
||||
builder = builder
|
||||
.hardware_addr(ethernet_addr.into())
|
||||
|
@ -3,13 +3,12 @@
|
||||
use managed::{ManagedMap, ManagedSlice};
|
||||
|
||||
use crate::storage::Assembler;
|
||||
use crate::time::Instant;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::Error;
|
||||
use crate::Result;
|
||||
|
||||
/// Holds different fragments of one packet, used for assembling fragmented packets.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PacketAssembler<'a> {
|
||||
buffer: ManagedSlice<'a, u8>,
|
||||
assembler: AssemblerState,
|
||||
@ -17,14 +16,12 @@ pub struct PacketAssembler<'a> {
|
||||
|
||||
/// Holds the state of the assembling of one packet.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum AssemblerState {
|
||||
NotInit,
|
||||
Assembling {
|
||||
assembler: Assembler,
|
||||
total_size: usize,
|
||||
last_updated: Instant,
|
||||
started_on: Instant,
|
||||
total_size: Option<usize>,
|
||||
expires_at: Instant,
|
||||
offset_correction: isize,
|
||||
},
|
||||
}
|
||||
@ -51,32 +48,71 @@ impl<'a> PacketAssembler<'a> {
|
||||
/// fragments of a packet.
|
||||
pub(crate) fn start(
|
||||
&mut self,
|
||||
total_size: usize,
|
||||
start_time: Instant,
|
||||
total_size: Option<usize>,
|
||||
expires_at: Instant,
|
||||
offset_correction: isize,
|
||||
) -> Result<()> {
|
||||
match &mut self.buffer {
|
||||
ManagedSlice::Borrowed(b) if b.len() < total_size => {
|
||||
ManagedSlice::Borrowed(b) => {
|
||||
if let Some(total_size) = total_size {
|
||||
if b.len() < total_size {
|
||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||
}
|
||||
ManagedSlice::Borrowed(_) => (),
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
ManagedSlice::Owned(b) => {
|
||||
if let Some(total_size) = total_size {
|
||||
b.resize(total_size, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.assembler = AssemblerState::Assembling {
|
||||
assembler: Assembler::new(total_size),
|
||||
assembler: Assembler::new(if let Some(total_size) = total_size {
|
||||
total_size
|
||||
} else {
|
||||
usize::MAX
|
||||
}),
|
||||
total_size,
|
||||
last_updated: start_time,
|
||||
started_on: start_time,
|
||||
expires_at,
|
||||
offset_correction,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the total size of the packet assembler.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - Returns [`Error::PacketAssemblerNotInit`] when the assembler was not initialized (try initializing the
|
||||
/// assembler with [Self::start]).
|
||||
pub(crate) fn set_total_size(&mut self, size: usize) -> Result<()> {
|
||||
match self.assembler {
|
||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling {
|
||||
ref mut total_size, ..
|
||||
} => {
|
||||
*total_size = Some(size);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the instant when the assembler expires.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - Returns [`Error::PacketAssemblerNotInit`] when the assembler was not initialized (try initializing the
|
||||
/// assembler with [Self::start]).
|
||||
pub(crate) fn expires_at(&self) -> Result<Instant> {
|
||||
match self.assembler {
|
||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling { expires_at, .. } => Ok(expires_at),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a fragment into the packet that is being reassembled.
|
||||
///
|
||||
/// # Errors
|
||||
@ -86,22 +122,31 @@ impl<'a> PacketAssembler<'a> {
|
||||
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when trying to add data into the buffer at a non-existing
|
||||
/// place.
|
||||
/// - Returns [`Error::PacketAssemblerOverlap`] when there was an overlap when adding data.
|
||||
pub(crate) fn add(&mut self, data: &[u8], offset: usize, now: Instant) -> Result<bool> {
|
||||
pub(crate) fn add(&mut self, data: &[u8], offset: usize) -> Result<bool> {
|
||||
match self.assembler {
|
||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling {
|
||||
ref mut assembler,
|
||||
total_size,
|
||||
ref mut last_updated,
|
||||
offset_correction,
|
||||
..
|
||||
} => {
|
||||
let offset = offset as isize + offset_correction;
|
||||
let offset = if offset <= 0 { 0 } else { offset as usize };
|
||||
|
||||
if offset + data.len() > total_size {
|
||||
match &mut self.buffer {
|
||||
ManagedSlice::Borrowed(b) => {
|
||||
if offset + data.len() > b.len() {
|
||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
ManagedSlice::Owned(b) => {
|
||||
if offset + data.len() > b.len() {
|
||||
b.resize(offset + data.len(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let len = data.len();
|
||||
self.buffer[offset..][..len].copy_from_slice(data);
|
||||
@ -111,7 +156,6 @@ impl<'a> PacketAssembler<'a> {
|
||||
if overlap {
|
||||
net_debug!("packet was added, but there was an overlap.");
|
||||
}
|
||||
*last_updated = now;
|
||||
self.is_complete()
|
||||
}
|
||||
// NOTE(thvdveld): hopefully we wont get too many holes errors I guess?
|
||||
@ -134,6 +178,8 @@ impl<'a> PacketAssembler<'a> {
|
||||
AssemblerState::NotInit => return Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling { total_size, .. } => {
|
||||
if self.is_complete()? {
|
||||
// NOTE: we can unwrap because `is_complete` already checks this.
|
||||
let total_size = total_size.unwrap();
|
||||
let a = &self.buffer[..total_size];
|
||||
self.assembler = AssemblerState::NotInit;
|
||||
a
|
||||
@ -158,13 +204,10 @@ impl<'a> PacketAssembler<'a> {
|
||||
assembler,
|
||||
total_size,
|
||||
..
|
||||
} => {
|
||||
if let Some(front) = assembler.peek_front() {
|
||||
Ok(front == *total_size)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} => match (total_size, assembler.peek_front()) {
|
||||
(Some(total_size), Some(front)) => Ok(front == *total_size),
|
||||
_ => Ok(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,40 +216,20 @@ impl<'a> PacketAssembler<'a> {
|
||||
self.assembler == AssemblerState::NotInit
|
||||
}
|
||||
|
||||
/// Returns the [`Instant`] when the packet assembler was started.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - Returns [`Error::PacketAssemblerNotInit`] when the packet assembler was not initialized.
|
||||
pub fn start_time(&self) -> Result<Instant> {
|
||||
match self.assembler {
|
||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling { started_on, .. } => Ok(started_on),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`Instant`] when the packet assembler was last updated.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - Returns [`Error::PacketAssemblerNotInit`] when the packet assembler was not initialized.
|
||||
pub fn last_update_time(&self) -> Result<Instant> {
|
||||
match self.assembler {
|
||||
AssemblerState::NotInit => Err(Error::PacketAssemblerNotInit),
|
||||
AssemblerState::Assembling { last_updated, .. } => Ok(last_updated),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark this assembler as [`AssemblerState::NotInit`].
|
||||
/// This is then cleaned up by the [`PacketAssemblerSet`].
|
||||
pub fn mark_discarded(&mut self) {
|
||||
self.assembler = AssemblerState::NotInit;
|
||||
}
|
||||
|
||||
/// Returns `true` when the [`AssemblerState`] is discarded.
|
||||
pub fn is_discarded(&self) -> bool {
|
||||
matches!(self.assembler, AssemblerState::NotInit)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set holding multiple [`PacketAssembler`].
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PacketAssemblerSet<'a, Key: Eq + Ord + Clone + Copy> {
|
||||
packet_buffer: ManagedSlice<'a, PacketAssembler<'a>>,
|
||||
index_buffer: ManagedMap<'a, Key, usize>,
|
||||
@ -296,7 +319,7 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
|
||||
match &mut self.packet_buffer {
|
||||
ManagedSlice::Borrowed(_) => (),
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
ManagedSlice::Owned(b) => b.push(PacketAssembler::new(vec![])),
|
||||
ManagedSlice::Owned(b) => b.push(PacketAssembler::new(alloc::vec![])),
|
||||
}
|
||||
|
||||
self.packet_buffer
|
||||
@ -341,7 +364,10 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
|
||||
loop {
|
||||
let mut key = None;
|
||||
for (k, i) in self.index_buffer.iter() {
|
||||
if self.packet_buffer[*i as usize].assembler == AssemblerState::NotInit {
|
||||
if matches!(
|
||||
self.packet_buffer[*i as usize].assembler,
|
||||
AssemblerState::NotInit
|
||||
) {
|
||||
key = Some(*k);
|
||||
break;
|
||||
}
|
||||
@ -355,17 +381,28 @@ impl<'a, K: Eq + Ord + Clone + Copy> PacketAssemblerSet<'a, K> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all [`PacketAssembler`]s for which `f` returns `Ok(true)`.
|
||||
pub fn remove_when(
|
||||
&mut self,
|
||||
f: impl Fn(&mut PacketAssembler<'_>) -> Result<bool>,
|
||||
) -> Result<()> {
|
||||
/// Mark all [`PacketAssembler`]s as discarded for which `f` returns `Ok(true)`.
|
||||
/// This does not remove them from the buffer.
|
||||
pub fn mark_discarded_when<F>(&mut self, f: F) -> Result<()>
|
||||
where
|
||||
F: Fn(&mut PacketAssembler<'_>) -> Result<bool>,
|
||||
{
|
||||
for (_, i) in &mut self.index_buffer.iter() {
|
||||
let frag = &mut self.packet_buffer[*i as usize];
|
||||
if f(frag)? {
|
||||
frag.mark_discarded();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove all [`PacketAssembler`]s for which `f` returns `Ok(true)`.
|
||||
pub fn remove_when<F>(&mut self, f: F) -> Result<()>
|
||||
where
|
||||
F: Fn(&mut PacketAssembler<'_>) -> Result<bool>,
|
||||
{
|
||||
self.mark_discarded_when(f)?;
|
||||
self.remove_discarded();
|
||||
|
||||
Ok(())
|
||||
@ -386,7 +423,7 @@ mod tests {
|
||||
let mut p_assembler = PacketAssembler::new(vec![]);
|
||||
let data = b"Hello World!";
|
||||
assert_eq!(
|
||||
p_assembler.add(&data[..], data.len(), Instant::now()),
|
||||
p_assembler.add(&data[..], data.len()),
|
||||
Err(Error::PacketAssemblerNotInit)
|
||||
);
|
||||
|
||||
@ -403,14 +440,14 @@ mod tests {
|
||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||
|
||||
assert_eq!(
|
||||
p_assembler.start(2, Instant::now(), 0),
|
||||
p_assembler.start(Some(2), Instant::from_secs(0), 0),
|
||||
Err(Error::PacketAssemblerBufferTooSmall)
|
||||
);
|
||||
assert_eq!(p_assembler.start(1, Instant::now(), 0), Ok(()));
|
||||
assert_eq!(p_assembler.start(Some(1), Instant::from_secs(0), 0), Ok(()));
|
||||
|
||||
let data = b"Hello World!";
|
||||
assert_eq!(
|
||||
p_assembler.add(&data[..], data.len(), Instant::now()),
|
||||
p_assembler.add(&data[..], data.len()),
|
||||
Err(Error::PacketAssemblerBufferTooSmall)
|
||||
);
|
||||
}
|
||||
@ -420,12 +457,14 @@ mod tests {
|
||||
let mut storage = [0u8; 5];
|
||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||
|
||||
p_assembler.start(5, Instant::now(), 0).unwrap();
|
||||
p_assembler
|
||||
.start(Some(5), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
let data = b"Rust";
|
||||
|
||||
p_assembler.add(&data[..], 0, Instant::now()).unwrap();
|
||||
p_assembler.add(&data[..], 0).unwrap();
|
||||
|
||||
assert_eq!(p_assembler.add(&data[..], 1, Instant::now()), Ok(true));
|
||||
assert_eq!(p_assembler.add(&data[..], 1), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -435,18 +474,40 @@ mod tests {
|
||||
|
||||
let data = b"Hello World!";
|
||||
|
||||
p_assembler.start(data.len(), Instant::now(), 0).unwrap();
|
||||
p_assembler
|
||||
.start(Some(data.len()), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
|
||||
p_assembler.add(b"Hello ", 0, Instant::now()).unwrap();
|
||||
p_assembler.add(b"Hello ", 0).unwrap();
|
||||
assert_eq!(
|
||||
p_assembler.assemble(),
|
||||
Err(Error::PacketAssemblerIncomplete)
|
||||
);
|
||||
|
||||
p_assembler.add(b"World!", b"Hello ".len()).unwrap();
|
||||
|
||||
assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packet_assembler_out_of_order_assemble() {
|
||||
let mut storage = [0u8; 12];
|
||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||
|
||||
let data = b"Hello World!";
|
||||
|
||||
p_assembler
|
||||
.add(b"World!", b"Hello ".len(), Instant::now())
|
||||
.start(Some(data.len()), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
|
||||
p_assembler.add(b"World!", b"Hello ".len()).unwrap();
|
||||
assert_eq!(
|
||||
p_assembler.assemble(),
|
||||
Err(Error::PacketAssemblerIncomplete)
|
||||
);
|
||||
|
||||
p_assembler.add(b"Hello ", 0).unwrap();
|
||||
|
||||
assert_eq!(p_assembler.assemble(), Ok(&b"Hello World!"[..]));
|
||||
}
|
||||
|
||||
@ -494,7 +555,7 @@ mod tests {
|
||||
set.reserve_with_key(&key).unwrap();
|
||||
set.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.start(0, Instant::now(), 0)
|
||||
.start(Some(0), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
set.get_assembled_packet(&key).unwrap();
|
||||
|
||||
@ -502,7 +563,7 @@ mod tests {
|
||||
set.reserve_with_key(&key).unwrap();
|
||||
set.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.start(0, Instant::now(), 0)
|
||||
.start(Some(0), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
set.get_assembled_packet(&key).unwrap();
|
||||
|
||||
@ -510,7 +571,7 @@ mod tests {
|
||||
set.reserve_with_key(&key).unwrap();
|
||||
set.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.start(0, Instant::now(), 0)
|
||||
.start(Some(0), Instant::from_secs(0), 0)
|
||||
.unwrap();
|
||||
set.get_assembled_packet(&key).unwrap();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
use core::cmp;
|
||||
use managed::{ManagedMap, ManagedSlice};
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
|
||||
use super::fragmentation::PacketAssemblerSet;
|
||||
use super::socket_set::SocketSet;
|
||||
use crate::iface::Routes;
|
||||
@ -23,19 +23,27 @@ use crate::wire::*;
|
||||
use crate::{Error, Result};
|
||||
|
||||
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>,
|
||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "proto-ipv4-fragmentation",
|
||||
feature = "proto-sixlowpan-fragmentation"
|
||||
)))]
|
||||
_lifetime: core::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
pub(crate) struct OutPackets<'a> {
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_packet: SixlowpanOutPacket<'a>,
|
||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||
|
||||
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||
_lifetime: core::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
pub(crate) struct SixlowpanOutPacket<'a> {
|
||||
/// The buffer that holds the unfragmented 6LoWPAN packet.
|
||||
@ -59,7 +67,7 @@ pub(crate) struct SixlowpanOutPacket<'a> {
|
||||
ll_src_addr: Ieee802154Address,
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
impl<'a> SixlowpanOutPacket<'a> {
|
||||
pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
|
||||
Self {
|
||||
@ -121,7 +129,7 @@ pub struct InterfaceInner<'a> {
|
||||
sequence_no: u8,
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
pan_id: Option<Ieee802154Pan>,
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag: u16,
|
||||
ip_addrs: ManagedSlice<'a, IpCidr>,
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
@ -151,9 +159,13 @@ pub struct InterfaceBuilder<'a> {
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
|
||||
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>>,
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_buffer: Option<ManagedSlice<'a, u8>>,
|
||||
}
|
||||
|
||||
@ -167,6 +179,8 @@ impl<'a> InterfaceBuilder<'a> {
|
||||
|
||||
```
|
||||
# use std::collections::BTreeMap;
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
use smoltcp::iface::FragmentsCache;
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache};
|
||||
# use smoltcp::phy::{Loopback, Medium};
|
||||
use smoltcp::wire::{EthernetAddress, IpCidr, IpAddress};
|
||||
@ -177,13 +191,20 @@ let hw_addr = // ...
|
||||
# EthernetAddress::default();
|
||||
let neighbor_cache = // ...
|
||||
# NeighborCache::new(BTreeMap::new());
|
||||
# #[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
# let ipv4_frag_cache = // ...
|
||||
# FragmentsCache::new(vec![], BTreeMap::new());
|
||||
let ip_addrs = // ...
|
||||
# [];
|
||||
let iface = InterfaceBuilder::new()
|
||||
let builder = InterfaceBuilder::new()
|
||||
.hardware_addr(hw_addr.into())
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.ip_addrs(ip_addrs)
|
||||
.finalize(&mut device);
|
||||
.ip_addrs(ip_addrs);
|
||||
|
||||
# #[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 []),
|
||||
random_seed: 0,
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_fragments: None,
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments: None,
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_buffer: None,
|
||||
}
|
||||
}
|
||||
@ -321,7 +345,13 @@ let iface = InterfaceBuilder::new()
|
||||
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(
|
||||
mut self,
|
||||
storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
@ -330,7 +360,7 @@ let iface = InterfaceBuilder::new()
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_out_packet_cache<T>(mut self, storage: T) -> Self
|
||||
where
|
||||
T: Into<ManagedSlice<'a, u8>>,
|
||||
@ -422,22 +452,29 @@ let iface = InterfaceBuilder::new()
|
||||
|
||||
Interface {
|
||||
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
|
||||
.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,
|
||||
},
|
||||
out_packets: OutPackets {
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_packet: SixlowpanOutPacket::new(
|
||||
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,
|
||||
},
|
||||
inner: InterfaceInner {
|
||||
@ -459,7 +496,7 @@ let iface = InterfaceBuilder::new()
|
||||
sequence_no,
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
pan_id: self.pan_id,
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag,
|
||||
rand,
|
||||
},
|
||||
@ -760,12 +797,11 @@ impl<'a> Interface<'a> {
|
||||
pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
|
||||
self.ip_addrs()
|
||||
.iter()
|
||||
.filter_map(|cidr| match cidr.address() {
|
||||
.find_map(|cidr| match cidr.address() {
|
||||
IpAddress::Ipv4(addr) => Some(addr),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
/// Update the IP addresses of the interface.
|
||||
@ -825,35 +861,33 @@ impl<'a> Interface<'a> {
|
||||
{
|
||||
self.inner.now = timestamp;
|
||||
|
||||
let mut readiness_may_have_changed = false;
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
if let Err(e) = self
|
||||
.fragments
|
||||
.ipv4_fragments
|
||||
.remove_when(|frag| Ok(timestamp >= frag.expires_at()?))
|
||||
{
|
||||
let SixlowpanOutPacket {
|
||||
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 Err(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 {
|
||||
let processed_any = self.socket_ingress(device, sockets);
|
||||
let emitted_any = self.socket_egress(device, sockets);
|
||||
@ -923,15 +957,16 @@ impl<'a> Interface<'a> {
|
||||
let mut processed_any = false;
|
||||
let Self {
|
||||
inner,
|
||||
fragments: _fragments,
|
||||
fragments: ref mut _fragments,
|
||||
out_packets: _out_packets,
|
||||
} = self;
|
||||
|
||||
while let Some((rx_token, tx_token)) = device.receive() {
|
||||
let res = rx_token.consume(inner.now, |frame| {
|
||||
match inner.caps.medium {
|
||||
#[cfg(feature = "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) {
|
||||
net_debug!("Failed to send response: {}", err);
|
||||
}
|
||||
@ -939,7 +974,7 @@ impl<'a> Interface<'a> {
|
||||
}
|
||||
#[cfg(feature = "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) {
|
||||
net_debug!("Failed to send response: {}", err);
|
||||
}
|
||||
@ -947,11 +982,8 @@ impl<'a> Interface<'a> {
|
||||
}
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
Medium::Ieee802154 => {
|
||||
if let Some(packet) = inner.process_ieee802154(
|
||||
sockets,
|
||||
&frame,
|
||||
&mut _fragments.sixlowpan_fragments,
|
||||
) {
|
||||
if let Some(packet) = inner.process_ieee802154(sockets, &frame, _fragments)
|
||||
{
|
||||
if let Err(err) =
|
||||
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| {
|
||||
neighbor_addr = Some(response.ip_repr().dst_addr());
|
||||
match device.transmit().ok_or(Error::Exhausted) {
|
||||
Ok(t) => {
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
if let Err(_e) = inner.dispatch_ip(t, response, Some(_out_packets)) {
|
||||
Ok(_t) => {
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
if let Err(_e) = inner.dispatch_ip(_t, response, Some(_out_packets)) {
|
||||
net_debug!("failed to dispatch IP: {}", _e);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||
if let Err(_e) = inner.dispatch_ip(t, response, None) {
|
||||
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||
if let Err(_e) = inner.dispatch_ip(_t, response, None) {
|
||||
net_debug!("failed to dispatch IP: {}", _e);
|
||||
}
|
||||
emitted_any = true;
|
||||
@ -1140,6 +1172,41 @@ impl<'a> Interface<'a> {
|
||||
_ => 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> {
|
||||
@ -1256,7 +1323,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
sequence_no: 1,
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag: 1,
|
||||
|
||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||
@ -1301,7 +1368,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
no
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
|
||||
let tag = self.tag;
|
||||
self.tag = self.tag.wrapping_add(1);
|
||||
@ -1336,14 +1403,11 @@ impl<'a> InterfaceInner<'a> {
|
||||
/// Get the first IPv4 address of the interface.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub fn ipv4_address(&self) -> Option<Ipv4Address> {
|
||||
self.ip_addrs
|
||||
.iter()
|
||||
.filter_map(|addr| match *addr {
|
||||
self.ip_addrs.iter().find_map(|addr| match *addr {
|
||||
IpCidr::Ipv4(cidr) => Some(cidr.address()),
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpCidr::Ipv6(_) => None,
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
/// Check whether the interface listens to given destination multicast IP address.
|
||||
@ -1367,6 +1431,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
&mut self,
|
||||
sockets: &mut SocketSet,
|
||||
frame: &'frame T,
|
||||
_fragments: &'frame mut FragmentsBuffer<'a>,
|
||||
) -> Option<EthernetPacket<'frame>> {
|
||||
let eth_frame = check!(EthernetFrame::new_checked(frame));
|
||||
|
||||
@ -1384,8 +1449,14 @@ impl<'a> InterfaceInner<'a> {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
EthernetProtocol::Ipv4 => {
|
||||
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")]
|
||||
EthernetProtocol::Ipv6 => {
|
||||
@ -1403,12 +1474,20 @@ impl<'a> InterfaceInner<'a> {
|
||||
&mut self,
|
||||
sockets: &mut SocketSet,
|
||||
ip_payload: &'frame T,
|
||||
_fragments: &'frame mut FragmentsBuffer<'a>,
|
||||
) -> Option<IpPacket<'frame>> {
|
||||
match IpVersion::of_packet(ip_payload.as_ref()) {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
Ok(IpVersion::Ipv4) => {
|
||||
let ipv4_packet = check!(Ipv4Packet::new_checked(ip_payload));
|
||||
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")]
|
||||
Ok(IpVersion::Ipv6) => {
|
||||
@ -1425,7 +1504,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
&mut self,
|
||||
sockets: &mut SocketSet,
|
||||
sixlowpan_payload: &'payload T,
|
||||
fragments: &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
_fragments: &'output mut FragmentsBuffer<'a>,
|
||||
) -> Option<IpPacket<'output>> {
|
||||
let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
|
||||
let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
|
||||
@ -1449,7 +1528,15 @@ impl<'a> InterfaceInner<'a> {
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
@ -1460,15 +1547,18 @@ impl<'a> InterfaceInner<'a> {
|
||||
sockets: &mut SocketSet,
|
||||
ieee802154_repr: &Ieee802154Repr,
|
||||
payload: &'payload T,
|
||||
fragments: &'output mut PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
_fragments: Option<&'output mut PacketAssemblerSet<'a, SixlowpanFragKey>>,
|
||||
) -> 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)) {
|
||||
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||
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,
|
||||
// unless we have a complete one after processing this fragment.
|
||||
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
|
||||
// (other than the first one) are added.
|
||||
check!(check!(fragments.reserve_with_key(&key)).start(
|
||||
Some(
|
||||
frag.datagram_size() as usize - uncompressed_header_size
|
||||
+ compressed_header_size,
|
||||
self.now,
|
||||
+ compressed_header_size
|
||||
),
|
||||
self.now + Duration::from_secs(60),
|
||||
-((uncompressed_header_size - compressed_header_size) as isize),
|
||||
));
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// Add the fragment to the packet assembler.
|
||||
match frags.add(frag.payload(), offset, self.now) {
|
||||
match frags.add(frag.payload(), offset) {
|
||||
Ok(true) => {
|
||||
net_trace!("6LoWPAN: fragmented packet now complete");
|
||||
check!(fragments.get_assembled_packet(&key))
|
||||
@ -1830,22 +1916,76 @@ impl<'a> InterfaceInner<'a> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
fn process_ipv4<'frame, T: AsRef<[u8]> + ?Sized>(
|
||||
fn process_ipv4<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
|
||||
&mut self,
|
||||
sockets: &mut SocketSet,
|
||||
ipv4_packet: &Ipv4Packet<&'frame T>,
|
||||
) -> Option<IpPacket<'frame>> {
|
||||
ipv4_packet: &Ipv4Packet<&'payload T>,
|
||||
_fragments: Option<&'output mut PacketAssemblerSet<'a, Ipv4FragKey>>,
|
||||
) -> Option<IpPacket<'output>> {
|
||||
let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
|
||||
|
||||
if !self.is_unicast_v4(ipv4_repr.src_addr) {
|
||||
// Discard packets with non-unicast source addresses.
|
||||
net_debug!("non-unicast source address");
|
||||
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_repr = IpRepr::Ipv4(ipv4_repr);
|
||||
|
||||
#[cfg(feature = "socket-raw")]
|
||||
let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
|
||||
#[cfg(not(feature = "socket-raw"))]
|
||||
@ -1862,8 +2002,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
{
|
||||
if let Some(dhcp_socket) = sockets
|
||||
.items_mut()
|
||||
.filter_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
|
||||
.next()
|
||||
.find_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
|
||||
{
|
||||
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
||||
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>(
|
||||
&mut self,
|
||||
ll_dst_a: Ieee802154Address,
|
||||
ip_repr: &IpRepr,
|
||||
tx_token: Tx,
|
||||
packet: IpPacket,
|
||||
out_packet: Option<&mut OutPackets>,
|
||||
_out_packet: Option<&mut OutPackets>,
|
||||
) -> Result<()> {
|
||||
// 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
|
||||
@ -2798,14 +2937,14 @@ impl<'a> InterfaceInner<'a> {
|
||||
// We need to know this, such that we know when to do the fragmentation.
|
||||
let mut total_size = 0;
|
||||
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)]
|
||||
match packet {
|
||||
#[cfg(feature = "socket-udp")]
|
||||
IpPacket::Udp((_, udpv6_repr, payload)) => {
|
||||
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();
|
||||
}
|
||||
#[cfg(feature = "socket-tcp")]
|
||||
@ -2822,6 +2961,8 @@ impl<'a> InterfaceInner<'a> {
|
||||
let ieee_len = ieee_repr.buffer_len();
|
||||
|
||||
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.
|
||||
// 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.
|
||||
@ -2840,7 +2981,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
ll_dst_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_src_addr = ll_src_a;
|
||||
@ -2869,7 +3010,8 @@ impl<'a> InterfaceInner<'a> {
|
||||
}
|
||||
#[cfg(feature = "socket-tcp")]
|
||||
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(
|
||||
&mut tcp_packet,
|
||||
&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].
|
||||
//
|
||||
// [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)
|
||||
+ compressed_headers_len;
|
||||
+ _compressed_headers_len;
|
||||
*fragn_size = (125 - ieee_len - fragn.buffer_len()) & 0xffff_fff8;
|
||||
|
||||
*sent_bytes = frag1_size;
|
||||
@ -2931,7 +3073,8 @@ impl<'a> InterfaceInner<'a> {
|
||||
ieee_len + frag1.buffer_len() + frag1_size,
|
||||
|mut tx_buf| {
|
||||
// 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);
|
||||
tx_buf = &mut tx_buf[ieee_len..];
|
||||
|
||||
@ -2946,6 +3089,11 @@ impl<'a> InterfaceInner<'a> {
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
} else {
|
||||
net_debug!("Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support.");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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| {
|
||||
@ -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>(
|
||||
&mut self,
|
||||
tx_token: Tx,
|
||||
@ -3162,6 +3313,11 @@ mod test {
|
||||
];
|
||||
|
||||
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")]
|
||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||
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),
|
||||
];
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
let iface_builder = InterfaceBuilder::new()
|
||||
.hardware_addr(EthernetAddress::default().into())
|
||||
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
||||
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.sixlowpan_out_packet_cache(vec![])
|
||||
.ip_addrs(ip_addrs);
|
||||
|
||||
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||
let iface_builder = InterfaceBuilder::new()
|
||||
.hardware_addr(EthernetAddress::default().into())
|
||||
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
||||
.ip_addrs(ip_addrs);
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let iface_builder = iface_builder
|
||||
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.sixlowpan_out_packet_cache(vec![]);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let iface_builder =
|
||||
iface_builder.ipv4_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()));
|
||||
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
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
|
||||
// ICMP error response when the destination address is a
|
||||
// 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]
|
||||
@ -3339,8 +3506,20 @@ mod test {
|
||||
|
||||
// Ensure that the unknown protocol triggers an error response.
|
||||
// And we correctly handle no payload.
|
||||
|
||||
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
|
||||
assert_eq!(
|
||||
iface.inner.process_ipv4(&mut sockets, &frame),
|
||||
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)
|
||||
);
|
||||
}
|
||||
@ -3632,8 +3811,19 @@ mod test {
|
||||
};
|
||||
let expected_packet = IpPacket::Icmpv4((expected_ipv4_repr, expected_icmpv4_repr));
|
||||
|
||||
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
|
||||
assert_eq!(
|
||||
iface.inner.process_ipv4(&mut sockets, &frame),
|
||||
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)
|
||||
);
|
||||
}
|
||||
@ -3682,8 +3872,8 @@ mod test {
|
||||
);
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
let ip_repr = Ipv4Repr {
|
||||
src_addr: src_addr,
|
||||
dst_addr: dst_addr,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
next_header: IpProtocol::Udp,
|
||||
hop_limit: 64,
|
||||
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
|
||||
@ -3788,7 +3978,7 @@ mod test {
|
||||
assert_eq!(
|
||||
iface
|
||||
.inner
|
||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
||||
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Reply,
|
||||
source_hardware_addr: local_hw_addr,
|
||||
@ -3863,7 +4053,7 @@ mod test {
|
||||
assert_eq!(
|
||||
iface
|
||||
.inner
|
||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
||||
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||
Some(EthernetPacket::Ip(IpPacket::Icmpv6((
|
||||
ipv6_expected,
|
||||
icmpv6_expected
|
||||
@ -3910,7 +4100,7 @@ mod test {
|
||||
assert_eq!(
|
||||
iface
|
||||
.inner
|
||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
||||
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||
None
|
||||
);
|
||||
|
||||
@ -3962,7 +4152,7 @@ mod test {
|
||||
assert_eq!(
|
||||
iface
|
||||
.inner
|
||||
.process_ethernet(&mut sockets, frame.into_inner()),
|
||||
.process_ethernet(&mut sockets, frame.into_inner(), &mut iface.fragments),
|
||||
Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Reply,
|
||||
source_hardware_addr: local_hw_addr,
|
||||
@ -4289,8 +4479,8 @@ mod test {
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
let ipv4_repr = Ipv4Repr {
|
||||
src_addr: src_addr,
|
||||
dst_addr: dst_addr,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
next_header: IpProtocol::Udp,
|
||||
hop_limit: 64,
|
||||
payload_len: udp_repr.header_len() + PAYLOAD_LEN,
|
||||
@ -4314,7 +4504,17 @@ mod test {
|
||||
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]
|
||||
@ -4370,8 +4570,8 @@ mod test {
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
let ipv4_repr = Ipv4Repr {
|
||||
src_addr: src_addr,
|
||||
dst_addr: dst_addr,
|
||||
src_addr,
|
||||
dst_addr,
|
||||
next_header: IpProtocol::Udp,
|
||||
hop_limit: 64,
|
||||
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
|
||||
@ -4396,7 +4596,17 @@ mod test {
|
||||
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
|
||||
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.
|
||||
*/
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
|
||||
mod fragmentation;
|
||||
mod interface;
|
||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||
@ -22,7 +22,7 @@ pub use self::neighbor::Neighbor;
|
||||
pub use self::route::{Route, Routes};
|
||||
pub use socket_set::{SocketHandle, SocketSet, SocketStorage};
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
|
||||
pub use self::fragmentation::{PacketAssembler, PacketAssemblerSet as FragmentsCache};
|
||||
|
||||
pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};
|
||||
|
@ -21,6 +21,13 @@ pub use super::IpProtocol as Protocol;
|
||||
// accept a packet of the following size.
|
||||
pub const MIN_MTU: usize = 576;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
|
||||
pub struct Key {
|
||||
id: u16,
|
||||
src_addr: Address,
|
||||
dst_addr: Address,
|
||||
}
|
||||
|
||||
/// A four-octet IPv4 address.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
||||
pub struct Address(pub [u8; 4]);
|
||||
@ -443,6 +450,15 @@ impl<T: AsRef<[u8]>> Packet<T> {
|
||||
let data = self.buffer.as_ref();
|
||||
checksum::data(&data[..self.header_len() as usize]) == !0
|
||||
}
|
||||
|
||||
/// Returns the key for identifying the packet.
|
||||
pub fn get_key(&self) -> Key {
|
||||
Key {
|
||||
id: self.ident(),
|
||||
src_addr: self.src_addr(),
|
||||
dst_addr: self.dst_addr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
|
||||
@ -617,15 +633,14 @@ impl Repr {
|
||||
if checksum_caps.ipv4.rx() && !packet.verify_checksum() {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
|
||||
// We do not support fragmentation.
|
||||
if packet.more_frags() || packet.frag_offset() != 0 {
|
||||
return Err(Error);
|
||||
}
|
||||
// Since the packet is not fragmented, it must include the entire payload.
|
||||
|
||||
let payload_len = packet.total_len() as usize - packet.header_len() as usize;
|
||||
if packet.payload().len() < payload_len {
|
||||
return Err(Error);
|
||||
}
|
||||
|
||||
// All DSCP values are acceptable, since they are of no concern to receiving endpoint.
|
||||
// All ECN values are acceptable, since ECN requires opt-in from both endpoints.
|
||||
@ -634,7 +649,7 @@ impl Repr {
|
||||
src_addr: packet.src_addr(),
|
||||
dst_addr: packet.dst_addr(),
|
||||
next_header: packet.next_header(),
|
||||
payload_len: payload_len,
|
||||
payload_len,
|
||||
hop_limit: packet.hop_limit(),
|
||||
})
|
||||
}
|
||||
@ -749,10 +764,21 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
||||
Ok(ip_packet) => match Repr::parse(&ip_packet, &checksum_caps) {
|
||||
Err(_) => return Ok(()),
|
||||
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)?;
|
||||
format_checksum(f, ip_packet.verify_checksum())?;
|
||||
(ip_repr, ip_packet.payload())
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -169,8 +169,8 @@ pub use self::ip::{
|
||||
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub use self::ipv4::{
|
||||
Address as Ipv4Address, Cidr as Ipv4Cidr, Packet as Ipv4Packet, Repr as Ipv4Repr,
|
||||
HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
|
||||
Address as Ipv4Address, Cidr as Ipv4Cidr, Key as Ipv4FragKey, Packet as Ipv4Packet,
|
||||
Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
|
||||
};
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
|
@ -359,6 +359,7 @@ pub mod frag {
|
||||
}
|
||||
|
||||
impl Repr {
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub(crate) fn set_offset(&mut self, value: u8) {
|
||||
match self {
|
||||
Repr::FirstFragment { .. } => (),
|
||||
@ -2105,15 +2106,15 @@ mod test {
|
||||
.reserve_with_key(&key)
|
||||
.unwrap()
|
||||
.start(
|
||||
frag.datagram_size() as usize - uncompressed + compressed,
|
||||
Instant::now(),
|
||||
Some(frag.datagram_size() as usize - uncompressed + compressed),
|
||||
Instant::now() + crate::time::Duration::from_secs(60),
|
||||
-((uncompressed - compressed) as isize),
|
||||
)
|
||||
.unwrap();
|
||||
frags_cache
|
||||
.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.add(frag.payload(), 0, Instant::now())
|
||||
.add(frag.payload(), 0)
|
||||
.unwrap();
|
||||
|
||||
let frame2: &[u8] = &[
|
||||
@ -2149,11 +2150,7 @@ mod test {
|
||||
frags_cache
|
||||
.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.add(
|
||||
frag.payload(),
|
||||
frag.datagram_offset() as usize * 8,
|
||||
Instant::now(),
|
||||
)
|
||||
.add(frag.payload(), frag.datagram_offset() as usize * 8)
|
||||
.unwrap();
|
||||
|
||||
let frame3: &[u8] = &[
|
||||
@ -2188,11 +2185,7 @@ mod test {
|
||||
frags_cache
|
||||
.get_packet_assembler_mut(&key)
|
||||
.unwrap()
|
||||
.add(
|
||||
frag.payload(),
|
||||
frag.datagram_offset() as usize * 8,
|
||||
Instant::now(),
|
||||
)
|
||||
.add(frag.payload(), frag.datagram_offset() as usize * 8)
|
||||
.unwrap();
|
||||
|
||||
let assembled_packet = frags_cache.get_assembled_packet(&key).unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user