#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DestUnreachableHeader {
Network,
Host,
Protocol,
Port,
FragmentationNeeded { next_hop_mtu: u16 },
SourceRouteFailed,
NetworkUnknown,
HostUnknown,
Isolated,
NetworkProhibited,
HostProhibited,
TosNetwork,
TosHost,
FilterProhibited,
HostPrecedenceViolation,
PrecedenceCutoff,
}
impl DestUnreachableHeader {
pub fn from_values(code_u8: u8, next_hop_mtu: u16) -> Option<DestUnreachableHeader> {
use crate::icmpv4::{DestUnreachableHeader::*, *};
match code_u8 {
CODE_DST_UNREACH_NET => Some(Network),
CODE_DST_UNREACH_HOST => Some(Host),
CODE_DST_UNREACH_PROTOCOL => Some(Protocol),
CODE_DST_UNREACH_PORT => Some(Port),
CODE_DST_UNREACH_NEED_FRAG => Some(FragmentationNeeded { next_hop_mtu }),
CODE_DST_UNREACH_SOURCE_ROUTE_FAILED => Some(SourceRouteFailed),
CODE_DST_UNREACH_NET_UNKNOWN => Some(NetworkUnknown),
CODE_DST_UNREACH_HOST_UNKNOWN => Some(HostUnknown),
CODE_DST_UNREACH_ISOLATED => Some(Isolated),
CODE_DST_UNREACH_NET_PROHIB => Some(NetworkProhibited),
CODE_DST_UNREACH_HOST_PROHIB => Some(HostProhibited),
CODE_DST_UNREACH_TOS_NET => Some(TosNetwork),
CODE_DST_UNREACH_TOS_HOST => Some(TosHost),
CODE_DST_UNREACH_FILTER_PROHIB => Some(FilterProhibited),
CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION => Some(HostPrecedenceViolation),
CODE_DST_UNREACH_PRECEDENCE_CUTOFF => Some(PrecedenceCutoff),
_ => None,
}
}
#[inline]
pub fn code_u8(&self) -> u8 {
use crate::icmpv4::{DestUnreachableHeader::*, *};
match self {
Network => CODE_DST_UNREACH_NET,
Host => CODE_DST_UNREACH_HOST,
Protocol => CODE_DST_UNREACH_PROTOCOL,
Port => CODE_DST_UNREACH_PORT,
FragmentationNeeded { next_hop_mtu: _ } => CODE_DST_UNREACH_NEED_FRAG,
SourceRouteFailed => CODE_DST_UNREACH_SOURCE_ROUTE_FAILED,
NetworkUnknown => CODE_DST_UNREACH_NET_UNKNOWN,
HostUnknown => CODE_DST_UNREACH_HOST_UNKNOWN,
Isolated => CODE_DST_UNREACH_ISOLATED,
NetworkProhibited => CODE_DST_UNREACH_NET_PROHIB,
HostProhibited => CODE_DST_UNREACH_HOST_PROHIB,
TosNetwork => CODE_DST_UNREACH_TOS_NET,
TosHost => CODE_DST_UNREACH_TOS_HOST,
FilterProhibited => CODE_DST_UNREACH_FILTER_PROHIB,
HostPrecedenceViolation => CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION,
PrecedenceCutoff => CODE_DST_UNREACH_PRECEDENCE_CUTOFF,
}
}
}
#[cfg(test)]
mod test {
use crate::icmpv4::*;
use alloc::format;
use proptest::prelude::*;
fn conversion_values(next_hop_mtu: u16) -> [(u8, DestUnreachableHeader); 16] {
use DestUnreachableHeader::*;
[
(CODE_DST_UNREACH_NET, Network),
(CODE_DST_UNREACH_HOST, Host),
(CODE_DST_UNREACH_PROTOCOL, Protocol),
(CODE_DST_UNREACH_PORT, Port),
(
CODE_DST_UNREACH_NEED_FRAG,
FragmentationNeeded { next_hop_mtu },
),
(CODE_DST_UNREACH_SOURCE_ROUTE_FAILED, SourceRouteFailed),
(CODE_DST_UNREACH_NET_UNKNOWN, NetworkUnknown),
(CODE_DST_UNREACH_HOST_UNKNOWN, HostUnknown),
(CODE_DST_UNREACH_ISOLATED, Isolated),
(CODE_DST_UNREACH_NET_PROHIB, NetworkProhibited),
(CODE_DST_UNREACH_HOST_PROHIB, HostProhibited),
(CODE_DST_UNREACH_TOS_NET, TosNetwork),
(CODE_DST_UNREACH_TOS_HOST, TosHost),
(CODE_DST_UNREACH_FILTER_PROHIB, FilterProhibited),
(
CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION,
HostPrecedenceViolation,
),
(CODE_DST_UNREACH_PRECEDENCE_CUTOFF, PrecedenceCutoff),
]
}
proptest! {
#[test]
fn from_values(
next_hop_mtu in any::<u16>(),
) {
{
let valid_values = conversion_values(next_hop_mtu);
for t in valid_values {
assert_eq!(Some(t.1), DestUnreachableHeader::from_values(t.0, next_hop_mtu));
}
}
for code_u8 in 16u8..=u8::MAX {
assert_eq!(None, DestUnreachableHeader::from_values(code_u8, next_hop_mtu));
}
}
}
proptest! {
#[test]
fn code_u8(
next_hop_mtu in any::<u16>(),
) {
let valid_values = conversion_values(next_hop_mtu);
for t in valid_values {
assert_eq!(t.0, t.1.code_u8());
}
}
}
#[test]
fn clone_eq() {
use DestUnreachableHeader::*;
let values = [
Network,
Host,
Protocol,
Port,
FragmentationNeeded { next_hop_mtu: 0 },
SourceRouteFailed,
NetworkUnknown,
HostUnknown,
Isolated,
NetworkProhibited,
HostProhibited,
TosNetwork,
TosHost,
FilterProhibited,
HostPrecedenceViolation,
PrecedenceCutoff,
];
for value in values {
assert_eq!(value.clone(), value);
}
}
#[test]
fn debug() {
use DestUnreachableHeader::*;
let tests = [
("Network", Network),
("Host", Host),
("Protocol", Protocol),
("Port", Port),
(
"FragmentationNeeded { next_hop_mtu: 0 }",
FragmentationNeeded { next_hop_mtu: 0 },
),
("SourceRouteFailed", SourceRouteFailed),
("NetworkUnknown", NetworkUnknown),
("HostUnknown", HostUnknown),
("Isolated", Isolated),
("NetworkProhibited", NetworkProhibited),
("HostProhibited", HostProhibited),
("TosNetwork", TosNetwork),
("TosHost", TosHost),
("FilterProhibited", FilterProhibited),
("HostPrecedenceViolation", HostPrecedenceViolation),
("PrecedenceCutoff", PrecedenceCutoff),
];
for t in tests {
assert_eq!(t.0, format!("{:?}", t.1));
}
}
}