mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-02 07:10:39 +00:00
change(socket/icmp): split ICMPv4/v6 processing
Splitting the accept and process functions into separate functions for IPv4 and IPv6 allows us to avoid the `IpRepr` enum and instead use the `Ipv4Repr` and `Ipv6Repr` structs directly. This reduces the binary size by 1.5 KiB.
This commit is contained in:
parent
5ee728a579
commit
951b59ba1c
@ -187,11 +187,8 @@ fn main() {
|
||||
remote_addr
|
||||
);
|
||||
icmp_repr.emit(
|
||||
&iface
|
||||
.get_source_address_ipv6(&address)
|
||||
.unwrap()
|
||||
.into_address(),
|
||||
&remote_addr,
|
||||
&iface.get_source_address_ipv6(&address).unwrap(),
|
||||
&address,
|
||||
&mut icmp_packet,
|
||||
&device_caps.checksum,
|
||||
);
|
||||
@ -223,11 +220,8 @@ fn main() {
|
||||
IpAddress::Ipv6(address) => {
|
||||
let icmp_packet = Icmpv6Packet::new_checked(&payload).unwrap();
|
||||
let icmp_repr = Icmpv6Repr::parse(
|
||||
&remote_addr,
|
||||
&iface
|
||||
.get_source_address_ipv6(&address)
|
||||
.unwrap()
|
||||
.into_address(),
|
||||
&address,
|
||||
&iface.get_source_address_ipv6(&address).unwrap(),
|
||||
&icmp_packet,
|
||||
&device_caps.checksum,
|
||||
)
|
||||
|
@ -166,16 +166,13 @@ impl InterfaceInner {
|
||||
if udp_packet.src_port() == dhcp_socket.server_port
|
||||
&& udp_packet.dst_port() == dhcp_socket.client_port
|
||||
{
|
||||
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
||||
let udp_repr = check!(UdpRepr::parse(
|
||||
&udp_packet,
|
||||
&src_addr,
|
||||
&dst_addr,
|
||||
&ipv4_repr.src_addr.into(),
|
||||
&ipv4_repr.dst_addr.into(),
|
||||
&self.caps.checksum
|
||||
));
|
||||
let udp_payload = udp_packet.payload();
|
||||
|
||||
dhcp_socket.process(self, &ipv4_repr, &udp_repr, udp_payload);
|
||||
dhcp_socket.process(self, &ipv4_repr, &udp_repr, udp_packet.payload());
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@ -200,7 +197,7 @@ impl InterfaceInner {
|
||||
}
|
||||
|
||||
match ipv4_repr.next_header {
|
||||
IpProtocol::Icmp => self.process_icmpv4(sockets, ip_repr, ip_payload),
|
||||
IpProtocol::Icmp => self.process_icmpv4(sockets, ipv4_repr, ip_payload),
|
||||
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
IpProtocol::Igmp => self.process_igmp(ipv4_repr, ip_payload),
|
||||
@ -298,7 +295,7 @@ impl InterfaceInner {
|
||||
pub(super) fn process_icmpv4<'frame>(
|
||||
&mut self,
|
||||
_sockets: &mut SocketSet,
|
||||
ip_repr: IpRepr,
|
||||
ip_repr: Ipv4Repr,
|
||||
ip_payload: &'frame [u8],
|
||||
) -> Option<Packet<'frame>> {
|
||||
let icmp_packet = check!(Icmpv4Packet::new_checked(ip_payload));
|
||||
@ -312,8 +309,8 @@ impl InterfaceInner {
|
||||
.items_mut()
|
||||
.filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
|
||||
{
|
||||
if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
|
||||
icmp_socket.process(self, &ip_repr, &icmp_repr.into());
|
||||
if icmp_socket.accepts_v4(self, &ip_repr, &icmp_repr) {
|
||||
icmp_socket.process_v4(self, &ip_repr, &icmp_repr);
|
||||
handled_by_icmp_socket = true;
|
||||
}
|
||||
}
|
||||
@ -331,11 +328,7 @@ impl InterfaceInner {
|
||||
seq_no,
|
||||
data,
|
||||
};
|
||||
match ip_repr {
|
||||
IpRepr::Ipv4(ipv4_repr) => self.icmpv4_reply(ipv4_repr, icmp_reply_repr),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.icmpv4_reply(ip_repr, icmp_reply_repr)
|
||||
}
|
||||
|
||||
// Ignore any echo replies.
|
||||
|
@ -260,7 +260,7 @@ impl InterfaceInner {
|
||||
ip_payload: &'frame [u8],
|
||||
) -> Option<Packet<'frame>> {
|
||||
match nxt_hdr {
|
||||
IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr.into(), ip_payload),
|
||||
IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr, ip_payload),
|
||||
|
||||
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
|
||||
IpProtocol::Udp => self.process_udp(
|
||||
@ -296,13 +296,13 @@ impl InterfaceInner {
|
||||
pub(super) fn process_icmpv6<'frame>(
|
||||
&mut self,
|
||||
_sockets: &mut SocketSet,
|
||||
ip_repr: IpRepr,
|
||||
ip_repr: Ipv6Repr,
|
||||
ip_payload: &'frame [u8],
|
||||
) -> Option<Packet<'frame>> {
|
||||
let icmp_packet = check!(Icmpv6Packet::new_checked(ip_payload));
|
||||
let icmp_repr = check!(Icmpv6Repr::parse(
|
||||
&ip_repr.src_addr(),
|
||||
&ip_repr.dst_addr(),
|
||||
&ip_repr.src_addr,
|
||||
&ip_repr.dst_addr,
|
||||
&icmp_packet,
|
||||
&self.caps.checksum,
|
||||
));
|
||||
@ -317,8 +317,8 @@ impl InterfaceInner {
|
||||
.items_mut()
|
||||
.filter_map(|i| IcmpSocket::downcast_mut(&mut i.socket))
|
||||
{
|
||||
if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
|
||||
icmp_socket.process(self, &ip_repr, &icmp_repr.into());
|
||||
if icmp_socket.accepts_v6(self, &ip_repr, &icmp_repr) {
|
||||
icmp_socket.process_v6(self, &ip_repr, &icmp_repr);
|
||||
handled_by_icmp_socket = true;
|
||||
}
|
||||
}
|
||||
@ -330,35 +330,27 @@ impl InterfaceInner {
|
||||
ident,
|
||||
seq_no,
|
||||
data,
|
||||
} => match ip_repr {
|
||||
IpRepr::Ipv6(ipv6_repr) => {
|
||||
let icmp_reply_repr = Icmpv6Repr::EchoReply {
|
||||
ident,
|
||||
seq_no,
|
||||
data,
|
||||
};
|
||||
self.icmpv6_reply(ipv6_repr, icmp_reply_repr)
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
},
|
||||
} => {
|
||||
let icmp_reply_repr = Icmpv6Repr::EchoReply {
|
||||
ident,
|
||||
seq_no,
|
||||
data,
|
||||
};
|
||||
self.icmpv6_reply(ip_repr, icmp_reply_repr)
|
||||
}
|
||||
|
||||
// Ignore any echo replies.
|
||||
Icmpv6Repr::EchoReply { .. } => None,
|
||||
|
||||
// Forward any NDISC packets to the ndisc packet handler
|
||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||
Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit() == 0xff => match ip_repr {
|
||||
IpRepr::Ipv6(ipv6_repr) => match self.caps.medium {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => self.process_ndisc(ipv6_repr, repr),
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
Medium::Ieee802154 => self.process_ndisc(ipv6_repr, repr),
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => None,
|
||||
},
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit == 0xff => match self.caps.medium {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => self.process_ndisc(ip_repr, repr),
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
Medium::Ieee802154 => self.process_ndisc(ip_repr, repr),
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => None,
|
||||
},
|
||||
|
||||
// Don't report an error if a packet with unknown type
|
||||
|
@ -508,8 +508,8 @@ impl InterfaceInner {
|
||||
match &mut packet.payload {
|
||||
IpPayload::Icmpv6(icmp_repr) => {
|
||||
icmp_repr.emit(
|
||||
&packet.header.src_addr.into(),
|
||||
&packet.header.dst_addr.into(),
|
||||
&packet.header.src_addr,
|
||||
&packet.header.dst_addr,
|
||||
&mut Icmpv6Packet::new_unchecked(&mut buffer[..icmp_repr.buffer_len()]),
|
||||
checksum_caps,
|
||||
);
|
||||
|
@ -565,7 +565,6 @@ fn test_icmpv4_socket(#[case] medium: Medium) {
|
||||
payload_len: 24,
|
||||
hop_limit: 64,
|
||||
};
|
||||
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
||||
|
||||
// Open a socket and ensure the packet is handled due to the listening
|
||||
// socket.
|
||||
@ -583,7 +582,9 @@ fn test_icmpv4_socket(#[case] medium: Medium) {
|
||||
..ipv4_repr
|
||||
};
|
||||
assert_eq!(
|
||||
iface.inner.process_icmpv4(&mut sockets, ip_repr, icmp_data),
|
||||
iface
|
||||
.inner
|
||||
.process_icmpv4(&mut sockets, ipv4_repr, icmp_data),
|
||||
Some(Packet::new_ipv4(ipv4_reply, IpPayload::Icmpv4(echo_reply)))
|
||||
);
|
||||
|
||||
|
@ -16,8 +16,8 @@ fn parse_ipv6(data: &[u8]) -> crate::wire::Result<Packet<'_>> {
|
||||
IpProtocol::IpSecAh => todo!(),
|
||||
IpProtocol::Icmpv6 => {
|
||||
let icmp = Icmpv6Repr::parse(
|
||||
&ipv6.src_addr.into(),
|
||||
&ipv6.dst_addr.into(),
|
||||
&ipv6.src_addr,
|
||||
&ipv6.dst_addr,
|
||||
&Icmpv6Packet::new_checked(ipv6_header.payload())?,
|
||||
&Default::default(),
|
||||
)?;
|
||||
@ -707,8 +707,8 @@ fn test_handle_valid_ndisc_request(#[case] medium: Medium) {
|
||||
frame.set_ethertype(EthernetProtocol::Ipv6);
|
||||
ip_repr.emit(frame.payload_mut(), &ChecksumCapabilities::default());
|
||||
solicit.emit(
|
||||
&remote_ip_addr.into(),
|
||||
&local_ip_addr.solicited_node().into(),
|
||||
&remote_ip_addr,
|
||||
&local_ip_addr.solicited_node(),
|
||||
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.header_len()..]),
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
|
@ -163,7 +163,10 @@ impl Cache {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_IP_ADDR_4};
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
use crate::wire::ipv4::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_IP_ADDR_4};
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
use crate::wire::ipv6::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_IP_ADDR_4};
|
||||
|
||||
use crate::wire::EthernetAddress;
|
||||
|
||||
@ -177,30 +180,30 @@ mod test {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::Found(HADDR_A)
|
||||
);
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
assert!(!cache
|
||||
.lookup(
|
||||
&MOCK_IP_ADDR_1,
|
||||
&MOCK_IP_ADDR_1.into(),
|
||||
Instant::from_millis(0) + Cache::ENTRY_LIFETIME * 2
|
||||
)
|
||||
.found(),);
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(0));
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
}
|
||||
|
||||
@ -208,14 +211,14 @@ mod test {
|
||||
fn test_expire() {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::Found(HADDR_A)
|
||||
);
|
||||
assert!(!cache
|
||||
.lookup(
|
||||
&MOCK_IP_ADDR_1,
|
||||
&MOCK_IP_ADDR_1.into(),
|
||||
Instant::from_millis(0) + Cache::ENTRY_LIFETIME * 2
|
||||
)
|
||||
.found(),);
|
||||
@ -225,14 +228,14 @@ mod test {
|
||||
fn test_replace() {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::Found(HADDR_A)
|
||||
);
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_B, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_B, Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::Found(HADDR_B)
|
||||
);
|
||||
}
|
||||
@ -241,23 +244,23 @@ mod test {
|
||||
fn test_evict() {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(100));
|
||||
cache.fill(MOCK_IP_ADDR_2, HADDR_B, Instant::from_millis(50));
|
||||
cache.fill(MOCK_IP_ADDR_3, HADDR_C, Instant::from_millis(200));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(100));
|
||||
cache.fill(MOCK_IP_ADDR_2.into(), HADDR_B, Instant::from_millis(50));
|
||||
cache.fill(MOCK_IP_ADDR_3.into(), HADDR_C, Instant::from_millis(200));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(1000)),
|
||||
cache.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(1000)),
|
||||
Answer::Found(HADDR_B)
|
||||
);
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_4, Instant::from_millis(1000))
|
||||
.lookup(&MOCK_IP_ADDR_4.into(), Instant::from_millis(1000))
|
||||
.found());
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_4, HADDR_D, Instant::from_millis(300));
|
||||
cache.fill(MOCK_IP_ADDR_4.into(), HADDR_D, Instant::from_millis(300));
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(1000))
|
||||
.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(1000))
|
||||
.found());
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_4, Instant::from_millis(1000)),
|
||||
cache.lookup(&MOCK_IP_ADDR_4.into(), Instant::from_millis(1000)),
|
||||
Answer::Found(HADDR_D)
|
||||
);
|
||||
}
|
||||
@ -267,17 +270,17 @@ mod test {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::NotFound
|
||||
);
|
||||
|
||||
cache.limit_rate(Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(100)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(100)),
|
||||
Answer::RateLimited
|
||||
);
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(2000)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(2000)),
|
||||
Answer::NotFound
|
||||
);
|
||||
}
|
||||
@ -286,21 +289,21 @@ mod test {
|
||||
fn test_flush() {
|
||||
let mut cache = Cache::new();
|
||||
|
||||
cache.fill(MOCK_IP_ADDR_1, HADDR_A, Instant::from_millis(0));
|
||||
cache.fill(MOCK_IP_ADDR_1.into(), HADDR_A, Instant::from_millis(0));
|
||||
assert_eq!(
|
||||
cache.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0)),
|
||||
cache.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0)),
|
||||
Answer::Found(HADDR_A)
|
||||
);
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_2, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_2.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
|
||||
cache.flush();
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
assert!(!cache
|
||||
.lookup(&MOCK_IP_ADDR_1, Instant::from_millis(0))
|
||||
.lookup(&MOCK_IP_ADDR_1.into(), Instant::from_millis(0))
|
||||
.found());
|
||||
}
|
||||
}
|
||||
|
@ -84,12 +84,20 @@ impl<'p> Packet<'p> {
|
||||
#[cfg(feature = "proto-igmp")]
|
||||
IpPayload::Igmp(igmp_repr) => igmp_repr.emit(&mut IgmpPacket::new_unchecked(payload)),
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IpPayload::Icmpv6(icmpv6_repr) => icmpv6_repr.emit(
|
||||
&_ip_repr.src_addr(),
|
||||
&_ip_repr.dst_addr(),
|
||||
&mut Icmpv6Packet::new_unchecked(payload),
|
||||
&caps.checksum,
|
||||
),
|
||||
IpPayload::Icmpv6(icmpv6_repr) => {
|
||||
let ipv6_repr = match _ip_repr {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IpRepr::Ipv4(_) => unreachable!(),
|
||||
IpRepr::Ipv6(repr) => repr,
|
||||
};
|
||||
|
||||
icmpv6_repr.emit(
|
||||
&ipv6_repr.src_addr,
|
||||
&ipv6_repr.dst_addr,
|
||||
&mut Icmpv6Packet::new_unchecked(payload),
|
||||
&caps.checksum,
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "socket-raw")]
|
||||
IpPayload::Raw(raw_packet) => payload.copy_from_slice(raw_packet),
|
||||
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
|
||||
|
@ -412,41 +412,68 @@ impl<'a> Socket<'a> {
|
||||
Ok((length, endpoint))
|
||||
}
|
||||
|
||||
/// Filter determining which packets received by the interface are appended to
|
||||
/// the given sockets received buffer.
|
||||
pub(crate) fn accepts(&self, cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) -> bool {
|
||||
/// Fitler determining whether the socket accepts a given ICMPv4 packet.
|
||||
/// Accepted packets are enqueued into the socket's receive buffer.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
#[inline]
|
||||
pub(crate) fn accepts_v4(
|
||||
&self,
|
||||
cx: &mut Context,
|
||||
ip_repr: &Ipv4Repr,
|
||||
icmp_repr: &Icmpv4Repr,
|
||||
) -> bool {
|
||||
match (&self.endpoint, icmp_repr) {
|
||||
// If we are bound to ICMP errors associated to a UDP port, only
|
||||
// accept Destination Unreachable or Time Exceeded messages with
|
||||
// the data containing a UDP packet send from the local port we
|
||||
// are bound to.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
(
|
||||
&Endpoint::Udp(endpoint),
|
||||
&IcmpRepr::Ipv4(
|
||||
Icmpv4Repr::DstUnreachable { data, header, .. }
|
||||
| Icmpv4Repr::TimeExceeded { data, header, .. },
|
||||
),
|
||||
) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => {
|
||||
let packet = UdpPacket::new_unchecked(data);
|
||||
match UdpRepr::parse(
|
||||
&packet,
|
||||
&header.src_addr.into(),
|
||||
&header.dst_addr.into(),
|
||||
&cx.checksum_caps(),
|
||||
) {
|
||||
Ok(repr) => endpoint.port == repr.src_port,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
(
|
||||
&Endpoint::Udp(endpoint),
|
||||
&IcmpRepr::Ipv6(
|
||||
Icmpv6Repr::DstUnreachable { data, header, .. }
|
||||
| Icmpv6Repr::TimeExceeded { data, header, .. },
|
||||
),
|
||||
) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr()) => {
|
||||
&Icmpv4Repr::DstUnreachable { data, header, .. }
|
||||
| &Icmpv4Repr::TimeExceeded { data, header, .. },
|
||||
) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr.into()) => {
|
||||
let packet = UdpPacket::new_unchecked(data);
|
||||
match UdpRepr::parse(
|
||||
&packet,
|
||||
&header.src_addr.into(),
|
||||
&header.dst_addr.into(),
|
||||
&cx.checksum_caps(),
|
||||
) {
|
||||
Ok(repr) => endpoint.port == repr.src_port,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
// If we are bound to a specific ICMP identifier value, only accept an
|
||||
// Echo Request/Reply with the identifier field matching the endpoint
|
||||
// port.
|
||||
(&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoRequest { ident, .. })
|
||||
| (&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoReply { ident, .. }) => {
|
||||
ident == bound_ident
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fitler determining whether the socket accepts a given ICMPv6 packet.
|
||||
/// Accepted packets are enqueued into the socket's receive buffer.
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
#[inline]
|
||||
pub(crate) fn accepts_v6(
|
||||
&self,
|
||||
cx: &mut Context,
|
||||
ip_repr: &Ipv6Repr,
|
||||
icmp_repr: &Icmpv6Repr,
|
||||
) -> bool {
|
||||
match (&self.endpoint, icmp_repr) {
|
||||
// If we are bound to ICMP errors associated to a UDP port, only
|
||||
// accept Destination Unreachable or Time Exceeded messages with
|
||||
// the data containing a UDP packet send from the local port we
|
||||
// are bound to.
|
||||
(
|
||||
&Endpoint::Udp(endpoint),
|
||||
&Icmpv6Repr::DstUnreachable { data, header, .. }
|
||||
| &Icmpv6Repr::TimeExceeded { data, header, .. },
|
||||
) if endpoint.addr.is_none() || endpoint.addr == Some(ip_repr.dst_addr.into()) => {
|
||||
let packet = UdpPacket::new_unchecked(data);
|
||||
match UdpRepr::parse(
|
||||
&packet,
|
||||
@ -461,64 +488,60 @@ impl<'a> Socket<'a> {
|
||||
// If we are bound to a specific ICMP identifier value, only accept an
|
||||
// Echo Request/Reply with the identifier field matching the endpoint
|
||||
// port.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
(
|
||||
&Endpoint::Ident(bound_ident),
|
||||
&IcmpRepr::Ipv4(Icmpv4Repr::EchoRequest { ident, .. }),
|
||||
)
|
||||
| (
|
||||
&Endpoint::Ident(bound_ident),
|
||||
&IcmpRepr::Ipv4(Icmpv4Repr::EchoReply { ident, .. }),
|
||||
) => ident == bound_ident,
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
(
|
||||
&Endpoint::Ident(bound_ident),
|
||||
&IcmpRepr::Ipv6(Icmpv6Repr::EchoRequest { ident, .. }),
|
||||
)
|
||||
| (
|
||||
&Endpoint::Ident(bound_ident),
|
||||
&IcmpRepr::Ipv6(Icmpv6Repr::EchoReply { ident, .. }),
|
||||
&Icmpv6Repr::EchoRequest { ident, .. } | &Icmpv6Repr::EchoReply { ident, .. },
|
||||
) => ident == bound_ident,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn process(&mut self, _cx: &mut Context, ip_repr: &IpRepr, icmp_repr: &IcmpRepr) {
|
||||
match icmp_repr {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
IcmpRepr::Ipv4(icmp_repr) => {
|
||||
net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub(crate) fn process_v4(
|
||||
&mut self,
|
||||
_cx: &mut Context,
|
||||
ip_repr: &Ipv4Repr,
|
||||
icmp_repr: &Icmpv4Repr,
|
||||
) {
|
||||
net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
|
||||
|
||||
match self
|
||||
.rx_buffer
|
||||
.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
|
||||
{
|
||||
Ok(packet_buf) => {
|
||||
icmp_repr.emit(
|
||||
&mut Icmpv4Packet::new_unchecked(packet_buf),
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
}
|
||||
Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
|
||||
}
|
||||
match self
|
||||
.rx_buffer
|
||||
.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr.into())
|
||||
{
|
||||
Ok(packet_buf) => {
|
||||
icmp_repr.emit(
|
||||
&mut Icmpv4Packet::new_unchecked(packet_buf),
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
IcmpRepr::Ipv6(icmp_repr) => {
|
||||
net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
|
||||
Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
|
||||
}
|
||||
|
||||
match self
|
||||
.rx_buffer
|
||||
.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())
|
||||
{
|
||||
Ok(packet_buf) => icmp_repr.emit(
|
||||
&ip_repr.src_addr(),
|
||||
&ip_repr.dst_addr(),
|
||||
&mut Icmpv6Packet::new_unchecked(packet_buf),
|
||||
&ChecksumCapabilities::default(),
|
||||
),
|
||||
Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "async")]
|
||||
self.rx_waker.wake();
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) fn process_v6(
|
||||
&mut self,
|
||||
_cx: &mut Context,
|
||||
ip_repr: &Ipv6Repr,
|
||||
icmp_repr: &Icmpv6Repr,
|
||||
) {
|
||||
net_trace!("icmp: receiving {} octets", icmp_repr.buffer_len());
|
||||
|
||||
match self
|
||||
.rx_buffer
|
||||
.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr.into())
|
||||
{
|
||||
Ok(packet_buf) => icmp_repr.emit(
|
||||
&ip_repr.src_addr,
|
||||
&ip_repr.dst_addr,
|
||||
&mut Icmpv6Packet::new_unchecked(packet_buf),
|
||||
&ChecksumCapabilities::default(),
|
||||
),
|
||||
Err(_) => net_trace!("icmp: buffer full, dropped incoming packet"),
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
@ -583,8 +606,8 @@ impl<'a> Socket<'a> {
|
||||
};
|
||||
let packet = Icmpv6Packet::new_unchecked(&*packet_buf);
|
||||
let repr = match Icmpv6Repr::parse(
|
||||
&src_addr.into(),
|
||||
&dst_addr.into(),
|
||||
&src_addr,
|
||||
&dst_addr,
|
||||
&packet,
|
||||
&ChecksumCapabilities::ignored(),
|
||||
) {
|
||||
@ -684,13 +707,13 @@ mod test_ipv4 {
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
|
||||
static REMOTE_IPV4_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr {
|
||||
static REMOTE_IPV4_REPR: Ipv4Repr = Ipv4Repr {
|
||||
src_addr: REMOTE_IPV4,
|
||||
dst_addr: LOCAL_IPV4,
|
||||
next_header: IpProtocol::Icmp,
|
||||
payload_len: 24,
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_send_unaddressable() {
|
||||
@ -816,12 +839,12 @@ mod test_ipv4 {
|
||||
ECHOV4_REPR.emit(&mut packet, &checksum);
|
||||
let data = &*packet.into_inner();
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
|
||||
assert!(socket.accepts_v4(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR));
|
||||
socket.process_v4(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR);
|
||||
assert!(socket.can_recv());
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
|
||||
assert!(socket.accepts_v4(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR));
|
||||
socket.process_v4(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR);
|
||||
|
||||
assert_eq!(socket.recv(), Ok((data, REMOTE_IPV4.into())));
|
||||
assert!(!socket.can_recv());
|
||||
@ -849,7 +872,7 @@ mod test_ipv4 {
|
||||
|
||||
// Ensure that a packet with an identifier that isn't the bound
|
||||
// ID is not accepted
|
||||
assert!(!socket.accepts(cx, &REMOTE_IPV4_REPR, &icmp_repr.into()));
|
||||
assert!(!socket.accepts_v4(cx, &REMOTE_IPV4_REPR, &icmp_repr));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@ -888,20 +911,20 @@ mod test_ipv4 {
|
||||
},
|
||||
data,
|
||||
};
|
||||
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
|
||||
let ip_repr = Ipv4Repr {
|
||||
src_addr: REMOTE_IPV4,
|
||||
dst_addr: LOCAL_IPV4,
|
||||
next_header: IpProtocol::Icmp,
|
||||
payload_len: icmp_repr.buffer_len(),
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
};
|
||||
|
||||
assert!(!socket.can_recv());
|
||||
|
||||
// Ensure we can accept ICMP error response to the bound
|
||||
// UDP port
|
||||
assert!(socket.accepts(cx, &ip_repr, &icmp_repr.into()));
|
||||
socket.process(cx, &ip_repr, &icmp_repr.into());
|
||||
assert!(socket.accepts_v4(cx, &ip_repr, &icmp_repr));
|
||||
socket.process_v4(cx, &ip_repr, &icmp_repr);
|
||||
assert!(socket.can_recv());
|
||||
|
||||
let mut bytes = [0x00; 46];
|
||||
@ -939,21 +962,21 @@ mod test_ipv6 {
|
||||
data: &[0xff; 16],
|
||||
};
|
||||
|
||||
static LOCAL_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
|
||||
static LOCAL_IPV6_REPR: Ipv6Repr = Ipv6Repr {
|
||||
src_addr: LOCAL_IPV6,
|
||||
dst_addr: REMOTE_IPV6,
|
||||
next_header: IpProtocol::Icmpv6,
|
||||
payload_len: 24,
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
};
|
||||
|
||||
static REMOTE_IPV6_REPR: IpRepr = IpRepr::Ipv6(Ipv6Repr {
|
||||
static REMOTE_IPV6_REPR: Ipv6Repr = Ipv6Repr {
|
||||
src_addr: REMOTE_IPV6,
|
||||
dst_addr: LOCAL_IPV6,
|
||||
next_header: IpProtocol::Icmpv6,
|
||||
payload_len: 24,
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_send_unaddressable() {
|
||||
@ -986,12 +1009,7 @@ mod test_ipv6 {
|
||||
|
||||
let mut bytes = vec![0xff; 24];
|
||||
let mut packet = Icmpv6Packet::new_unchecked(&mut bytes);
|
||||
ECHOV6_REPR.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
ECHOV6_REPR.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
|
||||
assert_eq!(
|
||||
socket.send_slice(&*packet.into_inner(), REMOTE_IPV6.into()),
|
||||
@ -1005,7 +1023,7 @@ mod test_ipv6 {
|
||||
|
||||
assert_eq!(
|
||||
socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
|
||||
assert_eq!(ip_repr, LOCAL_IPV6_REPR);
|
||||
assert_eq!(ip_repr, LOCAL_IPV6_REPR.into());
|
||||
assert_eq!(icmp_repr, ECHOV6_REPR.into());
|
||||
Err(())
|
||||
}),
|
||||
@ -1016,7 +1034,7 @@ mod test_ipv6 {
|
||||
|
||||
assert_eq!(
|
||||
socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
|
||||
assert_eq!(ip_repr, LOCAL_IPV6_REPR);
|
||||
assert_eq!(ip_repr, LOCAL_IPV6_REPR.into());
|
||||
assert_eq!(icmp_repr, ECHOV6_REPR.into());
|
||||
Ok::<_, ()>(())
|
||||
}),
|
||||
@ -1038,12 +1056,7 @@ mod test_ipv6 {
|
||||
|
||||
let mut bytes = vec![0xff; 24];
|
||||
let mut packet = Icmpv6Packet::new_unchecked(&mut bytes);
|
||||
ECHOV6_REPR.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
ECHOV6_REPR.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
|
||||
s.set_hop_limit(Some(0x2a));
|
||||
|
||||
@ -1086,20 +1099,15 @@ mod test_ipv6 {
|
||||
|
||||
let mut bytes = [0xff; 24];
|
||||
let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]);
|
||||
ECHOV6_REPR.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
ECHOV6_REPR.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
let data = &*packet.into_inner();
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
|
||||
assert!(socket.accepts_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR));
|
||||
socket.process_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR);
|
||||
assert!(socket.can_recv());
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
|
||||
assert!(socket.accepts_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR));
|
||||
socket.process_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR);
|
||||
|
||||
assert_eq!(socket.recv(), Ok((data, REMOTE_IPV6.into())));
|
||||
assert!(!socket.can_recv());
|
||||
@ -1119,19 +1127,14 @@ mod test_ipv6 {
|
||||
|
||||
let mut bytes = [0xff; 24];
|
||||
let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]);
|
||||
ECHOV6_REPR.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
ECHOV6_REPR.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
|
||||
assert!(socket.accepts_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR));
|
||||
socket.process_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR);
|
||||
assert!(socket.can_recv());
|
||||
|
||||
assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
|
||||
socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
|
||||
assert!(socket.accepts_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR));
|
||||
socket.process_v6(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR);
|
||||
|
||||
let mut buffer = [0u8; 1];
|
||||
assert_eq!(
|
||||
@ -1159,16 +1162,11 @@ mod test_ipv6 {
|
||||
seq_no: 0x5678,
|
||||
data: &[0xff; 16],
|
||||
};
|
||||
icmp_repr.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
icmp_repr.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
|
||||
// Ensure that a packet with an identifier that isn't the bound
|
||||
// ID is not accepted
|
||||
assert!(!socket.accepts(cx, &REMOTE_IPV6_REPR, &icmp_repr.into()));
|
||||
assert!(!socket.accepts_v6(cx, &REMOTE_IPV6_REPR, &icmp_repr));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@ -1207,30 +1205,25 @@ mod test_ipv6 {
|
||||
},
|
||||
data,
|
||||
};
|
||||
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
|
||||
let ip_repr = Ipv6Repr {
|
||||
src_addr: REMOTE_IPV6,
|
||||
dst_addr: LOCAL_IPV6,
|
||||
next_header: IpProtocol::Icmpv6,
|
||||
payload_len: icmp_repr.buffer_len(),
|
||||
hop_limit: 0x40,
|
||||
});
|
||||
};
|
||||
|
||||
assert!(!socket.can_recv());
|
||||
|
||||
// Ensure we can accept ICMP error response to the bound
|
||||
// UDP port
|
||||
assert!(socket.accepts(cx, &ip_repr, &icmp_repr.into()));
|
||||
socket.process(cx, &ip_repr, &icmp_repr.into());
|
||||
assert!(socket.accepts_v6(cx, &ip_repr, &icmp_repr));
|
||||
socket.process_v6(cx, &ip_repr, &icmp_repr);
|
||||
assert!(socket.can_recv());
|
||||
|
||||
let mut bytes = [0x00; 66];
|
||||
let mut packet = Icmpv6Packet::new_unchecked(&mut bytes[..]);
|
||||
icmp_repr.emit(
|
||||
&LOCAL_IPV6.into(),
|
||||
&REMOTE_IPV6.into(),
|
||||
&mut packet,
|
||||
&checksum,
|
||||
);
|
||||
icmp_repr.emit(&LOCAL_IPV6, &REMOTE_IPV6, &mut packet, &checksum);
|
||||
assert_eq!(
|
||||
socket.recv(),
|
||||
Ok((&*packet.into_inner(), REMOTE_IPV6.into()))
|
||||
|
@ -9,7 +9,7 @@ use crate::wire::MldRepr;
|
||||
use crate::wire::NdiscRepr;
|
||||
#[cfg(feature = "proto-rpl")]
|
||||
use crate::wire::RplRepr;
|
||||
use crate::wire::{IpAddress, IpProtocol, Ipv6Packet, Ipv6Repr};
|
||||
use crate::wire::{IpProtocol, Ipv6Address, Ipv6Packet, Ipv6Repr};
|
||||
use crate::wire::{IPV6_HEADER_LEN, IPV6_MIN_MTU};
|
||||
|
||||
/// Error packets must not exceed min MTU
|
||||
@ -421,14 +421,14 @@ impl<T: AsRef<[u8]>> Packet<T> {
|
||||
///
|
||||
/// # Fuzzing
|
||||
/// This function always returns `true` when fuzzing.
|
||||
pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
|
||||
pub fn verify_checksum(&self, src_addr: &Ipv6Address, dst_addr: &Ipv6Address) -> bool {
|
||||
if cfg!(fuzzing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let data = self.buffer.as_ref();
|
||||
checksum::combine(&[
|
||||
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6, data.len() as u32),
|
||||
checksum::pseudo_header_v6(src_addr, dst_addr, IpProtocol::Icmpv6, data.len() as u32),
|
||||
checksum::data(data),
|
||||
]) == !0
|
||||
}
|
||||
@ -535,12 +535,17 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
||||
}
|
||||
|
||||
/// Compute and fill in the header checksum.
|
||||
pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) {
|
||||
pub fn fill_checksum(&mut self, src_addr: &Ipv6Address, dst_addr: &Ipv6Address) {
|
||||
self.set_checksum(0);
|
||||
let checksum = {
|
||||
let data = self.buffer.as_ref();
|
||||
!checksum::combine(&[
|
||||
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6, data.len() as u32),
|
||||
checksum::pseudo_header_v6(
|
||||
src_addr,
|
||||
dst_addr,
|
||||
IpProtocol::Icmpv6,
|
||||
data.len() as u32,
|
||||
),
|
||||
checksum::data(data),
|
||||
])
|
||||
};
|
||||
@ -609,8 +614,8 @@ impl<'a> Repr<'a> {
|
||||
/// Parse an Internet Control Message Protocol version 6 packet and return
|
||||
/// a high-level representation.
|
||||
pub fn parse<T>(
|
||||
src_addr: &IpAddress,
|
||||
dst_addr: &IpAddress,
|
||||
src_addr: &Ipv6Address,
|
||||
dst_addr: &Ipv6Address,
|
||||
packet: &Packet<&'a T>,
|
||||
checksum_caps: &ChecksumCapabilities,
|
||||
) -> Result<Repr<'a>>
|
||||
@ -725,8 +730,8 @@ impl<'a> Repr<'a> {
|
||||
/// packet.
|
||||
pub fn emit<T>(
|
||||
&self,
|
||||
src_addr: &IpAddress,
|
||||
dst_addr: &IpAddress,
|
||||
src_addr: &Ipv6Address,
|
||||
dst_addr: &Ipv6Address,
|
||||
packet: &mut Packet<&mut T>,
|
||||
checksum_caps: &ChecksumCapabilities,
|
||||
) where
|
||||
@ -840,9 +845,13 @@ impl<'a> Repr<'a> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
|
||||
use crate::wire::{IpProtocol, Ipv6Address, Ipv6Repr};
|
||||
|
||||
const MOCK_IP_ADDR_1: Ipv6Address =
|
||||
Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
const MOCK_IP_ADDR_2: Ipv6Address =
|
||||
Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||
|
||||
static ECHO_PACKET_BYTES: [u8; 12] = [
|
||||
0x80, 0x00, 0x19, 0xb3, 0x12, 0x34, 0xab, 0xcd, 0xaa, 0x00, 0x00, 0xff,
|
||||
];
|
||||
|
@ -753,7 +753,42 @@ pub mod checksum {
|
||||
propagate_carries(accum)
|
||||
}
|
||||
|
||||
/// Compute an IP pseudo header checksum.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub fn pseudo_header_v4(
|
||||
src_addr: &Ipv4Address,
|
||||
dst_addr: &Ipv4Address,
|
||||
next_header: Protocol,
|
||||
length: u32,
|
||||
) -> u16 {
|
||||
let mut proto_len = [0u8; 4];
|
||||
proto_len[1] = next_header.into();
|
||||
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
|
||||
|
||||
combine(&[
|
||||
data(src_addr.as_bytes()),
|
||||
data(dst_addr.as_bytes()),
|
||||
data(&proto_len[..]),
|
||||
])
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub fn pseudo_header_v6(
|
||||
src_addr: &Ipv6Address,
|
||||
dst_addr: &Ipv6Address,
|
||||
next_header: Protocol,
|
||||
length: u32,
|
||||
) -> u16 {
|
||||
let mut proto_len = [0u8; 4];
|
||||
proto_len[1] = next_header.into();
|
||||
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
|
||||
|
||||
combine(&[
|
||||
data(src_addr.as_bytes()),
|
||||
data(dst_addr.as_bytes()),
|
||||
data(&proto_len[..]),
|
||||
])
|
||||
}
|
||||
|
||||
pub fn pseudo_header(
|
||||
src_addr: &Address,
|
||||
dst_addr: &Address,
|
||||
@ -762,32 +797,15 @@ pub mod checksum {
|
||||
) -> u16 {
|
||||
match (src_addr, dst_addr) {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
(&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
|
||||
let mut proto_len = [0u8; 4];
|
||||
proto_len[1] = next_header.into();
|
||||
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
|
||||
|
||||
combine(&[
|
||||
data(src_addr.as_bytes()),
|
||||
data(dst_addr.as_bytes()),
|
||||
data(&proto_len[..]),
|
||||
])
|
||||
(Address::Ipv4(src_addr), Address::Ipv4(dst_addr)) => {
|
||||
pseudo_header_v4(src_addr, dst_addr, next_header, length)
|
||||
}
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
(&Address::Ipv6(src_addr), &Address::Ipv6(dst_addr)) => {
|
||||
let mut proto_len = [0u8; 8];
|
||||
proto_len[7] = next_header.into();
|
||||
NetworkEndian::write_u32(&mut proto_len[0..4], length);
|
||||
combine(&[
|
||||
data(src_addr.as_bytes()),
|
||||
data(dst_addr.as_bytes()),
|
||||
data(&proto_len[..]),
|
||||
])
|
||||
(Address::Ipv6(src_addr), Address::Ipv6(dst_addr)) => {
|
||||
pseudo_header_v6(src_addr, dst_addr, next_header, length)
|
||||
}
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!("Unexpected pseudo header addresses: {src_addr}, {dst_addr}"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -882,36 +900,6 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(
|
||||
pub(crate) mod test {
|
||||
#![allow(unused)]
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv6(Ipv6Address([
|
||||
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
]));
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv6(Ipv6Address([
|
||||
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
|
||||
]));
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv6(Ipv6Address([
|
||||
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
|
||||
]));
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv6(Ipv6Address([
|
||||
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
|
||||
]));
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv6(Ipv6Address::UNSPECIFIED);
|
||||
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 3]));
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 4]));
|
||||
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||
pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv4(Ipv4Address::UNSPECIFIED);
|
||||
|
||||
use super::*;
|
||||
use crate::wire::{IpAddress, IpCidr, IpProtocol};
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
|
@ -796,9 +796,20 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
pub(crate) mod test {
|
||||
use super::*;
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_1: Address = Address([192, 168, 1, 1]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_2: Address = Address([192, 168, 1, 2]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_3: Address = Address([192, 168, 1, 3]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_4: Address = Address([192, 168, 1, 4]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
|
||||
|
||||
static PACKET_BYTES: [u8; 30] = [
|
||||
0x45, 0x00, 0x00, 0x1e, 0x01, 0x02, 0x62, 0x03, 0x1a, 0x01, 0xd5, 0x6e, 0x11, 0x12, 0x13,
|
||||
0x14, 0x21, 0x22, 0x23, 0x24, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
|
@ -897,7 +897,7 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
pub(crate) mod test {
|
||||
use super::Error;
|
||||
use super::{Address, Cidr};
|
||||
use super::{Packet, Protocol, Repr};
|
||||
@ -906,6 +906,21 @@ mod test {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
use crate::wire::ipv4::Address as Ipv4Address;
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_1: Address =
|
||||
Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_2: Address =
|
||||
Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_3: Address =
|
||||
Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_IP_ADDR_4: Address =
|
||||
Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]);
|
||||
#[allow(unused)]
|
||||
pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
|
||||
|
||||
const LINK_LOCAL_ADDR: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
|
||||
const UNIQUE_LOCAL_ADDR: Address = Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
|
||||
const GLOBAL_UNICAST_ADDR: Address = Address::new(0x2001, 0xdb8, 0x3, 0, 0, 0, 0, 1);
|
||||
|
@ -476,8 +476,8 @@ mod test {
|
||||
.copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
|
||||
packet.clear_reserved();
|
||||
packet.fill_checksum(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
);
|
||||
assert_eq!(&*packet.into_inner(), &QUERY_PACKET_BYTES[..]);
|
||||
}
|
||||
@ -519,8 +519,8 @@ mod test {
|
||||
.copy_from_slice(Ipv6Address::LINK_LOCAL_ALL_ROUTERS.as_bytes());
|
||||
}
|
||||
packet.fill_checksum(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
);
|
||||
assert_eq!(&*packet.into_inner(), &REPORT_PACKET_BYTES[..]);
|
||||
}
|
||||
@ -529,8 +529,8 @@ mod test {
|
||||
fn test_query_repr_parse() {
|
||||
let packet = Packet::new_unchecked(&QUERY_PACKET_BYTES[..]);
|
||||
let repr = Icmpv6Repr::parse(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
&packet,
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
@ -541,8 +541,8 @@ mod test {
|
||||
fn test_report_repr_parse() {
|
||||
let packet = Packet::new_unchecked(&REPORT_PACKET_BYTES[..]);
|
||||
let repr = Icmpv6Repr::parse(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
&packet,
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
@ -555,8 +555,8 @@ mod test {
|
||||
let mut packet = Packet::new_unchecked(&mut bytes[..]);
|
||||
let repr = create_repr(Message::MldQuery);
|
||||
repr.emit(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
&mut packet,
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
@ -569,8 +569,8 @@ mod test {
|
||||
let mut packet = Packet::new_unchecked(&mut bytes[..]);
|
||||
let repr = create_repr(Message::MldReport);
|
||||
repr.emit(
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||
&Ipv6Address::LINK_LOCAL_ALL_NODES,
|
||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS,
|
||||
&mut packet,
|
||||
&ChecksumCapabilities::default(),
|
||||
);
|
||||
|
@ -97,9 +97,9 @@ pub mod ieee802154;
|
||||
mod igmp;
|
||||
pub(crate) mod ip;
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
mod ipv4;
|
||||
pub(crate) mod ipv4;
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
mod ipv6;
|
||||
pub(crate) mod ipv6;
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
mod ipv6ext_header;
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
|
@ -459,10 +459,14 @@ impl<'a> Repr<'a> {
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::phy::ChecksumCapabilities;
|
||||
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
|
||||
use crate::wire::EthernetAddress;
|
||||
use crate::wire::Icmpv6Repr;
|
||||
|
||||
const MOCK_IP_ADDR_1: Ipv6Address =
|
||||
Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
const MOCK_IP_ADDR_2: Ipv6Address =
|
||||
Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||
|
||||
static ROUTER_ADVERT_BYTES: [u8; 24] = [
|
||||
0x86, 0x00, 0xa9, 0xde, 0x40, 0x80, 0x03, 0x84, 0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x03,
|
||||
0x84, 0x01, 0x01, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56,
|
||||
|
@ -2414,8 +2414,8 @@ mod tests {
|
||||
SixlowpanNextHeader::Uncompressed(IpProtocol::Icmpv6) => {
|
||||
let icmp_packet = Icmpv6Packet::new_checked(packet.payload()).unwrap();
|
||||
match Icmpv6Repr::parse(
|
||||
&IpAddress::Ipv6(repr.src_addr),
|
||||
&IpAddress::Ipv6(repr.dst_addr),
|
||||
&repr.src_addr,
|
||||
&repr.dst_addr,
|
||||
&icmp_packet,
|
||||
&ChecksumCapabilities::ignored(),
|
||||
) {
|
||||
|
@ -4,12 +4,7 @@
|
||||
use super::{Error, NextHeader, Result, DISPATCH_EXT_HEADER, DISPATCH_UDP_HEADER};
|
||||
use crate::{
|
||||
phy::ChecksumCapabilities,
|
||||
wire::{
|
||||
ip::{checksum, Address as IpAddress},
|
||||
ipv6,
|
||||
udp::Repr as UdpRepr,
|
||||
IpProtocol,
|
||||
},
|
||||
wire::{ip::checksum, ipv6, udp::Repr as UdpRepr, IpProtocol},
|
||||
};
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
use ipv6::Address;
|
||||
@ -708,9 +703,9 @@ impl<'a> UdpNhcRepr {
|
||||
if checksum_caps.udp.rx() {
|
||||
let payload_len = packet.payload().len();
|
||||
let chk_sum = !checksum::combine(&[
|
||||
checksum::pseudo_header(
|
||||
&IpAddress::Ipv6(*src_addr),
|
||||
&IpAddress::Ipv6(*dst_addr),
|
||||
checksum::pseudo_header_v6(
|
||||
src_addr,
|
||||
dst_addr,
|
||||
crate::wire::ip::Protocol::Udp,
|
||||
payload_len as u32 + 8,
|
||||
),
|
||||
@ -763,9 +758,9 @@ impl<'a> UdpNhcRepr {
|
||||
|
||||
if checksum_caps.udp.tx() {
|
||||
let chk_sum = !checksum::combine(&[
|
||||
checksum::pseudo_header(
|
||||
&IpAddress::Ipv6(*src_addr),
|
||||
&IpAddress::Ipv6(*dst_addr),
|
||||
checksum::pseudo_header_v6(
|
||||
src_addr,
|
||||
dst_addr,
|
||||
crate::wire::ip::Protocol::Udp,
|
||||
payload_len as u32 + 8,
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user