1use crate::*;
2use arrayvec::ArrayVec;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct MacsecHeader {
8 pub ptype: MacsecPType,
11
12 pub endstation_id: bool,
14
15 pub scb: bool,
17
18 pub an: MacsecAn,
20
21 pub short_len: MacsecShortLen,
23
24 pub packet_nr: u32,
26
27 pub sci: Option<u64>,
29}
30
31impl MacsecHeader {
32 pub const MIN_LEN: usize = 6;
34
35 pub const MAX_LEN: usize = 16;
37
38 #[inline]
41 pub fn encrypted(&self) -> bool {
42 use MacsecPType::*;
43 matches!(self.ptype, Encrypted | EncryptedUnmodified)
44 }
45
46 pub fn userdata_changed(&self) -> bool {
48 use MacsecPType::*;
49 matches!(self.ptype, Encrypted | Modified)
50 }
51
52 pub fn next_ether_type(&self) -> Option<EtherType> {
54 if let MacsecPType::Unmodified(re) = self.ptype {
55 Some(re)
56 } else {
57 None
58 }
59 }
60
61 pub fn from_slice(slice: &[u8]) -> Result<MacsecHeader, err::macsec::HeaderSliceError> {
64 MacsecHeaderSlice::from_slice(slice).map(|v| v.to_header())
65 }
66
67 pub fn to_bytes(&self) -> ArrayVec<u8, { MacsecHeader::MAX_LEN }> {
69 let tci_an = (self.an.value() & 0b11)
83 | if self.userdata_changed() { 0b100 } else { 0 }
84 | if self.encrypted() { 0b1000 } else { 0 }
85 | if self.scb { 0b1_0000 } else { 0 }
86 | if self.sci.is_some() { 0b10_0000 } else { 0 }
87 | if self.endstation_id { 0b100_0000 } else { 0 };
88 let pn_be = self.packet_nr.to_be_bytes();
89 let sci_be = self.sci.unwrap_or(0).to_be_bytes();
90 let et_be = if let MacsecPType::Unmodified(e) = self.ptype {
91 e.0
92 } else {
93 0
94 }
95 .to_be_bytes();
96 let mut result: ArrayVec<u8, { MacsecHeader::MAX_LEN }> = if self.sci.is_some() {
97 [
98 tci_an,
99 self.short_len.value() & 0b0011_1111,
100 pn_be[0],
101 pn_be[1],
102 pn_be[2],
103 pn_be[3],
104 sci_be[0],
105 sci_be[1],
106 sci_be[2],
107 sci_be[3],
108 sci_be[4],
109 sci_be[5],
110 sci_be[6],
111 sci_be[7],
112 et_be[0],
113 et_be[1],
114 ]
115 } else {
116 [
117 tci_an,
118 self.short_len.value() & 0b0011_1111,
119 pn_be[0],
120 pn_be[1],
121 pn_be[2],
122 pn_be[3],
123 et_be[0],
124 et_be[1],
125 0,
126 0,
127 0,
128 0,
129 0,
130 0,
131 0,
132 0,
133 ]
134 }
135 .into();
136 unsafe {
138 result.set_len(
139 6 + if self.sci.is_some() { 8 } else { 0 }
140 + if matches!(self.ptype, MacsecPType::Unmodified(_)) {
141 2
142 } else {
143 0
144 },
145 );
146 }
147 result
148 }
149
150 #[cfg(feature = "std")]
152 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
153 pub fn read<T: std::io::Read + Sized>(
154 reader: &mut T,
155 ) -> Result<MacsecHeader, err::macsec::HeaderReadError> {
156 use err::macsec::HeaderError::*;
157 use err::macsec::HeaderReadError::*;
158
159 let mut bytes = [0; MacsecHeader::MAX_LEN];
160 reader.read_exact(&mut bytes[..6]).map_err(Io)?;
161
162 let tci_an = bytes[0];
164 if 0 != tci_an & 0b1000_0000 {
165 return Err(Content(UnexpectedVersion));
166 }
167
168 let unmodified = 0 == tci_an & 0b1100;
170 if unmodified {
171 let short_len = bytes[1] & 0b0011_1111;
173 if short_len == 1 {
176 return Err(Content(InvalidUnmodifiedShortLen));
177 }
178 }
179
180 let required_len =
182 6 + if unmodified { 2 } else { 0 } + if 0 != tci_an & 0b10_0000 { 8 } else { 0 };
183
184 if required_len > 6 {
185 reader.read_exact(&mut bytes[6..required_len]).map_err(Io)?;
186 }
187
188 Ok(MacsecHeaderSlice {
189 slice: &bytes[..required_len],
190 }
191 .to_header())
192 }
193
194 #[cfg(feature = "std")]
197 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
198 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
199 writer.write_all(&self.to_bytes())
200 }
201
202 #[inline]
204 pub fn header_len(&self) -> usize {
205 6 + if self.sci.is_some() { 8 } else { 0 }
206 + if matches!(self.ptype, MacsecPType::Unmodified(_)) {
207 2
208 } else {
209 0
210 }
211 }
212
213 #[inline]
219 pub fn expected_payload_len(&self) -> Option<usize> {
220 let sl = self.short_len.value() as usize;
221 if sl > 0 {
222 if matches!(self.ptype, MacsecPType::Unmodified(_)) {
223 if sl < 2 {
224 None
225 } else {
226 Some(sl - 2)
227 }
228 } else {
229 Some(sl)
231 }
232 } else {
233 None
234 }
235 }
236
237 #[inline]
241 pub fn set_payload_len(&mut self, payload_len: usize) {
242 if matches!(self.ptype, MacsecPType::Unmodified(_)) {
243 if payload_len > MacsecShortLen::MAX_USIZE - 2 {
244 self.short_len = MacsecShortLen::ZERO;
245 } else {
246 self.short_len =
249 unsafe { MacsecShortLen::from_u8_unchecked(payload_len as u8 + 2) };
250 }
251 } else if payload_len > MacsecShortLen::MAX_USIZE {
252 self.short_len = MacsecShortLen::ZERO;
253 } else {
254 self.short_len = unsafe { MacsecShortLen::from_u8_unchecked(payload_len as u8) };
257 }
258 }
259}
260
261#[cfg(test)]
262mod test {
263 use super::*;
264 use crate::test_gens::*;
265 use proptest::prelude::*;
266 use std::io::Cursor;
267
268 proptest! {
269 #[test]
270 fn from_slice_to_bytes(
271 header in macsec_any()
272 ) {
273 let mut header = header.clone();
274 if matches!(header.ptype, MacsecPType::Unmodified(_)) && header.short_len.value() == 1 {
275 header.short_len = MacsecShortLen::ZERO;
276 }
277 let bytes = header.to_bytes();
278 let actual = MacsecHeader::from_slice(&bytes);
279 assert_eq!(actual, Ok(header.clone()));
280 }
281 }
282
283 proptest! {
284 #[test]
285 fn getter(
286 macsec in macsec_any(),
287 ethertype in ether_type_any(),
288 ) {
289
290 let tests = [
291 (MacsecPType::Unmodified(ethertype), false, false, Some(ethertype)),
293 (MacsecPType::Modified, false, true, None),
294 (MacsecPType::Encrypted, true, true, None),
295 (MacsecPType::EncryptedUnmodified, true, false, None),
296 ];
297
298 for test in tests {
299 let mut macsec = macsec.clone();
300 macsec.ptype = test.0;
301
302 assert_eq!(test.1, macsec.encrypted());
303 assert_eq!(test.2, macsec.userdata_changed());
304 assert_eq!(test.3, macsec.next_ether_type());
305 }
306 }
307 }
308
309 proptest! {
310 #[test]
311 fn header_len(
312 macsec in macsec_any(),
313 ethertype in ether_type_any(),
314 sci in any::<u64>(),
315 ) {
316 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
318 {
320 let mut macsec = macsec.clone();
321 macsec.ptype = ptype;
322 macsec.sci = None;
323 assert_eq!(6, macsec.header_len());
324 }
325 {
327 let mut macsec = macsec.clone();
328 macsec.ptype = ptype;
329 macsec.sci = Some(sci);
330 assert_eq!(14, macsec.header_len());
331 }
332 }
333
334 {
337 let mut macsec = macsec.clone();
338 macsec.ptype = MacsecPType::Unmodified(ethertype);
339 macsec.sci = None;
340 assert_eq!(8, macsec.header_len());
341 }
342 {
344 let mut macsec = macsec.clone();
345 macsec.ptype = MacsecPType::Unmodified(ethertype);
346 macsec.sci = Some(sci);
347 assert_eq!(16, macsec.header_len());
348 }
349 }
350 }
351
352 proptest! {
353 #[test]
354 fn read(
355 macsec in macsec_any(),
356 ether_type in ether_type_any(),
357 sci in any::<u64>()
358 ) {
359 use MacsecPType::*;
360 use err::macsec::*;
361
362 for ptype in [Unmodified(ether_type), Modified, Encrypted, EncryptedUnmodified] {
364 for has_sci in [false, true] {
365 let mut macsec = macsec.clone();
366 macsec.ptype = ptype;
367 macsec.sci = if has_sci {
368 Some(sci)
369 } else {
370 None
371 };
372 if matches!(ptype, MacsecPType::Unmodified(_)) && macsec.short_len.value() == 1 {
373 macsec.short_len = MacsecShortLen::ZERO;
374 }
375
376 {
378 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
379 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
380 let mut cursor = Cursor::new(&bytes);
381 let m = MacsecHeader::read(&mut cursor).unwrap();
382 assert_eq!(m, macsec);
383 assert_eq!(macsec.header_len() as u64, cursor.position());
384 }
385
386 {
388 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
389 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
390 bytes.try_extend_from_slice(&[1]).unwrap();
391
392 bytes[0] = bytes[0] | 0b1000_0000;
394
395 let mut cursor = Cursor::new(&bytes);
396 let m = MacsecHeader::read(&mut cursor).unwrap_err();
397 assert_eq!(m.content_error(), Some(HeaderError::UnexpectedVersion));
398 }
399
400 if matches!(ptype, MacsecPType::Unmodified(_)) {
402 let mut macsec = macsec.clone();
403 macsec.short_len = MacsecShortLen::try_from_u8(1).unwrap();
404 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
405 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
406
407 let mut cursor = Cursor::new(&bytes);
408 let m = MacsecHeader::read(&mut cursor).unwrap_err();
409 assert_eq!(m.content_error(), Some(HeaderError::InvalidUnmodifiedShortLen));
410 }
411
412 for len in 0..macsec.header_len() {
414 let mut bytes = ArrayVec::<u8, { MacsecHeader::MAX_LEN + 1 }>::new();
415 bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
416
417 let mut cursor = Cursor::new(&bytes[..len]);
418 let m = MacsecHeader::read(&mut cursor);
419 assert!(m.unwrap_err().io_error().is_some());
420 }
421 }
422 }
423 }
424 }
425
426 proptest! {
427 #[test]
428 fn write(
429 header in macsec_any()
430 ) {
431 {
433 let mut buffer = ArrayVec::<u8, {MacsecHeader::MAX_LEN}>::new();
434 header.write(&mut buffer).unwrap();
435 assert_eq!(&buffer, &header.to_bytes());
436 }
437 {
439 let mut buffer = [0u8;MacsecHeader::MAX_LEN];
440 let mut cursor = Cursor::new(&mut buffer[..header.header_len() - 1]);
441 header.write(&mut cursor).unwrap_err();
442 }
443 }
444 }
445
446 proptest! {
447 #[test]
448 fn expected_payload_len(
449 header in macsec_any(),
450 ether_type in ether_type_any(),
451 valid_unmodified_len in 2u8..=MacsecShortLen::MAX_U8,
452 valid_modified_len in 1u8..=MacsecShortLen::MAX_U8
453 ) {
454 {
456 let mut header = header.clone();
457 header.ptype = MacsecPType::Unmodified(ether_type);
458 header.short_len = MacsecShortLen::try_from_u8(valid_unmodified_len).unwrap();
459 assert_eq!(Some(valid_unmodified_len as usize - 2), header.expected_payload_len());
460 }
461
462 for short_len in 0..2u8 {
464 let mut header = header.clone();
465 header.ptype = MacsecPType::Unmodified(ether_type);
466 header.short_len = MacsecShortLen::try_from_u8(short_len).unwrap();
467 assert_eq!(None, header.expected_payload_len());
468 }
469
470 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
472 let mut header = header.clone();
473 header.ptype = ptype;
474 header.short_len = MacsecShortLen::try_from_u8(valid_modified_len).unwrap();
475 assert_eq!(Some(valid_modified_len as usize), header.expected_payload_len());
476 }
477
478 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
480 let mut header = header.clone();
481 header.ptype = ptype;
482 header.short_len = MacsecShortLen::ZERO;
483 assert_eq!(None, header.expected_payload_len());
484 }
485 }
486 }
487
488 proptest! {
489 #[test]
490 fn set_payload_len(
491 header in macsec_any(),
492 ether_type in ether_type_any(),
493 valid_unmodified_len in 0..=(MacsecShortLen::MAX_USIZE - 2),
494 invalid_unmodified_len in (MacsecShortLen::MAX_USIZE - 1)..=usize::MAX,
495 valid_modified_len in 1..=MacsecShortLen::MAX_USIZE,
496 invalid_modified_len in (MacsecShortLen::MAX_USIZE + 1)..=usize::MAX
497 ) {
498 {
500 let mut header = header.clone();
501 header.ptype = MacsecPType::Unmodified(ether_type);
502 header.set_payload_len(valid_unmodified_len);
503 assert_eq!(header.short_len.value() as usize, valid_unmodified_len + 2);
504 }
505
506 {
508 let mut header = header.clone();
509 header.ptype = MacsecPType::Unmodified(ether_type);
510 header.set_payload_len(invalid_unmodified_len);
511 assert_eq!(0, header.short_len.value());
512 }
513
514 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
516 let mut header = header.clone();
517 header.ptype = ptype;
518 header.set_payload_len(valid_modified_len);
519 assert_eq!(valid_modified_len, header.short_len.value() as usize);
520 }
521
522 for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
524 let mut header = header.clone();
525 header.ptype = ptype;
526 header.set_payload_len(invalid_modified_len);
527 assert_eq!(0, header.short_len.value());
528 }
529 }
530 }
531}