mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-01 14:50:58 +00:00
sixlowpan: add fragmentation logic in interface
This commit is contained in:
parent
d1107f4ead
commit
adf56a1701
@ -47,11 +47,13 @@ use std::collections::BTreeMap;
|
|||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use smoltcp::iface::{InterfaceBuilder, NeighborCache};
|
use smoltcp::iface::{FragmentsCache, InterfaceBuilder, NeighborCache};
|
||||||
use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
|
use smoltcp::phy::{wait as phy_wait, Medium, RawSocket};
|
||||||
use smoltcp::socket::udp;
|
use smoltcp::socket::udp;
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
|
use smoltcp::wire::{Ieee802154Pan, IpAddress, IpCidr};
|
||||||
|
use smoltcp::socket::tcp;
|
||||||
|
use smoltcp::storage::RingBuffer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
utils::setup_logging("");
|
utils::setup_logging("");
|
||||||
@ -72,6 +74,10 @@ fn main() {
|
|||||||
let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 128]);
|
let udp_tx_buffer = udp::PacketBuffer::new(vec![udp::PacketMetadata::EMPTY], vec![0; 128]);
|
||||||
let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
|
let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer);
|
||||||
|
|
||||||
|
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
|
||||||
|
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; 4096]);
|
||||||
|
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||||
|
|
||||||
let ieee802154_addr = smoltcp::wire::Ieee802154Address::Extended([
|
let ieee802154_addr = smoltcp::wire::Ieee802154Address::Extended([
|
||||||
0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
0x1a, 0x0b, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||||
]);
|
]);
|
||||||
@ -80,22 +86,44 @@ fn main() {
|
|||||||
64,
|
64,
|
||||||
)];
|
)];
|
||||||
|
|
||||||
|
let cache = FragmentsCache::new(vec![], BTreeMap::new());
|
||||||
|
|
||||||
|
let buffer: Vec<(usize, managed::ManagedSlice<'_, u8>)> = (0..12)
|
||||||
|
.into_iter()
|
||||||
|
.map(|_| (0_usize, managed::ManagedSlice::from(vec![0; 127])))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let out_fragments_cache = RingBuffer::new(buffer);
|
||||||
|
|
||||||
let mut builder = InterfaceBuilder::new(device, vec![])
|
let mut builder = InterfaceBuilder::new(device, vec![])
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.pan_id(Ieee802154Pan(0xbeef));
|
.pan_id(Ieee802154Pan(0xbeef));
|
||||||
builder = builder
|
builder = builder
|
||||||
.hardware_addr(ieee802154_addr.into())
|
.hardware_addr(ieee802154_addr.into())
|
||||||
.neighbor_cache(neighbor_cache);
|
.neighbor_cache(neighbor_cache)
|
||||||
|
.sixlowpan_fragments_cache(cache)
|
||||||
|
.out_fragments_cache(out_fragments_cache);
|
||||||
let mut iface = builder.finalize();
|
let mut iface = builder.finalize();
|
||||||
|
|
||||||
let udp_handle = iface.add_socket(udp_socket);
|
let udp_handle = iface.add_socket(udp_socket);
|
||||||
|
let tcp_handle = iface.add_socket(tcp_socket);
|
||||||
|
|
||||||
|
let socket = iface.get_socket::<tcp::Socket>(tcp_handle);
|
||||||
|
socket.listen(50000).unwrap();
|
||||||
|
|
||||||
|
let mut tcp_active = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let timestamp = Instant::now();
|
let timestamp = Instant::now();
|
||||||
match iface.poll(timestamp) {
|
|
||||||
Ok(_) => {}
|
let mut poll = true;
|
||||||
Err(e) => {
|
while poll {
|
||||||
debug!("poll error: {}", e);
|
match iface.poll(timestamp) {
|
||||||
|
Ok(r) => poll = r,
|
||||||
|
Err(e) => {
|
||||||
|
debug!("poll error: {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +133,7 @@ fn main() {
|
|||||||
socket.bind(6969).unwrap()
|
socket.bind(6969).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0; 1500];
|
||||||
let client = match socket.recv() {
|
let client = match socket.recv() {
|
||||||
Ok((data, endpoint)) => {
|
Ok((data, endpoint)) => {
|
||||||
debug!(
|
debug!(
|
||||||
@ -112,17 +141,51 @@ fn main() {
|
|||||||
str::from_utf8(data).unwrap(),
|
str::from_utf8(data).unwrap(),
|
||||||
endpoint
|
endpoint
|
||||||
);
|
);
|
||||||
Some(endpoint)
|
buffer[..data.len()].copy_from_slice(data);
|
||||||
|
Some((data.len(), endpoint))
|
||||||
}
|
}
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
};
|
};
|
||||||
if let Some(endpoint) = client {
|
if let Some((len, endpoint)) = client {
|
||||||
let data = b"hello\n";
|
|
||||||
debug!(
|
debug!(
|
||||||
"udp:6969 send data: {:?}",
|
"udp:6969 send data: {:?}",
|
||||||
str::from_utf8(data.as_ref()).unwrap()
|
str::from_utf8(&buffer[..len]).unwrap()
|
||||||
);
|
);
|
||||||
socket.send_slice(data, endpoint).unwrap();
|
socket.send_slice(&buffer[..len], endpoint).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let socket = iface.get_socket::<tcp::Socket>(tcp_handle);
|
||||||
|
if socket.is_active() && !tcp_active {
|
||||||
|
debug!("connected");
|
||||||
|
} else if !socket.is_active() && tcp_active {
|
||||||
|
debug!("disconnected");
|
||||||
|
}
|
||||||
|
tcp_active = socket.is_active();
|
||||||
|
|
||||||
|
if socket.may_recv() {
|
||||||
|
let data = socket
|
||||||
|
.recv(|data| {
|
||||||
|
let data = data.to_owned();
|
||||||
|
if !data.is_empty() {
|
||||||
|
debug!(
|
||||||
|
"recv data: {:?}",
|
||||||
|
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(data.len(), data)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if socket.can_send() && !data.is_empty() {
|
||||||
|
debug!(
|
||||||
|
"send data: {:?}",
|
||||||
|
str::from_utf8(data.as_ref()).unwrap_or("(invalid utf8)")
|
||||||
|
);
|
||||||
|
socket.send_slice(&data[..]).unwrap();
|
||||||
|
}
|
||||||
|
} else if socket.may_send() {
|
||||||
|
debug!("close");
|
||||||
|
socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
phy_wait(fd, iface.poll_delay(timestamp)).expect("wait error");
|
phy_wait(fd, iface.poll_delay(timestamp)).expect("wait error");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use smoltcp::wire::{Ipv6Address, SixlowpanUdpPacket, SixlowpanUdpRepr};
|
use smoltcp::wire::{Ipv6Address, SixlowpanUdpNhcPacket, SixlowpanUdpNhcRepr};
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, arbitrary::Arbitrary)]
|
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, arbitrary::Arbitrary)]
|
||||||
pub struct AddressFuzzer(pub [u8; 16]);
|
pub struct AddressFuzzer(pub [u8; 16]);
|
||||||
@ -16,21 +16,19 @@ struct SixlowpanUdpPacketFuzzer<'a> {
|
|||||||
data: &'a [u8],
|
data: &'a [u8],
|
||||||
src_addr: AddressFuzzer,
|
src_addr: AddressFuzzer,
|
||||||
dst_addr: AddressFuzzer,
|
dst_addr: AddressFuzzer,
|
||||||
checksum: Option<u16>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fuzz_target!(|fuzz: SixlowpanUdpPacketFuzzer| {
|
fuzz_target!(|fuzz: SixlowpanUdpPacketFuzzer| {
|
||||||
if let Ok(ref frame) = SixlowpanUdpPacket::new_checked(fuzz.data) {
|
if let Ok(ref frame) = SixlowpanUdpNhcPacket::new_checked(fuzz.data) {
|
||||||
if let Ok(repr) = SixlowpanUdpRepr::parse(
|
if let Ok(repr) = SixlowpanUdpNhcRepr::parse(
|
||||||
frame,
|
frame,
|
||||||
&fuzz.src_addr.into(),
|
&fuzz.src_addr.into(),
|
||||||
&fuzz.dst_addr.into(),
|
&fuzz.dst_addr.into(),
|
||||||
fuzz.checksum,
|
|
||||||
) {
|
) {
|
||||||
let payload = frame.payload();
|
let payload = frame.payload();
|
||||||
let mut buffer = vec![0; repr.header_len() + payload.len()];
|
let mut buffer = vec![0; repr.header_len() + payload.len()];
|
||||||
|
|
||||||
let mut frame = SixlowpanUdpPacket::new_unchecked(&mut buffer[..]);
|
let mut frame = SixlowpanUdpNhcPacket::new_unchecked(&mut buffer[..]);
|
||||||
repr.emit(
|
repr.emit(
|
||||||
&mut frame,
|
&mut frame,
|
||||||
&fuzz.src_addr.into(),
|
&fuzz.src_addr.into(),
|
||||||
|
@ -25,6 +25,7 @@ enum AssemblerState {
|
|||||||
total_size: usize,
|
total_size: usize,
|
||||||
last_updated: Instant,
|
last_updated: Instant,
|
||||||
started_on: Instant,
|
started_on: Instant,
|
||||||
|
offset_correction: isize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +49,12 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
///
|
///
|
||||||
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when the buffer is too small for holding all the
|
/// - Returns [`Error::PacketAssemblerBufferTooSmall`] when the buffer is too small for holding all the
|
||||||
/// fragments of a packet.
|
/// fragments of a packet.
|
||||||
pub(crate) fn start(&mut self, total_size: usize, start_time: Instant) -> Result<()> {
|
pub(crate) fn start(
|
||||||
|
&mut self,
|
||||||
|
total_size: usize,
|
||||||
|
start_time: Instant,
|
||||||
|
offset_correction: isize,
|
||||||
|
) -> Result<()> {
|
||||||
match &mut self.buffer {
|
match &mut self.buffer {
|
||||||
ManagedSlice::Borrowed(b) if b.len() < total_size => {
|
ManagedSlice::Borrowed(b) if b.len() < total_size => {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||||
@ -65,6 +71,7 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
total_size,
|
total_size,
|
||||||
last_updated: start_time,
|
last_updated: start_time,
|
||||||
started_on: start_time,
|
started_on: start_time,
|
||||||
|
offset_correction,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -86,8 +93,12 @@ impl<'a> PacketAssembler<'a> {
|
|||||||
ref mut assembler,
|
ref mut assembler,
|
||||||
total_size,
|
total_size,
|
||||||
ref mut last_updated,
|
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 {
|
if offset + data.len() > total_size {
|
||||||
return Err(Error::PacketAssemblerBufferTooSmall);
|
return Err(Error::PacketAssemblerBufferTooSmall);
|
||||||
}
|
}
|
||||||
@ -392,10 +403,10 @@ mod tests {
|
|||||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
p_assembler.start(2, Instant::now()),
|
p_assembler.start(2, Instant::now(), 0),
|
||||||
Err(Error::PacketAssemblerBufferTooSmall)
|
Err(Error::PacketAssemblerBufferTooSmall)
|
||||||
);
|
);
|
||||||
assert_eq!(p_assembler.start(1, Instant::now()), Ok(()));
|
assert_eq!(p_assembler.start(1, Instant::now(), 0), Ok(()));
|
||||||
|
|
||||||
let data = b"Hello World!";
|
let data = b"Hello World!";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -409,7 +420,7 @@ mod tests {
|
|||||||
let mut storage = [0u8; 5];
|
let mut storage = [0u8; 5];
|
||||||
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
let mut p_assembler = PacketAssembler::new(&mut storage[..]);
|
||||||
|
|
||||||
p_assembler.start(5, Instant::now()).unwrap();
|
p_assembler.start(5, Instant::now(), 0).unwrap();
|
||||||
let data = b"Rust";
|
let data = b"Rust";
|
||||||
|
|
||||||
p_assembler.add(&data[..], 0, Instant::now()).unwrap();
|
p_assembler.add(&data[..], 0, Instant::now()).unwrap();
|
||||||
@ -424,7 +435,7 @@ mod tests {
|
|||||||
|
|
||||||
let data = b"Hello World!";
|
let data = b"Hello World!";
|
||||||
|
|
||||||
p_assembler.start(data.len(), Instant::now()).unwrap();
|
p_assembler.start(data.len(), Instant::now(), 0).unwrap();
|
||||||
|
|
||||||
p_assembler.add(b"Hello ", 0, Instant::now()).unwrap();
|
p_assembler.add(b"Hello ", 0, Instant::now()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -483,7 +494,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now())
|
.start(0, Instant::now(), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
|
|
||||||
@ -491,7 +502,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now())
|
.start(0, Instant::now(), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
|
|
||||||
@ -499,7 +510,7 @@ mod tests {
|
|||||||
set.reserve_with_key(&key).unwrap();
|
set.reserve_with_key(&key).unwrap();
|
||||||
set.get_packet_assembler_mut(&key)
|
set.get_packet_assembler_mut(&key)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start(0, Instant::now())
|
.start(0, Instant::now(), 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
set.get_assembled_packet(&key).unwrap();
|
set.get_assembled_packet(&key).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
use managed::{ManagedMap, ManagedSlice};
|
use managed::{ManagedMap, ManagedSlice};
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
use super::fragmentation::PacketAssemblerSet;
|
use super::fragmentation::PacketAssemblerSet;
|
||||||
use super::socket_set::SocketSet;
|
use super::socket_set::SocketSet;
|
||||||
@ -20,10 +19,16 @@ use crate::socket::dhcpv4;
|
|||||||
#[cfg(feature = "socket-dns")]
|
#[cfg(feature = "socket-dns")]
|
||||||
use crate::socket::dns;
|
use crate::socket::dns;
|
||||||
use crate::socket::*;
|
use crate::socket::*;
|
||||||
|
use crate::storage::RingBuffer;
|
||||||
use crate::time::{Duration, Instant};
|
use crate::time::{Duration, Instant};
|
||||||
use crate::wire::*;
|
use crate::wire::*;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
|
|
||||||
|
type OutBuffer<'a> = RingBuffer<'a, (usize, ManagedSlice<'a, u8>)>;
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
type SixlowpanFragmentsBuffer<'a> = PacketAssemblerSet<'a, SixlowpanFragKey>;
|
||||||
|
|
||||||
macro_rules! check {
|
macro_rules! check {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
match $e {
|
match $e {
|
||||||
@ -49,6 +54,11 @@ pub struct Interface<'a, DeviceT: for<'d> Device<'d>> {
|
|||||||
device: DeviceT,
|
device: DeviceT,
|
||||||
sockets: SocketSet<'a>,
|
sockets: SocketSet<'a>,
|
||||||
inner: InterfaceInner<'a>,
|
inner: InterfaceInner<'a>,
|
||||||
|
// Currently this is behind the sixlowpan feature. However, this buffer could also be used for other protocols.
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments: OutBuffer<'a>,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
sixlowpan_fragments: SixlowpanFragmentsBuffer<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The device independent part of an Ethernet network interface.
|
/// The device independent part of an Ethernet network interface.
|
||||||
@ -61,6 +71,7 @@ pub struct Interface<'a, DeviceT: for<'d> Device<'d>> {
|
|||||||
pub struct InterfaceInner<'a> {
|
pub struct InterfaceInner<'a> {
|
||||||
caps: DeviceCapabilities,
|
caps: DeviceCapabilities,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
neighbor_cache: Option<NeighborCache<'a>>,
|
neighbor_cache: Option<NeighborCache<'a>>,
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
@ -69,6 +80,8 @@ pub struct InterfaceInner<'a> {
|
|||||||
sequence_no: u8,
|
sequence_no: u8,
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pan_id: Option<Ieee802154Pan>,
|
pan_id: Option<Ieee802154Pan>,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
tag: u16,
|
||||||
ip_addrs: ManagedSlice<'a, IpCidr>,
|
ip_addrs: ManagedSlice<'a, IpCidr>,
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
any_ip: bool,
|
any_ip: bool,
|
||||||
@ -99,6 +112,10 @@ pub struct InterfaceBuilder<'a, DeviceT: for<'d> Device<'d>> {
|
|||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
|
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
|
||||||
random_seed: u64,
|
random_seed: u64,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
sixlowpan_fragments: Option<SixlowpanFragmentsBuffer<'a>>,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments: Option<OutBuffer<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, DeviceT> InterfaceBuilder<'a, DeviceT>
|
impl<'a, DeviceT> InterfaceBuilder<'a, DeviceT>
|
||||||
@ -108,7 +125,7 @@ where
|
|||||||
/// Create a builder used for creating a network interface using the
|
/// Create a builder used for creating a network interface using the
|
||||||
/// given device and address.
|
/// given device and address.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "medium-ethernet",
|
all(feature = "medium-ethernet", not(feature = "proto-sixlowpan")),
|
||||||
doc = r##"
|
doc = r##"
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
@ -139,7 +156,7 @@ let iface = InterfaceBuilder::new(device, vec![])
|
|||||||
SocketsT: Into<ManagedSlice<'a, SocketStorage<'a>>>,
|
SocketsT: Into<ManagedSlice<'a, SocketStorage<'a>>>,
|
||||||
{
|
{
|
||||||
InterfaceBuilder {
|
InterfaceBuilder {
|
||||||
device: device,
|
device,
|
||||||
sockets: SocketSet::new(sockets),
|
sockets: SocketSet::new(sockets),
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
@ -157,6 +174,11 @@ let iface = InterfaceBuilder::new(device, vec![])
|
|||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
ipv4_multicast_groups: ManagedMap::Borrowed(&mut []),
|
ipv4_multicast_groups: ManagedMap::Borrowed(&mut []),
|
||||||
random_seed: 0,
|
random_seed: 0,
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
sixlowpan_fragments: None,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +290,18 @@ let iface = InterfaceBuilder::new(device, vec![])
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
pub fn sixlowpan_fragments_cache(mut self, storage: SixlowpanFragmentsBuffer<'a>) -> Self {
|
||||||
|
self.sixlowpan_fragments = Some(storage);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
pub fn out_fragments_cache(mut self, storage: OutBuffer<'a>) -> Self {
|
||||||
|
self.out_fragments = Some(storage);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a network interface using the previously provided configuration.
|
/// Create a network interface using the previously provided configuration.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
@ -337,9 +371,28 @@ let iface = InterfaceBuilder::new(device, vec![])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
let mut tag;
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
loop {
|
||||||
|
tag = (rand.rand_u32() & 0xffff) as u16;
|
||||||
|
if tag != 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Interface {
|
Interface {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
sockets: self.sockets,
|
sockets: self.sockets,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
sixlowpan_fragments: self
|
||||||
|
.sixlowpan_fragments
|
||||||
|
.expect("Cache for incoming 6LoWPAN fragments is required"),
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments: self
|
||||||
|
.out_fragments
|
||||||
|
.expect("Cache for outgoing fragments is required"),
|
||||||
inner: InterfaceInner {
|
inner: InterfaceInner {
|
||||||
now: Instant::from_secs(0),
|
now: Instant::from_secs(0),
|
||||||
caps,
|
caps,
|
||||||
@ -359,6 +412,8 @@ let iface = InterfaceBuilder::new(device, vec![])
|
|||||||
sequence_no,
|
sequence_no,
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pan_id: self.pan_id,
|
pan_id: self.pan_id,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
tag,
|
||||||
rand,
|
rand,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -654,7 +709,7 @@ where
|
|||||||
{
|
{
|
||||||
// Send initial membership report
|
// Send initial membership report
|
||||||
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
||||||
self.inner.dispatch_ip(tx_token, pkt)?;
|
self.inner.dispatch_ip(tx_token, pkt, None)?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@ -686,7 +741,7 @@ where
|
|||||||
} else if let Some(pkt) = self.inner.igmp_leave_packet(addr) {
|
} else if let Some(pkt) = self.inner.igmp_leave_packet(addr) {
|
||||||
// Send group leave packet
|
// Send group leave packet
|
||||||
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
||||||
self.inner.dispatch_ip(tx_token, pkt)?;
|
self.inner.dispatch_ip(tx_token, pkt, None)?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@ -771,6 +826,7 @@ where
|
|||||||
self.inner.now = timestamp;
|
self.inner.now = timestamp;
|
||||||
|
|
||||||
let mut readiness_may_have_changed = false;
|
let mut readiness_may_have_changed = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let processed_any = self.socket_ingress();
|
let processed_any = self.socket_ingress();
|
||||||
let emitted_any = self.socket_egress();
|
let emitted_any = self.socket_egress();
|
||||||
@ -784,6 +840,19 @@ where
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
while !self.out_fragments.is_empty() {
|
||||||
|
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
||||||
|
|
||||||
|
// FIXME(thvdveld): remove the unwrap
|
||||||
|
let (len, buffer) = self.out_fragments.dequeue_one().unwrap();
|
||||||
|
tx_token.consume(self.inner.now, *len, |tx_token| {
|
||||||
|
tx_token.copy_from_slice(&buffer[..*len]);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(readiness_may_have_changed)
|
Ok(readiness_may_have_changed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,7 +907,10 @@ where
|
|||||||
device,
|
device,
|
||||||
inner,
|
inner,
|
||||||
sockets,
|
sockets,
|
||||||
..
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
sixlowpan_fragments,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments,
|
||||||
} = self;
|
} = self;
|
||||||
while let Some((rx_token, tx_token)) = device.receive() {
|
while let Some((rx_token, tx_token)) = device.receive() {
|
||||||
let res = rx_token.consume(inner.now, |frame| {
|
let res = rx_token.consume(inner.now, |frame| {
|
||||||
@ -854,15 +926,19 @@ where
|
|||||||
#[cfg(feature = "medium-ip")]
|
#[cfg(feature = "medium-ip")]
|
||||||
Medium::Ip => {
|
Medium::Ip => {
|
||||||
if let Some(packet) = inner.process_ip(sockets, &frame) {
|
if let Some(packet) = inner.process_ip(sockets, &frame) {
|
||||||
if let Err(err) = inner.dispatch_ip(tx_token, packet) {
|
if let Err(err) = inner.dispatch_ip(tx_token, packet, None) {
|
||||||
net_debug!("Failed to send response: {}", err);
|
net_debug!("Failed to send response: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
Medium::Ieee802154 => {
|
Medium::Ieee802154 => {
|
||||||
if let Some(packet) = inner.process_ieee802154(sockets, &frame) {
|
if let Some(packet) =
|
||||||
if let Err(err) = inner.dispatch_ieee802154(tx_token, packet) {
|
inner.process_ieee802154(sockets, &frame, sixlowpan_fragments)
|
||||||
|
{
|
||||||
|
if let Err(err) =
|
||||||
|
inner.dispatch_ip(tx_token, packet, Some(out_fragments))
|
||||||
|
{
|
||||||
net_debug!("Failed to send response: {}", err);
|
net_debug!("Failed to send response: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -885,6 +961,8 @@ where
|
|||||||
device,
|
device,
|
||||||
inner,
|
inner,
|
||||||
sockets,
|
sockets,
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
out_fragments,
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
let _caps = device.capabilities();
|
let _caps = device.capabilities();
|
||||||
@ -901,8 +979,16 @@ where
|
|||||||
let mut neighbor_addr = None;
|
let mut neighbor_addr = None;
|
||||||
let mut respond = |inner: &mut InterfaceInner, response: IpPacket| {
|
let mut respond = |inner: &mut InterfaceInner, response: IpPacket| {
|
||||||
neighbor_addr = Some(response.ip_repr().dst_addr());
|
neighbor_addr = Some(response.ip_repr().dst_addr());
|
||||||
let tx_token = device.transmit().ok_or(Error::Exhausted)?;
|
// FIXME(thvdveld): remove unwrap
|
||||||
inner.dispatch_ip(tx_token, response)?;
|
let tx_token = device.transmit().ok_or(Error::Exhausted).unwrap();
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
{
|
||||||
|
inner.dispatch_ip(tx_token, response, Some(out_fragments)).unwrap();
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||||
|
{
|
||||||
|
check!(inner.dispatch_ip(tx_token, response, None));
|
||||||
|
}
|
||||||
emitted_any = true;
|
emitted_any = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
@ -982,7 +1068,7 @@ where
|
|||||||
if let Some(pkt) = self.inner.igmp_report_packet(version, group) {
|
if let Some(pkt) = self.inner.igmp_report_packet(version, group) {
|
||||||
// Send initial membership report
|
// Send initial membership report
|
||||||
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
||||||
self.inner.dispatch_ip(tx_token, pkt)?;
|
self.inner.dispatch_ip(tx_token, pkt, None)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner.igmp_report_state = IgmpReportState::Inactive;
|
self.inner.igmp_report_state = IgmpReportState::Inactive;
|
||||||
@ -1006,7 +1092,7 @@ where
|
|||||||
if let Some(pkt) = self.inner.igmp_report_packet(version, addr) {
|
if let Some(pkt) = self.inner.igmp_report_packet(version, addr) {
|
||||||
// Send initial membership report
|
// Send initial membership report
|
||||||
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
let tx_token = self.device.transmit().ok_or(Error::Exhausted)?;
|
||||||
self.inner.dispatch_ip(tx_token, pkt)?;
|
self.inner.dispatch_ip(tx_token, pkt, None)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_timeout = (timeout + interval).max(self.inner.now);
|
let next_timeout = (timeout + interval).max(self.inner.now);
|
||||||
@ -1142,7 +1228,10 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pan_id: Some(crate::wire::Ieee802154Pan(0xabcd)),
|
pan_id: Some(crate::wire::Ieee802154Pan(0xabcd)),
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
sequence_no: 0,
|
sequence_no: 1,
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
tag: 1,
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
hardware_addr: Some(crate::wire::HardwareAddress::Ethernet(
|
hardware_addr: Some(crate::wire::HardwareAddress::Ethernet(
|
||||||
@ -1186,6 +1275,13 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
no
|
no
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
|
||||||
|
let tag = self.tag;
|
||||||
|
self.tag = self.tag.wrapping_add(1);
|
||||||
|
tag
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine if the given `Ipv6Address` is the solicited node
|
/// Determine if the given `Ipv6Address` is the solicited node
|
||||||
/// multicast address for a IPv6 addresses assigned to the interface.
|
/// multicast address for a IPv6 addresses assigned to the interface.
|
||||||
/// See [RFC 4291 § 2.7.1] for more details.
|
/// See [RFC 4291 § 2.7.1] for more details.
|
||||||
@ -1299,11 +1395,12 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
fn process_ieee802154<'frame, T: AsRef<[u8]> + ?Sized>(
|
fn process_ieee802154<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
sixlowpan_payload: &'frame T,
|
sixlowpan_payload: &'payload T,
|
||||||
) -> Option<IpPacket<'frame>> {
|
fragments: &'output mut SixlowpanFragmentsBuffer<'a>,
|
||||||
|
) -> Option<IpPacket<'output>> {
|
||||||
let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
|
let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload));
|
||||||
let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
|
let ieee802154_repr = check!(Ieee802154Repr::parse(&ieee802154_frame));
|
||||||
|
|
||||||
@ -1319,25 +1416,130 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
&& ieee802154_repr.dst_pan_id != Some(Ieee802154Pan::BROADCAST)
|
&& ieee802154_repr.dst_pan_id != Some(Ieee802154Pan::BROADCAST)
|
||||||
{
|
{
|
||||||
net_debug!(
|
net_debug!(
|
||||||
"dropping {:?} because not our PAN id (or not broadcast)",
|
"IEEE802.15.4: dropping {:?} because not our PAN id (or not broadcast)",
|
||||||
ieee802154_repr
|
ieee802154_repr
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
match ieee802154_frame.payload() {
|
match ieee802154_frame.payload() {
|
||||||
Some(payload) => self.process_sixlowpan(sockets, &ieee802154_repr, payload),
|
Some(payload) => self.process_sixlowpan(sockets, &ieee802154_repr, payload, fragments),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-sixlowpan")]
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
fn process_sixlowpan<'frame, T: AsRef<[u8]> + ?Sized>(
|
fn process_sixlowpan<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
sockets: &mut SocketSet,
|
sockets: &mut SocketSet,
|
||||||
ieee802154_repr: &Ieee802154Repr,
|
ieee802154_repr: &Ieee802154Repr,
|
||||||
payload: &'frame T,
|
payload: &'payload T,
|
||||||
) -> Option<IpPacket<'frame>> {
|
fragments: &'output mut SixlowpanFragmentsBuffer<'a>,
|
||||||
|
) -> 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)) {
|
||||||
|
SixlowpanPacket::FragmentHeader => {
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// The key specifies to which 6LoWPAN fragment it belongs too.
|
||||||
|
// It is based on the link layer addresses, the tag and the size.
|
||||||
|
let key = frag.get_key(ieee802154_repr);
|
||||||
|
|
||||||
|
// The offset of this fragment in increments of 8 octets.
|
||||||
|
let offset = frag.datagram_offset() as usize * 8;
|
||||||
|
|
||||||
|
if frag.is_first_fragment() {
|
||||||
|
// The first fragment contains the total size of the IPv6 packet.
|
||||||
|
// However, we received a packet that is compressed following the 6LoWPAN
|
||||||
|
// standard. This means we need to convert the IPv6 packet size to a 6LoWPAN
|
||||||
|
// packet size. The packet size can be different because of first the
|
||||||
|
// compression of the IP header and when UDP is used (because the UDP header
|
||||||
|
// can also be compressed). Other headers are not compressed by 6LoWPAN.
|
||||||
|
|
||||||
|
let iphc = check!(SixlowpanIphcPacket::new_checked(frag.payload()));
|
||||||
|
let iphc_repr = check!(SixlowpanIphcRepr::parse(
|
||||||
|
&iphc,
|
||||||
|
ieee802154_repr.src_addr,
|
||||||
|
ieee802154_repr.dst_addr,
|
||||||
|
));
|
||||||
|
|
||||||
|
// The uncompressed header size always starts with 40, since this is the size
|
||||||
|
// of a IPv6 header.
|
||||||
|
let mut uncompressed_header_size = 40;
|
||||||
|
let mut compressed_header_size = iphc.header_len();
|
||||||
|
|
||||||
|
// We need to check if we have an UDP packet, since this header can also be
|
||||||
|
// compressed by 6LoWPAN. We currently don't support extension headers yet.
|
||||||
|
match iphc_repr.next_header {
|
||||||
|
SixlowpanNextHeader::Compressed => {
|
||||||
|
match check!(SixlowpanNhcPacket::dispatch(iphc.payload())) {
|
||||||
|
SixlowpanNhcPacket::ExtHeader => {
|
||||||
|
net_debug!("6LoWPAN: extension headers not supported");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
SixlowpanNhcPacket::UdpHeader => {
|
||||||
|
let udp_packet =
|
||||||
|
check!(SixlowpanUdpNhcPacket::new_checked(iphc.payload()));
|
||||||
|
|
||||||
|
uncompressed_header_size += 8;
|
||||||
|
compressed_header_size +=
|
||||||
|
1 + udp_packet.ports_size() + udp_packet.checksum_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SixlowpanNextHeader::Uncompressed(_) => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
// We reserve a spot in the packet assembler set and add the required
|
||||||
|
// information to the packet assembler.
|
||||||
|
// This information is the total size of the packet when it is fully assmbled.
|
||||||
|
// 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(
|
||||||
|
frag.datagram_size() as usize - uncompressed_header_size
|
||||||
|
+ compressed_header_size,
|
||||||
|
self.now,
|
||||||
|
-((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) {
|
||||||
|
Ok(true) => {
|
||||||
|
net_trace!("6LoWPAN: fragmented packet now complete");
|
||||||
|
check!(fragments.get_assembled_packet(&key))
|
||||||
|
}
|
||||||
|
Ok(false) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Err(Error::PacketAssemblerOverlap) => {
|
||||||
|
net_trace!("6LoWPAN: overlap in packet");
|
||||||
|
frags.mark_discarded();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Err(_) => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SixlowpanPacket::IphcHeader => payload.as_ref(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// At this point we should have a valid 6LoWPAN packet.
|
||||||
// The first header needs to be an IPHC header.
|
// The first header needs to be an IPHC header.
|
||||||
let iphc_packet = check!(SixlowpanIphcPacket::new_checked(payload));
|
let iphc_packet = check!(SixlowpanIphcPacket::new_checked(payload));
|
||||||
let iphc_repr = check!(SixlowpanIphcRepr::parse(
|
let iphc_repr = check!(SixlowpanIphcRepr::parse(
|
||||||
@ -1352,10 +1554,9 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
dst_addr: iphc_repr.dst_addr,
|
dst_addr: iphc_repr.dst_addr,
|
||||||
hop_limit: iphc_repr.hop_limit,
|
hop_limit: iphc_repr.hop_limit,
|
||||||
next_header: IpProtocol::Unknown(0),
|
next_header: IpProtocol::Unknown(0),
|
||||||
payload_len: iphc_repr.buffer_len(),
|
payload_len: 40,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Currently we assume the next header is a UDP, so we ignore everything else.
|
|
||||||
match iphc_repr.next_header {
|
match iphc_repr.next_header {
|
||||||
SixlowpanNextHeader::Compressed => {
|
SixlowpanNextHeader::Compressed => {
|
||||||
match check!(SixlowpanNhcPacket::dispatch(payload)) {
|
match check!(SixlowpanNhcPacket::dispatch(payload)) {
|
||||||
@ -1370,9 +1571,10 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "socket-udp")]
|
||||||
SixlowpanNhcPacket::UdpHeader => {
|
SixlowpanNhcPacket::UdpHeader => {
|
||||||
ipv6_repr.next_header = IpProtocol::Udp;
|
|
||||||
// Handle the UDP
|
|
||||||
let udp_packet = check!(SixlowpanUdpNhcPacket::new_checked(payload));
|
let udp_packet = check!(SixlowpanUdpNhcPacket::new_checked(payload));
|
||||||
|
ipv6_repr.next_header = IpProtocol::Udp;
|
||||||
|
ipv6_repr.payload_len += 8 + udp_packet.payload().len();
|
||||||
|
|
||||||
let udp_repr = check!(SixlowpanUdpNhcRepr::parse(
|
let udp_repr = check!(SixlowpanUdpNhcRepr::parse(
|
||||||
&udp_packet,
|
&udp_packet,
|
||||||
&iphc_repr.src_addr,
|
&iphc_repr.src_addr,
|
||||||
@ -1381,6 +1583,10 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
|
|
||||||
// Look for UDP sockets that will accept the UDP packet.
|
// Look for UDP sockets that will accept the UDP packet.
|
||||||
// If it does not accept the packet, then send an ICMP message.
|
// If it does not accept the packet, then send an ICMP message.
|
||||||
|
//
|
||||||
|
// NOTE(thvdveld): this is currently the same code as in self.process_udp.
|
||||||
|
// However, we cannot use that one because the payload passed to it is a
|
||||||
|
// normal IPv6 UDP payload, which is not what we have here.
|
||||||
for udp_socket in sockets
|
for udp_socket in sockets
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|i| udp::Socket::downcast(&mut i.socket))
|
.filter_map(|i| udp::Socket::downcast(&mut i.socket))
|
||||||
@ -1396,6 +1602,8 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When we are here then then there was no UDP socket that accepted the UDP
|
||||||
|
// message.
|
||||||
let payload_len = icmp_reply_payload_len(
|
let payload_len = icmp_reply_payload_len(
|
||||||
payload.len(),
|
payload.len(),
|
||||||
IPV6_MIN_MTU,
|
IPV6_MIN_MTU,
|
||||||
@ -1415,8 +1623,14 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
ipv6_repr.next_header = IpProtocol::Icmpv6;
|
ipv6_repr.next_header = IpProtocol::Icmpv6;
|
||||||
self.process_icmpv6(sockets, IpRepr::Ipv6(ipv6_repr), iphc_packet.payload())
|
self.process_icmpv6(sockets, IpRepr::Ipv6(ipv6_repr), iphc_packet.payload())
|
||||||
}
|
}
|
||||||
_ => {
|
#[cfg(feature = "socket-tcp")]
|
||||||
net_debug!("Headers other than ICMPv6 and compressed headers are currently not supported for 6LoWPAN");
|
IpProtocol::Tcp => {
|
||||||
|
ipv6_repr.next_header = nxt_hdr;
|
||||||
|
ipv6_repr.payload_len += payload.len();
|
||||||
|
self.process_tcp(sockets, IpRepr::Ipv6(ipv6_repr), iphc_packet.payload())
|
||||||
|
}
|
||||||
|
proto => {
|
||||||
|
net_debug!("6LoWPAN: {} currently not supported", proto);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2046,7 +2260,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
Icmpv4Repr::EchoReply { .. } => match self.ipv4_address() {
|
Icmpv4Repr::EchoReply { .. } => match self.ipv4_address() {
|
||||||
Some(src_addr) => {
|
Some(src_addr) => {
|
||||||
let ipv4_reply_repr = Ipv4Repr {
|
let ipv4_reply_repr = Ipv4Repr {
|
||||||
src_addr: src_addr,
|
src_addr,
|
||||||
dst_addr: ipv4_repr.src_addr,
|
dst_addr: ipv4_repr.src_addr,
|
||||||
next_header: IpProtocol::Icmp,
|
next_header: IpProtocol::Icmp,
|
||||||
payload_len: icmp_repr.buffer_len(),
|
payload_len: icmp_repr.buffer_len(),
|
||||||
@ -2214,7 +2428,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
arp_repr.emit(&mut packet);
|
arp_repr.emit(&mut packet);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet),
|
EthernetPacket::Ip(packet) => self.dispatch_ip(tx_token, packet, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2406,7 +2620,7 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
solicit,
|
solicit,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.dispatch_ip(tx_token, packet)?;
|
self.dispatch_ip(tx_token, packet, None)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
@ -2424,7 +2638,12 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_ip<Tx: TxToken>(&mut self, tx_token: Tx, packet: IpPacket) -> Result<()> {
|
fn dispatch_ip<Tx: TxToken>(
|
||||||
|
&mut self,
|
||||||
|
tx_token: Tx,
|
||||||
|
packet: IpPacket,
|
||||||
|
_out_fragments: Option<&mut OutBuffer<'_>>,
|
||||||
|
) -> Result<()> {
|
||||||
let ip_repr = packet.ip_repr();
|
let ip_repr = packet.ip_repr();
|
||||||
assert!(!ip_repr.dst_addr().is_unspecified());
|
assert!(!ip_repr.dst_addr().is_unspecified());
|
||||||
|
|
||||||
@ -2471,17 +2690,6 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
Medium::Ieee802154 => self.dispatch_ieee802154(tx_token, packet),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
fn dispatch_ieee802154<Tx: TxToken>(&mut self, tx_token: Tx, packet: IpPacket) -> Result<()> {
|
|
||||||
let ip_repr = packet.ip_repr();
|
|
||||||
assert!(!ip_repr.dst_addr().is_unspecified());
|
|
||||||
|
|
||||||
match self.caps.medium {
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
Medium::Ieee802154 => {
|
Medium::Ieee802154 => {
|
||||||
let (dst_hardware_addr, tx_token) = match self.lookup_hardware_addr(
|
let (dst_hardware_addr, tx_token) = match self.lookup_hardware_addr(
|
||||||
@ -2493,134 +2701,246 @@ impl<'a> InterfaceInner<'a> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ack_request = dst_hardware_addr.is_unicast();
|
self.dispatch_ieee802154(
|
||||||
|
dst_hardware_addr,
|
||||||
|
&ip_repr,
|
||||||
|
tx_token,
|
||||||
|
packet,
|
||||||
|
_out_fragments,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ack_request = match packet {
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
IpPacket::Icmpv6(_) => false,
|
fn dispatch_ieee802154<Tx: TxToken>(
|
||||||
_ => ack_request,
|
&mut self,
|
||||||
};
|
ll_dst_addr: Ieee802154Address,
|
||||||
|
ip_repr: &IpRepr,
|
||||||
|
tx_token: Tx,
|
||||||
|
packet: IpPacket,
|
||||||
|
out_fragments: Option<&mut OutBuffer<'_>>,
|
||||||
|
) -> 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
|
||||||
|
// fragment it.
|
||||||
|
let ll_src_addr = self.hardware_addr.map_or_else(
|
||||||
|
|| Err(Error::Malformed),
|
||||||
|
|addr| match addr {
|
||||||
|
HardwareAddress::Ieee802154(addr) => Ok(addr),
|
||||||
|
_ => Err(Error::Malformed),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut tx_len = 0;
|
let (src_addr, dst_addr) = match (ip_repr.src_addr(), ip_repr.dst_addr()) {
|
||||||
|
(IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => (src_addr, dst_addr),
|
||||||
|
_ => return Err(Error::Unaddressable),
|
||||||
|
};
|
||||||
|
|
||||||
let ll_src_addr =
|
// Create the IEEE802.15.4 header.
|
||||||
if let Some(HardwareAddress::Ieee802154(addr)) = self.hardware_addr {
|
let mut ieee_repr = Ieee802154Repr {
|
||||||
Some(addr)
|
frame_type: Ieee802154FrameType::Data,
|
||||||
} else {
|
security_enabled: false,
|
||||||
return Err(Error::Malformed);
|
frame_pending: false,
|
||||||
};
|
ack_request: false,
|
||||||
|
sequence_number: Some(self.get_sequence_number()),
|
||||||
let ieee_repr = Ieee802154Repr {
|
pan_id_compression: true,
|
||||||
frame_type: Ieee802154FrameType::Data,
|
frame_version: Ieee802154FrameVersion::Ieee802154_2003,
|
||||||
security_enabled: false,
|
dst_pan_id: self.pan_id,
|
||||||
frame_pending: false,
|
dst_addr: Some(ll_dst_addr),
|
||||||
ack_request,
|
src_pan_id: self.pan_id,
|
||||||
sequence_number: Some(self.get_sequence_number()),
|
src_addr: Some(ll_src_addr),
|
||||||
pan_id_compression: true,
|
};
|
||||||
frame_version: Ieee802154FrameVersion::Ieee802154_2003,
|
|
||||||
dst_pan_id: self.pan_id,
|
|
||||||
dst_addr: Some(dst_hardware_addr),
|
|
||||||
src_pan_id: self.pan_id,
|
|
||||||
src_addr: ll_src_addr,
|
|
||||||
};
|
|
||||||
|
|
||||||
let (src_addr, dst_addr) = match (ip_repr.src_addr(), ip_repr.dst_addr()) {
|
|
||||||
(IpAddress::Ipv6(src_addr), IpAddress::Ipv6(dst_addr)) => (src_addr, dst_addr),
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
_ => return Err(Error::Unaddressable),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Create the 6LoWPAN IPHC header.
|
||||||
|
let iphc_repr = SixlowpanIphcRepr {
|
||||||
|
src_addr,
|
||||||
|
ll_src_addr: Some(ll_src_addr),
|
||||||
|
dst_addr,
|
||||||
|
ll_dst_addr: Some(ll_dst_addr),
|
||||||
|
next_header: match &packet {
|
||||||
|
IpPacket::Icmpv6(_) => SixlowpanNextHeader::Uncompressed(IpProtocol::Icmpv6),
|
||||||
|
#[cfg(feature = "socket-tcp")]
|
||||||
|
IpPacket::Tcp(_) => SixlowpanNextHeader::Uncompressed(IpProtocol::Tcp),
|
||||||
|
#[cfg(feature = "socket-udp")]
|
||||||
|
IpPacket::Udp(_) => SixlowpanNextHeader::Compressed,
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
let (next_header, hop_limit) = match &packet {
|
_ => return Err(Error::Unrecognized),
|
||||||
#[cfg(feature = "socket-udp")]
|
},
|
||||||
IpPacket::Udp(_) => (SixlowpanNextHeader::Compressed, 64),
|
hop_limit: ip_repr.hop_limit(),
|
||||||
IpPacket::Icmpv6((_, repr)) => (
|
ecn: None,
|
||||||
SixlowpanNextHeader::Uncompressed(IpProtocol::Icmpv6),
|
dscp: None,
|
||||||
match repr {
|
flow_label: None,
|
||||||
Icmpv6Repr::Ndisc(_) => 255,
|
};
|
||||||
_ => 64,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_ => return Err(Error::Unrecognized),
|
|
||||||
};
|
|
||||||
|
|
||||||
let iphc_repr = SixlowpanIphcRepr {
|
// We will first emit every packet into this buffer.
|
||||||
src_addr,
|
// When we emitted everything we know if we need fragmentation or not.
|
||||||
ll_src_addr,
|
// This method is not ideal, but emitting UDP frames require that the full buffer is passed
|
||||||
dst_addr,
|
// to the `emit` function. However, the buffer for IEEE802.15.4 is usually 125 bytes.
|
||||||
ll_dst_addr: Some(dst_hardware_addr),
|
let mut buffer = [0; 4096];
|
||||||
next_header,
|
let mut total_size = 0;
|
||||||
hop_limit,
|
|
||||||
ecn: None,
|
|
||||||
dscp: None,
|
|
||||||
flow_label: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
tx_len += ieee_repr.buffer_len();
|
let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut buffer[..]);
|
||||||
tx_len += iphc_repr.buffer_len();
|
ieee_repr.emit(&mut ieee_packet);
|
||||||
|
total_size += ieee_repr.buffer_len();
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
let mut iphc_packet = SixlowpanIphcPacket::new_unchecked(&mut buffer[total_size..]);
|
||||||
match &packet {
|
iphc_repr.emit(&mut iphc_packet);
|
||||||
#[cfg(feature = "socket-udp")]
|
total_size += iphc_repr.buffer_len();
|
||||||
IpPacket::Udp((_, udp_repr, payload)) => {
|
|
||||||
let udp_repr = SixlowpanUdpNhcRepr(*udp_repr);
|
|
||||||
tx_len += udp_repr.header_len() + payload.len();
|
|
||||||
}
|
|
||||||
IpPacket::Icmpv6((_, icmp)) => {
|
|
||||||
tx_len += icmp.buffer_len();
|
|
||||||
}
|
|
||||||
_ => return Err(Error::Unrecognized),
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_token.consume(self.now, tx_len, |mut tx_buffer| {
|
let mut compressed_headers_len = iphc_repr.buffer_len();
|
||||||
// 1. Create the header of 802.15.4
|
|
||||||
let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buffer);
|
|
||||||
ieee_repr.emit(&mut ieee_packet);
|
|
||||||
|
|
||||||
let mut start = ieee_repr.buffer_len();
|
#[allow(unreachable_patterns)]
|
||||||
|
match packet {
|
||||||
|
#[cfg(feature = "socket-udp")]
|
||||||
|
IpPacket::Udp((_, udpv6_repr, payload)) => {
|
||||||
|
let udp_repr = SixlowpanUdpNhcRepr(udpv6_repr);
|
||||||
|
let mut udp_packet = SixlowpanUdpNhcPacket::new_unchecked(
|
||||||
|
&mut buffer[total_size..][..udp_repr.header_len() + payload.len()],
|
||||||
|
);
|
||||||
|
udp_repr.emit(
|
||||||
|
&mut udp_packet,
|
||||||
|
&iphc_repr.src_addr,
|
||||||
|
&iphc_repr.dst_addr,
|
||||||
|
payload.len(),
|
||||||
|
|buf| buf.copy_from_slice(payload),
|
||||||
|
);
|
||||||
|
|
||||||
// 2. Create the header for 6LoWPAN IPHC
|
compressed_headers_len += udp_repr.header_len();
|
||||||
let mut iphc_packet =
|
total_size += udp_repr.header_len() + payload.len();
|
||||||
SixlowpanIphcPacket::new_unchecked(&mut tx_buffer[start..tx_len]);
|
}
|
||||||
iphc_repr.emit(&mut iphc_packet);
|
#[cfg(feature = "socket-tcp")]
|
||||||
start += iphc_repr.buffer_len();
|
IpPacket::Tcp((_, tcp_repr)) => {
|
||||||
|
let mut tcp_packet =
|
||||||
|
TcpPacket::new_unchecked(&mut buffer[total_size..][..tcp_repr.buffer_len()]);
|
||||||
|
tcp_repr.emit(
|
||||||
|
&mut tcp_packet,
|
||||||
|
&iphc_repr.src_addr.into(),
|
||||||
|
&iphc_repr.dst_addr.into(),
|
||||||
|
&self.caps.checksum,
|
||||||
|
);
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
total_size += tcp_repr.buffer_len();
|
||||||
match packet {
|
}
|
||||||
#[cfg(feature = "socket-udp")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
IpPacket::Udp((_, udp_repr, payload)) => {
|
IpPacket::Icmpv6((_, icmp_repr)) => {
|
||||||
// 3. Create the header for 6LoWPAN UDP
|
let mut icmp_packet = Icmpv6Packet::new_unchecked(
|
||||||
let mut udp_packet =
|
&mut buffer[total_size..][..icmp_repr.buffer_len()],
|
||||||
SixlowpanUdpNhcPacket::new_unchecked(&mut tx_buffer[start..tx_len]);
|
);
|
||||||
|
icmp_repr.emit(
|
||||||
|
&iphc_repr.src_addr.into(),
|
||||||
|
&iphc_repr.dst_addr.into(),
|
||||||
|
&mut icmp_packet,
|
||||||
|
&self.caps.checksum,
|
||||||
|
);
|
||||||
|
|
||||||
SixlowpanUdpNhcRepr(udp_repr).emit(
|
total_size += icmp_repr.buffer_len();
|
||||||
&mut udp_packet,
|
}
|
||||||
&iphc_repr.src_addr,
|
_ => return Err(Error::Unrecognized),
|
||||||
&iphc_repr.dst_addr,
|
}
|
||||||
payload.len(),
|
|
||||||
|buf| buf.copy_from_slice(payload),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
IpPacket::Icmpv6((_, icmp_repr)) => {
|
|
||||||
// 3. Create the header for ICMPv6
|
|
||||||
let mut icmp_packet =
|
|
||||||
Icmpv6Packet::new_unchecked(&mut tx_buffer[start..tx_len]);
|
|
||||||
|
|
||||||
icmp_repr.emit(
|
if total_size > 125 {
|
||||||
&iphc_repr.src_addr.into(),
|
// Fragmentation is required because the data does not fit into a IEEE802.15.4 packet.
|
||||||
&iphc_repr.dst_addr.into(),
|
// Everything has already been emitted in the buffer, thus we only need to insert the
|
||||||
&mut icmp_packet,
|
// fragmentation headers in the correct places.
|
||||||
&self.caps.checksum,
|
//
|
||||||
);
|
// The first fragment header is right after the first IEEE802.15.4 header.
|
||||||
}
|
//
|
||||||
_ => return Err(Error::Unrecognized),
|
// Since we can only use `tx_token` once we need to store other packets into the
|
||||||
}
|
// out_fragments buffer.
|
||||||
|
|
||||||
|
let out_fragments = out_fragments.unwrap();
|
||||||
|
|
||||||
|
// The datagram size that we need to set in the first fragment header is equal to the
|
||||||
|
// IPv6 payload length + 40.
|
||||||
|
let datagram_size = (packet.ip_repr().payload_len() + 40) as u16;
|
||||||
|
// We generate a random tag.
|
||||||
|
let tag = self.get_sixlowpan_fragment_tag();
|
||||||
|
|
||||||
|
let ieee_len = ieee_repr.buffer_len();
|
||||||
|
|
||||||
|
// We calculate how much data we can send in the first fragment and the other
|
||||||
|
// fragments. The eventual IPv6 sizes of these fragments need to be a multiple of eight
|
||||||
|
// (except for the last fragment) since the offset field in the fragment is an offset
|
||||||
|
// 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 = SixlowpanFragRepr::FirstFragment {
|
||||||
|
size: datagram_size,
|
||||||
|
tag,
|
||||||
|
};
|
||||||
|
let mut fragn = SixlowpanFragRepr::Fragment {
|
||||||
|
size: datagram_size,
|
||||||
|
tag,
|
||||||
|
offset: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let frag1_size = ((125 - ieee_len - frag1.buffer_len() - compressed_headers_len)
|
||||||
|
& 0xffff_fff8)
|
||||||
|
+ compressed_headers_len;
|
||||||
|
let fragn_size = (125 - ieee_len - fragn.buffer_len()) & 0xffff_fff8;
|
||||||
|
|
||||||
|
tx_token.consume(
|
||||||
|
self.now,
|
||||||
|
ieee_len + frag1.buffer_len() + frag1_size,
|
||||||
|
|mut tx_buf| {
|
||||||
|
// Copy the IEEE header
|
||||||
|
tx_buf[..ieee_len].copy_from_slice(&buffer[..ieee_len]);
|
||||||
|
tx_buf = &mut tx_buf[ieee_len..];
|
||||||
|
|
||||||
|
// Add the first fragment header
|
||||||
|
let mut frag1_packet = SixlowpanFragPacket::new_unchecked(&mut tx_buf);
|
||||||
|
frag1.emit(&mut frag1_packet);
|
||||||
|
tx_buf = &mut tx_buf[frag1.buffer_len()..];
|
||||||
|
|
||||||
|
// Add the buffer part.
|
||||||
|
tx_buf[..frag1_size].copy_from_slice(&buffer[ieee_len..][..frag1_size]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut written = ieee_len + frag1_size;
|
||||||
|
|
||||||
|
// We need to save the the rest of the packets into the `out_fragments` buffer.
|
||||||
|
while written < total_size {
|
||||||
|
out_fragments.enqueue_one_with::<'_, (), Error, _>(|(len, tx_buf)| {
|
||||||
|
let mut tx_buf = &mut tx_buf[..];
|
||||||
|
|
||||||
|
// Modify the sequence number of the IEEE header
|
||||||
|
ieee_repr.sequence_number = Some(self.get_sequence_number());
|
||||||
|
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..];
|
||||||
|
|
||||||
|
// Add the next fragment header
|
||||||
|
let datagram_offset = ((40 + written - ieee_len) / 8) as u8;
|
||||||
|
fragn.set_offset(datagram_offset);
|
||||||
|
let mut frag_packet =
|
||||||
|
SixlowpanFragPacket::new_unchecked(&mut tx_buf[..fragn.buffer_len()]);
|
||||||
|
fragn.emit(&mut frag_packet);
|
||||||
|
tx_buf = &mut tx_buf[fragn.buffer_len()..];
|
||||||
|
|
||||||
|
// Add the buffer part
|
||||||
|
let frag_size = (total_size - written).min(fragn_size);
|
||||||
|
tx_buf[..frag_size].copy_from_slice(&buffer[written..][..frag_size]);
|
||||||
|
written += frag_size;
|
||||||
|
|
||||||
|
// Save the lenght of this packet.
|
||||||
|
*len = ieee_len + fragn.buffer_len() + frag_size;
|
||||||
|
Ok(())
|
||||||
|
}).unwrap().unwrap();
|
||||||
}
|
}
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
_ => Err(Error::NotSupported),
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// No fragmentation is needed thus we can copy everything over that already has been
|
||||||
|
// emitted in the buffer.
|
||||||
|
tx_token.consume(self.now, total_size, |tx_buffer| {
|
||||||
|
tx_buffer.copy_from_slice(&buffer[..total_size]);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2732,10 +3052,20 @@ mod test {
|
|||||||
IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64),
|
IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
|
let iface_builder = InterfaceBuilder::new(device, vec![])
|
||||||
|
.hardware_addr(EthernetAddress::default().into())
|
||||||
|
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
||||||
|
.sixlowpan_fragments_cache(PacketAssemblerSet::new(vec![], BTreeMap::new()))
|
||||||
|
.out_fragments_cache(RingBuffer::new(vec![]))
|
||||||
|
.ip_addrs(ip_addrs);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proto-sixlowpan"))]
|
||||||
let iface_builder = InterfaceBuilder::new(device, vec![])
|
let iface_builder = InterfaceBuilder::new(device, vec![])
|
||||||
.hardware_addr(EthernetAddress::default().into())
|
.hardware_addr(EthernetAddress::default().into())
|
||||||
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
|
||||||
.ip_addrs(ip_addrs);
|
.ip_addrs(ip_addrs);
|
||||||
|
|
||||||
#[cfg(feature = "proto-igmp")]
|
#[cfg(feature = "proto-igmp")]
|
||||||
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
let iface_builder = iface_builder.ipv4_multicast_groups(BTreeMap::new());
|
||||||
iface_builder.finalize()
|
iface_builder.finalize()
|
||||||
@ -2985,7 +3315,7 @@ mod test {
|
|||||||
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
|
payload_len: udp_repr.header_len() + UDP_PAYLOAD.len(),
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
},
|
},
|
||||||
data: data,
|
data,
|
||||||
};
|
};
|
||||||
let expected_repr = IpPacket::Icmpv4((
|
let expected_repr = IpPacket::Icmpv4((
|
||||||
Ipv4Repr {
|
Ipv4Repr {
|
||||||
@ -3232,8 +3562,8 @@ mod test {
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
let ip_repr = Ipv6Repr {
|
let ip_repr = Ipv6Repr {
|
||||||
src_addr: src_addr,
|
src_addr,
|
||||||
dst_addr: dst_addr,
|
dst_addr,
|
||||||
next_header: IpProtocol::Udp,
|
next_header: IpProtocol::Udp,
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
|
payload_len: udp_repr.header_len() + MAX_PAYLOAD_LEN,
|
||||||
@ -3468,7 +3798,11 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(feature = "medium-ethernet", feature = "proto-ipv4"))]
|
#[cfg(all(
|
||||||
|
feature = "medium-ethernet",
|
||||||
|
feature = "proto-ipv4",
|
||||||
|
not(feature = "medium-ieee802154")
|
||||||
|
))]
|
||||||
fn test_arp_flush_after_update_ip() {
|
fn test_arp_flush_after_update_ip() {
|
||||||
let mut iface = create_loopback_ethernet();
|
let mut iface = create_loopback_ethernet();
|
||||||
|
|
||||||
|
@ -2059,7 +2059,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sixlowpan_three_fragments() {
|
fn sixlowpan_three_fragments() {
|
||||||
use crate::iface::{FragmentsCache, SixlowpanAssemblerInfo};
|
use crate::iface::FragmentsCache;
|
||||||
use crate::time::Instant;
|
use crate::time::Instant;
|
||||||
use crate::wire::ieee802154::Frame as Ieee802154Frame;
|
use crate::wire::ieee802154::Frame as Ieee802154Frame;
|
||||||
use crate::wire::ieee802154::Repr as Ieee802154Repr;
|
use crate::wire::ieee802154::Repr as Ieee802154Repr;
|
||||||
@ -2106,8 +2106,8 @@ mod test {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.start(
|
.start(
|
||||||
frag.datagram_size() as usize - uncompressed + compressed,
|
frag.datagram_size() as usize - uncompressed + compressed,
|
||||||
SixlowpanAssemblerInfo::new(uncompressed - compressed),
|
|
||||||
Instant::now(),
|
Instant::now(),
|
||||||
|
-((uncompressed - compressed) as isize),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
frags_cache
|
frags_cache
|
||||||
|
Loading…
x
Reference in New Issue
Block a user