mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-09-30 06:10:55 +00:00
Merge #634
634: IPv4 fragmentation (for outgoing) r=Dirbaio a=thvdveld
Almost ready for review, just need to clean up some things 🎉
Co-authored-by: Thibaut Vandervelden <thvdveld@vub.be>
This commit is contained in:
commit
70915655b3
@ -9,7 +9,7 @@ use std::str::{self, FromStr};
|
||||
feature = "proto-sixlowpan-fragmentation",
|
||||
feature = "proto-ipv4-fragmentation"
|
||||
))]
|
||||
use smoltcp::iface::FragmentsCache;
|
||||
use smoltcp::iface::ReassemblyBuffer;
|
||||
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, Routes, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||
@ -51,20 +51,24 @@ fn main() {
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs).routes(routes);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let mut ipv4_out_packet_cache = [0u8; 1280];
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
{
|
||||
let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.ipv4_reassembly_buffer(ipv4_frag_cache)
|
||||
.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let mut out_packet_buffer = [0u8; 1280];
|
||||
let mut sixlowpan_out_packet_cache = [0u8; 1280];
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
{
|
||||
let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.sixlowpan_fragments_cache(sixlowpan_frag_cache)
|
||||
.sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
|
||||
.sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
|
||||
.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
|
||||
}
|
||||
|
||||
if medium == Medium::Ethernet {
|
||||
|
@ -4,13 +4,12 @@ use log::debug;
|
||||
use std::collections::BTreeMap;
|
||||
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::ReassemblyBuffer;
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Device, Medium};
|
||||
use smoltcp::socket::{tcp, udp};
|
||||
@ -32,8 +31,14 @@ fn main() {
|
||||
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
|
||||
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_rx_buffer = udp::PacketBuffer::new(
|
||||
vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY],
|
||||
vec![0; 65535],
|
||||
);
|
||||
let udp_tx_buffer = udp::PacketBuffer::new(
|
||||
vec![udp::PacketMetadata::EMPTY, 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]);
|
||||
@ -62,20 +67,31 @@ fn main() {
|
||||
let medium = device.capabilities().medium;
|
||||
let mut builder = InterfaceBuilder::new().ip_addrs(ip_addrs);
|
||||
|
||||
builder = builder.random_seed(
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs(),
|
||||
);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let mut ipv4_out_packet_cache = [0u8; 10_000];
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
{
|
||||
let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.ipv4_reassembly_buffer(ipv4_frag_cache)
|
||||
.ipv4_fragmentation_buffer(&mut ipv4_out_packet_cache[..]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let mut out_packet_buffer = [0u8; 1280];
|
||||
let mut sixlowpan_out_packet_cache = [0u8; 1280];
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
{
|
||||
let sixlowpan_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.sixlowpan_fragments_cache(sixlowpan_frag_cache)
|
||||
.sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
|
||||
.sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
|
||||
.sixlowpan_fragmentation_buffer(&mut sixlowpan_out_packet_cache[..]);
|
||||
}
|
||||
|
||||
if medium == Medium::Ethernet {
|
||||
@ -110,22 +126,16 @@ fn main() {
|
||||
|
||||
let client = match socket.recv() {
|
||||
Ok((data, endpoint)) => {
|
||||
debug!(
|
||||
"udp:6969 recv data: {:?} from {}",
|
||||
str::from_utf8(data).unwrap(),
|
||||
endpoint
|
||||
);
|
||||
Some(endpoint)
|
||||
debug!("udp:6969 recv data: {:?} from {}", data, endpoint);
|
||||
let mut data = data.to_vec();
|
||||
data.reverse();
|
||||
Some((endpoint, data))
|
||||
}
|
||||
Err(_) => None,
|
||||
};
|
||||
if let Some(endpoint) = client {
|
||||
let data = b"hello\n";
|
||||
debug!(
|
||||
"udp:6969 send data: {:?}",
|
||||
str::from_utf8(data.as_ref()).unwrap()
|
||||
);
|
||||
socket.send_slice(data, endpoint).unwrap();
|
||||
if let Some((endpoint, data)) = client {
|
||||
debug!("udp:6969 send data: {:?} to {}", data, endpoint,);
|
||||
socket.send_slice(&data, endpoint).unwrap();
|
||||
}
|
||||
|
||||
// tcp:6969: respond "hello"
|
||||
@ -160,10 +170,7 @@ fn main() {
|
||||
let recvd_len = buffer.len();
|
||||
let mut data = buffer.to_owned();
|
||||
if !data.is_empty() {
|
||||
debug!(
|
||||
"tcp:6970 recv data: {:?}",
|
||||
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)")
|
||||
);
|
||||
debug!("tcp:6970 recv data: {:?}", data);
|
||||
data = data.split(|&b| b == b'\n').collect::<Vec<_>>().concat();
|
||||
data.reverse();
|
||||
data.extend(b"\n");
|
||||
@ -172,10 +179,7 @@ fn main() {
|
||||
})
|
||||
.unwrap();
|
||||
if socket.can_send() && !data.is_empty() {
|
||||
debug!(
|
||||
"tcp:6970 send data: {:?}",
|
||||
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)")
|
||||
);
|
||||
debug!("tcp:6970 send data: {:?}", data);
|
||||
socket.send_slice(&data[..]).unwrap();
|
||||
}
|
||||
} else if socket.may_send() {
|
||||
|
@ -47,7 +47,7 @@ use std::collections::BTreeMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::str;
|
||||
|
||||
use smoltcp::iface::{FragmentsCache, InterfaceBuilder, NeighborCache, SocketSet};
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, ReassemblyBuffer, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
|
||||
use smoltcp::socket::tcp;
|
||||
use smoltcp::socket::udp;
|
||||
@ -95,18 +95,18 @@ fn main() {
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
{
|
||||
let ipv4_frag_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
let ipv4_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder.ipv4_reassembly_buffer(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());
|
||||
let sixlowpan_frag_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
builder = builder
|
||||
.sixlowpan_fragments_cache(sixlowpan_frag_cache)
|
||||
.sixlowpan_out_packet_cache(&mut out_packet_buffer[..]);
|
||||
.sixlowpan_reassembly_buffer(sixlowpan_frag_cache)
|
||||
.sixlowpan_fragmentation_buffer(&mut out_packet_buffer[..]);
|
||||
}
|
||||
|
||||
let mut iface = builder.finalize(&mut device);
|
||||
|
@ -48,7 +48,7 @@ use std::collections::BTreeMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::str;
|
||||
|
||||
use smoltcp::iface::{FragmentsCache, InterfaceBuilder, NeighborCache, SocketSet};
|
||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache, ReassemblyBuffer, SocketSet};
|
||||
use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
|
||||
use smoltcp::socket::tcp;
|
||||
use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
|
||||
@ -166,7 +166,7 @@ fn main() {
|
||||
64,
|
||||
)];
|
||||
|
||||
let cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
let cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
|
||||
let mut builder = InterfaceBuilder::new()
|
||||
.ip_addrs(ip_addrs)
|
||||
@ -174,8 +174,8 @@ fn main() {
|
||||
builder = builder
|
||||
.hardware_addr(ieee802154_addr.into())
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.sixlowpan_fragments_cache(cache)
|
||||
.sixlowpan_out_packet_cache(vec![]);
|
||||
.sixlowpan_reassembly_buffer(cache)
|
||||
.sixlowpan_fragmentation_buffer(vec![]);
|
||||
let mut iface = builder.finalize(&mut device);
|
||||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
|
@ -37,6 +37,8 @@ pub(crate) struct FragmentsBuffer<'a> {
|
||||
}
|
||||
|
||||
pub(crate) struct OutPackets<'a> {
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_out_packet: Ipv4OutPacket<'a>,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_packet: SixlowpanOutPacket<'a>,
|
||||
|
||||
@ -45,10 +47,90 @@ pub(crate) struct OutPackets<'a> {
|
||||
}
|
||||
|
||||
impl<'a> OutPackets<'a> {
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
#[cfg(any(
|
||||
feature = "proto-ipv4-fragmentation",
|
||||
feature = "proto-sixlowpan-fragmentation"
|
||||
))]
|
||||
/// Returns `true` when all the data of the outgoing buffers are transmitted.
|
||||
fn all_transmitted(&self) -> bool {
|
||||
self.sixlowpan_out_packet.finished() || self.sixlowpan_out_packet.is_empty()
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
if !self.ipv4_out_packet.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
if !self.sixlowpan_out_packet.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub(crate) struct Ipv4OutPacket<'a> {
|
||||
/// The buffer that holds the unfragmented 6LoWPAN packet.
|
||||
buffer: ManagedSlice<'a, u8>,
|
||||
/// The size of the packet without the IEEE802.15.4 header and the fragmentation headers.
|
||||
packet_len: usize,
|
||||
/// The amount of bytes that already have been transmitted.
|
||||
sent_bytes: usize,
|
||||
|
||||
/// The IPv4 representation.
|
||||
repr: Ipv4Repr,
|
||||
/// The destination hardware address.
|
||||
dst_hardware_addr: EthernetAddress,
|
||||
/// The offset of the next fragment.
|
||||
frag_offset: u16,
|
||||
/// The identifier of the stream.
|
||||
ident: u16,
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
impl<'a> Ipv4OutPacket<'a> {
|
||||
pub(crate) fn new(buffer: ManagedSlice<'a, u8>) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
packet_len: 0,
|
||||
sent_bytes: 0,
|
||||
repr: Ipv4Repr {
|
||||
src_addr: Ipv4Address::default(),
|
||||
dst_addr: Ipv4Address::default(),
|
||||
next_header: IpProtocol::Unknown(0),
|
||||
payload_len: 0,
|
||||
hop_limit: 0,
|
||||
},
|
||||
dst_hardware_addr: EthernetAddress::default(),
|
||||
frag_offset: 0,
|
||||
ident: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` when everything is transmitted.
|
||||
#[inline]
|
||||
fn finished(&self) -> bool {
|
||||
self.packet_len == self.sent_bytes
|
||||
}
|
||||
|
||||
/// Returns `true` when there is nothing to transmit.
|
||||
#[inline]
|
||||
fn is_empty(&self) -> bool {
|
||||
self.packet_len == 0
|
||||
}
|
||||
|
||||
// Reset the buffer.
|
||||
fn reset(&mut self) {
|
||||
self.packet_len = 0;
|
||||
self.sent_bytes = 0;
|
||||
self.repr = Ipv4Repr {
|
||||
src_addr: Ipv4Address::default(),
|
||||
dst_addr: Ipv4Address::default(),
|
||||
next_header: IpProtocol::Unknown(0),
|
||||
payload_len: 0,
|
||||
hop_limit: 0,
|
||||
};
|
||||
self.dst_hardware_addr = EthernetAddress::default();
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +245,8 @@ pub struct InterfaceInner<'a> {
|
||||
sequence_no: u8,
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
pan_id: Option<Ieee802154Pan>,
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_id: u16,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag: u16,
|
||||
ip_addrs: ManagedSlice<'a, IpCidr>,
|
||||
@ -195,14 +279,16 @@ pub struct InterfaceBuilder<'a> {
|
||||
random_seed: u64,
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_fragments: Option<PacketAssemblerSet<'a, Ipv4FragKey>>,
|
||||
ipv4_fragments: PacketAssemblerSet<'a, Ipv4FragKey>,
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_out_buffer: ManagedSlice<'a, u8>,
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments: Option<PacketAssemblerSet<'a, SixlowpanFragKey>>,
|
||||
sixlowpan_fragments: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments_cache_timeout: Duration,
|
||||
sixlowpan_reassembly_buffer_timeout: Duration,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_buffer: Option<ManagedSlice<'a, u8>>,
|
||||
sixlowpan_out_buffer: ManagedSlice<'a, u8>,
|
||||
}
|
||||
|
||||
impl<'a> InterfaceBuilder<'a> {
|
||||
@ -238,7 +324,9 @@ let builder = InterfaceBuilder::new()
|
||||
.ip_addrs(ip_addrs);
|
||||
|
||||
# #[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let builder = builder.ipv4_fragments_cache(ipv4_frag_cache);
|
||||
let builder = builder
|
||||
.ipv4_reassembly_buffer(ipv4_frag_cache)
|
||||
.ipv4_fragmentation_buffer(vec![]);
|
||||
|
||||
let iface = builder.finalize(&mut device);
|
||||
```
|
||||
@ -264,14 +352,16 @@ let iface = builder.finalize(&mut device);
|
||||
random_seed: 0,
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_fragments: None,
|
||||
ipv4_fragments: PacketAssemblerSet::new(&mut [][..], &mut [][..]),
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments: None,
|
||||
sixlowpan_fragments: PacketAssemblerSet::new(&mut [][..], &mut [][..]),
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments_cache_timeout: Duration::from_secs(60),
|
||||
sixlowpan_reassembly_buffer_timeout: Duration::from_secs(60),
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_buffer: None,
|
||||
sixlowpan_out_buffer: ManagedSlice::Borrowed(&mut [][..]),
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,35 +474,44 @@ let iface = builder.finalize(&mut device);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
pub fn ipv4_fragments_cache(mut self, storage: PacketAssemblerSet<'a, Ipv4FragKey>) -> Self {
|
||||
self.ipv4_fragments = Some(storage);
|
||||
pub fn ipv4_reassembly_buffer(mut self, storage: PacketAssemblerSet<'a, Ipv4FragKey>) -> Self {
|
||||
self.ipv4_fragments = storage;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_fragments_cache(
|
||||
mut self,
|
||||
storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
) -> Self {
|
||||
self.sixlowpan_fragments = Some(storage);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_fragments_cache_timeout(mut self, timeout: Duration) -> Self {
|
||||
if timeout > Duration::from_secs(60) {
|
||||
net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
|
||||
}
|
||||
self.sixlowpan_fragments_cache_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_out_packet_cache<T>(mut self, storage: T) -> Self
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
pub fn ipv4_fragmentation_buffer<T>(mut self, storage: T) -> Self
|
||||
where
|
||||
T: Into<ManagedSlice<'a, u8>>,
|
||||
{
|
||||
self.sixlowpan_out_buffer = Some(storage.into());
|
||||
self.ipv4_out_buffer = storage.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_reassembly_buffer(
|
||||
mut self,
|
||||
storage: PacketAssemblerSet<'a, SixlowpanFragKey>,
|
||||
) -> Self {
|
||||
self.sixlowpan_fragments = storage;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_reassembly_buffer_timeout(mut self, timeout: Duration) -> Self {
|
||||
if timeout > Duration::from_secs(60) {
|
||||
net_debug!("RFC 4944 specifies that the reassembly timeout MUST be set to a maximum of 60 seconds");
|
||||
}
|
||||
self.sixlowpan_reassembly_buffer_timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
pub fn sixlowpan_fragmentation_buffer<T>(mut self, storage: T) -> Self
|
||||
where
|
||||
T: Into<ManagedSlice<'a, u8>>,
|
||||
{
|
||||
self.sixlowpan_out_buffer = storage.into();
|
||||
self
|
||||
}
|
||||
|
||||
@ -471,10 +570,7 @@ let iface = builder.finalize(&mut device);
|
||||
),
|
||||
};
|
||||
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
let mut rand = Rand::new(self.random_seed);
|
||||
#[cfg(not(feature = "medium-ieee802154"))]
|
||||
let rand = Rand::new(self.random_seed);
|
||||
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
let mut sequence_no;
|
||||
@ -491,24 +587,31 @@ let iface = builder.finalize(&mut device);
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan")]
|
||||
loop {
|
||||
tag = (rand.rand_u32() & 0xffff) as u16;
|
||||
tag = rand.rand_u16();
|
||||
if tag != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
let mut ipv4_id;
|
||||
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
loop {
|
||||
ipv4_id = rand.rand_u16();
|
||||
if ipv4_id != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Interface {
|
||||
fragments: FragmentsBuffer {
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_fragments: self
|
||||
.ipv4_fragments
|
||||
.expect("Cache for incoming IPv4 fragments is required"),
|
||||
ipv4_fragments: self.ipv4_fragments,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments: self
|
||||
.sixlowpan_fragments
|
||||
.expect("Cache for incoming 6LoWPAN fragments is required"),
|
||||
sixlowpan_fragments: self.sixlowpan_fragments,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_fragments_cache_timeout: self.sixlowpan_fragments_cache_timeout,
|
||||
sixlowpan_fragments_cache_timeout: self.sixlowpan_reassembly_buffer_timeout,
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "proto-ipv4-fragmentation",
|
||||
@ -517,11 +620,10 @@ let iface = builder.finalize(&mut device);
|
||||
_lifetime: core::marker::PhantomData,
|
||||
},
|
||||
out_packets: OutPackets {
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_out_packet: Ipv4OutPacket::new(self.ipv4_out_buffer),
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
sixlowpan_out_packet: SixlowpanOutPacket::new(
|
||||
self.sixlowpan_out_buffer
|
||||
.expect("Cache for outgoing 6LoWPAN fragments is required"),
|
||||
),
|
||||
sixlowpan_out_packet: SixlowpanOutPacket::new(self.sixlowpan_out_buffer),
|
||||
|
||||
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||
_lifetime: core::marker::PhantomData,
|
||||
@ -547,6 +649,8 @@ let iface = builder.finalize(&mut device);
|
||||
pan_id: self.pan_id,
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag,
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_id,
|
||||
rand,
|
||||
},
|
||||
}
|
||||
@ -603,7 +707,7 @@ impl<'a> IpPacket<'a> {
|
||||
|
||||
pub(crate) fn emit_payload(
|
||||
&self,
|
||||
_ip_repr: IpRepr,
|
||||
_ip_repr: &IpRepr,
|
||||
payload: &mut [u8],
|
||||
caps: &DeviceCapabilities,
|
||||
) {
|
||||
@ -645,7 +749,7 @@ impl<'a> IpPacket<'a> {
|
||||
// I'm really not happy about this "solution" but I don't know what else to do.
|
||||
if let Some(max_burst_size) = caps.max_burst_size {
|
||||
let mut max_segment_size = caps.max_transmission_unit;
|
||||
max_segment_size -= _ip_repr.buffer_len();
|
||||
max_segment_size -= _ip_repr.header_len();
|
||||
max_segment_size -= tcp_repr.header_len();
|
||||
|
||||
let max_window_size = max_burst_size * max_segment_size;
|
||||
@ -928,6 +1032,13 @@ impl<'a> Interface<'a> {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
match self.ipv4_egress(device) {
|
||||
Ok(true) => return Ok(true),
|
||||
Err(e) => return Err(e),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
match self.sixlowpan_egress(device) {
|
||||
Ok(true) => return Ok(true),
|
||||
@ -1021,7 +1132,7 @@ impl<'a> Interface<'a> {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => {
|
||||
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, Some(_out_packets)) {
|
||||
net_debug!("Failed to send response: {}", err);
|
||||
}
|
||||
}
|
||||
@ -1029,7 +1140,9 @@ impl<'a> Interface<'a> {
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => {
|
||||
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, Some(_out_packets))
|
||||
{
|
||||
net_debug!("Failed to send response: {}", err);
|
||||
}
|
||||
}
|
||||
@ -1083,13 +1196,19 @@ impl<'a> Interface<'a> {
|
||||
neighbor_addr = Some(response.ip_repr().dst_addr());
|
||||
match device.transmit().ok_or(Error::Exhausted) {
|
||||
Ok(_t) => {
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
#[cfg(any(
|
||||
feature = "proto-ipv4-fragmentation",
|
||||
feature = "proto-sixlowpan-fragmentation"
|
||||
))]
|
||||
if let Err(e) = inner.dispatch_ip(_t, response, Some(_out_packets)) {
|
||||
net_debug!("failed to dispatch IP: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
|
||||
#[cfg(not(any(
|
||||
feature = "proto-ipv4-fragmentation",
|
||||
feature = "proto-sixlowpan-fragmentation"
|
||||
)))]
|
||||
if let Err(e) = inner.dispatch_ip(_t, response, None) {
|
||||
net_debug!("failed to dispatch IP: {}", e);
|
||||
return Err(e);
|
||||
@ -1230,11 +1349,60 @@ impl<'a> Interface<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
fn ipv4_egress<D>(&mut self, device: &mut D) -> Result<bool>
|
||||
where
|
||||
D: for<'d> Device<'d> + ?Sized,
|
||||
{
|
||||
// Reset the buffer when we transmitted everything.
|
||||
if self.out_packets.ipv4_out_packet.finished() {
|
||||
self.out_packets.ipv4_out_packet.reset();
|
||||
}
|
||||
|
||||
if self.out_packets.ipv4_out_packet.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let Ipv4OutPacket {
|
||||
packet_len,
|
||||
sent_bytes,
|
||||
..
|
||||
} = &self.out_packets.ipv4_out_packet;
|
||||
|
||||
if *packet_len > *sent_bytes {
|
||||
match device.transmit().ok_or(Error::Exhausted) {
|
||||
Ok(tx_token) => {
|
||||
if let Err(e) = self
|
||||
.inner
|
||||
.dispatch_ipv4_out_packet(tx_token, &mut self.out_packets.ipv4_out_packet)
|
||||
{
|
||||
net_debug!("failed to transmit: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
net_debug!("failed to transmit: {}", e);
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
fn sixlowpan_egress<D>(&mut self, device: &mut D) -> Result<bool>
|
||||
where
|
||||
D: for<'d> Device<'d> + ?Sized,
|
||||
{
|
||||
// Reset the buffer when we transmitted everything.
|
||||
if self.out_packets.sixlowpan_out_packet.finished() {
|
||||
self.out_packets.sixlowpan_out_packet.reset();
|
||||
}
|
||||
|
||||
if self.out_packets.sixlowpan_out_packet.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let SixlowpanOutPacket {
|
||||
packet_len,
|
||||
sent_bytes,
|
||||
@ -1254,11 +1422,6 @@ impl<'a> Interface<'a> {
|
||||
) {
|
||||
net_debug!("failed to transmit: {}", e);
|
||||
}
|
||||
|
||||
// Reset the buffer when we transmitted everything.
|
||||
if self.out_packets.sixlowpan_out_packet.finished() {
|
||||
self.out_packets.sixlowpan_out_packet.reset();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
net_debug!("failed to transmit: {}", e);
|
||||
@ -1388,6 +1551,9 @@ impl<'a> InterfaceInner<'a> {
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
tag: 1,
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
ipv4_id: 1,
|
||||
|
||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||
hardware_addr: Some(crate::wire::HardwareAddress::Ethernet(
|
||||
crate::wire::EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]),
|
||||
@ -1430,6 +1596,13 @@ impl<'a> InterfaceInner<'a> {
|
||||
no
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
fn get_ipv4_ident(&mut self) -> u16 {
|
||||
let ipv4_id = self.ipv4_id;
|
||||
self.ipv4_id = self.ipv4_id.wrapping_add(1);
|
||||
ipv4_id
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
|
||||
let tag = self.tag;
|
||||
@ -2031,11 +2204,21 @@ impl<'a> InterfaceInner<'a> {
|
||||
let f = match fragments.get_packet_assembler_mut(&key) {
|
||||
Ok(f) => f,
|
||||
Err(_) => {
|
||||
check!(check!(fragments.reserve_with_key(&key)).start(
|
||||
let p = match fragments.reserve_with_key(&key) {
|
||||
Ok(p) => p,
|
||||
Err(Error::PacketAssemblerSetFull) => {
|
||||
net_debug!("No available packet assembler for fragmented packet");
|
||||
return Default::default();
|
||||
}
|
||||
e => check!(e),
|
||||
};
|
||||
|
||||
check!(p.start(
|
||||
None,
|
||||
self.now + Duration::from_secs(REASSEMBLY_TIMEOUT),
|
||||
0,
|
||||
0
|
||||
));
|
||||
|
||||
check!(fragments.get_packet_assembler_mut(&key))
|
||||
}
|
||||
};
|
||||
@ -2661,7 +2844,12 @@ impl<'a> InterfaceInner<'a> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
fn dispatch<Tx>(&mut self, tx_token: Tx, packet: EthernetPacket) -> Result<()>
|
||||
fn dispatch<Tx>(
|
||||
&mut self,
|
||||
tx_token: Tx,
|
||||
packet: EthernetPacket,
|
||||
_out_packet: Option<&mut OutPackets<'_>>,
|
||||
) -> Result<()>
|
||||
where
|
||||
Tx: TxToken,
|
||||
{
|
||||
@ -2683,7 +2871,7 @@ impl<'a> InterfaceInner<'a> {
|
||||
arp_repr.emit(&mut packet);
|
||||
})
|
||||
}
|
||||
EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, None),
|
||||
EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, _out_packet),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2899,65 +3087,196 @@ impl<'a> InterfaceInner<'a> {
|
||||
packet: IpPacket,
|
||||
_out_packet: Option<&mut OutPackets<'_>>,
|
||||
) -> Result<()> {
|
||||
let ip_repr = packet.ip_repr();
|
||||
let mut ip_repr = packet.ip_repr();
|
||||
assert!(!ip_repr.dst_addr().is_unspecified());
|
||||
|
||||
match self.caps.medium {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => {
|
||||
let (dst_hardware_addr, tx_token) = match self.lookup_hardware_addr(
|
||||
tx_token,
|
||||
&ip_repr.src_addr(),
|
||||
&ip_repr.dst_addr(),
|
||||
)? {
|
||||
(HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token),
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
(HardwareAddress::Ieee802154(_), _) => unreachable!(),
|
||||
};
|
||||
// Dispatch IEEE802.15.4:
|
||||
|
||||
let caps = self.caps.clone();
|
||||
self.dispatch_ethernet(tx_token, ip_repr.total_len(), |mut frame| {
|
||||
frame.set_dst_addr(dst_hardware_addr);
|
||||
match ip_repr {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IpRepr::Ipv4(_) => frame.set_ethertype(EthernetProtocol::Ipv4),
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpRepr::Ipv6(_) => frame.set_ethertype(EthernetProtocol::Ipv6),
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
if matches!(self.caps.medium, Medium::Ieee802154) {
|
||||
let (dst_hardware_addr, tx_token) = match self.lookup_hardware_addr(
|
||||
tx_token,
|
||||
&ip_repr.src_addr(),
|
||||
&ip_repr.dst_addr(),
|
||||
)? {
|
||||
(HardwareAddress::Ieee802154(addr), tx_token) => (addr, tx_token),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
return self.dispatch_ieee802154(
|
||||
dst_hardware_addr,
|
||||
&ip_repr,
|
||||
tx_token,
|
||||
packet,
|
||||
_out_packet,
|
||||
);
|
||||
}
|
||||
|
||||
// Dispatch IP/Ethernet:
|
||||
|
||||
let caps = self.caps.clone();
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let ipv4_id = self.get_ipv4_ident();
|
||||
|
||||
// First we calculate the total length that we will have to emit.
|
||||
let mut total_len = ip_repr.buffer_len();
|
||||
|
||||
// Add the size of the Ethernet header if the medium is Ethernet.
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(self.caps.medium, Medium::Ethernet) {
|
||||
total_len = EthernetFrame::<&[u8]>::buffer_len(total_len);
|
||||
}
|
||||
|
||||
// If the medium is Ethernet, then we need to retrieve the destination hardware address.
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
let (dst_hardware_addr, tx_token) =
|
||||
match self.lookup_hardware_addr(tx_token, &ip_repr.src_addr(), &ip_repr.dst_addr())? {
|
||||
(HardwareAddress::Ethernet(addr), tx_token) => (addr, tx_token),
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
(HardwareAddress::Ieee802154(_), _) => unreachable!(),
|
||||
};
|
||||
|
||||
// Emit function for the Ethernet header.
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
|
||||
let mut frame = EthernetFrame::new_unchecked(tx_buffer);
|
||||
|
||||
let src_addr = if let Some(HardwareAddress::Ethernet(addr)) = self.hardware_addr {
|
||||
addr
|
||||
} else {
|
||||
return Err(Error::Malformed);
|
||||
};
|
||||
|
||||
frame.set_src_addr(src_addr);
|
||||
frame.set_dst_addr(dst_hardware_addr);
|
||||
|
||||
match repr.version() {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
// Emit function for the IP header and payload.
|
||||
let emit_ip = |repr: &IpRepr, mut tx_buffer: &mut [u8]| {
|
||||
repr.emit(&mut tx_buffer, &self.caps.checksum);
|
||||
|
||||
let payload = &mut tx_buffer[repr.header_len()..];
|
||||
packet.emit_payload(repr, payload, &caps);
|
||||
};
|
||||
|
||||
let total_ip_len = ip_repr.buffer_len();
|
||||
|
||||
match ip_repr {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IpRepr::Ipv4(ref mut repr) => {
|
||||
// If we have an IPv4 packet, then we need to check if we need to fragment it.
|
||||
if total_ip_len > self.caps.max_transmission_unit {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "proto-ipv4-fragmentation")] {
|
||||
net_debug!("start fragmentation");
|
||||
|
||||
let Ipv4OutPacket {
|
||||
buffer,
|
||||
packet_len,
|
||||
sent_bytes,
|
||||
repr: out_packet_repr,
|
||||
frag_offset,
|
||||
ident,
|
||||
dst_hardware_addr: dst_address,
|
||||
} = &mut _out_packet.unwrap().ipv4_out_packet;
|
||||
|
||||
// Calculate how much we will send now (including the Ethernet header).
|
||||
let tx_len = self.caps.max_transmission_unit;
|
||||
|
||||
let ip_header_len = repr.buffer_len();
|
||||
let first_frag_ip_len = self.caps.ip_mtu();
|
||||
|
||||
if buffer.len() < first_frag_ip_len {
|
||||
net_debug!("Fragmentation buffer is too small");
|
||||
return Err(Error::Exhausted);
|
||||
}
|
||||
|
||||
*dst_address = dst_hardware_addr;
|
||||
|
||||
// Save the total packet len (without the Ethernet header, but with the first
|
||||
// IP header).
|
||||
*packet_len = total_ip_len;
|
||||
|
||||
// Save the IP header for other fragments.
|
||||
*out_packet_repr = *repr;
|
||||
|
||||
// Save how much bytes we will send now.
|
||||
*sent_bytes = first_frag_ip_len;
|
||||
|
||||
// Modify the IP header
|
||||
repr.payload_len = first_frag_ip_len - repr.buffer_len();
|
||||
|
||||
// Emit the IP header to the buffer.
|
||||
emit_ip(&ip_repr, buffer);
|
||||
let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut buffer[..]);
|
||||
*ident = ipv4_id;
|
||||
ipv4_packet.set_ident(ipv4_id);
|
||||
ipv4_packet.set_more_frags(true);
|
||||
ipv4_packet.set_dont_frag(false);
|
||||
ipv4_packet.set_frag_offset(0);
|
||||
|
||||
if caps.checksum.ipv4.tx() {
|
||||
ipv4_packet.fill_checksum();
|
||||
}
|
||||
|
||||
// Transmit the first packet.
|
||||
tx_token.consume(self.now, tx_len, |mut tx_buffer| {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(self.caps.medium, Medium::Ethernet) {
|
||||
emit_ethernet(&ip_repr, tx_buffer)?;
|
||||
tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
|
||||
}
|
||||
|
||||
// Change the offset for the next packet.
|
||||
*frag_offset = (first_frag_ip_len - ip_header_len) as u16;
|
||||
|
||||
// Copy the IP header and the payload.
|
||||
tx_buffer[..first_frag_ip_len]
|
||||
.copy_from_slice(&buffer[..first_frag_ip_len]);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
} else {
|
||||
net_debug!("Enable the `proto-ipv4-fragmentation` feature for fragmentation support.");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No fragmentation is required.
|
||||
tx_token.consume(self.now, total_len, |mut tx_buffer| {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(self.caps.medium, Medium::Ethernet) {
|
||||
emit_ethernet(&ip_repr, tx_buffer)?;
|
||||
tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
|
||||
}
|
||||
|
||||
ip_repr.emit(frame.payload_mut(), &caps.checksum);
|
||||
|
||||
let payload = &mut frame.payload_mut()[ip_repr.buffer_len()..];
|
||||
packet.emit_payload(ip_repr, payload, &caps);
|
||||
})
|
||||
emit_ip(&ip_repr, tx_buffer);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => {
|
||||
let tx_len = ip_repr.total_len();
|
||||
tx_token.consume(self.now, tx_len, |mut tx_buffer| {
|
||||
debug_assert!(tx_buffer.as_ref().len() == tx_len);
|
||||
// We don't support IPv6 fragmentation yet.
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpRepr::Ipv6(_) => tx_token.consume(self.now, total_len, |mut tx_buffer| {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(self.caps.medium, Medium::Ethernet) {
|
||||
emit_ethernet(&ip_repr, tx_buffer)?;
|
||||
tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
|
||||
}
|
||||
|
||||
ip_repr.emit(&mut tx_buffer, &self.caps.checksum);
|
||||
|
||||
let payload = &mut tx_buffer[ip_repr.buffer_len()..];
|
||||
packet.emit_payload(ip_repr, payload, &self.caps);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
Medium::Ieee802154 => {
|
||||
let (dst_hardware_addr, tx_token) = match self.lookup_hardware_addr(
|
||||
tx_token,
|
||||
&ip_repr.src_addr(),
|
||||
&ip_repr.dst_addr(),
|
||||
)? {
|
||||
(HardwareAddress::Ieee802154(addr), tx_token) => (addr, tx_token),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.dispatch_ieee802154(dst_hardware_addr, &ip_repr, tx_token, packet, _out_packet)
|
||||
}
|
||||
emit_ip(&ip_repr, tx_buffer);
|
||||
Ok(())
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3076,6 +3395,11 @@ impl<'a> InterfaceInner<'a> {
|
||||
..
|
||||
} = &mut _out_packet.unwrap().sixlowpan_out_packet;
|
||||
|
||||
if buffer.len() < total_size {
|
||||
net_debug!("6LoWPAN: Fragmentation buffer is too small");
|
||||
return Err(Error::Exhausted);
|
||||
}
|
||||
|
||||
*ll_dst_addr = ll_dst_a;
|
||||
*ll_src_addr = ll_src_a;
|
||||
|
||||
@ -3316,6 +3640,91 @@ impl<'a> InterfaceInner<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
fn dispatch_ipv4_out_packet<Tx: TxToken>(
|
||||
&mut self,
|
||||
tx_token: Tx,
|
||||
out_packet: &mut Ipv4OutPacket,
|
||||
) -> Result<()> {
|
||||
let Ipv4OutPacket {
|
||||
buffer,
|
||||
packet_len,
|
||||
sent_bytes,
|
||||
repr,
|
||||
dst_hardware_addr,
|
||||
frag_offset,
|
||||
ident,
|
||||
..
|
||||
} = out_packet;
|
||||
|
||||
let caps = self.caps.clone();
|
||||
|
||||
let mtu_max = self.ip_mtu();
|
||||
let ip_len = (*packet_len - *sent_bytes + repr.buffer_len()).min(mtu_max);
|
||||
let payload_len = ip_len - repr.buffer_len();
|
||||
|
||||
let more_frags = (*packet_len - *sent_bytes) != payload_len;
|
||||
repr.payload_len = payload_len;
|
||||
*sent_bytes += payload_len;
|
||||
|
||||
let mut tx_len = ip_len;
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(caps.medium, Medium::Ethernet) {
|
||||
tx_len += EthernetFrame::<&[u8]>::header_len();
|
||||
}
|
||||
|
||||
// Emit function for the Ethernet header.
|
||||
let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
|
||||
let mut frame = EthernetFrame::new_unchecked(tx_buffer);
|
||||
|
||||
let src_addr = if let Some(HardwareAddress::Ethernet(addr)) = self.hardware_addr {
|
||||
addr
|
||||
} else {
|
||||
return Err(Error::Malformed);
|
||||
};
|
||||
|
||||
frame.set_src_addr(src_addr);
|
||||
frame.set_dst_addr(*dst_hardware_addr);
|
||||
|
||||
match repr.version() {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
tx_token.consume(self.now, tx_len, |mut tx_buffer| {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
if matches!(self.caps.medium, Medium::Ethernet) {
|
||||
emit_ethernet(&IpRepr::Ipv4(*repr), tx_buffer)?;
|
||||
tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
|
||||
}
|
||||
|
||||
let mut packet = Ipv4Packet::new_unchecked(&mut tx_buffer[..repr.buffer_len()]);
|
||||
repr.emit(&mut packet, &caps.checksum);
|
||||
packet.set_ident(*ident);
|
||||
packet.set_more_frags(more_frags);
|
||||
packet.set_dont_frag(false);
|
||||
packet.set_frag_offset(*frag_offset);
|
||||
|
||||
if caps.checksum.ipv4.tx() {
|
||||
packet.fill_checksum();
|
||||
}
|
||||
|
||||
tx_buffer[repr.buffer_len()..][..payload_len].copy_from_slice(
|
||||
&buffer[*frag_offset as usize + repr.buffer_len() as usize..][..payload_len],
|
||||
);
|
||||
|
||||
// Update the frag offset for the next fragment.
|
||||
*frag_offset += payload_len as u16;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
fn igmp_report_packet<'any>(
|
||||
&self,
|
||||
@ -3335,7 +3744,6 @@ impl<'a> InterfaceInner<'a> {
|
||||
next_header: IpProtocol::Igmp,
|
||||
payload_len: igmp_repr.buffer_len(),
|
||||
hop_limit: 1,
|
||||
// TODO: add Router Alert IPv4 header option. See
|
||||
// [#183](https://github.com/m-labs/smoltcp/issues/183).
|
||||
},
|
||||
igmp_repr,
|
||||
@ -3408,8 +3816,9 @@ 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()));
|
||||
let iface_builder = iface_builder
|
||||
.ipv4_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.ipv4_fragmentation_buffer(vec![]);
|
||||
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||
@ -3438,12 +3847,13 @@ mod test {
|
||||
|
||||
#[cfg(feature = "proto-sixlowpan-fragmentation")]
|
||||
let iface_builder = iface_builder
|
||||
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.sixlowpan_out_packet_cache(vec![]);
|
||||
.sixlowpan_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.sixlowpan_fragmentation_buffer(vec![]);
|
||||
|
||||
#[cfg(feature = "proto-ipv4-fragmentation")]
|
||||
let iface_builder =
|
||||
iface_builder.ipv4_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()));
|
||||
let iface_builder = iface_builder
|
||||
.ipv4_reassembly_buffer(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||
.ipv4_fragmentation_buffer(vec![]);
|
||||
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||
@ -4124,7 +4534,7 @@ mod test {
|
||||
solicit.emit(
|
||||
&remote_ip_addr.into(),
|
||||
&local_ip_addr.solicited_node().into(),
|
||||
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.buffer_len()..]),
|
||||
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.header_len()..]),
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
|
||||
|
@ -23,6 +23,6 @@ pub use self::route::{Route, Routes};
|
||||
pub use socket_set::{SocketHandle, SocketSet, SocketStorage};
|
||||
|
||||
#[cfg(any(feature = "proto-ipv4", feature = "proto-sixlowpan"))]
|
||||
pub use self::fragmentation::{PacketAssembler, PacketAssemblerSet as FragmentsCache};
|
||||
pub use self::fragmentation::{PacketAssembler, PacketAssemblerSet as ReassemblyBuffer};
|
||||
|
||||
pub use self::interface::{Interface, InterfaceBuilder, InterfaceInner as Context};
|
||||
|
@ -261,7 +261,7 @@ impl<'a> Socket<'a> {
|
||||
pub(crate) fn process(&mut self, cx: &mut Context, ip_repr: &IpRepr, payload: &[u8]) {
|
||||
debug_assert!(self.accepts(ip_repr));
|
||||
|
||||
let header_len = ip_repr.buffer_len();
|
||||
let header_len = ip_repr.header_len();
|
||||
let total_len = header_len + payload.len();
|
||||
|
||||
net_trace!(
|
||||
|
@ -2099,7 +2099,7 @@ impl<'a> Socket<'a> {
|
||||
// 3. MSS we can send, determined by our MTU.
|
||||
let size = win_limit
|
||||
.min(self.remote_mss)
|
||||
.min(cx.ip_mtu() - ip_repr.buffer_len() - TCP_HEADER_LEN);
|
||||
.min(cx.ip_mtu() - ip_repr.header_len() - TCP_HEADER_LEN);
|
||||
|
||||
let offset = self.remote_last_seq - self.local_seq_no;
|
||||
repr.payload = self.tx_buffer.get_allocated(offset, size);
|
||||
@ -2161,7 +2161,7 @@ impl<'a> Socket<'a> {
|
||||
|
||||
if repr.control == TcpControl::Syn {
|
||||
// Fill the MSS option. See RFC 6691 for an explanation of this calculation.
|
||||
let max_segment_size = cx.ip_mtu() - ip_repr.buffer_len() - TCP_HEADER_LEN;
|
||||
let max_segment_size = cx.ip_mtu() - ip_repr.header_len() - TCP_HEADER_LEN;
|
||||
repr.max_seg_size = Some(max_segment_size as u16);
|
||||
}
|
||||
|
||||
|
@ -665,7 +665,7 @@ mod test {
|
||||
packet.set_echo_seq_no(0xabcd);
|
||||
packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
|
||||
packet.fill_checksum();
|
||||
assert_eq!(&*packet.into_inner(), &ECHO_PACKET_BYTES[..]);
|
||||
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
|
||||
}
|
||||
|
||||
fn echo_packet_repr() -> Repr<'static> {
|
||||
@ -689,7 +689,7 @@ mod test {
|
||||
let mut bytes = vec![0xa5; repr.buffer_len()];
|
||||
let mut packet = Packet::new_unchecked(&mut bytes);
|
||||
repr.emit(&mut packet, &ChecksumCapabilities::default());
|
||||
assert_eq!(&*packet.into_inner(), &ECHO_PACKET_BYTES[..]);
|
||||
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -666,7 +666,7 @@ impl Repr {
|
||||
}
|
||||
|
||||
/// Return the length of a header that will be emitted from this high-level representation.
|
||||
pub fn buffer_len(&self) -> usize {
|
||||
pub fn header_len(&self) -> usize {
|
||||
match *self {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
Repr::Ipv4(repr) => repr.buffer_len(),
|
||||
@ -693,8 +693,8 @@ impl Repr {
|
||||
/// high-level representation.
|
||||
///
|
||||
/// This is the same as `repr.buffer_len() + repr.payload_len()`.
|
||||
pub fn total_len(&self) -> usize {
|
||||
self.buffer_len() + self.payload_len()
|
||||
pub fn buffer_len(&self) -> usize {
|
||||
self.header_len() + self.payload_len()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ pub struct Key {
|
||||
id: u16,
|
||||
src_addr: Address,
|
||||
dst_addr: Address,
|
||||
protocol: Protocol,
|
||||
}
|
||||
|
||||
/// A four-octet IPv4 address.
|
||||
@ -457,6 +458,7 @@ impl<T: AsRef<[u8]>> Packet<T> {
|
||||
id: self.ident(),
|
||||
src_addr: self.src_addr(),
|
||||
dst_addr: self.dst_addr(),
|
||||
protocol: self.next_header(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ let repr = Ipv4Repr {
|
||||
dst_addr: Ipv4Address::new(10, 0, 0, 2),
|
||||
next_header: IpProtocol::Tcp,
|
||||
payload_len: 10,
|
||||
hop_limit: 64
|
||||
hop_limit: 64,
|
||||
};
|
||||
let mut buffer = vec![0; repr.buffer_len() + repr.payload_len];
|
||||
{ // emission
|
||||
|
@ -2067,14 +2067,14 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn sixlowpan_three_fragments() {
|
||||
use crate::iface::FragmentsCache;
|
||||
use crate::iface::ReassemblyBuffer;
|
||||
use crate::time::Instant;
|
||||
use crate::wire::ieee802154::Frame as Ieee802154Frame;
|
||||
use crate::wire::ieee802154::Repr as Ieee802154Repr;
|
||||
use crate::wire::Ieee802154Address;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
let mut frags_cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||
let mut frags_cache = ReassemblyBuffer::new(vec![], BTreeMap::new());
|
||||
|
||||
let frame1: &[u8] = &[
|
||||
0x41, 0xcc, 0x92, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
|
||||
|
Loading…
x
Reference in New Issue
Block a user