etherparse/link/
lax_macsec_slice.rs

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