1 use super::*;
2 
3 /// "Destination Unreachable" ICMPv6 code containing a reason why a
4 /// destination could not be reached.
5 ///
6 /// # RFC 4443 Description:
7 ///
8 /// A Destination Unreachable message SHOULD be generated by a router, or
9 /// by the IPv6 layer in the originating node, in response to a packet
10 /// that cannot be delivered to its destination address for reasons other
11 /// than congestion.  (An ICMPv6 message MUST NOT be generated if a
12 /// packet is dropped due to congestion.)
13 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
14 pub enum DestUnreachableCode {
15     /// No route to destination
16     NoRoute = 0,
17     /// Communication with destination administratively prohibited
18     Prohibited = 1,
19     /// Beyond scope of source address
20     BeyondScope = 2,
21     /// Address unreachable
22     Address = 3,
23     /// Port unreachable
24     Port = 4,
25     /// Source address failed ingress/egress policy
26     SourceAddressFailedPolicy = 5,
27     /// Reject route to destination
28     RejectRoute = 6,
29 }
30 
31 impl DestUnreachableCode {
32     /// Converts the u8 code value from an ICMPv6 "destination unreachable"
33     /// packet to an `icmpv6::DestUnreachableCode` enum.
34     ///
35     /// # Example Usage:
36     ///
37     /// ```
38     /// use etherparse::{icmpv6, icmpv6::DestUnreachableCode};
39     /// let icmp_packet: [u8;8] = [
40     ///     icmpv6::TYPE_DST_UNREACH, icmpv6::CODE_DST_UNREACH_PORT, 0, 0,
41     ///     0, 0, 0, 0,
42     /// ];
43     ///
44     /// if icmpv6::TYPE_DST_UNREACH == icmp_packet[0] {
45     ///     let dst = icmpv6::DestUnreachableCode::from_u8(
46     ///         icmp_packet[1]
47     ///     );
48     ///     assert_eq!(dst, Some(icmpv6::DestUnreachableCode::Port));
49     /// }
50     /// ```
from_u8(code_u8: u8) -> Option<DestUnreachableCode>51     pub fn from_u8(code_u8: u8) -> Option<DestUnreachableCode> {
52         use DestUnreachableCode::*;
53         match code_u8 {
54             CODE_DST_UNREACH_NO_ROUTE => Some(NoRoute),
55             CODE_DST_UNREACH_PROHIBITED => Some(Prohibited),
56             CODE_DST_UNREACH_BEYOND_SCOPE => Some(BeyondScope),
57             CODE_DST_UNREACH_ADDR => Some(Address),
58             CODE_DST_UNREACH_PORT => Some(Port),
59             CODE_DST_UNREACH_SOURCE_ADDRESS_FAILED_POLICY => Some(SourceAddressFailedPolicy),
60             CODE_DST_UNREACH_REJECT_ROUTE_TO_DEST => Some(RejectRoute),
61             _ => None,
62         }
63     }
64 
65     /// Returns the code value of the destination unreachable packet.
66     ///
67     /// This is the second byte of an ICMPv6 packet.
68     #[inline]
code_u8(&self) -> u869     pub fn code_u8(&self) -> u8 {
70         *self as u8
71     }
72 }
73 
74 #[cfg(test)]
75 pub(crate) mod dest_unreachable_code_test_consts {
76     use super::{DestUnreachableCode::*, *};
77 
78     pub const VALID_VALUES: [(DestUnreachableCode, u8); 7] = [
79         (NoRoute, CODE_DST_UNREACH_NO_ROUTE),
80         (Prohibited, CODE_DST_UNREACH_PROHIBITED),
81         (BeyondScope, CODE_DST_UNREACH_BEYOND_SCOPE),
82         (Address, CODE_DST_UNREACH_ADDR),
83         (Port, CODE_DST_UNREACH_PORT),
84         (
85             SourceAddressFailedPolicy,
86             CODE_DST_UNREACH_SOURCE_ADDRESS_FAILED_POLICY,
87         ),
88         (RejectRoute, CODE_DST_UNREACH_REJECT_ROUTE_TO_DEST),
89     ];
90 }
91 
92 #[cfg(test)]
93 mod test {
94     use super::{dest_unreachable_code_test_consts::*, DestUnreachableCode::*, *};
95     use alloc::format;
96 
97     #[test]
from_u8()98     fn from_u8() {
99         for (code, code_u8) in VALID_VALUES {
100             assert_eq!(code, DestUnreachableCode::from_u8(code_u8).unwrap());
101         }
102         for code_u8 in 7u8..=0xff {
103             assert!(DestUnreachableCode::from_u8(code_u8).is_none());
104         }
105     }
106 
107     #[test]
code_u8()108     fn code_u8() {
109         for (code, code_u8) in VALID_VALUES {
110             assert_eq!(code.code_u8(), code_u8);
111         }
112     }
113 
114     #[test]
clone_eq()115     fn clone_eq() {
116         for (code, _) in VALID_VALUES {
117             assert_eq!(code.clone(), code);
118         }
119     }
120 
121     #[test]
debug()122     fn debug() {
123         let tests = [
124             (NoRoute, "NoRoute"),
125             (Prohibited, "Prohibited"),
126             (BeyondScope, "BeyondScope"),
127             (Address, "Address"),
128             (Port, "Port"),
129             (SourceAddressFailedPolicy, "SourceAddressFailedPolicy"),
130             (RejectRoute, "RejectRoute"),
131         ];
132         for test in tests {
133             assert_eq!(format!("{:?}", test.0), test.1);
134         }
135     }
136 }
137