1 use super::{Error, Result};
2 use core::fmt;
3 
4 use byteorder::{ByteOrder, NetworkEndian};
5 
6 pub use super::IpProtocol as Protocol;
7 
8 /// A read/write wrapper around an IPv6 Fragment Header.
9 #[derive(Debug, PartialEq, Eq)]
10 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
11 pub struct Header<T: AsRef<[u8]>> {
12     buffer: T,
13 }
14 
15 // Format of the Fragment Header
16 //
17 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18 // |  Next Header  |   Reserved    |      Fragment Offset    |Res|M|
19 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 // |                         Identification                        |
21 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22 //
23 // See https://tools.ietf.org/html/rfc8200#section-4.5 for details.
24 mod field {
25     use crate::wire::field::*;
26 
27     // 8-bit identifier of the header immediately following this header.
28     pub const NXT_HDR: usize = 0;
29     // 8-bit reserved field.
30     pub const RESERVED: usize = 1;
31     // 16-bit field containing the fragment offset, reserved and more fragments values.
32     pub const FR_OF_M: Field = 2..4;
33     // 32-bit field identifying the fragmented packet
34     pub const IDENT: Field = 4..8;
35 }
36 
37 impl<T: AsRef<[u8]>> Header<T> {
38     /// Create a raw octet buffer with an IPv6 Fragment Header structure.
new_unchecked(buffer: T) -> Header<T>39     pub const fn new_unchecked(buffer: T) -> Header<T> {
40         Header { buffer }
41     }
42 
43     /// Shorthand for a combination of [new_unchecked] and [check_len].
44     ///
45     /// [new_unchecked]: #method.new_unchecked
46     /// [check_len]: #method.check_len
new_checked(buffer: T) -> Result<Header<T>>47     pub fn new_checked(buffer: T) -> Result<Header<T>> {
48         let header = Self::new_unchecked(buffer);
49         header.check_len()?;
50         Ok(header)
51     }
52 
53     /// Ensure that no accessor method will panic if called.
54     /// Returns `Err(Error)` if the buffer is too short.
check_len(&self) -> Result<()>55     pub fn check_len(&self) -> Result<()> {
56         let data = self.buffer.as_ref();
57         let len = data.len();
58 
59         if len < field::IDENT.end {
60             Err(Error)
61         } else {
62             Ok(())
63         }
64     }
65 
66     /// Consume the header, returning the underlying buffer.
into_inner(self) -> T67     pub fn into_inner(self) -> T {
68         self.buffer
69     }
70 
71     /// Return the next header field.
72     #[inline]
next_header(&self) -> Protocol73     pub fn next_header(&self) -> Protocol {
74         let data = self.buffer.as_ref();
75         Protocol::from(data[field::NXT_HDR])
76     }
77 
78     /// Return the fragment offset field.
79     #[inline]
frag_offset(&self) -> u1680     pub fn frag_offset(&self) -> u16 {
81         let data = self.buffer.as_ref();
82         NetworkEndian::read_u16(&data[field::FR_OF_M]) >> 3
83     }
84 
85     /// Return more fragment flag field.
86     #[inline]
more_frags(&self) -> bool87     pub fn more_frags(&self) -> bool {
88         let data = self.buffer.as_ref();
89         (data[3] & 0x1) == 1
90     }
91 
92     /// Return the fragment identification value field.
93     #[inline]
ident(&self) -> u3294     pub fn ident(&self) -> u32 {
95         let data = self.buffer.as_ref();
96         NetworkEndian::read_u32(&data[field::IDENT])
97     }
98 }
99 
100 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
101     /// Set the next header field.
102     #[inline]
set_next_header(&mut self, value: Protocol)103     pub fn set_next_header(&mut self, value: Protocol) {
104         let data = self.buffer.as_mut();
105         data[field::NXT_HDR] = value.into();
106     }
107 
108     /// Set reserved fields.
109     ///
110     /// Set 8-bit reserved field after the next header field.
111     /// Set 2-bit reserved field between fragment offset and more fragments.
112     #[inline]
clear_reserved(&mut self)113     pub fn clear_reserved(&mut self) {
114         let data = self.buffer.as_mut();
115 
116         data[field::RESERVED] = 0;
117 
118         // Retain the higher order 5 bits and lower order 1 bit
119         data[3] &= 0xf9;
120     }
121 
122     /// Set the fragment offset field.
123     #[inline]
set_frag_offset(&mut self, value: u16)124     pub fn set_frag_offset(&mut self, value: u16) {
125         let data = self.buffer.as_mut();
126         // Retain the lower order 3 bits
127         let raw = ((value & 0x1fff) << 3) | ((data[3] & 0x7) as u16);
128         NetworkEndian::write_u16(&mut data[field::FR_OF_M], raw);
129     }
130 
131     /// Set the more fragments flag field.
132     #[inline]
set_more_frags(&mut self, value: bool)133     pub fn set_more_frags(&mut self, value: bool) {
134         let data = self.buffer.as_mut();
135         // Retain the high order 7 bits
136         let raw = (data[3] & 0xfe) | (value as u8 & 0x1);
137         data[3] = raw;
138     }
139 
140     /// Set the fragmentation identification field.
141     #[inline]
set_ident(&mut self, value: u32)142     pub fn set_ident(&mut self, value: u32) {
143         let data = self.buffer.as_mut();
144         NetworkEndian::write_u32(&mut data[field::IDENT], value);
145     }
146 }
147 
148 impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result149     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150         match Repr::parse(self) {
151             Ok(repr) => write!(f, "{repr}"),
152             Err(err) => {
153                 write!(f, "IPv6 Fragment ({err})")?;
154                 Ok(())
155             }
156         }
157     }
158 }
159 
160 /// A high-level representation of an IPv6 Fragment header.
161 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
162 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
163 pub struct Repr {
164     /// The type of header immediately following the Fragment header.
165     pub next_header: Protocol,
166     /// The offset of the data following this header, relative to the start of the Fragmentable
167     /// Part of the original packet.
168     pub frag_offset: u16,
169     /// When there are more fragments following this header
170     pub more_frags: bool,
171     /// The identification for every packet that is fragmented.
172     pub ident: u32,
173 }
174 
175 impl Repr {
176     /// Parse an IPv6 Fragment Header and return a high-level representation.
parse<T>(header: &Header<&T>) -> Result<Repr> where T: AsRef<[u8]> + ?Sized,177     pub fn parse<T>(header: &Header<&T>) -> Result<Repr>
178     where
179         T: AsRef<[u8]> + ?Sized,
180     {
181         Ok(Repr {
182             next_header: header.next_header(),
183             frag_offset: header.frag_offset(),
184             more_frags: header.more_frags(),
185             ident: header.ident(),
186         })
187     }
188 
189     /// Return the length, in bytes, of a header that will be emitted from this high-level
190     /// representation.
buffer_len(&self) -> usize191     pub const fn buffer_len(&self) -> usize {
192         field::IDENT.end
193     }
194 
195     /// Emit a high-level representation into an IPv6 Fragment Header.
emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>)196     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
197         header.set_next_header(self.next_header);
198         header.clear_reserved();
199         header.set_frag_offset(self.frag_offset);
200         header.set_more_frags(self.more_frags);
201         header.set_ident(self.ident);
202     }
203 }
204 
205 impl fmt::Display for Repr {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result206     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207         write!(
208             f,
209             "IPv6 Fragment next_hdr={} offset={} more={} ident={}",
210             self.next_header, self.frag_offset, self.more_frags, self.ident
211         )
212     }
213 }
214 
215 #[cfg(test)]
216 mod test {
217     use super::*;
218 
219     // A Fragment Header with more fragments remaining
220     static BYTES_HEADER_MORE_FRAG: [u8; 8] = [0x6, 0x0, 0x0, 0x1, 0x0, 0x0, 0x30, 0x39];
221 
222     // A Fragment Header with no more fragments remaining
223     static BYTES_HEADER_LAST_FRAG: [u8; 8] = [0x6, 0x0, 0xa, 0x0, 0x0, 0x1, 0x9, 0x32];
224 
225     #[test]
test_check_len()226     fn test_check_len() {
227         // less than 8 bytes
228         assert_eq!(
229             Err(Error),
230             Header::new_unchecked(&BYTES_HEADER_MORE_FRAG[..7]).check_len()
231         );
232         // valid
233         assert_eq!(
234             Ok(()),
235             Header::new_unchecked(&BYTES_HEADER_MORE_FRAG).check_len()
236         );
237     }
238 
239     #[test]
test_header_deconstruct()240     fn test_header_deconstruct() {
241         let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
242         assert_eq!(header.next_header(), Protocol::Tcp);
243         assert_eq!(header.frag_offset(), 0);
244         assert!(header.more_frags());
245         assert_eq!(header.ident(), 12345);
246 
247         let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG);
248         assert_eq!(header.next_header(), Protocol::Tcp);
249         assert_eq!(header.frag_offset(), 320);
250         assert!(!header.more_frags());
251         assert_eq!(header.ident(), 67890);
252     }
253 
254     #[test]
test_repr_parse_valid()255     fn test_repr_parse_valid() {
256         let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
257         let repr = Repr::parse(&header).unwrap();
258         assert_eq!(
259             repr,
260             Repr {
261                 next_header: Protocol::Tcp,
262                 frag_offset: 0,
263                 more_frags: true,
264                 ident: 12345
265             }
266         );
267 
268         let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG);
269         let repr = Repr::parse(&header).unwrap();
270         assert_eq!(
271             repr,
272             Repr {
273                 next_header: Protocol::Tcp,
274                 frag_offset: 320,
275                 more_frags: false,
276                 ident: 67890
277             }
278         );
279     }
280 
281     #[test]
test_repr_emit()282     fn test_repr_emit() {
283         let repr = Repr {
284             next_header: Protocol::Tcp,
285             frag_offset: 0,
286             more_frags: true,
287             ident: 12345,
288         };
289         let mut bytes = [0u8; 8];
290         let mut header = Header::new_unchecked(&mut bytes);
291         repr.emit(&mut header);
292         assert_eq!(header.into_inner(), &BYTES_HEADER_MORE_FRAG[0..8]);
293 
294         let repr = Repr {
295             next_header: Protocol::Tcp,
296             frag_offset: 320,
297             more_frags: false,
298             ident: 67890,
299         };
300         let mut bytes = [0u8; 8];
301         let mut header = Header::new_unchecked(&mut bytes);
302         repr.emit(&mut header);
303         assert_eq!(header.into_inner(), &BYTES_HEADER_LAST_FRAG[0..8]);
304     }
305 
306     #[test]
test_buffer_len()307     fn test_buffer_len() {
308         let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG);
309         let repr = Repr::parse(&header).unwrap();
310         assert_eq!(repr.buffer_len(), BYTES_HEADER_MORE_FRAG.len());
311     }
312 }
313