blob: 13691d6f4e2b12da32b775e78c7baeeef7fce524 [file] [log] [blame] [edit]
use crate::*;
use alloc::vec::Vec;
#[derive(Clone)]
pub(crate) struct TestPacket {
pub link: Option<LinkHeader>,
pub vlan: Option<VlanHeader>,
pub net: Option<NetHeaders>,
pub transport: Option<TransportHeader>,
}
impl TestPacket {
pub fn len(&self, payload: &[u8]) -> usize {
self.link.as_ref().map_or(0, |x| x.header_len())
+ self.vlan.as_ref().map_or(0, |x| x.header_len())
+ self.net.as_ref().map_or(0, |x| x.header_len())
+ self.transport.as_ref().map_or(0, |x| x.header_len())
+ payload.len()
}
pub fn to_vec(&self, payload: &[u8]) -> Vec<u8> {
let mut result = Vec::with_capacity(self.len(payload));
if let Some(link) = &self.link {
link.write(&mut result).unwrap();
}
if let Some(vlan) = &self.vlan {
vlan.write(&mut result).unwrap();
}
if let Some(ip) = &self.net {
match ip {
NetHeaders::Ipv4(ipv4, exts) => {
ipv4.write_raw(&mut result).unwrap();
exts.write(&mut result, ipv4.protocol).unwrap();
}
NetHeaders::Ipv6(ipv6, exts) => {
ipv6.write(&mut result).unwrap();
exts.write(&mut result, ipv6.next_header).unwrap();
}
}
}
if let Some(transport) = &self.transport {
transport.write(&mut result).unwrap();
}
result.extend_from_slice(payload);
result
}
pub fn set_ether_type(&mut self, ether_type: EtherType) {
if let Some(vlan) = &mut self.vlan {
use VlanHeader::*;
match vlan {
Single(single) => {
single.ether_type = ether_type;
}
Double(double) => {
double.inner.ether_type = ether_type;
}
}
} else if let Some(link) = &mut self.link {
match link {
LinkHeader::Ethernet2(ethernet) => ethernet.ether_type = ether_type,
LinkHeader::LinuxSll(linux_sll) => {
linux_sll.protocol_type.change_value(ether_type.0)
}
}
}
}
pub fn set_payload_len(&mut self, payload_len: usize) {
use NetHeaders::*;
match &mut self.net {
None => {}
Some(Ipv4(ref mut header, ref mut exts)) => {
header
.set_payload_len(
exts.header_len()
+ self.transport.as_ref().map_or(0, |t| t.header_len())
+ payload_len,
)
.unwrap();
}
Some(Ipv6(ref mut header, ref mut exts)) => {
header
.set_payload_length(
exts.header_len()
+ self.transport.as_ref().map_or(0, |t| t.header_len())
+ payload_len,
)
.unwrap();
}
}
use TransportHeader::*;
match &mut self.transport {
None => {}
Some(Udp(ref mut udp)) => {
udp.length = udp.header_len_u16() + payload_len as u16;
}
Some(Tcp(_)) => {}
Some(Icmpv4(_)) => {}
Some(Icmpv6(_)) => {}
}
}
/// Set the length relative to the end of the ip headers.
pub fn set_payload_le_from_ip_on(&mut self, payload_len_from_ip_on: isize) {
use NetHeaders::*;
match self.net.as_mut().unwrap() {
Ipv4(ref mut header, ref mut exts) => {
header
.set_payload_len((exts.header_len() as isize + payload_len_from_ip_on) as usize)
.unwrap();
}
Ipv6(ref mut header, ref mut exts) => {
header
.set_payload_length(
(exts.header_len() as isize + payload_len_from_ip_on) as usize,
)
.unwrap();
}
}
}
pub fn is_ip_payload_fragmented(&self) -> bool {
self.net.as_ref().map_or(false, |net| match net {
NetHeaders::Ipv4(h, _) => h.is_fragmenting_payload(),
NetHeaders::Ipv6(_, e) => e.is_fragmenting_payload(),
})
}
}