| 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(), |
| }) |
| } |
| } |