use super::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PacketHeaders<'a> {
pub link: Option<Ethernet2Header>,
pub vlan: Option<VlanHeader>,
pub ip: Option<IpHeader>,
pub transport: Option<TransportHeader>,
pub payload: &'a [u8]
}
impl<'a> PacketHeaders<'a> {
pub fn from_ethernet_slice<'b>(packet: &'b [u8]) -> Result<PacketHeaders<'b>, ReadError> {
use std::io::Cursor;
let mut cursor = Cursor::new(&packet);
let ethernet = Ethernet2Header::read(&mut cursor)?;
let mut ether_type = ethernet.ether_type;
let mut result = PacketHeaders{
link: Some(ethernet),
vlan: None,
ip: None,
transport: None,
payload: &[]
};
use EtherType::*;
const VLAN_TAGGED_FRAME: u16 = VlanTaggedFrame as u16;
const PROVIDER_BRIDGING: u16 = ProviderBridging as u16;
const VLAN_DOUBLE_TAGGED_FRAME: u16 = VlanDoubleTaggedFrame as u16;
result.vlan = match ether_type {
VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
use VlanHeader::*;
let outer = SingleVlanHeader::read(&mut cursor)?;
ether_type = outer.ether_type;
match ether_type {
VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
let inner = SingleVlanHeader::read(&mut cursor)?;
ether_type = inner.ether_type;
Some(Double(DoubleVlanHeader{
outer: outer,
inner: inner
}))
},
_ => Some(Single(outer))
}
},
_ => None
};
const IPV4: u16 = Ipv4 as u16;
const IPV6: u16 = Ipv6 as u16;
let read_transport = |protocol: u8, cursor: &mut Cursor<&&[u8]>| -> Result<Option<TransportHeader>, ReadError> {
use IpTrafficClass::*;
const UDP: u8 = Udp as u8;
const TCP: u8 = Tcp as u8;
match protocol {
UDP => Ok(Some(TransportHeader::Udp(UdpHeader::read(cursor)?))),
TCP => Ok(Some(TransportHeader::Tcp(TcpHeader::read(cursor)?))),
_ => Ok(None)
}
};
match ether_type {
IPV4 => {
let ip = Ipv4Header::read(&mut cursor)?;
ip.skip_options(&mut cursor)?;
result.transport = read_transport(ip.protocol, &mut cursor)?;
result.ip = Some(IpHeader::Version4(ip));
},
IPV6 => {
let ip = Ipv6Header::read(&mut cursor)?;
let next_header = Ipv6Header::skip_all_header_extensions(&mut cursor, ip.next_header)?;
result.transport = read_transport(next_header, &mut cursor)?;
result.ip = Some(IpHeader::Version6(ip));
},
_ => {}
}
result.payload = &packet[(cursor.position() as usize)..];
Ok(result)
}
}