etherparse/link/
link_slice.rs

1use crate::*;
2
3/// A slice containing the link layer header (currently only Ethernet II and
4/// SLL are supported).
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub enum LinkSlice<'a> {
7    /// A slice containing an Ethernet II header.
8    Ethernet2(Ethernet2Slice<'a>),
9
10    /// A slice containing a Linux Cooked Capture v1 (SLL) header.
11    LinuxSll(LinuxSllSlice<'a>),
12
13    /// Ether payload without header.
14    EtherPayload(EtherPayloadSlice<'a>),
15
16    /// Sll payload without header.
17    LinuxSllPayload(LinuxSllPayloadSlice<'a>),
18}
19
20impl<'a> LinkSlice<'a> {
21    /// Convert the link slice to a header
22    pub fn to_header(&self) -> Option<LinkHeader> {
23        use LinkSlice::*;
24        match self {
25            Ethernet2(slice) => Some(LinkHeader::Ethernet2(slice.to_header())),
26            LinuxSll(slice) => Some(LinkHeader::LinuxSll(slice.to_header())),
27            EtherPayload(_) => None,
28            LinuxSllPayload(_) => None,
29        }
30    }
31
32    /// Returns the link layer ether payload (slice + ether type number).
33    pub fn ether_payload(&self) -> Option<EtherPayloadSlice<'a>> {
34        use LinkSlice::*;
35        match self {
36            Ethernet2(s) => Some(s.payload().clone()),
37            LinuxSll(s) => Some(EtherPayloadSlice::try_from(s.payload()).ok()?.clone()),
38            EtherPayload(p) => Some(p.clone()),
39            LinuxSllPayload(p) => Some(EtherPayloadSlice::try_from(p.clone()).ok()?),
40        }
41    }
42
43    /// Returns the link layer sll payload (slice + link layer protocol type).
44    pub fn sll_payload(&self) -> LinuxSllPayloadSlice<'a> {
45        use LinkSlice::*;
46        match self {
47            Ethernet2(s) => LinuxSllPayloadSlice::from(s.payload().clone()),
48            LinuxSll(s) => s.payload().clone(),
49            EtherPayload(p) => LinuxSllPayloadSlice::from(p.clone()),
50            LinuxSllPayload(p) => p.clone(),
51        }
52    }
53}
54
55#[cfg(test)]
56mod test {
57    use super::*;
58    use crate::test_gens::*;
59    use alloc::{format, vec::Vec};
60    use proptest::prelude::*;
61
62    proptest! {
63        #[test]
64        fn debug_clone_eq(ref eth in ethernet_2_unknown()) {
65            let bytes = eth.to_bytes();
66            let e = Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap();
67            let slice = LinkSlice::Ethernet2(
68                e.clone()
69            );
70
71            // clone & eq
72            assert_eq!(slice.clone(), slice);
73
74            // debug
75            assert_eq!(
76                format!("{:?}", slice),
77                format!("Ethernet2({:?})", e),
78            );
79        }
80    }
81
82    proptest! {
83        #[test]
84        fn to_header(
85            ref eth in ethernet_2_unknown(),
86            ref linux_sll in linux_sll_any()
87        ) {
88            {
89                let bytes = eth.to_bytes();
90                let slice = LinkSlice::Ethernet2(
91                    Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap()
92                );
93                assert_eq!(
94                    slice.to_header(),
95                    Some(LinkHeader::Ethernet2(eth.clone()))
96                );
97            }
98            {
99                let bytes = linux_sll.to_bytes();
100                let slice = LinkSlice::LinuxSll(
101                    LinuxSllSlice::from_slice(&bytes).unwrap()
102                );
103                assert_eq!(
104                    slice.to_header(),
105                    Some(LinkHeader::LinuxSll(linux_sll.clone()))
106                );
107            }
108            {
109                let slice = LinkSlice::EtherPayload(EtherPayloadSlice {
110                    ether_type: ether_type::IPV4,
111                    len_source: LenSource::Slice,
112                    payload: &[]
113                });
114                assert_eq!(
115                    slice.to_header(),
116                    None
117                );
118            }
119            {
120                let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice {
121                    protocol_type: LinuxSllProtocolType::EtherType(ether_type::IPV4),
122                    payload: &[]
123                });
124                assert_eq!(
125                    slice.to_header(),
126                    None
127                );
128            }
129        }
130    }
131
132    proptest! {
133        #[test]
134        fn ether_payload(
135            ref eth in ethernet_2_unknown(),
136            ref linux_sll in linux_sll_any()
137        ) {
138            let p = [1,2,3,4];
139            {
140                let mut bytes = Vec::with_capacity(Ethernet2Header::LEN + p.len());
141                bytes.extend_from_slice(&eth.to_bytes());
142                bytes.extend_from_slice(&p);
143                let slice = LinkSlice::Ethernet2(
144                    Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap()
145                );
146                assert_eq!(
147                    slice.ether_payload().unwrap(),
148                    EtherPayloadSlice{
149                        ether_type: eth.ether_type,
150                        len_source: LenSource::Slice,
151                        payload: &p
152                    }
153                );
154            }
155            {
156                let slice = LinkSlice::EtherPayload(EtherPayloadSlice {
157                    ether_type: eth.ether_type,
158                    len_source: LenSource::Slice,
159                    payload: &p
160                });
161                assert_eq!(
162                    slice.ether_payload().unwrap(),
163                    EtherPayloadSlice{
164                        ether_type: eth.ether_type,
165                        len_source: LenSource::Slice,
166                        payload: &p
167                    }
168                );
169            }
170            {
171                let mut bytes = Vec::with_capacity(LinuxSllHeader::LEN + p.len());
172                bytes.extend_from_slice(&linux_sll.to_bytes());
173                bytes.extend_from_slice(&p);
174                let slice = LinkSlice::LinuxSll(
175                    LinuxSllSlice::from_slice(&bytes).unwrap()
176                );
177                match linux_sll.protocol_type {
178                    LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!(
179                            slice.ether_payload().unwrap(),
180                            EtherPayloadSlice{
181                                ether_type: EtherType(v),
182                                len_source: LenSource::Slice,
183                                payload: &p,
184                            }
185                    );}
186                    _ => { assert!(slice.ether_payload().is_none());}
187                }
188            }
189            {
190                let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice {
191                    protocol_type: linux_sll.protocol_type,
192                    payload: &p
193                });
194                match linux_sll.protocol_type {
195                    LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!(
196                        slice.ether_payload().unwrap(),
197                            EtherPayloadSlice{
198                                ether_type: EtherType(v),
199                                len_source: LenSource::Slice,
200                                payload: &p,
201                            }
202                    );}
203                    _ => { assert!(slice.ether_payload().is_none());}
204                }
205            }
206        }
207    }
208
209    proptest! {
210        #[test]
211        fn sll_payload(
212            ref eth in ethernet_2_unknown(),
213            ref linux_sll in linux_sll_any()
214        ) {
215            let p = [1,2,3,4];
216            {
217                let mut bytes = Vec::with_capacity(Ethernet2Header::LEN + p.len());
218                bytes.extend_from_slice(&eth.to_bytes());
219                bytes.extend_from_slice(&p);
220                let slice = LinkSlice::Ethernet2(
221                    Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap()
222                );
223                assert_eq!(
224                    slice.sll_payload(),
225                    LinuxSllPayloadSlice{
226                        protocol_type: LinuxSllProtocolType::EtherType(eth.ether_type),
227                        payload: &p
228                    }
229                );
230            }
231            {
232                let slice = LinkSlice::EtherPayload(EtherPayloadSlice {
233                    ether_type: eth.ether_type,
234                    len_source: LenSource::Slice,
235                    payload: &p
236                });
237                assert_eq!(
238                    slice.sll_payload(),
239                    LinuxSllPayloadSlice{
240                        protocol_type: LinuxSllProtocolType::EtherType(eth.ether_type),
241                        payload: &p
242                    }
243                );
244            }
245            {
246                let mut bytes = Vec::with_capacity(LinuxSllHeader::LEN + p.len());
247                bytes.extend_from_slice(&linux_sll.to_bytes());
248                bytes.extend_from_slice(&p);
249                let slice = LinkSlice::LinuxSll(
250                    LinuxSllSlice::from_slice(&bytes).unwrap()
251                );
252                assert_eq!(
253                    slice.sll_payload(),
254                    LinuxSllPayloadSlice{
255                        protocol_type: linux_sll.protocol_type,
256                        payload: &p
257                    }
258                );
259            }
260            {
261                let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice {
262                    protocol_type: linux_sll.protocol_type,
263                    payload: &p
264                });
265                assert_eq!(
266                    slice.sll_payload(),
267                    LinuxSllPayloadSlice{
268                        protocol_type: linux_sll.protocol_type,
269                        payload: &p
270                    }
271                );
272            }
273        }
274    }
275}