New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for ICMPv6 to ICMP sockets #205
Conversation
src/wire/mod.rs
Outdated
TimeExceeded as IcmpTimeExceeded, | ||
ParamProblem as IcmpParamProblem, | ||
Packet as IcmpPacket, | ||
Repr as IcmpRepr}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning to somehow unify the ICMPv4 and ICMPv6 Message
, DstUnreachable
, TimeExceeded
and ParamProblem
enums? This doesn't seem like the right way to go to me. Why is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it isn't
Other than the comment above, looks good! |
src/iface/ethernet.rs
Outdated
fn process_icmpv4<'frame>(&self, _sockets: &mut SocketSet, ip_repr: IpRepr, | ||
ip_payload: &'frame [u8]) -> Result<Packet<'frame>> | ||
#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))] | ||
fn process_icmp<'frame>(&self, _sockets: &mut SocketSet, ip_repr: IpRepr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ICMPv6 packets will be processed by process_icmpv6
. It has a different IP protocol number.
@@ -174,6 +176,13 @@ pub use self::icmpv6::{Message as Icmpv6Message, | |||
ParamProblem as Icmpv6ParamProblem, | |||
Packet as Icmpv6Packet, | |||
Repr as Icmpv6Repr}; | |||
#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
src/wire/mod.rs
Outdated
@@ -95,6 +95,8 @@ mod ipv6fragment; | |||
mod icmpv4; | |||
#[cfg(feature = "proto-ipv6")] | |||
mod icmpv6; | |||
#[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rely on the icmpv6
module for proto-ipv6
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment by @whitequark here was kind of what I was getting at and is a much clearer. If we get an ICMPv6 response we shouldn't be using the definitions in wire::icmpv4
.
Note: my assumption was that wire::icmp
was the same thing as wire::icmpv4
. If your intent was to make wire::icmp
a module that encapsulates ICMPv4 and ICMPv4 (similar to wire::ip
for IPv4 and IPv6), then your current approach might work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, except that it should be any()
and not all()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True.
OK, now that I see |
Yeah, I started by implementing all the enums before looking at the existing code. I'll remove them |
I'm getting three test failures:
My guess is that the two latter are because the checksum is never computed (which is not an issue for ICMPv4 tests, because ICMPv4 checksums can be blank). I tried solving them, with no success. Any idea? |
Do you know why this results in a Truncated error? |
No. I added a |
Sorry, I don't have time to investigate this right now. Maybe @dlrobertson can help you? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know why this results in a Truncated error?
I think it is returning Truncated
here I'll have to spend some quality time in gdb to confirm.
src/iface/ethernet.rs
Outdated
@@ -828,11 +833,11 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { | |||
|
|||
#[cfg(feature = "proto-ipv4")] | |||
fn process_icmpv4<'frame>(&self, _sockets: &mut SocketSet, ip_repr: IpRepr, | |||
ip_payload: &'frame [u8]) -> Result<Packet<'frame>> | |||
ip_payload: &'frame [u8]) -> Result<Packet<'frame>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: whitespace
src/iface/ethernet.rs
Outdated
{ | ||
let icmp_packet = Icmpv4Packet::new_checked(ip_payload)?; | ||
let checksum_caps = self.device_capabilities.checksum.clone(); | ||
let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &checksum_caps)?; | ||
let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &checksum_caps)?.into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new IcmpRepr
really shouldn't be used in the process_icmpv4
or process_icmpv6
functions. AFAIK it is really only needed for getting data from the socket to the interface, but I don't think it is needed for parsing data from the outside world.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's needed for IcmpSocket::accept
and IcmpSocket::process
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah this is more or less a nit. It might be cleaner to add a line like let socket_repr = IcmpRepr::from(icmp_repr)
then use socket_repr
for the IcmpSocket
functions and then you can still match icmp_repr
and you don't have the extra IcmpRepr::Ipv4(...)
, but this is just a nit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also need to add similar code to process_icmpv6
to ensure any ICMPv6 sockets actually receive data.
src/socket/icmp.rs
Outdated
IpAddress::Ipv6(ipv6_addr) => { | ||
let packet = Icmpv6Packet::new(&*packet_buf); | ||
let src_addr = Ipv6Address::default(); | ||
let repr = Icmpv6Repr::parse(&src_addr.into(), &ipv6_addr.into(), &packet, &ChecksumCapabilities::default())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we expect users to fill in the checksum? Or should we just parse it with ChecksumCapabilities::ignored()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't expect the users to fill in checksum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@progval you might update the corresponding line for ICMPv4 as well https://github.com/m-labs/smoltcp/pull/205/files#diff-7dff2f1b7b74bbfcd78f956578d349d1R308
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really understand what ChecksumCapabilities
mean (should the user of smoltcp verify them? or smoltcp itself? or the hardware?), but using ChecksumCapabilities::ignored
fixed two of the issues, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is essentially used to determine if the parse/emit function should verify/fill the checksum. It is typically used in the context of a device. For example, a device that we can offload IPv4 checksumming on transmit to would have a ChecksumCapabilities
structure with ipv4
equal to TX. However, in this case we don't want to evaluate the checksum so using ChecksumCapabilities::ignored
makes that happen.
Ha, I found why it's truncated, it's because the buffer allocated on the first line of Thanks for suggesting gdb, that's how I found the issue. |
src/wire/icmp.rs
Outdated
} | ||
} | ||
}; | ||
( $class:ident < $typearg:tt > ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only matching arm that is used right? Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, now it is. I think I'll remove the macro altogether, as there is only one class left.
(I just squashed some commits to make the git history cleaner) Looks like everything is working now, thanks for your help! |
Err(_) => false, | ||
} | ||
} | ||
#[cfg(feature = "proto-ipv6")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like these two cases ought to be unified, but not sure if this can be done cleanly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could use a function to factorize the code, but I'm not sure it improves readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of something like
match x {
#[cfg(foo)] Y | #[cfg(bar)] Z => t
}
but I don't know if it works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't
Looks good! Please squash all commits. After that, r=me. |
@m-labs-homu r+ |
📌 Commit 6eb23fa has been approved by |
☀️ Test successful - status-travis |
@progval thanks for working on this! |
Hi,
I started adding support for ICMPv6 to ICMP sockets (see #99 and #103).
Do you have some feedback on my changes (attached to this PR) before I implement it further?
Thanks!