use super::super::*;
pub const ICMPV6_EXTENDED_ECHO_REQUEST_L_BIT: u8 = 0x01;
pub const ICMPV6_EXTENDED_ECHO_REPLY_ACTIVE: u8 = 0x04;
pub const ICMPV6_EXTENDED_ECHO_REPLY_IPV4: u8 = 0x02;
pub const ICMPV6_EXTENDED_ECHO_REPLY_IPV6: u8 = 0x01;
pub const ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_ERROR: u8 = 0;
pub const ICMPV6_CODE_EXTENDED_ECHO_REPLY_MALFORMED_QUERY: u8 = 1;
pub const ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_INTERFACE: u8 = 2;
pub const ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_TABLE_ENTRY: u8 = 3;
pub const ICMPV6_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES: u8 = 4;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_RESERVED: u8 = 0;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_INCOMPLETE: u8 = 1;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_REACHABLE: u8 = 2;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_STALE: u8 = 3;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_DELAY: u8 = 4;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_PROBE: u8 = 5;
pub const ICMPV6_EXTENDED_ECHO_REPLY_STATE_FAILED: u8 = 6;
impl Icmpv6 {
pub fn extended_echo_request() -> Self {
Self::new().icmp_type(ICMPV6_EXTENDED_ECHO_REQUEST)
}
pub fn extended_echo_reply() -> Self {
Self::new().icmp_type(ICMPV6_EXTENDED_ECHO_REPLY)
}
}
#[cfg(test)]
mod tests {
use crate::protocols::icmp::{
IcmpExtension, IcmpExtensionInterfaceId, IcmpExtensionObject, Icmpv6,
ICMPV6_EXTENDED_ECHO_REPLY, ICMPV6_EXTENDED_ECHO_REQUEST,
ICMP_EXTENSION_CLASS_INTERFACE_ID, ICMP_INTERFACE_ID_CTYPE_INDEX,
};
use crate::protocols::icmp::{
ICMPV6_CODE_EXTENDED_ECHO_REPLY_MALFORMED_QUERY,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_ERROR,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_INTERFACE,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_TABLE_ENTRY,
ICMPV6_EXTENDED_ECHO_REPLY_STATE_REACHABLE,
};
use crate::{Ipv6, NetworkLayer, Packet};
use core::net::Ipv6Addr;
fn src() -> Ipv6Addr {
Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0010)
}
fn dst() -> Ipv6Addr {
Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0020)
}
#[test]
fn icmpv6_rfc8335_extended_echo_request_by_index_round_trips() {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_request().id(0x1234).seq(7)
/ IcmpExtension::new()
/ IcmpExtensionObject::new()
/ IcmpExtensionInterfaceId::by_index(42))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
assert_eq!(bytes[40], ICMPV6_EXTENDED_ECHO_REQUEST);
assert_eq!(bytes[41], 0);
assert_eq!(&bytes[44..46], &0x1234u16.to_be_bytes());
assert_eq!(bytes[46], 7);
assert_eq!(bytes[47], 0);
assert_eq!(bytes[48] >> 4, 2);
assert_eq!(bytes[54], ICMP_EXTENSION_CLASS_INTERFACE_ID);
assert_eq!(bytes[55], ICMP_INTERFACE_ID_CTYPE_INDEX);
assert_eq!(u16::from_be_bytes([bytes[52], bytes[53]]), 8);
assert_eq!(
u32::from_be_bytes([bytes[56], bytes[57], bytes[58], bytes[59]]),
42
);
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
let icmpv6 = decoded.layer::<Icmpv6>().unwrap();
assert_eq!(icmpv6.icmp_type_value(), ICMPV6_EXTENDED_ECHO_REQUEST);
assert_eq!(icmpv6.identifier_value(), Some(0x1234));
assert_eq!(icmpv6.sequence_number_value(), Some(7));
assert_eq!(icmpv6.extended_l_bit_value(), Some(false));
assert!(decoded.layer::<IcmpExtension>().is_some());
let id = decoded.layer::<IcmpExtensionInterfaceId>().unwrap();
assert_eq!(id.index_value(), Some(42));
assert_eq!(id.c_type(), ICMP_INTERFACE_ID_CTYPE_INDEX);
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
#[test]
fn icmpv6_rfc8335_extended_echo_request_by_name_round_trips() {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_request().id(1).seq(1)
/ IcmpExtension::new()
/ IcmpExtensionObject::new()
/ IcmpExtensionInterfaceId::by_name("eth0"))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
let id = decoded.layer::<IcmpExtensionInterfaceId>().unwrap();
assert_eq!(id.name_value(), Some(&b"eth0"[..]));
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
#[test]
fn icmpv6_rfc8335_extended_echo_request_l_bit_round_trips() {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_request()
.id(9)
.seq(3)
.extended_l_bit(true)
/ IcmpExtension::new()
/ IcmpExtensionObject::new()
/ IcmpExtensionInterfaceId::by_index(1))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
assert_eq!(bytes[47], 0x01);
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
let icmpv6 = decoded.layer::<Icmpv6>().unwrap();
assert_eq!(icmpv6.extended_l_bit_value(), Some(true));
assert_eq!(icmpv6.extended_state_value(), None);
assert_eq!(icmpv6.extended_active_value(), None);
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
#[test]
fn icmpv6_rfc8335_extended_echo_reply_all_codes_round_trip() {
let codes = [
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_ERROR,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_MALFORMED_QUERY,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_INTERFACE,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_SUCH_TABLE_ENTRY,
ICMPV6_CODE_EXTENDED_ECHO_REPLY_MULTIPLE_INTERFACES,
];
for code in codes {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_reply().id(0xabcd).seq(5).code(code))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
assert_eq!(bytes[40], ICMPV6_EXTENDED_ECHO_REPLY);
assert_eq!(bytes[41], code);
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
let icmpv6 = decoded.layer::<Icmpv6>().unwrap();
assert_eq!(icmpv6.code_value(), code);
assert_eq!(icmpv6.identifier_value(), Some(0xabcd));
assert_eq!(icmpv6.sequence_number_value(), Some(5));
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
}
#[test]
fn icmpv6_rfc8335_extended_echo_reply_state_and_flags_round_trip() {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_reply()
.code(ICMPV6_CODE_EXTENDED_ECHO_REPLY_NO_ERROR)
.extended_state(ICMPV6_EXTENDED_ECHO_REPLY_STATE_REACHABLE)
.extended_active(true)
.extended_ipv4(false)
.extended_ipv6(true))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
assert_eq!(bytes[47], 0x40 | 0x04 | 0x01);
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
let icmpv6 = decoded.layer::<Icmpv6>().unwrap();
assert_eq!(
icmpv6.extended_state_value(),
Some(ICMPV6_EXTENDED_ECHO_REPLY_STATE_REACHABLE)
);
assert_eq!(icmpv6.extended_active_value(), Some(true));
assert_eq!(icmpv6.extended_ipv4_value(), Some(false));
assert_eq!(icmpv6.extended_ipv6_value(), Some(true));
assert_eq!(icmpv6.extended_l_bit_value(), None);
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
#[test]
fn icmpv6_rfc8335_extended_echo_explicit_flag_byte_preserved() {
let compiled = (Ipv6::new().src(src()).dst(dst())
/ Icmpv6::extended_echo_request()
.id(1)
.seq(1)
.extended_flags(0xa5)
/ IcmpExtension::new()
/ IcmpExtensionObject::new()
/ IcmpExtensionInterfaceId::by_index(7))
.compile()
.unwrap();
let bytes = compiled.as_bytes();
assert_eq!(bytes[47], 0xa5);
let decoded = Packet::decode_from_l3(NetworkLayer::Ipv6, bytes).unwrap();
assert_eq!(
decoded.layer::<Icmpv6>().unwrap().extended_flags_value(),
Some(0xa5)
);
assert_eq!(decoded.compile().unwrap().as_bytes(), bytes);
}
}