zero_packet/network/extensions/
options.rs1use core::fmt;
2
3pub const OPTIONS_HEADER_MIN_LEN: usize = 8;
5
6pub struct OptionsHeaderWriter<'a> {
10 pub bytes: &'a mut [u8],
11}
12
13impl<'a> OptionsHeaderWriter<'a> {
14 #[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 #[inline]
26 pub fn header_len(&self) -> usize {
27 (self.bytes[1] as usize + 1) * 8
28 }
29
30 #[inline]
34 pub fn set_next_header(&mut self, next_header: u8) {
35 self.bytes[0] = next_header;
36 }
37
38 #[inline]
44 pub fn set_header_ext_len(&mut self, header_ext_len: u8) {
45 self.bytes[1] = header_ext_len;
46 }
47
48 #[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 #[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 #[inline]
95 pub fn next_header(&self) -> u8 {
96 self.bytes[0]
97 }
98
99 #[inline]
105 pub fn header_ext_len(&self) -> u8 {
106 self.bytes[1]
107 }
108
109 #[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 #[inline]
123 pub fn header_len(&self) -> usize {
124 (self.bytes[1] as usize + 1) * 8
125 }
126
127 #[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 #[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 let mut bytes = [0; 16];
174
175 let next_header = 6;
177 let header_ext_len = 1; let options = [1; 8];
179
180 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 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}