Skip to content

Commit 3fbef82

Browse files
authored
Merge pull request #740 from smoltcp-rs/fragmentation-unify
iface: unify ipv4/6lowpan fragmentation.
2 parents c900ffd + a656ab0 commit 3fbef82

File tree

8 files changed

+263
-362
lines changed

8 files changed

+263
-362
lines changed

Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ defmt = [ "dep:defmt", "heapless/defmt", "heapless/defmt-impl" ]
4545
"phy-tuntap_interface" = ["std", "libc", "medium-ethernet"]
4646

4747
"proto-ipv4" = []
48-
"proto-ipv4-fragmentation" = ["proto-ipv4"]
48+
"proto-ipv4-fragmentation" = ["proto-ipv4", "_proto-fragmentation"]
4949
"proto-igmp" = ["proto-ipv4"]
5050
"proto-dhcpv4" = ["proto-ipv4"]
5151
"proto-ipv6" = []
5252
"proto-sixlowpan" = ["proto-ipv6"]
53-
"proto-sixlowpan-fragmentation" = ["proto-sixlowpan"]
53+
"proto-sixlowpan-fragmentation" = ["proto-sixlowpan", "_proto-fragmentation"]
5454
"proto-dns" = []
5555

5656
"socket" = []
@@ -74,6 +74,12 @@ default = [
7474
"async"
7575
]
7676

77+
# Private features
78+
# Features starting with "_" are considered private. They should not be enabled by
79+
# other crates, and they are not considered semver-stable.
80+
81+
"_proto-fragmentation" = []
82+
7783
[[example]]
7884
name = "packet2pcap"
7985
path = "utils/packet2pcap.rs"

src/iface/interface/ethernet.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl InterfaceInner {
1515
&mut self,
1616
sockets: &mut SocketSet,
1717
frame: &'frame T,
18-
_fragments: &'frame mut FragmentsBuffer,
18+
fragments: &'frame mut FragmentsBuffer,
1919
) -> Option<EthernetPacket<'frame>> {
2020
let eth_frame = check!(EthernetFrame::new_checked(frame));
2121

