zero_packet/network/extensions/
options.rs

1use core::fmt;
2
3/// Minimum length of an Options extension header in bytes.
4pub const OPTIONS_HEADER_MIN_LEN: usize = 8;
5
6/// Writes an Options extension header fields.
7///
8/// May be Hop-by-Hop or Destination Options.
9pub struct OptionsHeaderWriter<'a> {
10    pub bytes: &'a mut [u8],
11}
12
13impl<'a> OptionsHeaderWriter<'a> {
14    /// Creates a new `OptionsHeaderWriter` from the given data slice.
15    #[inline]
16    pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
17        if bytes.len() < OPTIONS_HEADER_MIN_LEN {
18            return Err("Slice is too short to contain an Options extension header.");
19        }
20
21        Ok(Self { bytes })
22    }
23
24    /// Returns the total Wheader length in bytes.
25    #[inline]
26    pub fn header_len(&self) -> usize {
27        (self.bytes[1] as usize + 1) * 8
28    }
29
30    /// Sets the next header field.
31    ///
32    /// Specifies the type of the next header.
33    #[inline]
34    pub fn set_next_header(&mut self, next_header: u8) {
35        self.bytes[0] = next_header;
36    }
37
38    /// Sets the header extension length field.
39    ///
40    /// Length of the header in 8 bytes, not including the first 8 bytes.
41    /// 
42    /// E.g. Header length = (header_ext_len + 1) * 8.
43    #[inline]
44    pub fn set_header_ext_len(&mut self, header_ext_len: u8) {
45        self.bytes[1] = header_ext_len;
46    }
47
48    /// Sets the options and padding fields.
49    ///
50    /// Is of variable length.
51    #[inline]
52    pub fn set_options(&mut self, options: &[u8]) -> Result<(), &'static str> {
53        if options.len() < 6 {
54            return Err("Options field must be at least 6 bytes long.");
55        }
56
57        let extension_len = self.bytes[1] as usize * 8;
58
59        if extension_len != options.len() {
60            return Err("Options length must match the header extension length.");
61        }
62
63        let start_offset = 2;
64        let end_offset = start_offset + options.len();
65
66        if end_offset > self.bytes.len() {
67            return Err("Options exceed the allocated header length.");
68        }
69
70        self.bytes[start_offset..end_offset].copy_from_slice(options);
71        
72        Ok(())
73    }
74}
75
76pub struct OptionsHeaderReader<'a> {
77    pub bytes: &'a [u8],
78}
79
80impl<'a> OptionsHeaderReader<'a> {
81    /// Creates a new `OptionsHeaderReader` from the given data slice.
82    #[inline]
83    pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
84        if bytes.len() < OPTIONS_HEADER_MIN_LEN {
85            return Err("Slice is too short to contain an Options extension header.");
86        }
87
88        Ok(Self { bytes })
89    }
90
91    /// Returns the next header field.
92    ///
93    /// Specifies the type of the next header.
94    #[inline]
95    pub fn next_header(&self) -> u8 {
96        self.bytes[0]
97    }
98
99    /// Returns the header extension length field.
100    ///
101    /// Length of the header in 8 bytes, not including the first 8 bytes.
102    /// 
103    /// E.g. Header length = (header_ext_len + 1) * 8.
104    #[inline]
105    pub fn header_ext_len(&self) -> u8 {
106        self.bytes[1]
107    }
108
109    /// Returns the options and padding fields.
110    #[inline]
111    pub fn options(&self) -> Result<&'a [u8], &'static str> {
112        let end = self.header_len();
113
114        if self.bytes.len() < end {
115            return Err("Indicated header length exceeds the allocated buffer.");
116        }
117
118        Ok(&self.bytes[2..end])
119    }
120
121    /// Returns the total header length in bytes.
122    #[inline]
123    pub fn header_len(&self) -> usize {
124        (self.bytes[1] as usize + 1) * 8
125    }
126
127    /// Returns a reference to the header.
128    ///
129    /// May fail if the indicated header length exceeds the allocated buffer.
130    #[inline]
131    pub fn header(&self) -> Result<&'a [u8], &'static str> {
132        let end = self.header_len();
133
134        if end > self.bytes.len() {
135            return Err("Indicated IPv6 options header length exceeds the allocated buffer.");
136        }
137
138        Ok(&self.bytes[..end])
139    }
140
141    /// Returns a reference to the payload.
142    ///
143    /// May fail if the indicated header length exceeds the allocated buffer.
144    #[inline]
145    pub fn payload(&self) -> Result<&'a [u8], &'static str> {
146        let start = self.header_len();
147
148        if start > self.bytes.len() {
149            return Err("Indicated IPv6 options header length exceeds the allocated buffer.");
150        }
151
152        Ok(&self.bytes[self.header_len()..])
153    }
154}
155
156impl fmt::Debug for OptionsHeaderReader<'_> {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        f.debug_struct("OptionsHeaderReader")
159            .field("next_header", &self.next_header())
160            .field("header_ext_len", &self.header_ext_len())
161            .field("options", &self.options())
162            .finish()
163    }
164}
165
166#[cfg(test)]
167pub mod tests {
168    use super::*;
169
170    #[test]
171    fn getters_and_setters() {
172        // Raw packet.
173        let mut bytes = [0; 16];
174
175        // Random values.
176        let next_header = 6;
177        let header_ext_len = 1; // (header_ext_len + 1) * 8 = 16
178        let options = [1; 8];
179
180        // Write the Options extension header.
181        let mut writer = OptionsHeaderWriter::new(&mut bytes).unwrap();
182        writer.set_next_header(next_header);
183        writer.set_header_ext_len(header_ext_len);
184        writer.set_options(&options).unwrap();
185
186        // Read the Options extension header.
187        let reader = OptionsHeaderReader::new(&bytes).unwrap();
188        assert_eq!(reader.next_header(), next_header);
189        assert_eq!(reader.header_ext_len(), header_ext_len);
190        assert_eq!(
191            reader.options().unwrap(),
192            &[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
193        );
194    }
195}