Skip to main content

net_wire/icmpv6/
message.rs

1//! ICMPv6 checked borrowed message views.
2
3use super::types::Icmpv6Type;
4use crate::error::ParseError;
5
6pub(super) const HEADER_LENGTH: usize = 4;
7
8/// A structurally validated ICMPv6 message.
9///
10/// Parsing verifies only the common header. It preserves unknown type and code values and does
11/// not reject a message with an invalid checksum.
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct Icmpv6Message<'a> {
14    bytes: &'a [u8],
15}
16
17impl<'a> Icmpv6Message<'a> {
18    /// Parses a complete ICMPv6 message without checking its checksum.
19    #[inline]
20    pub fn parse(bytes: &'a [u8]) -> Result<Self, ParseError> {
21        if bytes.len() < HEADER_LENGTH {
22            return Err(ParseError::Truncated {
23                minimum: HEADER_LENGTH,
24                available: bytes.len(),
25            });
26        }
27        Ok(Self { bytes })
28    }
29
30    /// Returns the message type.
31    #[inline]
32    pub fn message_type(&self) -> Icmpv6Type {
33        Icmpv6Type::new(self.bytes[0])
34    }
35
36    /// Returns the message code.
37    #[inline]
38    pub fn code(&self) -> u8 {
39        self.bytes[1]
40    }
41
42    /// Returns the encoded checksum.
43    #[inline]
44    pub fn checksum(&self) -> u16 {
45        u16::from_be_bytes([self.bytes[2], self.bytes[3]])
46    }
47
48    /// Returns bytes after the common header.
49    #[inline]
50    pub fn body(&self) -> &'a [u8] {
51        &self.bytes[HEADER_LENGTH..]
52    }
53
54    /// Returns all represented message bytes.
55    #[inline]
56    pub fn as_bytes(&self) -> &'a [u8] {
57        self.bytes
58    }
59}
60
61/// A mutable structurally validated ICMPv6 message.
62#[derive(Debug, Eq, PartialEq)]
63pub struct Icmpv6MessageMut<'a> {
64    bytes: &'a mut [u8],
65}
66
67impl<'a> Icmpv6MessageMut<'a> {
68    /// Parses a complete ICMPv6 message without checking its checksum.
69    #[inline]
70    pub fn parse(bytes: &'a mut [u8]) -> Result<Self, ParseError> {
71        if bytes.len() < HEADER_LENGTH {
72            return Err(ParseError::Truncated {
73                minimum: HEADER_LENGTH,
74                available: bytes.len(),
75            });
76        }
77        Ok(Self { bytes })
78    }
79
80    pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
81        Self { bytes }
82    }
83
84    /// Returns the message type.
85    #[inline]
86    pub fn message_type(&self) -> Icmpv6Type {
87        Icmpv6Type::new(self.bytes[0])
88    }
89
90    /// Returns the message code.
91    #[inline]
92    pub fn code(&self) -> u8 {
93        self.bytes[1]
94    }
95
96    /// Returns the encoded checksum.
97    #[inline]
98    pub fn checksum(&self) -> u16 {
99        u16::from_be_bytes([self.bytes[2], self.bytes[3]])
100    }
101
102    /// Returns bytes after the common header.
103    #[inline]
104    pub fn body(&self) -> &[u8] {
105        &self.bytes[HEADER_LENGTH..]
106    }
107
108    /// Returns mutable body bytes without updating the checksum.
109    #[inline]
110    pub fn body_mut(&mut self) -> &mut [u8] {
111        &mut self.bytes[HEADER_LENGTH..]
112    }
113
114    /// Returns all represented message bytes.
115    #[inline]
116    pub fn as_bytes(&self) -> &[u8] {
117        self.bytes
118    }
119
120    /// Returns all represented message bytes mutably without updating the checksum.
121    #[inline]
122    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
123        self.bytes
124    }
125
126    /// Replaces the message type without updating the checksum.
127    #[inline]
128    pub fn set_message_type(&mut self, value: Icmpv6Type) {
129        self.bytes[0] = value.raw();
130    }
131
132    /// Replaces the message code without updating the checksum.
133    #[inline]
134    pub fn set_code(&mut self, value: u8) {
135        self.bytes[1] = value;
136    }
137
138    /// Replaces the encoded checksum directly.
139    #[inline]
140    pub fn set_checksum(&mut self, value: u16) {
141        self.bytes[2..4].copy_from_slice(&value.to_be_bytes());
142    }
143}