smoltcp/wire/
ipv6fragment.rs1use super::{Error, Result};
2use core::fmt;
3
4use byteorder::{ByteOrder, NetworkEndian};
5
6#[derive(Debug, PartialEq, Eq)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub struct Header<T: AsRef<[u8]>> {
10 buffer: T,
11}
12
13mod field {
25 use crate::wire::field::*;
26
27 pub const FR_OF_M: Field = 0..2;
29 pub const IDENT: Field = 2..6;
31 pub const M: usize = 1;
33}
34
35impl<T: AsRef<[u8]>> Header<T> {
36 pub const fn new_unchecked(buffer: T) -> Header<T> {
38 Header { buffer }
39 }
40
41 pub fn new_checked(buffer: T) -> Result<Header<T>> {
46 let header = Self::new_unchecked(buffer);
47 header.check_len()?;
48 Ok(header)
49 }
50
51 pub fn check_len(&self) -> Result<()> {
54 let data = self.buffer.as_ref();
55 let len = data.len();
56
57 if len < field::IDENT.end {
58 Err(Error)
59 } else {
60 Ok(())
61 }
62 }
63
64 pub fn into_inner(self) -> T {
66 self.buffer
67 }
68
69 #[inline]
71 pub fn frag_offset(&self) -> u16 {
72 let data = self.buffer.as_ref();
73 NetworkEndian::read_u16(&data[field::FR_OF_M]) >> 3
74 }
75
76 #[inline]
78 pub fn more_frags(&self) -> bool {
79 let data = self.buffer.as_ref();
80 (data[field::M] & 0x1) == 1
81 }
82
83 #[inline]
85 pub fn ident(&self) -> u32 {
86 let data = self.buffer.as_ref();
87 NetworkEndian::read_u32(&data[field::IDENT])
88 }
89}
90
91impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
92 #[inline]
97 pub fn clear_reserved(&mut self) {
98 let data = self.buffer.as_mut();
99 data[field::M] &= 0xf9;
101 }
102
103 #[inline]
105 pub fn set_frag_offset(&mut self, value: u16) {
106 let data = self.buffer.as_mut();
107 let raw = ((value & 0x1fff) << 3) | ((data[field::M] & 0x7) as u16);
109 NetworkEndian::write_u16(&mut data[field::FR_OF_M], raw);
110 }
111
112 #[inline]
114 pub fn set_more_frags(&mut self, value: bool) {
115 let data = self.buffer.as_mut();
116 let raw = (data[field::M] & 0xfe) | (value as u8 & 0x1);
118 data[field::M] = raw;
119 }
120
121 #[inline]
123 pub fn set_ident(&mut self, value: u32) {
124 let data = self.buffer.as_mut();
125 NetworkEndian::write_u32(&mut data[field::IDENT], value);
126 }
127}
128
129impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 match Repr::parse(self) {
132 Ok(repr) => write!(f, "{repr}"),
133 Err(err) => {
134 write!(f, "IPv6 Fragment ({err})")?;
135 Ok(())
136 }
137 }
138 }
139}
140
141#[derive(Debug, PartialEq, Eq, Clone, Copy)]
143#[cfg_attr(feature = "defmt", derive(defmt::Format))]
144pub struct Repr {
145 pub frag_offset: u16,
148 pub more_frags: bool,
150 pub ident: u32,
152}
153
154impl Repr {
155 pub fn parse<T>(header: &Header<&T>) -> Result<Repr>
157 where
158 T: AsRef<[u8]> + ?Sized,
159 {
160 header.check_len()?;
161 Ok(Repr {
162 frag_offset: header.frag_offset(),
163 more_frags: header.more_frags(),
164 ident: header.ident(),
165 })
166 }
167
168 pub const fn buffer_len(&self) -> usize {
171 field::IDENT.end
172 }
173
174 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
176 header.clear_reserved();
177 header.set_frag_offset(self.frag_offset);
178 header.set_more_frags(self.more_frags);
179 header.set_ident(self.ident);
180 }
181}
182
183impl fmt::Display for Repr {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 write!(
186 f,
187 "IPv6 Fragment offset={} more={} ident={}",
188 self.frag_offset, self.more_frags, self.ident
189 )
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::*;
196
197 static BYTES_HEADER_MORE_FRAG: [u8; 6] = [0x0, 0x1, 0x0, 0x0, 0x30, 0x39];
199
200 static BYTES_HEADER_LAST_FRAG: [u8; 6] = [0xa, 0x0, 0x0, 0x1, 0x9, 0x32];
202
203 #[test]
204 fn test_check_len() {
205 assert_eq!(
207 Err(Error),
208 Header::new_unchecked(&BYTES_HEADER_MORE_FRAG[..5]).check_len()
209 );
210 assert_eq!(
212 Ok(()),
213 Header::new_unchecked(&BYTES_HEADER_MORE_FRAG).check_len()
214 );
215 }
216
217 #[test]
218 fn test_header_deconstruct() {
219 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
220 assert_eq!(header.frag_offset(), 0);
221 assert!(header.more_frags());
222 assert_eq!(header.ident(), 12345);
223
224 let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG);
225 assert_eq!(header.frag_offset(), 320);
226 assert!(!header.more_frags());
227 assert_eq!(header.ident(), 67890);
228 }
229
230 #[test]
231 fn test_repr_parse_valid() {
232 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
233 let repr = Repr::parse(&header).unwrap();
234 assert_eq!(
235 repr,
236 Repr {
237 frag_offset: 0,
238 more_frags: true,
239 ident: 12345
240 }
241 );
242
243 let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG);
244 let repr = Repr::parse(&header).unwrap();
245 assert_eq!(
246 repr,
247 Repr {
248 frag_offset: 320,
249 more_frags: false,
250 ident: 67890
251 }
252 );
253 }
254
255 #[test]
256 fn test_repr_emit() {
257 let repr = Repr {
258 frag_offset: 0,
259 more_frags: true,
260 ident: 12345,
261 };
262 let mut bytes = [0u8; 6];
263 let mut header = Header::new_unchecked(&mut bytes);
264 repr.emit(&mut header);
265 assert_eq!(header.into_inner(), &BYTES_HEADER_MORE_FRAG[0..6]);
266
267 let repr = Repr {
268 frag_offset: 320,
269 more_frags: false,
270 ident: 67890,
271 };
272 let mut bytes = [0u8; 6];
273 let mut header = Header::new_unchecked(&mut bytes);
274 repr.emit(&mut header);
275 assert_eq!(header.into_inner(), &BYTES_HEADER_LAST_FRAG[0..6]);
276 }
277
278 #[test]
279 fn test_buffer_len() {
280 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
281 let repr = Repr::parse(&header).unwrap();
282 assert_eq!(repr.buffer_len(), BYTES_HEADER_MORE_FRAG.len());
283 }
284}