blob: 3257e6c49d008c686c4c2fe199c6d6fc2e680de3 [file] [log] [blame]
use crate::*;
/// A slice containing the link layer header (currently only Ethernet II and
/// SLL are supported).
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LinkSlice<'a> {
/// A slice containing an Ethernet II header.
Ethernet2(Ethernet2Slice<'a>),
/// A slice containing a Linux Cooked Capture v1 (SLL) header.
LinuxSll(LinuxSllSlice<'a>),
/// Ether payload without header.
EtherPayload(EtherPayloadSlice<'a>),
/// Sll payload without header.
LinuxSllPayload(LinuxSllPayloadSlice<'a>),
}
impl<'a> LinkSlice<'a> {
/// Convert the link slice to a header
pub fn to_header(&self) -> Option<LinkHeader> {
use LinkSlice::*;
match self {
Ethernet2(slice) => Some(LinkHeader::Ethernet2(slice.to_header())),
LinuxSll(slice) => Some(LinkHeader::LinuxSll(slice.to_header())),
EtherPayload(_) => None,
LinuxSllPayload(_) => None,
}
}
/// Returns the link layer ether payload (slice + ether type number).
pub fn ether_payload(&self) -> Option<EtherPayloadSlice<'a>> {
use LinkSlice::*;
match self {
Ethernet2(s) => Some(s.payload().clone()),
LinuxSll(s) => Some(EtherPayloadSlice::try_from(s.payload()).ok()?.clone()),
EtherPayload(p) => Some(p.clone()),
LinuxSllPayload(p) => Some(EtherPayloadSlice::try_from(p.clone()).ok()?),
}
}
/// Returns the link layer sll payload (slice + link layer protocol type).
pub fn sll_payload(&self) -> LinuxSllPayloadSlice<'a> {
use LinkSlice::*;
match self {
Ethernet2(s) => LinuxSllPayloadSlice::from(s.payload().clone()),
LinuxSll(s) => s.payload().clone(),
EtherPayload(p) => LinuxSllPayloadSlice::from(p.clone()),
LinuxSllPayload(p) => p.clone(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::test_gens::*;
use alloc::{format, vec::Vec};
use proptest::prelude::*;
proptest! {
#[test]
fn debug_clone_eq(ref eth in ethernet_2_unknown()) {
let bytes = eth.to_bytes();
let e = Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap();
let slice = LinkSlice::Ethernet2(
e.clone()
);
// clone & eq
assert_eq!(slice.clone(), slice);
// debug
assert_eq!(
format!("{:?}", slice),
format!("Ethernet2({:?})", e),
);
}
}
proptest! {
#[test]
fn to_header(
ref eth in ethernet_2_unknown(),
ref linux_sll in linux_sll_any()
) {
{
let bytes = eth.to_bytes();
let slice = LinkSlice::Ethernet2(
Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap()
);
assert_eq!(
slice.to_header(),
Some(LinkHeader::Ethernet2(eth.clone()))
);
}
{
let bytes = linux_sll.to_bytes();
let slice = LinkSlice::LinuxSll(
LinuxSllSlice::from_slice(&bytes).unwrap()
);
assert_eq!(
slice.to_header(),
Some(LinkHeader::LinuxSll(linux_sll.clone()))
);
}
{
let slice = LinkSlice::EtherPayload(EtherPayloadSlice {
ether_type: ether_type::IPV4,
payload: &[]
});
assert_eq!(
slice.to_header(),
None
);
}
{
let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice {
protocol_type: LinuxSllProtocolType::EtherType(ether_type::IPV4),
payload: &[]
});
assert_eq!(
slice.to_header(),
None
);
}
}
}
proptest! {
#[test]
fn ether_payload(
ref eth in ethernet_2_unknown(),
ref linux_sll in linux_sll_any()
) {
let p = [1,2,3,4];
{
let mut bytes = Vec::with_capacity(Ethernet2Header::LEN + p.len());
bytes.extend_from_slice(&eth.to_bytes());
bytes.extend_from_slice(&p);
let slice = LinkSlice::Ethernet2(
Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap()
);
assert_eq!(
slice.ether_payload().unwrap(),
EtherPayloadSlice{ ether_type: eth.ether_type, payload: &p }
);
}
{
let slice = LinkSlice::EtherPayload(EtherPayloadSlice {
ether_type: eth.ether_type,
payload: &p
});
assert_eq!(
slice.ether_payload().unwrap(),
EtherPayloadSlice{ ether_type: eth.ether_type, payload: &p }
);
}
{
let mut bytes = Vec::with_capacity(LinuxSllHeader::LEN + p.len());
bytes.extend_from_slice(&linux_sll.to_bytes());
bytes.extend_from_slice(&p);
let slice = LinkSlice::LinuxSll(
LinuxSllSlice::from_slice(&bytes).unwrap()
);
match linux_sll.protocol_type {
LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!(
slice.ether_payload().unwrap(),
EtherPayloadSlice{ ether_type: EtherType(v), payload: &p }
);}
_ => { assert!(slice.ether_payload().is_none());}
}
}
{
let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice {
protocol_type: linux_sll.protocol_type,
payload: &p
});
match linux_sll.protocol_type {
LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { assert_eq!(
slice.ether_payload().unwrap(),
EtherPayloadSlice{ ether_type: EtherType(v), payload: &p }
);}
_ => { assert!(slice.ether_payload().is_none());}
}
}
}
}
}