1 use 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)] 6 pub 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 20 impl<'a> LinkSlice<'a> { 21 /// Convert the link slice to a header to_header(&self) -> Option<LinkHeader>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). ether_payload(&self) -> Option<EtherPayloadSlice<'a>>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). sll_payload(&self) -> LinuxSllPayloadSlice<'a>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)] 56 mod 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 payload: &[] 112 }); 113 assert_eq!( 114 slice.to_header(), 115 None 116 ); 117 } 118 { 119 let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice { 120 protocol_type: LinuxSllProtocolType::EtherType(ether_type::IPV4), 121 payload: &[] 122 }); 123 assert_eq!( 124 slice.to_header(), 125 None 126 ); 127 } 128 } 129 } 130 131 proptest! { 132 #[test] 133 fn ether_payload( 134 ref eth in ethernet_2_unknown(), 135 ref linux_sll in linux_sll_any() 136 ) { 137 let p = [1,2,3,4]; 138 { 139 let mut bytes = Vec::with_capacity(Ethernet2Header::LEN + p.len()); 140 bytes.extend_from_slice(ð.to_bytes()); 141 bytes.extend_from_slice(&p); 142 let slice = LinkSlice::Ethernet2( 143 Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap() 144 ); 145 assert_eq!( 146 slice.ether_payload().unwrap(), 147 EtherPayloadSlice{ ether_type: eth.ether_type, payload: &p } 148 ); 149 } 150 { 151 let slice = LinkSlice::EtherPayload(EtherPayloadSlice { 152 ether_type: eth.ether_type, 153 payload: &p 154 }); 155 assert_eq!( 156 slice.ether_payload().unwrap(), 157 EtherPayloadSlice{ ether_type: eth.ether_type, payload: &p } 158 ); 159 } 160 { 161 let mut bytes = Vec::with_capacity(LinuxSllHeader::LEN + p.len()); 162 bytes.extend_from_slice(&linux_sll.to_bytes()); 163 bytes.extend_from_slice(&p); 164 let slice = LinkSlice::LinuxSll( 165 LinuxSllSlice::from_slice(&bytes).unwrap() 166 ); 167 match linux_sll.protocol_type { 168 LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!( 169 slice.ether_payload().unwrap(), 170 EtherPayloadSlice{ ether_type: EtherType(v), payload: &p } 171 );} 172 _ => { assert!(slice.ether_payload().is_none());} 173 } 174 } 175 { 176 let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice { 177 protocol_type: linux_sll.protocol_type, 178 payload: &p 179 }); 180 match linux_sll.protocol_type { 181 LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!( 182 slice.ether_payload().unwrap(), 183 EtherPayloadSlice{ ether_type: EtherType(v), payload: &p } 184 );} 185 _ => { assert!(slice.ether_payload().is_none());} 186 } 187 } 188 } 189 } 190 } 191