1use super::super::*;
2
3#[derive(Clone, Debug, Eq, PartialEq)]
5pub struct Ipv6FragmentHeader {
6 pub next_header: IpNumber,
10 pub fragment_offset: IpFragOffset,
13 pub more_fragments: bool,
15 pub identification: u32,
17}
18
19impl Ipv6FragmentHeader {
20 pub const LEN: usize = 8;
22
23 pub const fn new(
27 next_header: IpNumber,
28 fragment_offset: IpFragOffset,
29 more_fragments: bool,
30 identification: u32,
31 ) -> Ipv6FragmentHeader {
32 Ipv6FragmentHeader {
33 next_header,
34 fragment_offset,
35 more_fragments,
36 identification,
37 }
38 }
39
40 pub fn from_slice(slice: &[u8]) -> Result<(Ipv6FragmentHeader, &[u8]), err::LenError> {
42 let s = Ipv6FragmentHeaderSlice::from_slice(slice)?;
43 let rest = &slice[8..];
44 let header = s.to_header();
45 Ok((header, rest))
46 }
47
48 #[cfg(feature = "std")]
50 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
51 pub fn read<T: std::io::Read + std::io::Seek + Sized>(
52 reader: &mut T,
53 ) -> Result<Ipv6FragmentHeader, std::io::Error> {
54 let buffer = {
55 let mut buffer: [u8; 8] = [0; 8];
56 reader.read_exact(&mut buffer)?;
57 buffer
58 };
59
60 Ok(Ipv6FragmentHeader {
61 next_header: IpNumber(buffer[0]),
62 fragment_offset: unsafe {
63 IpFragOffset::new_unchecked(u16::from_be_bytes([
66 (buffer[2] >> 3) & 0b0001_1111u8,
67 ((buffer[2] << 5) & 0b1110_0000u8) | (buffer[3] & 0b0001_1111u8),
68 ]))
69 },
70 more_fragments: 0 != buffer[3] & 0b1000_0000u8,
71 identification: u32::from_be_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]),
72 })
73 }
74
75 #[cfg(feature = "std")]
77 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
78 pub fn read_limited<T: std::io::Read + std::io::Seek + Sized>(
79 reader: &mut crate::io::LimitedReader<T>,
80 ) -> Result<Ipv6FragmentHeader, crate::err::io::LimitedReadError> {
81 use err::Layer;
82
83 reader.start_layer(Layer::Ipv6FragHeader);
85
86 let buffer = {
87 let mut buffer: [u8; 8] = [0; 8];
88 reader.read_exact(&mut buffer)?;
89 buffer
90 };
91
92 Ok(Ipv6FragmentHeader {
93 next_header: IpNumber(buffer[0]),
94 fragment_offset: unsafe {
95 IpFragOffset::new_unchecked(u16::from_be_bytes([
98 (buffer[2] >> 3) & 0b0001_1111u8,
99 ((buffer[2] << 5) & 0b1110_0000u8) | (buffer[3] & 0b0001_1111u8),
100 ]))
101 },
102 more_fragments: 0 != buffer[3] & 0b1000_0000u8,
103 identification: u32::from_be_bytes([buffer[4], buffer[5], buffer[6], buffer[7]]),
104 })
105 }
106
107 #[cfg(feature = "std")]
109 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
110 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
111 writer.write_all(&self.to_bytes())
112 }
113
114 #[inline]
116 pub fn header_len(&self) -> usize {
117 Ipv6FragmentHeader::LEN
118 }
119
120 #[inline]
163 pub fn is_fragmenting_payload(&self) -> bool {
164 self.more_fragments || (0 != self.fragment_offset.value())
165 }
166
167 #[inline]
170 pub fn to_bytes(&self) -> [u8; 8] {
171 let fo_be: [u8; 2] = self.fragment_offset.value().to_be_bytes();
172 let id_be = self.identification.to_be_bytes();
173 [
174 self.next_header.0,
175 0,
176 (((fo_be[0] << 3) & 0b1111_1000u8) | ((fo_be[1] >> 5) & 0b0000_0111u8)),
177 ((fo_be[1] & 0b0001_1111u8)
178 | if self.more_fragments {
179 0b1000_0000u8
180 } else {
181 0
182 }),
183 id_be[0],
184 id_be[1],
185 id_be[2],
186 id_be[3],
187 ]
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use crate::{test_gens::*, *};
194 use alloc::{format, vec::Vec};
195 use proptest::prelude::*;
196 use std::io::Cursor;
197
198 proptest! {
199 #[test]
200 fn debug(input in ipv6_fragment_any()) {
201 assert_eq!(
202 &format!(
203 "Ipv6FragmentHeader {{ next_header: {:?}, fragment_offset: {:?}, more_fragments: {}, identification: {} }}",
204 input.next_header,
205 input.fragment_offset,
206 input.more_fragments,
207 input.identification
208 ),
209 &format!("{:?}", input)
210 );
211 }
212 }
213
214 proptest! {
215 #[test]
216 fn clone_eq(input in ipv6_fragment_any()) {
217 assert_eq!(input, input.clone());
218 }
219 }
220
221 proptest! {
222 #[test]
223 fn new(
224 next_header in ip_number_any(),
225 fragment_offset in 0..IpFragOffset::MAX_U16,
226 more_fragments in any::<bool>(),
227 identification in any::<u32>(),
228 ) {
229 let a = Ipv6FragmentHeader::new(
230 next_header,
231 fragment_offset.try_into().unwrap(),
232 more_fragments,
233 identification
234 );
235 assert_eq!(next_header, a.next_header);
236 assert_eq!(fragment_offset, a.fragment_offset.value());
237 assert_eq!(more_fragments, a.more_fragments);
238 assert_eq!(identification, a.identification);
239 }
240 }
241
242 proptest! {
243 #[test]
244 fn from_slice(
245 input in ipv6_fragment_any(),
246 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
247 ) {
248 let mut buffer: Vec<u8> = Vec::with_capacity(8 + dummy_data.len());
250 input.write(&mut buffer).unwrap();
251 buffer.extend(&dummy_data[..]);
252
253 {
255 let (result, rest) = Ipv6FragmentHeader::from_slice(&buffer[..]).unwrap();
256 assert_eq!(input, result);
257 assert_eq!(&buffer[8..], rest);
258 }
259 for len in 0..Ipv6FragmentHeader::LEN {
261 assert_eq!(
262 Ipv6FragmentHeader::from_slice(&buffer[0..len]).unwrap_err(),
263 err::LenError{
264 required_len: Ipv6FragmentHeader::LEN,
265 len: len,
266 len_source: LenSource::Slice,
267 layer: err::Layer::Ipv6FragHeader,
268 layer_start_offset: 0,
269 }
270 );
271 }
272 }
273 }
274
275 proptest! {
276 #[test]
277 fn read(
278 input in ipv6_fragment_any(),
279 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
280 ) {
281 use std::io::ErrorKind;
282
283 let mut buffer: Vec<u8> = Vec::with_capacity(8 + dummy_data.len());
285 input.write(&mut buffer).unwrap();
286 buffer.extend(&dummy_data[..]);
287
288 {
290 let mut cursor = Cursor::new(&buffer);
291 let result = Ipv6FragmentHeader::read(&mut cursor).unwrap();
292 assert_eq!(input, result);
293 assert_eq!(cursor.position(), 8);
294 }
295
296 for len in 0..Ipv6FragmentHeader::LEN {
298 let mut cursor = Cursor::new(&buffer[0..len]);
299 assert_eq!(
300 Ipv6FragmentHeader::read(&mut cursor)
301 .unwrap_err()
302 .kind(),
303 ErrorKind::UnexpectedEof
304 );
305 }
306 }
307 }
308
309 proptest! {
310 #[test]
311 fn write(input in ipv6_fragment_any()) {
312
313 {
315 let mut buffer = Vec::with_capacity(8);
316 input.write(&mut buffer).unwrap();
317 assert_eq!(
318 &buffer,
319 &input.to_bytes()
320 );
321 }
322
323 for len in 0..Ipv6FragmentHeader::LEN {
325 let mut buffer = [0u8;Ipv6FragmentHeader::LEN];
326 let mut cursor = Cursor::new(&mut buffer[..len]);
327 assert!(
328 input.write(&mut cursor).is_err()
329 );
330 }
331 }
332 }
333
334 proptest! {
335 #[test]
336 fn header_len(input in ipv6_fragment_any()) {
337 assert_eq!(8, input.header_len());
338 }
339 }
340
341 proptest! {
342 #[test]
343 fn is_fragmenting_payload(
344 non_zero_offset in 1u16..0b0001_1111_1111_1111u16,
345 identification in any::<u32>(),
346 next_header in ip_number_any(),
347
348 ) {
349 {
351 let header = Ipv6FragmentHeader {
352 next_header,
353 fragment_offset: 0.try_into().unwrap(),
354 more_fragments: false,
355 identification
356 };
357 assert!(false == header.is_fragmenting_payload());
358 }
359 {
361 let header = Ipv6FragmentHeader {
362 next_header,
363 fragment_offset: non_zero_offset.try_into().unwrap(),
364 more_fragments: false,
365 identification
366 };
367 assert!(header.is_fragmenting_payload());
368 }
369
370 {
372 let header = Ipv6FragmentHeader {
373 next_header,
374 fragment_offset: 0.try_into().unwrap(),
375 more_fragments: true,
376 identification
377 };
378 assert!(header.is_fragmenting_payload());
379 }
380
381 {
383 let header = Ipv6FragmentHeader {
384 next_header,
385 fragment_offset: non_zero_offset.try_into().unwrap(),
386 more_fragments: true,
387 identification
388 };
389 assert!(header.is_fragmenting_payload());
390 }
391 }
392 }
393
394 proptest! {
395 #[test]
396 fn to_bytes(input in ipv6_fragment_any()) {
397
398 {
400 let fragment_offset_be = input.fragment_offset.value().to_be_bytes();
401 let id_be = input.identification.to_be_bytes();
402 assert_eq!(
403 &input.to_bytes(),
404 &[
405 input.next_header.0,
406 0,
407 (
408 (fragment_offset_be[0] << 3 & 0b1111_1000u8) |
409 (fragment_offset_be[1] >> 5 & 0b0000_0111u8)
410 ),
411 (
412 (fragment_offset_be[1] & 0b0001_1111u8) |
413 if input.more_fragments {
414 0b1000_0000u8
415 } else {
416 0u8
417 }
418 ),
419 id_be[0],
420 id_be[1],
421 id_be[2],
422 id_be[3],
423 ]
424 );
425 }
426 }
427 }
428}