smoltcp/wire/
ipv6ext_header.rs

1#![allow(unused)]
2
3use super::IpProtocol;
4use super::{Error, Result};
5
6mod field {
7    #![allow(non_snake_case)]
8
9    use crate::wire::field::*;
10
11    pub const MIN_HEADER_SIZE: usize = 8;
12
13    pub const NXT_HDR: usize = 0;
14    pub const LENGTH: usize = 1;
15    // Variable-length field.
16    //
17    // Length of the header is in 8-octet units, not including the first 8 octets.
18    // The first two octets are the next header type and the header length.
19    pub const fn PAYLOAD(length_field: u8) -> Field {
20        let bytes = length_field as usize * 8 + 8;
21        2..bytes
22    }
23}
24
25/// A read/write wrapper around an IPv6 Extension Header buffer.
26#[derive(Debug, PartialEq, Eq)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub struct Header<T: AsRef<[u8]>> {
29    buffer: T,
30}
31
32/// Core getter methods relevant to any IPv6 extension header.
33impl<T: AsRef<[u8]>> Header<T> {
34    /// Create a raw octet buffer with an IPv6 Extension Header structure.
35    pub const fn new_unchecked(buffer: T) -> Self {
36        Header { buffer }
37    }
38
39    /// Shorthand for a combination of [new_unchecked] and [check_len].
40    ///
41    /// [new_unchecked]: #method.new_unchecked
42    /// [check_len]: #method.check_len
43    pub fn new_checked(buffer: T) -> Result<Self> {
44        let header = Self::new_unchecked(buffer);
45        header.check_len()?;
46        Ok(header)
47    }
48
49    /// Ensure that no accessor method will panic if called.
50    /// Returns `Err(Error)` if the buffer is too short.
51    ///
52    /// The result of this check is invalidated by calling [set_header_len].
53    ///
54    /// [set_header_len]: #method.set_header_len
55    pub fn check_len(&self) -> Result<()> {
56        let data = self.buffer.as_ref();
57
58        let len = data.len();
59        if len < field::MIN_HEADER_SIZE {
60            return Err(Error);
61        }
62
63        let of = field::PAYLOAD(data[field::LENGTH]);
64        if len < of.end {
65            return Err(Error);
66        }
67
68        Ok(())
69    }
70
71    /// Consume the header, returning the underlying buffer.
72    pub fn into_inner(self) -> T {
73        self.buffer
74    }
75
76    /// Return the next header field.
77    pub fn next_header(&self) -> IpProtocol {
78        let data = self.buffer.as_ref();
79        IpProtocol::from(data[field::NXT_HDR])
80    }
81
82    /// Return the header length field.
83    pub fn header_len(&self) -> u8 {
84        let data = self.buffer.as_ref();
85        data[field::LENGTH]
86    }
87}
88
89impl<'h, T: AsRef<[u8]> + ?Sized> Header<&'h T> {
90    /// Return the payload of the IPv6 extension header.
91    pub fn payload(&self) -> &'h [u8] {
92        let data = self.buffer.as_ref();
93        &data[field::PAYLOAD(data[field::LENGTH])]
94    }
95}
96
97impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
98    /// Set the next header field.
99    #[inline]
100    pub fn set_next_header(&mut self, value: IpProtocol) {
101        let data = self.buffer.as_mut();
102        data[field::NXT_HDR] = value.into();
103    }
104
105    /// Set the extension header data length. The length of the header is
106    /// in 8-octet units, not including the first 8 octets.
107    #[inline]
108    pub fn set_header_len(&mut self, value: u8) {
109        let data = self.buffer.as_mut();
110        data[field::LENGTH] = value;
111    }
112}
113
114impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Header<&'a mut T> {
115    /// Return a mutable pointer to the payload data.
116    #[inline]
117    pub fn payload_mut(&mut self) -> &mut [u8] {
118        let data = self.buffer.as_mut();
119        let len = data[field::LENGTH];
120        &mut data[field::PAYLOAD(len)]
121    }
122}
123
124#[derive(Debug, PartialEq, Eq, Clone, Copy)]
125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
126pub struct Repr<'a> {
127    pub next_header: IpProtocol,
128    pub length: u8,
129    pub data: &'a [u8],
130}
131
132impl<'a> Repr<'a> {
133    /// Parse an IPv6 Extension Header Header and return a high-level representation.
134    pub fn parse<T>(header: &Header<&'a T>) -> Result<Self>
135    where
136        T: AsRef<[u8]> + ?Sized,
137    {
138        header.check_len()?;
139        Ok(Self {
140            next_header: header.next_header(),
141            length: header.header_len(),
142            data: header.payload(),
143        })
144    }
145
146    /// Return the length, in bytes, of a header that will be emitted from this high-level
147    /// representation.
148    pub const fn header_len(&self) -> usize {
149        2
150    }
151
152    /// Emit a high-level representation into an IPv6 Extension Header.
153    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
154        header.set_next_header(self.next_header);
155        header.set_header_len(self.length);
156    }
157}
158
159#[cfg(test)]
160mod test {
161    use super::*;
162
163    // A Hop-by-Hop Option header with a PadN option of option data length 4.
164    static REPR_PACKET_PAD4: [u8; 8] = [0x6, 0x0, 0x1, 0x4, 0x0, 0x0, 0x0, 0x0];
165
166    // A Hop-by-Hop Option header with a PadN option of option data length 12.
167    static REPR_PACKET_PAD12: [u8; 16] = [
168        0x06, 0x1, 0x1, 0x0C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
169    ];
170
171    #[test]
172    fn test_check_len() {
173        // zero byte buffer
174        assert_eq!(
175            Err(Error),
176            Header::new_unchecked(&REPR_PACKET_PAD4[..0]).check_len()
177        );
178        // no length field
179        assert_eq!(
180            Err(Error),
181            Header::new_unchecked(&REPR_PACKET_PAD4[..1]).check_len()
182        );
183        // less than 8 bytes
184        assert_eq!(
185            Err(Error),
186            Header::new_unchecked(&REPR_PACKET_PAD4[..7]).check_len()
187        );
188        // valid
189        assert_eq!(Ok(()), Header::new_unchecked(&REPR_PACKET_PAD4).check_len());
190        // valid
191        assert_eq!(
192            Ok(()),
193            Header::new_unchecked(&REPR_PACKET_PAD12).check_len()
194        );
195        // length field value greater than number of bytes
196        let header: [u8; 8] = [0x06, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
197        assert_eq!(Err(Error), Header::new_unchecked(&header).check_len());
198    }
199
200    #[test]
201    fn test_header_deconstruct() {
202        let header = Header::new_unchecked(&REPR_PACKET_PAD4);
203        assert_eq!(header.next_header(), IpProtocol::Tcp);
204        assert_eq!(header.header_len(), 0);
205        assert_eq!(header.payload(), &REPR_PACKET_PAD4[2..]);
206
207        let header = Header::new_unchecked(&REPR_PACKET_PAD12);
208        assert_eq!(header.next_header(), IpProtocol::Tcp);
209        assert_eq!(header.header_len(), 1);
210        assert_eq!(header.payload(), &REPR_PACKET_PAD12[2..]);
211    }
212
213    #[test]
214    fn test_overlong() {
215        let mut bytes = vec![];
216        bytes.extend(&REPR_PACKET_PAD4[..]);
217        bytes.push(0);
218
219        assert_eq!(
220            Header::new_unchecked(&bytes).payload().len(),
221            REPR_PACKET_PAD4[2..].len()
222        );
223        assert_eq!(
224            Header::new_unchecked(&mut bytes).payload_mut().len(),
225            REPR_PACKET_PAD4[2..].len()
226        );
227
228        let mut bytes = vec![];
229        bytes.extend(&REPR_PACKET_PAD12[..]);
230        bytes.push(0);
231
232        assert_eq!(
233            Header::new_unchecked(&bytes).payload().len(),
234            REPR_PACKET_PAD12[2..].len()
235        );
236        assert_eq!(
237            Header::new_unchecked(&mut bytes).payload_mut().len(),
238            REPR_PACKET_PAD12[2..].len()
239        );
240    }
241
242    #[test]
243    fn test_header_len_overflow() {
244        let mut bytes = vec![];
245        bytes.extend(REPR_PACKET_PAD4);
246        let len = bytes.len() as u8;
247        Header::new_unchecked(&mut bytes).set_header_len(len + 1);
248
249        assert_eq!(Header::new_checked(&bytes).unwrap_err(), Error);
250
251        let mut bytes = vec![];
252        bytes.extend(REPR_PACKET_PAD12);
253        let len = bytes.len() as u8;
254        Header::new_unchecked(&mut bytes).set_header_len(len + 1);
255
256        assert_eq!(Header::new_checked(&bytes).unwrap_err(), Error);
257    }
258
259    #[test]
260    fn test_repr_parse_valid() {
261        let header = Header::new_unchecked(&REPR_PACKET_PAD4);
262        let repr = Repr::parse(&header).unwrap();
263        assert_eq!(
264            repr,
265            Repr {
266                next_header: IpProtocol::Tcp,
267                length: 0,
268                data: &REPR_PACKET_PAD4[2..]
269            }
270        );
271
272        let header = Header::new_unchecked(&REPR_PACKET_PAD12);
273        let repr = Repr::parse(&header).unwrap();
274        assert_eq!(
275            repr,
276            Repr {
277                next_header: IpProtocol::Tcp,
278                length: 1,
279                data: &REPR_PACKET_PAD12[2..]
280            }
281        );
282    }
283
284    #[test]
285    fn test_repr_emit() {
286        let repr = Repr {
287            next_header: IpProtocol::Tcp,
288            length: 0,
289            data: &REPR_PACKET_PAD4[2..],
290        };
291        let mut bytes = [0u8; 2];
292        let mut header = Header::new_unchecked(&mut bytes);
293        repr.emit(&mut header);
294        assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..2]);
295
296        let repr = Repr {
297            next_header: IpProtocol::Tcp,
298            length: 1,
299            data: &REPR_PACKET_PAD12[2..],
300        };
301        let mut bytes = [0u8; 2];
302        let mut header = Header::new_unchecked(&mut bytes);
303        repr.emit(&mut header);
304        assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..2]);
305    }
306}