etherparse/link/
linux_sll_header_slice.rs1use crate::*;
2use core::{cmp::min, slice::from_raw_parts};
3
4#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct LinuxSllHeaderSlice<'a> {
7 slice: &'a [u8],
8}
9
10impl<'a> LinuxSllHeaderSlice<'a> {
11 pub fn from_slice(
13 slice: &'a [u8],
14 ) -> Result<LinuxSllHeaderSlice<'a>, err::linux_sll::HeaderSliceError> {
15 if slice.len() < LinuxSllHeader::LEN {
17 return Err(err::linux_sll::HeaderSliceError::Len(err::LenError {
18 required_len: LinuxSllHeader::LEN,
19 len: slice.len(),
20 len_source: LenSource::Slice,
21 layer: err::Layer::LinuxSllHeader,
22 layer_start_offset: 0,
23 }));
24 }
25
26 let packet_type_val = unsafe { get_unchecked_be_u16(slice.as_ptr()) };
32 if let Err(err) = LinuxSllPacketType::try_from(packet_type_val) {
33 return Err(err::linux_sll::HeaderSliceError::Content(err));
34 }
35
36 let arp_hardware_id = unsafe { get_unchecked_be_u16(slice.as_ptr().add(2)) };
42 let arp_hardware_id = ArpHardwareId::from(arp_hardware_id);
43
44 let protocol_type = unsafe { get_unchecked_be_u16(slice.as_ptr().add(14)) };
48
49 if let Err(err) = LinuxSllProtocolType::try_from((arp_hardware_id, protocol_type)) {
50 return Err(err::linux_sll::HeaderSliceError::Content(err));
51 }
52
53 Ok(LinuxSllHeaderSlice {
55 slice: unsafe { from_raw_parts(slice.as_ptr(), LinuxSllHeader::LEN) },
59 })
60 }
61
62 #[inline]
74 #[cfg(feature = "std")]
75 pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> LinuxSllHeaderSlice {
76 debug_assert!(slice.len() == LinuxSllHeader::LEN);
77 LinuxSllHeaderSlice { slice }
78 }
79
80 #[inline]
82 pub fn slice(&self) -> &'a [u8] {
83 self.slice
84 }
85
86 #[inline]
88 pub fn packet_type(&self) -> LinuxSllPacketType {
89 let packet_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr()) };
93
94 unsafe { LinuxSllPacketType::try_from(packet_type_raw).unwrap_unchecked() }
97 }
98
99 #[inline]
101 pub fn arp_hardware_type(&self) -> ArpHardwareId {
102 let arp_hardware_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) };
106
107 ArpHardwareId::from(arp_hardware_type_raw)
108 }
109
110 #[inline]
112 pub fn sender_address_valid_length(&self) -> u16 {
113 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) }
117 }
118
119 #[inline]
122 pub fn sender_address_full(&self) -> [u8; 8] {
123 unsafe { get_unchecked_8_byte_array(self.slice.as_ptr().add(6)) }
127 }
128
129 #[inline]
131 pub fn sender_address(&self) -> &'a [u8] {
132 let length = self.sender_address_valid_length() as usize;
133 &self.slice[6..min(6 + length, 6 + 8)]
134 }
135
136 #[inline]
138 pub fn protocol_type(&self) -> LinuxSllProtocolType {
139 let arp_hardware_type = self.arp_hardware_type();
140 let protocol_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(14)) };
144
145 unsafe {
148 LinuxSllProtocolType::try_from((arp_hardware_type, protocol_type_raw))
149 .unwrap_unchecked()
150 }
151 }
152
153 pub fn to_header(&self) -> LinuxSllHeader {
155 LinuxSllHeader {
156 packet_type: self.packet_type(),
157 arp_hrd_type: self.arp_hardware_type(),
158 sender_address_valid_length: self.sender_address_valid_length(),
159 sender_address: self.sender_address_full(),
160 protocol_type: self.protocol_type(),
161 }
162 }
163}
164
165#[cfg(test)]
166mod test {
167 use super::*;
168 use crate::test_gens::*;
169 use alloc::{format, vec::Vec};
170 use proptest::prelude::*;
171
172 proptest! {
173 #[test]
174 fn from_slice(
175 input in linux_sll_any(),
176 dummy_data in proptest::collection::vec(any::<u8>(), 0..20),
177 bad_packet_type in LinuxSllPacketType::MAX_VAL + 1..=u16::MAX,
178 bad_hw_type in any::<u16>().prop_filter(
179 "hw id must be unknown",
180 |v| ![
181 ArpHardwareId::NETLINK,
182 ArpHardwareId::IPGRE,
183 ArpHardwareId::IEEE80211_RADIOTAP,
184 ArpHardwareId::FRAD,
185 ArpHardwareId::ETHERNET,
186 ].iter().any(|&x| *v == x.0)
187 )
188 ) {
189 let buffer = {
191 let mut buffer: Vec<u8> = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len());
192 input.write(&mut buffer).unwrap();
193 buffer.extend(&dummy_data[..]);
194 buffer
195 };
196
197 {
199 let result = LinuxSllHeaderSlice::from_slice(&buffer[..]).unwrap();
200 assert_eq!(&buffer[..LinuxSllHeader::LEN], result.slice());
201 }
202
203 for len in 0..=13 {
205 assert_eq!(
206 LinuxSllHeaderSlice::from_slice(&buffer[..len]),
207 Err(err::linux_sll::HeaderSliceError::Len(err::LenError{
208 required_len: LinuxSllHeader::LEN,
209 len: len,
210 len_source: LenSource::Slice,
211 layer: err::Layer::LinuxSllHeader,
212 layer_start_offset: 0,
213 }))
214 );
215 }
216
217 {
219 let mut modbuf = buffer.clone();
220 let p_be = bad_packet_type.to_be_bytes();
221 modbuf[0] = p_be[0];
222 modbuf[1] = p_be[1];
223 assert_eq!(
224 LinuxSllHeaderSlice::from_slice(&modbuf),
225 Err(err::linux_sll::HeaderSliceError::Content(
226 err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: bad_packet_type }
227 ))
228 );
229 }
230
231 {
233 let mut modbuf = buffer.clone();
234 let p_be = bad_hw_type.to_be_bytes();
235 modbuf[2] = p_be[0];
236 modbuf[3] = p_be[1];
237 assert_eq!(
238 LinuxSllHeaderSlice::from_slice(&modbuf),
239 Err(err::linux_sll::HeaderSliceError::Content(
240 err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId(bad_hw_type) }
241 ))
242 );
243 }
244 }
245 }
246
247 proptest! {
248 #[test]
249 fn getters(input in linux_sll_any()) {
250 let buffer = input.to_bytes();
251 let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
252 assert_eq!(input.packet_type, slice.packet_type());
253 assert_eq!(input.arp_hrd_type, slice.arp_hardware_type());
254 assert_eq!(input.sender_address_valid_length, slice.sender_address_valid_length());
255 assert_eq!(input.sender_address, slice.sender_address_full());
256 assert_eq!(&input.sender_address[..usize::from(input.sender_address_valid_length)], slice.sender_address());
257 assert_eq!(input.protocol_type, slice.protocol_type());
258 }
259 }
260
261 proptest! {
262 #[test]
263 fn to_header(input in linux_sll_any()) {
264 let buffer = input.to_bytes();
265 let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
266 assert_eq!(input, slice.to_header());
267 }
268 }
269
270 proptest! {
271 #[test]
272 fn clone_eq(input in linux_sll_any()) {
273 let buffer = input.to_bytes();
274 let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
275 assert_eq!(slice, slice.clone());
276 }
277 }
278
279 proptest! {
280 #[test]
281 fn dbg(input in linux_sll_any()) {
282 let buffer = input.to_bytes();
283 let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap();
284 assert_eq!(
285 &format!(
286 "LinuxSllHeaderSlice {{ slice: {:?} }}",
287 slice.slice()
288 ),
289 &format!("{:?}", slice)
290 );
291 }
292 }
293}