etherparse/link/
macsec_slice.rs

1use crate::{
2    err::{macsec, Layer, LenError},
3    *,
4};
5
6/// MACsec packet (SecTag header & payload).
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct MacsecSlice<'a> {
9    pub header: MacsecHeaderSlice<'a>,
10    pub payload: MacsecPayloadSlice<'a>,
11}
12
13impl<'a> MacsecSlice<'a> {
14    pub fn from_slice(slice: &'a [u8]) -> Result<MacsecSlice<'a>, macsec::HeaderSliceError> {
15        use macsec::HeaderSliceError::Len;
16
17        let header = MacsecHeaderSlice::from_slice(slice)?;
18
19        // validate the length of the slice if the short length is set
20        let (payload_slice, len_source) =
21            if let Some(req_payload_len) = header.expected_payload_len() {
22                let required_len = header.slice().len() + req_payload_len;
23                if slice.len() < required_len {
24                    return Err(Len(LenError {
25                        required_len,
26                        len: slice.len(),
27                        len_source: LenSource::MacsecShortLength,
28                        layer: Layer::MacsecPacket,
29                        layer_start_offset: 0,
30                    }));
31                }
32                // SAFETY: Safe as the length was verified above to be at least required_len.
33                (
34                    unsafe {
35                        core::slice::from_raw_parts(
36                            slice.as_ptr().add(header.slice().len()),
37                            req_payload_len,
38                        )
39                    },
40                    LenSource::MacsecShortLength,
41                )
42            } else {
43                // SAFETY: Safe as the header is a subslice of the original slice.
44                (
45                    unsafe {
46                        core::slice::from_raw_parts(
47                            slice.as_ptr().add(header.slice().len()),
48                            slice.len() - header.slice().len(),
49                        )
50                    },
51                    LenSource::Slice,
52                )
53            };
54
55        let payload = if let Some(ether_type) = header.next_ether_type() {
56            MacsecPayloadSlice::Unmodified(EtherPayloadSlice {
57                ether_type,
58                len_source,
59                payload: payload_slice,
60            })
61        } else {
62            MacsecPayloadSlice::Modified(payload_slice)
63        };
64
65        Ok(MacsecSlice { header, payload })
66    }
67
68    /// Get the ether payload if the macsec packet is unencrypted & unmodified.
69    pub fn ether_payload(&self) -> Option<EtherPayloadSlice<'a>> {
70        if let MacsecPayloadSlice::Unmodified(e) = &self.payload {
71            Some(e.clone())
72        } else {
73            None
74        }
75    }
76
77    /// Get the ether type of the payload if the macsec packet is unencrypted & unmodified.
78    pub fn next_ether_type(&self) -> Option<EtherType> {
79        self.header.next_ether_type()
80    }
81}
82
83#[cfg(test)]
84mod test {
85    use super::*;
86    use crate::{err::LenError, test_gens::*};
87    use arrayvec::ArrayVec;
88    use proptest::prelude::*;
89
90    proptest! {
91        #[test]
92        fn from_slice(
93            macsec in macsec_any(),
94            ethertype in ether_type_any(),
95            non_zero_sl_unmodified in 3u8..=0b0011_1111,
96            non_zero_sl_modified in 1u8..=0b0011_1111
97        ) {
98            // macsec (unmodified, complete, nonzero short length)
99            {
100                let mut macsec = macsec.clone();
101                macsec.ptype = MacsecPType::Unmodified(ethertype);
102                macsec.short_len = MacsecShortLen::try_from(non_zero_sl_unmodified).unwrap();
103
104                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize}>::new();
105                for v in 0..(non_zero_sl_unmodified - 2) {
106                    payload.push(v);
107                }
108
109                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN}>::new();
110                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
111                bytes.try_extend_from_slice(&payload).unwrap();
112                let m = MacsecSlice::from_slice(&bytes).unwrap();
113                assert_eq!(
114                    m.payload,
115                    MacsecPayloadSlice::Unmodified(EtherPayloadSlice{
116                        ether_type: ethertype,
117                        len_source: LenSource::MacsecShortLength,
118                        payload: &payload
119                    })
120                );
121                assert_eq!(
122                    m.ether_payload(),
123                    Some(EtherPayloadSlice{
124                        ether_type: ethertype,
125                        len_source: LenSource::MacsecShortLength,
126                        payload: &payload
127                    })
128                );
129                assert_eq!(m.next_ether_type(), Some(ethertype));
130            }
131            // macsec (incomplete, nonzero short length)
132            for ptype in [MacsecPType::Unmodified(ethertype), MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
133                let mut macsec = macsec.clone();
134                macsec.ptype = ptype;
135                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize}>::new();
136                if matches!(ptype, MacsecPType::Unmodified(_)) {
137                    macsec.short_len = MacsecShortLen::try_from(non_zero_sl_unmodified).unwrap();
138                    for v in 0..non_zero_sl_unmodified-3 {
139                        payload.push(v);
140                    }
141                } else {
142                    macsec.short_len = MacsecShortLen::try_from(non_zero_sl_modified).unwrap();
143                    for v in 0..non_zero_sl_modified-1 {
144                        payload.push(v);
145                    }
146                }
147
148                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN}>::new();
149                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
150                bytes.try_extend_from_slice(&payload).unwrap();
151                let m = MacsecSlice::from_slice(&bytes);
152                assert_eq!(
153                    m,
154                    Err(macsec::HeaderSliceError::Len(LenError{
155                        required_len: if matches!(ptype, MacsecPType::Unmodified(_)) {
156                            macsec.header_len() + non_zero_sl_unmodified as usize  - 2
157                        } else {
158                            macsec.header_len() + non_zero_sl_modified as usize
159                        },
160                        len: bytes.len(),
161                        len_source: LenSource::MacsecShortLength,
162                        layer: err::Layer::MacsecPacket,
163                        layer_start_offset: 0
164                    }))
165                );
166            }
167            // macsec (unmodified, zero short length)
168            {
169                let mut macsec = macsec.clone();
170                macsec.ptype = MacsecPType::Unmodified(ethertype);
171                macsec.short_len = MacsecShortLen::ZERO;
172
173                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + 1}>::new();
174                for v in 0..non_zero_sl_unmodified+1 {
175                    payload.push(v);
176                }
177
178                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN + 1}>::new();
179                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
180                bytes.try_extend_from_slice(&payload).unwrap();
181                let m = MacsecSlice::from_slice(&bytes).unwrap();
182                assert_eq!(
183                    m.payload,
184                    MacsecPayloadSlice::Unmodified(EtherPayloadSlice{
185                        ether_type: ethertype,
186                        len_source: LenSource::Slice,
187                        payload: &payload
188                    })
189                );
190                assert_eq!(
191                    m.ether_payload(),
192                    Some(EtherPayloadSlice{
193                        ether_type: ethertype,
194                        len_source: LenSource::Slice,
195                        payload: &payload
196                    })
197                );
198                assert_eq!(m.next_ether_type(), Some(ethertype));
199            }
200            // macsec (modified, complete, nonzero short length)
201            for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
202                let mut macsec = macsec.clone();
203                macsec.ptype = ptype;
204                macsec.short_len = MacsecShortLen::try_from(non_zero_sl_modified).unwrap();
205
206                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize}>::new();
207                for v in 0..non_zero_sl_modified {
208                    payload.push(v);
209                }
210
211                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN}>::new();
212                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
213                bytes.try_extend_from_slice(&payload).unwrap();
214                let m = MacsecSlice::from_slice(&bytes).unwrap();
215                assert_eq!(
216                    m.payload,
217                    MacsecPayloadSlice::Modified(&payload),
218                );
219                assert_eq!(m.ether_payload(), None);
220                assert_eq!(m.next_ether_type(), None);
221            }
222            // macsec (modified, incomplete, nonzero short length)
223            for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
224                let mut macsec = macsec.clone();
225                macsec.ptype = ptype;
226                macsec.short_len = MacsecShortLen::try_from(non_zero_sl_modified).unwrap();
227
228                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize}>::new();
229                for v in 0..non_zero_sl_modified-1 {
230                    payload.push(v);
231                }
232
233                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN}>::new();
234                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
235                bytes.try_extend_from_slice(&payload).unwrap();
236                let m = MacsecSlice::from_slice(&bytes);
237                assert_eq!(
238                    m,
239                    Err(macsec::HeaderSliceError::Len(LenError{
240                        required_len: macsec.header_len() + non_zero_sl_modified as usize,
241                        len: bytes.len(),
242                        len_source: LenSource::MacsecShortLength,
243                        layer: err::Layer::MacsecPacket,
244                        layer_start_offset: 0
245                    }))
246                );
247            }
248            // macsec (modified, zero short length)
249            for ptype in [MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
250                let mut macsec = macsec.clone();
251                macsec.ptype = ptype;
252                macsec.short_len = MacsecShortLen::ZERO;
253
254                let mut payload = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + 1}>::new();
255                for v in 0..non_zero_sl_modified+1 {
256                    payload.push(v);
257                }
258
259                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN + 1}>::new();
260                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
261                bytes.try_extend_from_slice(&payload).unwrap();
262                let m = MacsecSlice::from_slice(&bytes).unwrap();
263                assert_eq!(
264                    m.payload,
265                    MacsecPayloadSlice::Modified(&payload)
266                );
267                assert_eq!(m.ether_payload(), None);
268                assert_eq!(m.next_ether_type(), None);
269            }
270            // header parse error
271            for ptype in [MacsecPType::Unmodified(ethertype), MacsecPType::Modified, MacsecPType::Encrypted, MacsecPType::EncryptedUnmodified] {
272                let mut macsec = macsec.clone();
273                macsec.ptype = ptype;
274                macsec.short_len = MacsecShortLen::ZERO;
275
276                let mut bytes = ArrayVec::<u8, {MacsecShortLen::MAX_U8 as usize + MacsecHeader::MAX_LEN + 1}>::new();
277                bytes.try_extend_from_slice(&macsec.to_bytes()).unwrap();
278                let m = MacsecSlice::from_slice(&bytes[..bytes.len() - 1]);
279                assert_eq!(
280                    m,
281                    Err(macsec::HeaderSliceError::Len(LenError{
282                        required_len: macsec.header_len(),
283                        len: macsec.header_len() - 1,
284                        len_source: LenSource::Slice,
285                        layer: err::Layer::MacsecHeader,
286                        layer_start_offset: 0
287                    }))
288                );
289            }
290        }
291    }
292}