@@ -34,17 +34,8 @@ impl InterfaceInner {
3434
EthernetProtocol::Ipv4 => {
3535
let ipv4_packet = check!(Ipv4Packet::new_checked(eth_frame.payload()));
3636

37-
#[cfg(feature = "proto-ipv4-fragmentation")]
38-
{
39-
self.process_ipv4(sockets, &ipv4_packet, Some(&mut _fragments.ipv4_fragments))
40-
.map(EthernetPacket::Ip)
41-
}
42-
43-
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
44-
{
45-
self.process_ipv4(sockets, &ipv4_packet, None)
46-
.map(EthernetPacket::Ip)
47-
}
37+
self.process_ipv4(sockets, &ipv4_packet, fragments)
38+
.map(EthernetPacket::Ip)
4839
}
4940
#[cfg(feature = "proto-ipv6")]
5041
EthernetProtocol::Ipv6 => {

src/iface/interface/igmp.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ impl Interface {
5151
.ok_or(MulticastError::Exhausted)?;
5252

5353
// NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
54-
self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
54+
self.inner
55+
.dispatch_ip(tx_token, pkt, &mut self.fragmenter)
56+
.unwrap();
5557

5658
Ok(true)
5759
} else {
@@ -91,7 +93,9 @@ impl Interface {
9193
.ok_or(MulticastError::Exhausted)?;
9294

9395
// NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
94-
self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
96+
self.inner
97+
.dispatch_ip(tx_token, pkt, &mut self.fragmenter)
98+
.unwrap();
9599

96100
Ok(true)
97101
} else {
@@ -125,7 +129,9 @@ impl Interface {
125129
// Send initial membership report
126130
if let Some(tx_token) = device.transmit(self.inner.now) {
127131
// NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
128-
self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
132+
self.inner
133+
.dispatch_ip(tx_token, pkt, &mut self.fragmenter)
134+
.unwrap();
129135
} else {
130136
return false;
131137
}
@@ -153,7 +159,9 @@ impl Interface {
153159
// Send initial membership report
154160
if let Some(tx_token) = device.transmit(self.inner.now) {
155161
// NOTE(unwrap): packet destination is multicast, which is always routable and doesn't require neighbor discovery.
156-
self.inner.dispatch_ip(tx_token, pkt, None).unwrap();
162+
self.inner
163+
.dispatch_ip(tx_token, pkt, &mut self.fragmenter)
164+
.unwrap();
157165
} else {
158166
return false;
159167
}

src/iface/interface/ipv4.rs

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
1-
use super::check;
2-
use super::icmp_reply_payload_len;
3-
use super::InterfaceInner;
4-
use super::IpPacket;
5-
use super::PacketAssemblerSet;
6-
use super::SocketSet;
7-
8-
#[cfg(feature = "medium-ethernet")]
9-
use super::EthernetPacket;
10-
11-
#[cfg(feature = "proto-ipv4-fragmentation")]
12-
use super::Ipv4OutPacket;
1+
use super::*;
132

143
#[cfg(feature = "socket-dhcpv4")]
154
use crate::socket::dhcpv4;
@@ -18,16 +7,16 @@ use crate::socket::icmp;
187
use crate::socket::AnySocket;
198

209
use crate::phy::{Medium, TxToken};
21-
use crate::time::{Duration, Instant};
10+
use crate::time::Instant;
2211
use crate::wire::*;
2312

2413
impl InterfaceInner {
25-
pub(super) fn process_ipv4<'output, 'payload: 'output, T: AsRef<[u8]> + ?Sized>(
14+
pub(super) fn process_ipv4<'a, T: AsRef<[u8]> + ?Sized>(
2615
&mut self,
2716
sockets: &mut SocketSet,
28-
ipv4_packet: &Ipv4Packet<&'payload T>,
29-
_fragments: Option<&'output mut PacketAssemblerSet<Ipv4FragKey>>,
30-
) -> Option<IpPacket<'output>> {
17+
ipv4_packet: &Ipv4Packet<&'a T>,
18+
frag: &'a mut FragmentsBuffer,
19+
) -> Option<IpPacket<'a>> {
3120
let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
3221
if !self.is_unicast_v4(ipv4_repr.src_addr) {
3322
// Discard packets with non-unicast source addresses.
@@ -37,14 +26,10 @@ impl InterfaceInner {
3726

3827
#[cfg(feature = "proto-ipv4-fragmentation")]
3928
let ip_payload = {
40-
const REASSEMBLY_TIMEOUT: Duration = Duration::from_secs(90);
41-
42-
let fragments = _fragments.unwrap();
43-
4429
if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
45-
let key = ipv4_packet.get_key();
30+
let key = FragKey::Ipv4(ipv4_packet.get_key());
4631

47-
let f = match fragments.get(&key, self.now + REASSEMBLY_TIMEOUT) {
32+
let f = match frag.assembler.get(&key, self.now + frag.reassembly_timeout) {
4833
Ok(f) => f,
4934
Err(_) => {
5035
net_debug!("No available packet assembler for fragmented packet");
@@ -345,20 +330,16 @@ impl InterfaceInner {
345330
}
346331

347332
#[cfg(feature = "proto-ipv4-fragmentation")]
348-
pub(super) fn dispatch_ipv4_out_packet<Tx: TxToken>(
349-
&mut self,
350-
tx_token: Tx,
351-
pkt: &mut Ipv4OutPacket,
352-
) {
333+
pub(super) fn dispatch_ipv4_frag<Tx: TxToken>(&mut self, tx_token: Tx, frag: &mut Fragmenter) {
353334
let caps = self.caps.clone();
354335

355336
let mtu_max = self.ip_mtu();
356-
let ip_len = (pkt.packet_len - pkt.sent_bytes + pkt.repr.buffer_len()).min(mtu_max);
357-
let payload_len = ip_len - pkt.repr.buffer_len();
337+
let ip_len = (frag.packet_len - frag.sent_bytes + frag.ipv4.repr.buffer_len()).min(mtu_max);
338+
let payload_len = ip_len - frag.ipv4.repr.buffer_len();
358339

359-
let more_frags = (pkt.packet_len - pkt.sent_bytes) != payload_len;
360-
pkt.repr.payload_len = payload_len;
361-
pkt.sent_bytes += payload_len;
340+
let more_frags = (frag.packet_len - frag.sent_bytes) != payload_len;
341+
frag.ipv4.repr.payload_len = payload_len;
342+
frag.sent_bytes += payload_len;
362343

363344
let mut tx_len = ip_len;
364345
#[cfg(feature = "medium-ethernet")]
@@ -373,7 +354,7 @@ impl InterfaceInner {
373354

374355
let src_addr = self.hardware_addr.unwrap().ethernet_or_panic();
375356
frame.set_src_addr(src_addr);
376-
frame.set_dst_addr(pkt.dst_hardware_addr);
357+
frame.set_dst_addr(frag.ipv4.dst_hardware_addr);
377358

378359
match repr.version() {
379360
#[cfg(feature = "proto-ipv4")]
@@ -386,27 +367,29 @@ impl InterfaceInner {
386367
tx_token.consume(tx_len, |mut tx_buffer| {
387368
#[cfg(feature = "medium-ethernet")]
388369
if matches!(self.caps.medium, Medium::Ethernet) {
389-
emit_ethernet(&IpRepr::Ipv4(pkt.repr), tx_buffer);
370+
emit_ethernet(&IpRepr::Ipv4(frag.ipv4.repr), tx_buffer);
390371
tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
391372
}
392373

393-
let mut packet = Ipv4Packet::new_unchecked(&mut tx_buffer[..pkt.repr.buffer_len()]);
394-
pkt.repr.emit(&mut packet, &caps.checksum);
395-
packet.set_ident(pkt.ident);
374+
let mut packet =
375+
Ipv4Packet::new_unchecked(&mut tx_buffer[..frag.ipv4.repr.buffer_len()]);
376+
frag.ipv4.repr.emit(&mut packet, &caps.checksum);
377+
packet.set_ident(frag.ipv4.ident);
396378
packet.set_more_frags(more_frags);
397379
packet.set_dont_frag(false);
398-
packet.set_frag_offset(pkt.frag_offset);
380+
packet.set_frag_offset(frag.ipv4.frag_offset);
399381

400382
if caps.checksum.ipv4.tx() {
401383
packet.fill_checksum();
402384
}
403385

404-
tx_buffer[pkt.repr.buffer_len()..][..payload_len].copy_from_slice(
405-
&pkt.buffer[pkt.frag_offset as usize + pkt.repr.buffer_len()..][..payload_len],
386+
tx_buffer[frag.ipv4.repr.buffer_len()..][..payload_len].copy_from_slice(
387+
&frag.buffer[frag.ipv4.frag_offset as usize + frag.ipv4.repr.buffer_len()..]
388+
[..payload_len],
406389
);
407390

408391
// Update the frag offset for the next fragment.
409-
pkt.frag_offset += payload_len as u16;
392+
frag.ipv4.frag_offset += payload_len as u16;
410393
})
411394
}
412395

0 commit comments

Comments
 (0)