zero_packet/network/
icmpv6.rs1use super::checksum::internet_checksum;
2use core::fmt;
3
4pub const ICMPV6_HEADER_LENGTH: usize = 8;
6
7pub struct Icmpv6Writer<'a> {
9 pub bytes: &'a mut [u8],
10}
11
12impl<'a> Icmpv6Writer<'a> {
13 #[inline]
15 pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
16 if bytes.len() < ICMPV6_HEADER_LENGTH {
17 return Err("Slice is too short to contain an ICMP header.");
18 }
19
20 Ok(Self { bytes })
21 }
22
23 #[inline]
25 pub fn header_len(&self) -> usize {
26 ICMPV6_HEADER_LENGTH
27 }
28
29 #[inline]
31 pub fn packet_len(&self) -> usize {
32 self.bytes.len()
33 }
34
35 #[inline]
37 pub fn set_icmp_type(&mut self, icmp_type: u8) {
38 self.bytes[0] = icmp_type;
39 }
40
41 #[inline]
43 pub fn set_icmp_code(&mut self, icmp_code: u8) {
44 self.bytes[1] = icmp_code;
45 }
46
47 #[inline]
53 pub fn set_payload(&mut self, payload: &[u8]) -> Result<(), &'static str> {
54 let start = self.header_len();
55 let payload_len = payload.len();
56
57 if self.packet_len() - start < payload_len {
58 return Err("Payload is too large to fit in the ICMPv6 packet.");
59 }
60
61 let end = start + payload_len;
62 self.bytes[start..end].copy_from_slice(payload);
63
64 Ok(())
65 }
66
67 #[inline]
71 pub fn set_checksum(&mut self, pseudo_sum: u32) {
72 self.bytes[2] = 0;
73 self.bytes[3] = 0;
74 let checksum = internet_checksum(self.bytes, pseudo_sum);
75 self.bytes[2] = (checksum >> 8) as u8;
76 self.bytes[3] = (checksum & 0xff) as u8;
77 }
78}
79
80#[derive(PartialEq)]
82pub struct Icmpv6Reader<'a> {
83 pub bytes: &'a [u8],
84}
85
86impl<'a> Icmpv6Reader<'a> {
87 #[inline]
89 pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
90 if bytes.len() < ICMPV6_HEADER_LENGTH {
91 return Err("Slice is too short to contain an ICMP header.");
92 }
93
94 Ok(Self { bytes })
95 }
96
97 #[inline]
99 pub fn icmp_type(&self) -> u8 {
100 self.bytes[0]
101 }
102
103 #[inline]
105 pub fn icmp_code(&self) -> u8 {
106 self.bytes[1]
107 }
108
109 #[inline]
111 pub fn checksum(&self) -> u16 {
112 ((self.bytes[2] as u16) << 8) | (self.bytes[3] as u16)
113 }
114
115 #[inline]
117 pub fn header_len(&self) -> usize {
118 ICMPV6_HEADER_LENGTH
119 }
120
121 #[inline]
123 pub fn header(&self) -> &'a [u8] {
124 &self.bytes[..ICMPV6_HEADER_LENGTH]
125 }
126
127 #[inline]
129 pub fn payload(&self) -> &'a [u8] {
130 &self.bytes[ICMPV6_HEADER_LENGTH..]
131 }
132}
133
134impl fmt::Debug for Icmpv6Reader<'_> {
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 f.debug_struct("Icmpv6Packet")
137 .field("icmp_type", &self.icmp_type())
138 .field("icmp_code", &self.icmp_code())
139 .field("checksum", &self.checksum())
140 .finish()
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use crate::network::checksum::pseudo_header;
148
149 #[test]
150 fn getters_and_setters() {
151 let mut bytes = [0; ICMPV6_HEADER_LENGTH];
153
154 let icmp_type = 8;
156 let icmp_code = 0;
157
158 let src_addr = [
160 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70,
161 0x73, 0x34,
162 ];
163 let dest_addr = [
164 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0xb3, 0xff, 0xfe, 0x1e,
165 0x83, 0x29,
166 ];
167 let protocol = 58;
168 let length = 8;
169
170 let mut writer = Icmpv6Writer::new(&mut bytes).unwrap();
172
173 writer.set_icmp_type(icmp_type);
175 writer.set_icmp_code(icmp_code);
176
177 let pseudo_sum = pseudo_header(&src_addr, &dest_addr, protocol, length);
179 writer.set_checksum(pseudo_sum);
180
181 let reader = Icmpv6Reader::new(&bytes).unwrap();
183
184 assert_eq!(reader.icmp_type(), icmp_type);
186 assert_eq!(reader.icmp_code(), icmp_code);
187 }
188}