Skip to content

Commit 0025017

Browse files
committed
rebase onto main
1 parent 08c7be0 commit 0025017

17 files changed

Lines changed: 1835 additions & 106 deletions

File tree

benches/bench.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
mod wire {
44
use smoltcp::phy::ChecksumCapabilities;
5-
use smoltcp::wire::{IpAddress, IpProtocol};
5+
use smoltcp::wire::{IPV4_HEADER_LEN, IPV4_MAX_OPTIONS_SIZE, IpAddress, IpProtocol};
66
#[cfg(feature = "proto-ipv4")]
77
use smoltcp::wire::{Ipv4Address, Ipv4Packet, Ipv4Repr};
88
#[cfg(feature = "proto-ipv6")]
@@ -83,8 +83,16 @@ mod wire {
8383
src_addr: Ipv4Address::new(192, 168, 1, 1),
8484
dst_addr: Ipv4Address::new(192, 168, 1, 2),
8585
next_header: IpProtocol::Tcp,
86+
header_len: IPV4_HEADER_LEN,
8687
payload_len: 100,
88+
dscp: 0,
89+
ecn: 0,
90+
ident: 0,
91+
dont_frag: true,
92+
more_frags: false,
93+
frag_offset: 0,
8794
hop_limit: 64,
95+
options: [0u8; IPV4_MAX_OPTIONS_SIZE],
8896
};
8997
let mut bytes = vec![0xa5; repr.buffer_len()];
9098

src/iface/fragmentation.rs

Lines changed: 317 additions & 0 deletions
Large diffs are not rendered by default.

src/iface/interface/ipv4.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use crate::wire::ipv4::MAX_OPTIONS_SIZE;
23

34
impl Interface {
45
/// Process fragments that still need to be sent for IPv4 packets.
@@ -107,6 +108,14 @@ impl InterfaceInner {
107108
return None;
108109
}
109110

111+
// If this is the first fragment, capture the options.
112+
#[cfg(feature = "proto-ipv4-fragmentation")]
113+
if ipv4_packet.frag_offset() == 0 && ipv4_packet.has_options() {
114+
frag.options_buffer[..ipv4_repr.options_len()]
115+
.copy_from_slice(&ipv4_repr.options[..ipv4_repr.options_len()]);
116+
frag.options_len = ipv4_repr.options_len()
117+
}
118+
110119
#[cfg(feature = "proto-ipv4-fragmentation")]
111120
let ip_payload = {
112121
if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
@@ -133,7 +142,9 @@ impl InterfaceInner {
133142
return None;
134143
}
135144

145+
// Returns early if assembly is incomplete.
136146
let payload = f.assemble()?;
147+
137148
// Update the payload length, so that the raw sockets get the correct value.
138149
ipv4_repr.payload_len = payload.len();
139150
payload
@@ -145,6 +156,16 @@ impl InterfaceInner {
145156
#[cfg(not(feature = "proto-ipv4-fragmentation"))]
146157
let ip_payload = ipv4_packet.payload();
147158

159+
#[cfg(feature = "proto-ipv4-fragmentation")]
160+
// The first fragment will by definition have all options. The length of the options it
161+
// contains will be greater than or equal to size of the options in the other fragments.
162+
// Therefore, this is guaranteed to overwrite whatever was captured when the repr object
163+
// parsed the current packet.
164+
if let Err(e) = ipv4_repr.set_options(&frag.options_buffer[..frag.options_len]) {
165+
net_debug!("fragmentation assembler options error: {:?}", e);
166+
return None;
167+
}
168+
148169
let ip_repr = IpRepr::Ipv4(ipv4_repr);
149170

150171
#[cfg(feature = "socket-raw")]
@@ -384,8 +405,16 @@ impl InterfaceInner {
384405
src_addr: ipv4_repr.dst_addr,
385406
dst_addr: ipv4_repr.src_addr,
386407
next_header: IpProtocol::Icmp,
408+
header_len: IPV4_HEADER_LEN,
387409
payload_len: icmp_repr.buffer_len(),
410+
dscp: 0,
411+
ecn: 0,
412+
ident: 0,
413+
dont_frag: true,
414+
more_frags: false,
415+
frag_offset: 0,
388416
hop_limit: 64,
417+
options: [0u8; MAX_OPTIONS_SIZE],
389418
};
390419
Some(Packet::new_ipv4(
391420
ipv4_reply_repr,
@@ -400,8 +429,16 @@ impl InterfaceInner {
400429
src_addr,
401430
dst_addr: ipv4_repr.src_addr,
402431
next_header: IpProtocol::Icmp,
432+
header_len: IPV4_HEADER_LEN,
403433
payload_len: icmp_repr.buffer_len(),
434+
dscp: 0,
435+
ecn: 0,
436+
ident: 0,
437+
dont_frag: true,
438+
more_frags: false,
439+
frag_offset: 0,
404440
hop_limit: 64,
441+
options: [0u8; MAX_OPTIONS_SIZE],
405442
};
406443
Some(Packet::new_ipv4(
407444
ipv4_reply_repr,

src/iface/interface/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ macro_rules! check {
6767
}
6868
};
6969
}
70+
#[cfg(feature = "proto-ipv4")]
71+
use crate::wire::ipv4::MAX_OPTIONS_SIZE;
7072
use check;
7173

7274
/// Result returned by [`Interface::poll`].
@@ -253,6 +255,12 @@ impl Interface {
253255
assembler: PacketAssemblerSet::new(),
254256
#[cfg(feature = "_proto-fragmentation")]
255257
reassembly_timeout: Duration::from_secs(60),
258+
259+
#[cfg(feature = "proto-ipv4-fragmentation")]
260+
options_buffer: [0u8; MAX_OPTIONS_SIZE],
261+
262+
#[cfg(feature = "proto-ipv4-fragmentation")]
263+
options_len: 0,
256264
},
257265
fragmenter: Fragmenter::new(),
258266
inner: InterfaceInner {
@@ -1314,6 +1322,14 @@ impl InterfaceInner {
13141322
// Emit the IP header to the buffer.
13151323
emit_ip(&ip_repr, &mut frag.buffer);
13161324

1325+
// Verify that we can filter the options for the subsequent packets.
1326+
if frag.ipv4.filter_options().is_err() {
1327+
net_debug!(
1328+
"Could not fragment packet because options cannot be filtered. Dropping."
1329+
);
1330+
return Ok(());
1331+
};
1332+
13171333
let mut ipv4_packet = Ipv4Packet::new_unchecked(&mut frag.buffer[..]);
13181334
frag.ipv4.ident = ipv4_id;
13191335
ipv4_packet.set_ident(ipv4_id);
@@ -1394,12 +1410,14 @@ impl InterfaceInner {
13941410

13951411
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13961412
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1397-
enum DispatchError {
1413+
pub enum DispatchError {
13981414
/// No route to dispatch this packet. Retrying won't help unless
13991415
/// configuration is changed.
14001416
NoRoute,
14011417
/// We do have a route to dispatch this packet, but we haven't discovered
14021418
/// the neighbor for it yet. Discovery has been initiated, dispatch
14031419
/// should be retried later.
14041420
NeighborPending,
1421+
/// The packet must be fragmented but there was a parse error.
1422+
CannotFragment,
14051423
}

src/iface/interface/multicast.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use super::{Interface, InterfaceInner};
66
use super::{IpPayload, Packet, check};
77
use crate::config::{IFACE_MAX_ADDR_COUNT, IFACE_MAX_MULTICAST_GROUP_COUNT};
88
use crate::phy::{Device, PacketMeta};
9+
#[cfg(feature = "proto-ipv4")]
10+
use crate::wire::ipv4::MAX_OPTIONS_SIZE;
911
use crate::wire::*;
1012

1113
/// Error type for `join_multicast_group`, `leave_multicast_group`.
@@ -480,7 +482,15 @@ impl InterfaceInner {
480482
dst_addr: group_addr,
481483
next_header: IpProtocol::Igmp,
482484
payload_len: igmp_repr.buffer_len(),
485+
header_len: IPV4_HEADER_LEN,
486+
dscp: 0,
487+
ecn: 0,
488+
ident: 0,
489+
dont_frag: false,
490+
more_frags: false,
491+
frag_offset: 0,
483492
hop_limit: 1,
493+
options: [0u8; MAX_OPTIONS_SIZE],
484494
// [#183](https://github.com/m-labs/smoltcp/issues/183).
485495
},
486496
IpPayload::Igmp(igmp_repr),
@@ -498,7 +508,15 @@ impl InterfaceInner {
498508
dst_addr: IPV4_MULTICAST_ALL_ROUTERS,
499509
next_header: IpProtocol::Igmp,
500510
payload_len: igmp_repr.buffer_len(),
511+
header_len: IPV4_HEADER_LEN,
512+
dscp: 0,
513+
ecn: 0,
514+
ident: 0,
515+
dont_frag: false,
516+
more_frags: false,
517+
frag_offset: 0,
501518
hop_limit: 1,
519+
options: [0u8; MAX_OPTIONS_SIZE],
502520
},
503521
IpPayload::Igmp(igmp_repr),
504522
)

0 commit comments

Comments
 (0)