etherparse/link/
macsec_header_slice.rs1use crate::{
2 err::{Layer, LenError},
3 *,
4};
5
6#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8pub struct MacsecHeaderSlice<'a> {
9 pub(crate) slice: &'a [u8],
10}
11
12impl<'a> MacsecHeaderSlice<'a> {
13 pub fn from_slice(
16 slice: &'a [u8],
17 ) -> Result<MacsecHeaderSlice<'a>, err::macsec::HeaderSliceError> {
18 use err::macsec::{HeaderError::*, HeaderSliceError::*};
19
20 if slice.len() < 6 {
21 return Err(Len(LenError {
22 required_len: 6,
23 len: slice.len(),
24 len_source: LenSource::Slice,
25 layer: Layer::MacsecHeader,
26 layer_start_offset: 0,
27 }));
28 }
29
30 let tci_an = unsafe { slice.get_unchecked(0) };
32
33 if 0 != tci_an & 0b1000_0000 {
35 return Err(Content(UnexpectedVersion));
36 }
37
38 let unmodified = 0 == tci_an & 0b1100;
40 if unmodified {
41 let short_len = unsafe { slice.get_unchecked(1) & 0b0011_1111 };
43 if short_len == 1 {
45 return Err(Content(InvalidUnmodifiedShortLen));
46 }
47 }
48
49 let required_len =
51 6 + if unmodified { 2 } else { 0 } + if 0 != tci_an & 0b10_0000 { 8 } else { 0 };
52
53 if slice.len() < required_len {
54 return Err(Len(LenError {
55 required_len,
56 len: slice.len(),
57 len_source: LenSource::Slice,
58 layer: Layer::MacsecHeader,
59 layer_start_offset: 0,
60 }));
61 }
62
63 Ok(MacsecHeaderSlice {
64 slice: unsafe { core::slice::from_raw_parts(slice.as_ptr(), required_len) },
66 })
67 }
68
69 #[inline]
72 pub fn slice(&self) -> &'a [u8] {
73 self.slice
74 }
75
76 #[inline]
78 pub fn tci_an_raw(&self) -> u8 {
79 unsafe { *self.slice.get_unchecked(0) }
82 }
83
84 #[inline]
86 pub fn endstation_id(&self) -> bool {
87 0 != (self.tci_an_raw() & 0b100_0000)
88 }
89
90 #[inline]
92 pub fn tci_scb(&self) -> bool {
93 0 != (self.tci_an_raw() & 0b1_0000)
94 }
95
96 #[inline]
99 pub fn encrypted(&self) -> bool {
100 0 != (self.tci_an_raw() & 0b1000)
103 }
104
105 #[inline]
107 pub fn userdata_changed(&self) -> bool {
108 0 != (self.tci_an_raw() & 0b100)
111 }
112
113 #[inline]
115 pub fn is_unmodified(&self) -> bool {
116 0 == (self.tci_an_raw() & 0b1100)
119 }
120
121 #[inline]
124 pub fn ptype(&self) -> MacsecPType {
125 let e = self.encrypted();
126 let c = self.userdata_changed();
127 if e {
128 if c {
129 MacsecPType::Encrypted
130 } else {
131 MacsecPType::EncryptedUnmodified
132 }
133 } else if c {
134 MacsecPType::Modified
135 } else if 0 != (self.tci_an_raw() & 0b10_0000) {
136 MacsecPType::Unmodified(EtherType(u16::from_be_bytes(unsafe {
141 [*self.slice.get_unchecked(14), *self.slice.get_unchecked(15)]
142 })))
143 } else {
144 MacsecPType::Unmodified(EtherType(u16::from_be_bytes(unsafe {
149 [*self.slice.get_unchecked(6), *self.slice.get_unchecked(7)]
150 })))
151 }
152 }
153
154 #[inline]
156 pub fn an(&self) -> MacsecAn {
157 unsafe { MacsecAn::new_unchecked(self.tci_an_raw() & 0b11) }
160 }
161
162 #[inline]
164 pub fn short_len(&self) -> MacsecShortLen {
165 unsafe { MacsecShortLen::from_u8_unchecked(self.slice.get_unchecked(1) & 0b0011_1111) }
170 }
171
172 #[inline]
174 pub fn packet_nr(&self) -> u32 {
175 u32::from_be_bytes(unsafe {
179 [
180 *self.slice.get_unchecked(2),
181 *self.slice.get_unchecked(3),
182 *self.slice.get_unchecked(4),
183 *self.slice.get_unchecked(5),
184 ]
185 })
186 }
187
188 #[inline]
190 pub fn sci_present(&self) -> bool {
191 0 != (self.tci_an_raw() & 0b10_0000)
192 }
193
194 #[inline]
196 pub fn sci(&self) -> Option<u64> {
197 if self.sci_present() {
198 Some(u64::from_be_bytes(unsafe {
202 [
203 *self.slice.get_unchecked(6),
204 *self.slice.get_unchecked(7),
205 *self.slice.get_unchecked(8),
206 *self.slice.get_unchecked(9),
207 *self.slice.get_unchecked(10),
208 *self.slice.get_unchecked(11),
209 *self.slice.get_unchecked(12),
210 *self.slice.get_unchecked(13),
211 ]
212 }))
213 } else {
214 None
215 }
216 }
217
218 #[inline]
222 pub fn next_ether_type(&self) -> Option<EtherType> {
223 if 0 != self.tci_an_raw() & 0b1100 {
224 None
225 } else if self.sci_present() {
226 Some(EtherType(u16::from_be_bytes(unsafe {
231 [*self.slice.get_unchecked(14), *self.slice.get_unchecked(15)]
232 })))
233 } else {
234 Some(EtherType(u16::from_be_bytes(unsafe {
239 [*self.slice.get_unchecked(6), *self.slice.get_unchecked(7)]
240 })))
241 }
242 }
243
244 #[inline]
246 pub fn header_len(&self) -> usize {
247 6 + if self.sci_present() { 8 } else { 0 } + if self.is_unmodified() { 2 } else { 0 }
248 }
249
250 #[inline]
256 pub fn expected_payload_len(&self) -> Option<usize> {
257 let sl = self.short_len().value() as usize;
258 if sl > 0 {
259 if 0 != self.tci_an_raw() & 0b1100 {
260 Some(sl)
262 } else if sl < 2 {
263 None
264 } else {
265 Some(sl - 2)
266 }
267 } else {
268 None
269 }
270 }
271
272 #[inline]
275 pub fn to_header(&self) -> MacsecHeader {
276 MacsecHeader {
277 ptype: self.ptype(),
278 endstation_id: self.endstation_id(),
279 scb: self.tci_scb(),
280 an: self.an(),
281 short_len: self.short_len(),
282 packet_nr: self.packet_nr(),
283 sci: self.sci(),
284 }
285 }
286}
287
288#[cfg(test)]
289mod test {
290 use super::*;
291 use crate::test_gens::*;
292 use arrayvec::ArrayVec;
293 use proptest::prelude::*;
294
295 proptest! {
296 #[test]
297 fn from_slice(
298 macsec in macsec_any(),
299 ether_type in ether_type_any(),
300 sci in any::<u64>()
301 ) {
302 use MacsecPType::*;
303 use err::macsec::*;
304
305 for ptype in [Unmodified(ether_type), Modified, Encrypted, EncryptedUnmodified] {
307 for has_sci in [false, true] {
308 let mut macsec = macsec.clone();
309 macsec.ptype = ptype;
310 macsec.sci = if has_sci {
311 Some(sci)
312 } else {
313 None
314 };
315 if matches!(ptype, MacsecPType::Unmodified(_)) && macsec.short_len.value() == 1 {
316 macsec.short_len = MacsecShortLen::ZERO;
317 }
318
319 {
321 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
322 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
323 bytes.try_extend_from_slice(&[1]).unwrap();
324 let m = MacsecHeaderSlice::from_slice(&bytes).unwrap();
325 assert_eq!(m.to_header(), macsec);
326 assert_eq!(m.slice(), &bytes[..bytes.len() - 1]);
327 }
328
329 {
331 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
332 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
333 bytes.try_extend_from_slice(&[1]).unwrap();
334
335 bytes[0] = bytes[0] | 0b1000_0000;
337
338 let m = MacsecHeaderSlice::from_slice(&bytes);
339 assert_eq!(m, Err(HeaderSliceError::Content(HeaderError::UnexpectedVersion)));
340 }
341
342 if matches!(ptype, MacsecPType::Unmodified(_)) {
344 let mut macsec = macsec.clone();
345 macsec.short_len = MacsecShortLen::try_from_u8(1).unwrap();
346 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
347 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
348 bytes.try_extend_from_slice(&[1]).unwrap();
349
350 let m = MacsecHeaderSlice::from_slice(&bytes);
351 assert_eq!(m, Err(HeaderSliceError::Content(HeaderError::InvalidUnmodifiedShortLen)));
352 }
353
354 for len in 0..macsec.header_len() {
356 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
357 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
358 bytes.try_extend_from_slice(&[1]).unwrap();
359
360 let m = MacsecHeaderSlice::from_slice(&bytes[..len]);
361 assert_eq!(
362 m,
363 Err(HeaderSliceError::Len(err::LenError{
364 required_len: if len < 6 {
365 6
366 } else {
367 macsec.header_len()
368 },
369 len,
370 len_source: LenSource::Slice,
371 layer: Layer::MacsecHeader,
372 layer_start_offset: 0,
373 }))
374 );
375 }
376 }
377 }
378 }
379 }
380
381 proptest! {
382 #[test]
383 fn expected_payload_len(
384 header in macsec_any(),
385 ether_type in ether_type_any(),
386 valid_unmodified_len in 2u8..=MacsecShortLen::MAX_U8,
387 valid_modified_len in 1u8..=MacsecShortLen::MAX_U8
388 ) {
389 {
391 let mut header = header.clone();
392 header.ptype = MacsecPType::Unmodified(ether_type);
393 header.short_len = MacsecShortLen::try_from_u8(valid_unmodified_len).unwrap();
394 let bytes = header.to_bytes();
395 let slice = MacsecHeaderSlice::from_slice(&bytes).unwrap();
396 assert_eq!(Some(valid_unmodified_len as usize - 2), slice.expected_payload_len());
397 }
398
399 for short_len in 0..2u8 {
401 let mut header = header.clone();
402 header.ptype = MacsecPType::Unmodified(ether_type);
403 header.short_len = MacsecShortLen::try_from_u8(short_len).unwrap();
404 let bytes = header.to_bytes();
405 let slice = MacsecHeaderSlice{ slice: &bytes };
406 assert_eq!(None, slice.expected_payload_len());
407 }
408
409 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
411 let mut header = header.clone();
412 header.ptype = ptype;
413 header.short_len = MacsecShortLen::try_from_u8(valid_modified_len).unwrap();
414 let bytes = header.to_bytes();
415 let slice = MacsecHeaderSlice::from_slice(&bytes).unwrap();
416 assert_eq!(Some(valid_modified_len as usize), slice.expected_payload_len());
417 }
418
419 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
421 let mut header = header.clone();
422 header.ptype = ptype;
423 header.short_len = MacsecShortLen::ZERO;
424 let bytes = header.to_bytes();
425 let slice = MacsecHeaderSlice::from_slice(&bytes).unwrap();
426 assert_eq!(None, slice.expected_payload_len());
427 }
428 }
429 }
430}