use super::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LinkSlice<'a> {
Ethernet2(Ethernet2HeaderSlice<'a>)
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum VlanSlice<'a> {
SingleVlan(SingleVlanHeaderSlice<'a>),
DoubleVlan(DoubleVlanHeaderSlice<'a>),
}
impl<'a> VlanSlice<'a> {
pub fn to_header(&self) -> VlanHeader {
use VlanHeader::*;
use VlanSlice::*;
match self {
SingleVlan(value) => Single(value.to_header()),
DoubleVlan(value) => Double(value.to_header())
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum InternetSlice<'a> {
Ipv4(Ipv4HeaderSlice<'a>),
Ipv6(Ipv6HeaderSlice<'a>, [Option<(u8, Ipv6ExtensionHeaderSlice<'a>)>; IPV6_MAX_NUM_HEADER_EXTENSIONS]),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TransportSlice<'a> {
Udp(UdpHeaderSlice<'a>),
Tcp(TcpHeaderSlice<'a>)
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SlicedPacket<'a> {
pub link: Option<LinkSlice<'a>>,
pub vlan: Option<VlanSlice<'a>>,
pub ip: Option<InternetSlice<'a>>,
pub transport: Option<TransportSlice<'a>>,
pub payload: &'a [u8]
}
const ETH_IPV4: u16 = EtherType::Ipv4 as u16;
const ETH_IPV6: u16 = EtherType::Ipv6 as u16;
const ETH_VLAN: u16 = EtherType::VlanTaggedFrame as u16;
const ETH_BRIDGE: u16 = EtherType::ProviderBridging as u16;
const ETH_VLAN_DOUBLE: u16 = EtherType::VlanDoubleTaggedFrame as u16;
const IP_UDP: u8 = IpTrafficClass::Udp as u8;
const IP_TCP: u8 = IpTrafficClass::Tcp as u8;
const IPV6_HOP_BY_HOP: u8 = IpTrafficClass::IPv6HeaderHopByHop as u8;
const IPV6_ROUTE: u8 = IpTrafficClass::IPv6RouteHeader as u8;
const IPV6_FRAG: u8 = IpTrafficClass::IPv6FragmentationHeader as u8;
const IPV6_OPTIONS: u8 = IpTrafficClass::IPv6DestinationOptions as u8;
const IPV6_AUTH: u8 = IpTrafficClass::IPv6AuthenticationHeader as u8;
const IPV6_ENCAP_SEC: u8 = IpTrafficClass::IPv6EncapSecurityPayload as u8;
impl<'a> SlicedPacket<'a> {
pub fn from_ethernet(data: &'a [u8]) -> Result<SlicedPacket, ReadError> {
let (rest, ether_type, link) = {
use LinkSlice::*;
let value = Ethernet2HeaderSlice::from_slice(data)?;
(&data[value.slice().len()..],
value.ether_type(),
Some(Ethernet2(value)))
};
let (rest, ether_type, vlan) = match ether_type {
ETH_VLAN | ETH_BRIDGE | ETH_VLAN_DOUBLE => {
use VlanSlice::*;
let single = SingleVlanHeaderSlice::from_slice(rest)?;
let ether_type = single.ether_type();
match ether_type {
ETH_VLAN | ETH_BRIDGE | ETH_VLAN_DOUBLE => {
let double = DoubleVlanHeaderSlice::from_slice(rest)?;
(&rest[double.slice().len()..],
double.inner().ether_type(),
Some(DoubleVlan(double)))
},
_ => (&rest[single.slice().len()..],
ether_type,
Some(SingleVlan(single)))
}
},
_ => (rest, ether_type, None)
};
let (rest, protocol, ip) = match ether_type {
ETH_IPV4 => {
use InternetSlice::*;
let value = Ipv4HeaderSlice::from_slice(rest)?;
(&rest[value.slice().len()..],
value.protocol(),
Some(Ipv4(value)))
},
ETH_IPV6 => {
use InternetSlice::*;
let value = Ipv6HeaderSlice::from_slice(rest)?;
let mut rest = &rest[value.slice().len()..];
let mut ip_extensions = [None, None, None, None, None, None, None];
let mut next_header = value.next_header();
for i in 0..IPV6_MAX_NUM_HEADER_EXTENSIONS {
match next_header {
IPV6_HOP_BY_HOP |
IPV6_ROUTE |
IPV6_FRAG |
IPV6_OPTIONS |
IPV6_AUTH |
IPV6_ENCAP_SEC => {
let value = Ipv6ExtensionHeaderSlice::from_slice(next_header, rest)?;
let this_header = next_header;
next_header = value.next_header();
rest = &rest[value.slice().len()..];
ip_extensions[i] = Some((this_header, value));
},
_ => break
}
}
match next_header {
IPV6_HOP_BY_HOP |
IPV6_ROUTE |
IPV6_FRAG |
IPV6_OPTIONS |
IPV6_AUTH |
IPV6_ENCAP_SEC => {
return Err(ReadError::Ipv6TooManyHeaderExtensions)
},
_ => {}
}
(rest,
next_header,
Some(Ipv6(value, ip_extensions)))
},
_ => (rest, 0, None)
};
let (rest, transport) = if ip.is_some() {
match protocol {
IP_UDP => {
use TransportSlice::*;
let value = UdpHeaderSlice::from_slice(rest)?;
(&rest[value.slice().len()..],
Some(Udp(value)))
},
IP_TCP => {
use TransportSlice::*;
let value = TcpHeaderSlice::from_slice(rest)?;
(&rest[value.slice().len()..],
Some(Tcp(value)))
},
_ => (rest, None)
}
} else {
(rest, None)
};
Ok(SlicedPacket{
link: link,
vlan: vlan,
ip: ip,
transport: transport,
payload: rest
})
}
}