From 5fc681ea0617979afede2b4a45fcf28392c946e3 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Thu, 25 Apr 2024 16:43:49 +0200 Subject: [PATCH 01/21] add initial LinuxSllHeader with partially created types and complete LinuxSllType --- etherparse/src/err/value_type.rs | 3 + etherparse/src/link/arphrd_type.rs | 2 + etherparse/src/link/linux_sll_header.rs | 44 ++++++ etherparse/src/link/linux_sll_type.rs | 190 ++++++++++++++++++++++++ etherparse/src/link/mod.rs | 3 + 5 files changed, 242 insertions(+) create mode 100644 etherparse/src/link/arphrd_type.rs create mode 100644 etherparse/src/link/linux_sll_header.rs create mode 100644 etherparse/src/link/linux_sll_type.rs diff --git a/etherparse/src/err/value_type.rs b/etherparse/src/err/value_type.rs index 59530006..d2153ff3 100644 --- a/etherparse/src/err/value_type.rs +++ b/etherparse/src/err/value_type.rs @@ -37,6 +37,8 @@ pub enum ValueType { TcpPayloadLengthIpv6, /// Variable length data of an ICMPv6 packet. Icmpv6PayloadLength, + /// Packet type of a Linux Cooked Capture v1 (SLL) + LinuxSllType } impl core::fmt::Display for ValueType { @@ -56,6 +58,7 @@ impl core::fmt::Display for ValueType { TcpPayloadLengthIpv4 => write!(f, "TCP Payload Length (in IPv4 checksum calculation)"), TcpPayloadLengthIpv6 => write!(f, "TCP Payload Length (in IPv6 checksum calculation)"), Icmpv6PayloadLength => write!(f, "ICMPv6 Payload Length"), + LinuxSllType => write!(f, "Linux Cooked Capture v1 (SLL)"), } } } diff --git a/etherparse/src/link/arphrd_type.rs b/etherparse/src/link/arphrd_type.rs new file mode 100644 index 00000000..1d400b0e --- /dev/null +++ b/etherparse/src/link/arphrd_type.rs @@ -0,0 +1,2 @@ +#[derive(Clone, Debug, Eq, PartialEq, Default)] +pub struct ARPHRDType(u16); diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs new file mode 100644 index 00000000..302ac3d4 --- /dev/null +++ b/etherparse/src/link/linux_sll_header.rs @@ -0,0 +1,44 @@ +use crate::EtherType; + +use super::{arphrd_type::ARPHRDType, linux_sll_type::LinuxSllType}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LinuxSllProtocolType { + /// The protocol type does not have relevant information + Ignored, + /// Netlink protocol type for the associated Netlink payload + NetlinkProtocolType(u16), + /// Generic Routing Encapsulation protocol type + GenericRoutingEncapsulationProtocolType(u16), + /// The associated payload is a Novell 802.3 frame without an 802.2 LLC header + Novel802_3Frame, + /// The protocol type value is "0x0003", which is possibly an error on the + /// capture, but it is not known the specific cause + Unknown, + /// The associated payload begins with a 802.2 LLC header. + LLC, + /// The associated payload is a CAN bus frame + CANBusFrame, + /// The associated payload is a CAN FD (CAN with Flexible Data-Rate) frame + CANFDFrame, + /// The associated payload's ether type + EtherType(EtherType) +} + +/// Linux SLL Header +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinuxSllHeader { + /// Type of the captured packet + pub packet_type: LinuxSllType, + /// ARPHRD_ value for the link-layer device type + pub arp_hrd_type: ARPHRDType, + /// The size of the adress that is valid + pub sender_address_valid_length: u16, + /// The link-layer adress of the sender of the packet, with the meaningful + /// bytes specified by `sender_address_valid_length`. If the original is + /// larger, the value on the packet is truncated to the first 8 bytes. If + /// the original is smaller, the remaining bytes will be filled with 0s. + pub sender_address: [u8; 8], + /// The protocol type of the encapsulated packet + pub protocol_type: LinuxSllProtocolType, +} diff --git a/etherparse/src/link/linux_sll_type.rs b/etherparse/src/link/linux_sll_type.rs new file mode 100644 index 00000000..a3519123 --- /dev/null +++ b/etherparse/src/link/linux_sll_type.rs @@ -0,0 +1,190 @@ +use crate::err::{self, ValueTooBigError}; + +/// Represents the type of direction that the packet contained in the +/// LINUX_SLL packet +/// +/// You can convert `u16` in the valid range to an `LinuxSllType` and the +/// other way around +/// +/// ``` +/// use etherparse::LinuxSllType; +/// +/// // Convert to LinuxSllType using the from & into trait +/// let link_type: LinuxSllType = u16_1.into() +/// assert_eq!(LinuxSllType::BroadcastByOther, link_type) +/// +/// // convert to u16 using the from & into trait +/// let num: u16 = LinuxSllType::BroadcastByOther.into(); +/// assert_eq!(1, num); +/// ``` +/// +#[derive(Clone, Copy, Eq, PartialEq, Default)] +pub enum LinuxSllType { + /// The packet was specifically sent by other to the one that captured the + /// packet + #[default] + UnicastByOtherToReceiver, + /// The packet was multicasted by somebody else + BroadcastByOther, + /// The packet was broadcasted by somebody else + MulticastByOther, + /// The packet was sent by other to another + UnicastByOtherToOther, + /// The packet was sent by the one that captured the packet + SentByUs, +} + +impl LinuxSllType { + /// Asociated u16 value of `LinuxSllType::UnicastByOtherToReceiver` + pub const UNICAST_BY_OTHER_TO_US: u16 = 0; + /// Asociated u16 value of `LinuxSllType::BroadcastByOther` + pub const BROADCAST_BY_OTHER: u16 = 1; + /// Asociated u16 value of `LinuxSllType::MulticastByOther` + pub const MULTICAST_BY_OTHER: u16 = 2; + /// Asociated u16 value of `LinuxSllType::UnicastByOtherToOther` + pub const UNICAST_BY_OTHER_TO_OTHER: u16 = 3; + /// Asociated u16 value of `LinuxSllType::UnicastByOtherToOther` + pub const SENT_BY_US: u16 = 4; + /// Maximum associated value + pub const MAX_U16: u16 = 4; +} + +impl TryFrom for LinuxSllType { + type Error = ValueTooBigError; + + fn try_from(value: u16) -> Result { + match value { + LinuxSllType::UNICAST_BY_OTHER_TO_US => Ok(LinuxSllType::UnicastByOtherToReceiver), + LinuxSllType::BROADCAST_BY_OTHER => Ok(LinuxSllType::BroadcastByOther), + LinuxSllType::MULTICAST_BY_OTHER => Ok(LinuxSllType::MulticastByOther), + LinuxSllType::UNICAST_BY_OTHER_TO_OTHER => Ok(LinuxSllType::UnicastByOtherToOther), + LinuxSllType::SENT_BY_US => Ok(LinuxSllType::SentByUs), + LinuxSllType::MAX_U16..=u16::MAX => Err(ValueTooBigError { + actual: value, + max_allowed: LinuxSllType::MAX_U16, + value_type: err::ValueType::LinuxSllType, + }), + } + } +} + +impl From for u16 { + #[inline] + fn from(value: LinuxSllType) -> Self { + match value { + LinuxSllType::UnicastByOtherToReceiver => LinuxSllType::UNICAST_BY_OTHER_TO_US, + LinuxSllType::BroadcastByOther => LinuxSllType::BROADCAST_BY_OTHER, + LinuxSllType::MulticastByOther => LinuxSllType::MULTICAST_BY_OTHER, + LinuxSllType::UnicastByOtherToOther => LinuxSllType::UNICAST_BY_OTHER_TO_OTHER, + LinuxSllType::SentByUs => LinuxSllType::SENT_BY_US, + } + } +} + +impl core::fmt::Debug for LinuxSllType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + LinuxSllType::UnicastByOtherToReceiver => write!(f, "Unicast by other to receiver ({})", u16::from(*self)), + LinuxSllType::BroadcastByOther => write!(f, "Broadcast by other ({})", u16::from(*self)), + LinuxSllType::MulticastByOther => write!(f, "Multicast by other to receiver ({})", u16::from(*self)), + LinuxSllType::UnicastByOtherToOther => write!(f, "Unicast by other to other ({})", u16::from(*self)), + LinuxSllType::SentByUs => write!(f, "Sent by us ({})", u16::from(*self)), + } + } +} + +#[cfg(test)] +mod test { + use alloc::format; + + use super::*; + use crate::err::{self, ValueTooBigError}; + + #[test] + fn to_u16() { + assert_eq!(0, u16::from(LinuxSllType::UnicastByOtherToReceiver)); + assert_eq!(1, u16::from(LinuxSllType::BroadcastByOther)); + assert_eq!(2, u16::from(LinuxSllType::MulticastByOther)); + assert_eq!(3, u16::from(LinuxSllType::UnicastByOtherToOther)); + assert_eq!(4, u16::from(LinuxSllType::SentByUs)); + } + + #[test] + fn try_from_u16() { + assert_eq!(LinuxSllType::try_from(0), Ok(LinuxSllType::UnicastByOtherToReceiver)); + assert_eq!(LinuxSllType::try_from(1), Ok(LinuxSllType::BroadcastByOther)); + assert_eq!(LinuxSllType::try_from(2), Ok(LinuxSllType::MulticastByOther)); + assert_eq!(LinuxSllType::try_from(3), Ok(LinuxSllType::UnicastByOtherToOther)); + assert_eq!(LinuxSllType::try_from(4), Ok(LinuxSllType::SentByUs)); + assert_eq!(LinuxSllType::try_from(5), Err(ValueTooBigError { + actual: 5, + max_allowed: LinuxSllType::MAX_U16, + value_type: err::ValueType::LinuxSllType, + })); + assert_eq!(LinuxSllType::try_from(123), Err(ValueTooBigError { + actual: 123, + max_allowed: LinuxSllType::MAX_U16, + value_type: err::ValueType::LinuxSllType, + })); + } + + #[test] + fn dbg() { + let pairs = &[ + ( + LinuxSllType::UnicastByOtherToReceiver, + "Unicast by other to receiver (0)", + ), + ( + LinuxSllType::BroadcastByOther, + "Broadcast by other (1)", + ), + ( + LinuxSllType::MulticastByOther, + "Multicast by other to receiver (2)" + ), + ( + LinuxSllType::UnicastByOtherToOther, + "Unicast by other to other (3)" + ), + ( + LinuxSllType::SentByUs, + "Sent by us (4)" + ), + ]; + + for (ether_type, str_value) in pairs { + assert_eq!(str_value, &format!("{:?}", ether_type)); + } + } + + #[test] + fn default() { + let value: LinuxSllType = Default::default(); + assert_eq!(LinuxSllType::UnicastByOtherToReceiver, value); + } + + #[test] + fn clone_eq() { + let values = &[ + LinuxSllType::UnicastByOtherToReceiver, + LinuxSllType::BroadcastByOther, + LinuxSllType::MulticastByOther, + LinuxSllType::UnicastByOtherToOther, + LinuxSllType::SentByUs, + ]; + + // clone + for v in values { + assert_eq!(v, &v.clone()); + } + + // eq + for (a_pos, a) in values.iter().enumerate() { + for (b_pos, b) in values.iter().enumerate() { + assert_eq!(a_pos == b_pos, a == b); + assert_eq!(a_pos != b_pos, a != b); + } + } + } +} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 4b7b718c..74cd242a 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -1,3 +1,4 @@ +pub mod arphrd_type; pub mod double_vlan_header; pub mod double_vlan_header_slice; pub mod double_vlan_slice; @@ -6,6 +7,8 @@ pub mod ether_type_impl; pub mod ethernet2_header; pub mod ethernet2_header_slice; pub mod ethernet2_slice; +pub mod linux_sll_header; +pub mod linux_sll_type; pub mod link_slice; pub mod single_vlan_header; pub mod single_vlan_header_slice; From 403022baea927abf34a0686a47dfbe100c7adb21 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Thu, 25 Apr 2024 18:33:07 +0200 Subject: [PATCH 02/21] reference tcpdump page on readme --- README.md | 1 + etherparse/src/link/{arphrd_type.rs => arp_hardware_id.rs} | 2 +- etherparse/src/link/linux_sll_header.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename etherparse/src/link/{arphrd_type.rs => arp_hardware_id.rs} (60%) diff --git a/README.md b/README.md index f27d2b33..b92fb5ea 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ Read the documentations of the different methods for a more details: * [Internet Control Message Protocol version 6 (ICMPv6) Parameters](https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml) * Multicast Listener Discovery (MLD) for IPv6 [RFC 2710](https://datatracker.ietf.org/doc/html/rfc2710) * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) +* [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) ## License Licensed under either of Apache License, Version 2.0 or MIT license at your option. The corresponding license texts can be found in the LICENSE-APACHE file and the LICENSE-MIT file. diff --git a/etherparse/src/link/arphrd_type.rs b/etherparse/src/link/arp_hardware_id.rs similarity index 60% rename from etherparse/src/link/arphrd_type.rs rename to etherparse/src/link/arp_hardware_id.rs index 1d400b0e..b7adba66 100644 --- a/etherparse/src/link/arphrd_type.rs +++ b/etherparse/src/link/arp_hardware_id.rs @@ -1,2 +1,2 @@ #[derive(Clone, Debug, Eq, PartialEq, Default)] -pub struct ARPHRDType(u16); +pub struct ArpHardwareId(u16); diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index 302ac3d4..3e46a851 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -1,6 +1,6 @@ use crate::EtherType; -use super::{arphrd_type::ARPHRDType, linux_sll_type::LinuxSllType}; +use super::{arp_hardware_id::ArpHardwareId, linux_sll_type::LinuxSllType}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum LinuxSllProtocolType { @@ -31,7 +31,7 @@ pub struct LinuxSllHeader { /// Type of the captured packet pub packet_type: LinuxSllType, /// ARPHRD_ value for the link-layer device type - pub arp_hrd_type: ARPHRDType, + pub arp_hrd_type: ArpHardwareId, /// The size of the adress that is valid pub sender_address_valid_length: u16, /// The link-layer adress of the sender of the packet, with the meaningful From 34ef2220900f9fe0a02a5fe54044a0aba92a51bf Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Thu, 25 Apr 2024 20:21:59 +0200 Subject: [PATCH 03/21] fix doctest and export linux_sll types in lib --- etherparse/src/lib.rs | 2 ++ etherparse/src/link/linux_sll_type.rs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index e88881de..e34b42ce 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -302,6 +302,8 @@ pub use crate::link::ethernet2_header::*; pub use crate::link::ethernet2_header_slice::*; pub use crate::link::ethernet2_slice::*; pub use crate::link::link_slice::*; +pub use crate::link::linux_sll_header::*; +pub use crate::link::linux_sll_type::*; pub use crate::link::single_vlan_header::*; pub use crate::link::single_vlan_header_slice::*; pub use crate::link::single_vlan_slice::*; diff --git a/etherparse/src/link/linux_sll_type.rs b/etherparse/src/link/linux_sll_type.rs index a3519123..6784642d 100644 --- a/etherparse/src/link/linux_sll_type.rs +++ b/etherparse/src/link/linux_sll_type.rs @@ -9,9 +9,9 @@ use crate::err::{self, ValueTooBigError}; /// ``` /// use etherparse::LinuxSllType; /// -/// // Convert to LinuxSllType using the from & into trait -/// let link_type: LinuxSllType = u16_1.into() -/// assert_eq!(LinuxSllType::BroadcastByOther, link_type) +/// // Convert to LinuxSllType using the try_from & try_into trait +/// let link_type: LinuxSllType = 1_u16.try_into().unwrap(); +/// assert_eq!(LinuxSllType::BroadcastByOther, link_type); /// /// // convert to u16 using the from & into trait /// let num: u16 = LinuxSllType::BroadcastByOther.into(); From 26a1d46baab044a22c922cc3065e2fb8c83e4935 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Thu, 25 Apr 2024 20:23:40 +0200 Subject: [PATCH 04/21] add arp hardware definitions ids --- README.md | 2 + etherparse/src/lib.rs | 1 + etherparse/src/link/arp_hardware_id.rs | 515 ++++++++++++++++++++++++- etherparse/src/link/mod.rs | 2 +- 4 files changed, 517 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b92fb5ea..72a4b27d 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,8 @@ Read the documentations of the different methods for a more details: * Multicast Listener Discovery (MLD) for IPv6 [RFC 2710](https://datatracker.ietf.org/doc/html/rfc2710) * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) * [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) +* Address Resolution Protocol (ARP) Parameters [Harware Types](https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2) +* Arp hardware identifiers definitions on the Linux kernel [if_arp.h](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) ## License Licensed under either of Apache License, Version 2.0 or MIT license at your option. The corresponding license texts can be found in the LICENSE-APACHE file and the LICENSE-MIT file. diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index e34b42ce..28bb7a6d 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -293,6 +293,7 @@ extern crate std; pub mod err; mod link; +pub use crate::link::arp_hardware_id::*; pub use crate::link::double_vlan_header::*; pub use crate::link::double_vlan_header_slice::*; pub use crate::link::double_vlan_slice::*; diff --git a/etherparse/src/link/arp_hardware_id.rs b/etherparse/src/link/arp_hardware_id.rs index b7adba66..eba7d40f 100644 --- a/etherparse/src/link/arp_hardware_id.rs +++ b/etherparse/src/link/arp_hardware_id.rs @@ -1,2 +1,513 @@ -#[derive(Clone, Debug, Eq, PartialEq, Default)] -pub struct ArpHardwareId(u16); +/// Represents an ARP protocol hardware identifier. +/// +/// You can access the underlying `u16` value by using `.0` and any `u16` +/// can be converted to an `ArpHardwareId`: +/// +/// ``` +/// use etherparse::ArpHardwareId; +/// +/// assert_eq!(ArpHardwareId::ETHER.0, 0x0001); +/// assert_eq!(ArpHardwareId::ETHER, ArpHardwareId(0x0001)); +/// +/// // convert to ArpHardwareId using the from & into trait +/// let arp_hrd_id: ArpHardwareId = 0x0001.into(); +/// assert_eq!(ArpHardwareId::ETHER, arp_hrd_id); +/// +/// // convert to u16 using the from & into trait +/// let num: u16 = ArpHardwareId::ETHER.into(); +/// assert_eq!(0x0001, num); +/// ``` +/// + +#[derive(Clone, Eq, PartialEq, Default)] +pub struct ArpHardwareId(pub u16); + +impl ArpHardwareId { + // Numbers sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + pub const NETROM: ArpHardwareId = Self(0); + pub const ETHER: ArpHardwareId = Self(1); + pub const EETHER: ArpHardwareId = Self(2); + pub const AX25: ArpHardwareId = Self(3); + pub const PRONET: ArpHardwareId = Self(4); + pub const CHAOS: ArpHardwareId = Self(5); + pub const IEEE802: ArpHardwareId = Self(6); + pub const ARCNET: ArpHardwareId = Self(7); + pub const APPLETLK: ArpHardwareId = Self(8); + pub const DLCI: ArpHardwareId = Self(15); + pub const ATM: ArpHardwareId = Self(19); + pub const METRICOM: ArpHardwareId = Self(23); + pub const IEEE1394: ArpHardwareId = Self(24); + pub const EUI64: ArpHardwareId = Self(27); + pub const INFINIBAND: ArpHardwareId = Self(32); + pub const SLIP: ArpHardwareId = Self(256); + pub const CSLIP: ArpHardwareId = Self(257); + pub const SLIP6: ArpHardwareId = Self(258); + pub const CSLIP6: ArpHardwareId = Self(259); + pub const RSRVD: ArpHardwareId = Self(260); + pub const ADAPT: ArpHardwareId = Self(264); + pub const ROSE: ArpHardwareId = Self(270); + pub const X25: ArpHardwareId = Self(271); + pub const HWX25: ArpHardwareId = Self(272); + pub const CAN: ArpHardwareId = Self(280); + pub const PPP: ArpHardwareId = Self(512); + pub const CISCO_HDLC: ArpHardwareId = Self(513); + pub const LAPB: ArpHardwareId = Self(516); + pub const DDCMP: ArpHardwareId = Self(517); + pub const RAWHDLC: ArpHardwareId = Self(518); + pub const RAWIP: ArpHardwareId = Self(519); + pub const TUNNEL: ArpHardwareId = Self(768); + pub const TUNNEL6: ArpHardwareId = Self(769); + pub const FRAD: ArpHardwareId = Self(770); + pub const SKIP: ArpHardwareId = Self(771); + pub const LOOPBACK: ArpHardwareId = Self(772); + pub const LOCALTLK: ArpHardwareId = Self(773); + pub const FDDI: ArpHardwareId = Self(774); + pub const BIF: ArpHardwareId = Self(775); + pub const SIT: ArpHardwareId = Self(776); + pub const IPDDP: ArpHardwareId = Self(777); + pub const IPGRE: ArpHardwareId = Self(778); + pub const PIMREG: ArpHardwareId = Self(779); + pub const HIPPI: ArpHardwareId = Self(780); + pub const ASH: ArpHardwareId = Self(781); + pub const ECONET: ArpHardwareId = Self(782); + pub const IRDA: ArpHardwareId = Self(783); + pub const FCPP: ArpHardwareId = Self(784); + pub const FCAL: ArpHardwareId = Self(785); + pub const FCPL: ArpHardwareId = Self(786); + pub const FCFABRIC: ArpHardwareId = Self(787); + pub const IEEE802_TR: ArpHardwareId = Self(800); + pub const IEEE80211: ArpHardwareId = Self(801); + pub const IEEE80211_PRISM: ArpHardwareId = Self(802); + pub const IEEE80211_RADIOTAP: ArpHardwareId = Self(803); + pub const IEEE802154: ArpHardwareId = Self(804); + pub const IEEE802154_MONITOR: ArpHardwareId = Self(805); + pub const PHONET: ArpHardwareId = Self(820); + pub const PHONET_PIPE: ArpHardwareId = Self(821); + pub const CAIF: ArpHardwareId = Self(822); + pub const IP6GRE: ArpHardwareId = Self(823); + pub const NETLINK: ArpHardwareId = Self(824); + pub const IPV6LOWPAN: ArpHardwareId = Self(825); + pub const VSOCKMON: ArpHardwareId = Self(826); + pub const VOID: ArpHardwareId = Self(0xFFFF); + pub const NONE: ArpHardwareId = Self(0xFFFE); + +} + +impl From for ArpHardwareId { + #[inline] + fn from(val: u16) -> Self { + ArpHardwareId(val) + } +} + +impl From for u16 { + #[inline] + fn from(val: ArpHardwareId) -> Self { + val.0 + } +} + +impl core::fmt::Debug for ArpHardwareId { + // Names sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + Self::NETROM => write!(f, "{} (from KA9Q: NET/ROM pseudo)", self.0), + Self::ETHER => write!(f, "{} (Ethernet 10Mbps)", self.0), + Self::EETHER => write!(f, "{} (Experimental Ethernet)", self.0), + Self::AX25 => write!(f, "{} (AX.25 Level 2)", self.0), + Self::PRONET => write!(f, "{} (PROnet token ring)", self.0), + Self::CHAOS => write!(f, "{} (Chaosnet)", self.0), + Self::IEEE802 => write!(f, "{} (IEEE 802.2 Ethernet/TR/TB)", self.0), + Self::ARCNET => write!(f, "{} (ARCnet)", self.0), + Self::APPLETLK => write!(f, "{} (APPLEtalk)", self.0), + Self::DLCI => write!(f, "{} (Frame Relay DLCI)", self.0), + Self::ATM => write!(f, "{} (ATM)", self.0), + Self::METRICOM => write!(f, "{} (Metricom STRIP (new IANA id))", self.0), + Self::IEEE1394 => write!(f, "{} (IEEE 1394 IPv4 - RFC 2734)", self.0), + Self::EUI64 => write!(f, "{} (EUI-64)", self.0), + Self::INFINIBAND => write!(f, "{} (InfiniBand)", self.0), + Self::SLIP => write!(f, "{} (SLIP)", self.0), + Self::CSLIP => write!(f, "{} (CSLIP)", self.0), + Self::SLIP6 => write!(f, "{} (SLIP6)", self.0), + Self::CSLIP6 => write!(f, "{} (CSLIP6)", self.0), + Self::RSRVD => write!(f, "{} (Notional KISS type)", self.0), + Self::ADAPT => write!(f, "{} (ADAPT)", self.0), + Self::ROSE => write!(f, "{} (ROSE)", self.0), + Self::X25 => write!(f, "{} (CCITT X.25)", self.0), + Self::HWX25 => write!(f, "{} (Boards with X.25 in firmware)", self.0), + Self::CAN => write!(f, "{} (Controller Area Network)", self.0), + Self::PPP => write!(f, "{} (PPP)", self.0), + Self::CISCO_HDLC => write!(f, "{} (Cisco HDLC)", self.0), + Self::LAPB => write!(f, "{} (LAPB)", self.0), + Self::DDCMP => write!(f, "{} (Digital's DDCMP protocol)", self.0), + Self::RAWHDLC => write!(f, "{} (Raw HDLC)", self.0), + Self::RAWIP => write!(f, "{} (Raw IP)", self.0), + Self::TUNNEL => write!(f, "{} (IPIP tunnel)", self.0), + Self::TUNNEL6 => write!(f, "{} (IP6IP6 tunnel)", self.0), + Self::FRAD => write!(f, "{} (Frame Relay Access Device)", self.0), + Self::SKIP => write!(f, "{} (SKIP vif)", self.0), + Self::LOOPBACK => write!(f, "{} (Loopback device)", self.0), + Self::LOCALTLK => write!(f, "{} (Localtalk device)", self.0), + Self::FDDI => write!(f, "{} (Fiber Distributed Data Interface)", self.0), + Self::BIF => write!(f, "{} (AP1000 BIF)", self.0), + Self::SIT => write!(f, "{} (sit0 device - IPv6-in-IPv4)", self.0), + Self::IPDDP => write!(f, "{} (IP over DDP tunneller)", self.0), + Self::IPGRE => write!(f, "{} (GRE over IP)", self.0), + Self::PIMREG => write!(f, "{} (PIMSM register interface)", self.0), + Self::HIPPI => write!(f, "{} (High Performance Parallel Interface)", self.0), + Self::ASH => write!(f, "{} (Nexus 64Mbps Ash)", self.0), + Self::ECONET => write!(f, "{} (Acorn Econet)", self.0), + Self::IRDA => write!(f, "{} (Linux-IrDA)", self.0), + Self::FCPP => write!(f, "{} (Point to point fibrechannel)", self.0), + Self::FCAL => write!(f, "{} (Fibrechannel arbitrated loop)", self.0), + Self::FCPL => write!(f, "{} (Fibrechannel public loop)", self.0), + Self::FCFABRIC => write!(f, "{} (Fibrechannel fabric)", self.0), + Self::IEEE802_TR => write!(f, "{} (Magic type ident for TR)", self.0), + Self::IEEE80211 => write!(f, "{} (IEEE 802.11)", self.0), + Self::IEEE80211_PRISM => write!(f, "{} (IEEE 802.11 + Prism2 header)", self.0), + Self::IEEE80211_RADIOTAP => write!(f, "{} (IEEE 802.11 + radiotap header)", self.0), + Self::IEEE802154 => write!(f, "{} (IEEE 802.15.4)", self.0), + Self::IEEE802154_MONITOR => write!(f, "{} (IEEE 802.15.4 network monitor)", self.0), + Self::PHONET => write!(f, "{} (PhoNet media type)", self.0), + Self::PHONET_PIPE => write!(f, "{} (PhoNet pipe header)", self.0), + Self::CAIF => write!(f, "{} (CAIF media type)", self.0), + Self::IP6GRE => write!(f, "{} (GRE over IPv6)", self.0), + Self::NETLINK => write!(f, "{} (Netlink header)", self.0), + Self::IPV6LOWPAN => write!(f, "{} (IPv6 over LoWPAN)", self.0), + Self::VSOCKMON => write!(f, "{} (Vsock monitor header)", self.0), + Self::VOID => write!(f, "{:#06X} (Void type, nothing is known)", self.0), + Self::NONE => write!(f, "{:#06X} (zero header length)", self.0), + _ => write!(f, "{:#06X}", self.0), + } + } +} + + +#[cfg(test)] +mod test { + use super::*; + use alloc::format; + + #[test] + fn to_u16() { + assert_eq!(0, u16::from(ArpHardwareId::NETROM)); + assert_eq!(1, u16::from(ArpHardwareId::ETHER)); + assert_eq!(2, u16::from(ArpHardwareId::EETHER)); + assert_eq!(3, u16::from(ArpHardwareId::AX25)); + assert_eq!(4, u16::from(ArpHardwareId::PRONET)); + assert_eq!(5, u16::from(ArpHardwareId::CHAOS)); + assert_eq!(6, u16::from(ArpHardwareId::IEEE802)); + assert_eq!(7, u16::from(ArpHardwareId::ARCNET)); + assert_eq!(8, u16::from(ArpHardwareId::APPLETLK)); + assert_eq!(15, u16::from(ArpHardwareId::DLCI)); + assert_eq!(19, u16::from(ArpHardwareId::ATM)); + assert_eq!(23, u16::from(ArpHardwareId::METRICOM)); + assert_eq!(24, u16::from(ArpHardwareId::IEEE1394)); + assert_eq!(27, u16::from(ArpHardwareId::EUI64)); + assert_eq!(32, u16::from(ArpHardwareId::INFINIBAND)); + + assert_eq!(256, u16::from(ArpHardwareId::SLIP)); + assert_eq!(257, u16::from(ArpHardwareId::CSLIP)); + assert_eq!(258, u16::from(ArpHardwareId::SLIP6)); + assert_eq!(259, u16::from(ArpHardwareId::CSLIP6)); + assert_eq!(260, u16::from(ArpHardwareId::RSRVD)); + assert_eq!(264, u16::from(ArpHardwareId::ADAPT)); + assert_eq!(270, u16::from(ArpHardwareId::ROSE)); + assert_eq!(271, u16::from(ArpHardwareId::X25)); + assert_eq!(272, u16::from(ArpHardwareId::HWX25)); + assert_eq!(280, u16::from(ArpHardwareId::CAN)); + assert_eq!(512, u16::from(ArpHardwareId::PPP)); + assert_eq!(513, u16::from(ArpHardwareId::CISCO_HDLC)); + assert_eq!(516, u16::from(ArpHardwareId::LAPB)); + assert_eq!(517, u16::from(ArpHardwareId::DDCMP)); + assert_eq!(518, u16::from(ArpHardwareId::RAWHDLC)); + assert_eq!(519, u16::from(ArpHardwareId::RAWIP)); + + assert_eq!(768, u16::from(ArpHardwareId::TUNNEL)); + assert_eq!(769, u16::from(ArpHardwareId::TUNNEL6)); + assert_eq!(770, u16::from(ArpHardwareId::FRAD)); + assert_eq!(771, u16::from(ArpHardwareId::SKIP)); + assert_eq!(772, u16::from(ArpHardwareId::LOOPBACK)); + assert_eq!(773, u16::from(ArpHardwareId::LOCALTLK)); + assert_eq!(774, u16::from(ArpHardwareId::FDDI)); + assert_eq!(775, u16::from(ArpHardwareId::BIF)); + assert_eq!(776, u16::from(ArpHardwareId::SIT)); + assert_eq!(777, u16::from(ArpHardwareId::IPDDP)); + assert_eq!(778, u16::from(ArpHardwareId::IPGRE)); + assert_eq!(779, u16::from(ArpHardwareId::PIMREG)); + assert_eq!(780, u16::from(ArpHardwareId::HIPPI)); + assert_eq!(781, u16::from(ArpHardwareId::ASH)); + assert_eq!(782, u16::from(ArpHardwareId::ECONET)); + assert_eq!(783, u16::from(ArpHardwareId::IRDA)); + + assert_eq!(784, u16::from(ArpHardwareId::FCPP)); + assert_eq!(785, u16::from(ArpHardwareId::FCAL)); + assert_eq!(786, u16::from(ArpHardwareId::FCPL)); + assert_eq!(787, u16::from(ArpHardwareId::FCFABRIC)); + + assert_eq!(800, u16::from(ArpHardwareId::IEEE802_TR)); + assert_eq!(801, u16::from(ArpHardwareId::IEEE80211)); + assert_eq!(802, u16::from(ArpHardwareId::IEEE80211_PRISM)); + assert_eq!(803, u16::from(ArpHardwareId::IEEE80211_RADIOTAP)); + assert_eq!(804, u16::from(ArpHardwareId::IEEE802154)); + assert_eq!(805, u16::from(ArpHardwareId::IEEE802154_MONITOR)); + + assert_eq!(820, u16::from(ArpHardwareId::PHONET)); + assert_eq!(821, u16::from(ArpHardwareId::PHONET_PIPE)); + assert_eq!(822, u16::from(ArpHardwareId::CAIF)); + assert_eq!(823, u16::from(ArpHardwareId::IP6GRE)); + assert_eq!(824, u16::from(ArpHardwareId::NETLINK)); + assert_eq!(825, u16::from(ArpHardwareId::IPV6LOWPAN)); + assert_eq!(826, u16::from(ArpHardwareId::VSOCKMON)); + + assert_eq!(0xFFFF, u16::from(ArpHardwareId::VOID)); + assert_eq!(0xFFFE, u16::from(ArpHardwareId::NONE)); + } + + #[test] + fn from_u16() { + assert_eq!(ArpHardwareId::from(0), ArpHardwareId::NETROM); + assert_eq!(ArpHardwareId::from(1), ArpHardwareId::ETHER); + assert_eq!(ArpHardwareId::from(2), ArpHardwareId::EETHER); + assert_eq!(ArpHardwareId::from(3), ArpHardwareId::AX25); + assert_eq!(ArpHardwareId::from(4), ArpHardwareId::PRONET); + assert_eq!(ArpHardwareId::from(5), ArpHardwareId::CHAOS); + assert_eq!(ArpHardwareId::from(6), ArpHardwareId::IEEE802); + assert_eq!(ArpHardwareId::from(7), ArpHardwareId::ARCNET); + assert_eq!(ArpHardwareId::from(8), ArpHardwareId::APPLETLK); + assert_eq!(ArpHardwareId::from(15), ArpHardwareId::DLCI); + assert_eq!(ArpHardwareId::from(19), ArpHardwareId::ATM); + assert_eq!(ArpHardwareId::from(23), ArpHardwareId::METRICOM); + assert_eq!(ArpHardwareId::from(24), ArpHardwareId::IEEE1394); + assert_eq!(ArpHardwareId::from(27), ArpHardwareId::EUI64); + assert_eq!(ArpHardwareId::from(32), ArpHardwareId::INFINIBAND); + + assert_eq!(ArpHardwareId::from(256), ArpHardwareId::SLIP); + assert_eq!(ArpHardwareId::from(257), ArpHardwareId::CSLIP); + assert_eq!(ArpHardwareId::from(258), ArpHardwareId::SLIP6); + assert_eq!(ArpHardwareId::from(259), ArpHardwareId::CSLIP6); + assert_eq!(ArpHardwareId::from(260), ArpHardwareId::RSRVD); + assert_eq!(ArpHardwareId::from(264), ArpHardwareId::ADAPT); + assert_eq!(ArpHardwareId::from(270), ArpHardwareId::ROSE); + assert_eq!(ArpHardwareId::from(271), ArpHardwareId::X25); + assert_eq!(ArpHardwareId::from(272), ArpHardwareId::HWX25); + assert_eq!(ArpHardwareId::from(280), ArpHardwareId::CAN); + assert_eq!(ArpHardwareId::from(512), ArpHardwareId::PPP); + assert_eq!(ArpHardwareId::from(513), ArpHardwareId::CISCO_HDLC); + assert_eq!(ArpHardwareId::from(516), ArpHardwareId::LAPB); + assert_eq!(ArpHardwareId::from(517), ArpHardwareId::DDCMP); + assert_eq!(ArpHardwareId::from(518), ArpHardwareId::RAWHDLC); + assert_eq!(ArpHardwareId::from(519), ArpHardwareId::RAWIP); + + assert_eq!(ArpHardwareId::from(768), ArpHardwareId::TUNNEL); + assert_eq!(ArpHardwareId::from(769), ArpHardwareId::TUNNEL6); + assert_eq!(ArpHardwareId::from(770), ArpHardwareId::FRAD); + assert_eq!(ArpHardwareId::from(771), ArpHardwareId::SKIP); + assert_eq!(ArpHardwareId::from(772), ArpHardwareId::LOOPBACK); + assert_eq!(ArpHardwareId::from(773), ArpHardwareId::LOCALTLK); + assert_eq!(ArpHardwareId::from(774), ArpHardwareId::FDDI); + assert_eq!(ArpHardwareId::from(775), ArpHardwareId::BIF); + assert_eq!(ArpHardwareId::from(776), ArpHardwareId::SIT); + assert_eq!(ArpHardwareId::from(777), ArpHardwareId::IPDDP); + assert_eq!(ArpHardwareId::from(778), ArpHardwareId::IPGRE); + assert_eq!(ArpHardwareId::from(779), ArpHardwareId::PIMREG); + assert_eq!(ArpHardwareId::from(780), ArpHardwareId::HIPPI); + assert_eq!(ArpHardwareId::from(781), ArpHardwareId::ASH); + assert_eq!(ArpHardwareId::from(782), ArpHardwareId::ECONET); + assert_eq!(ArpHardwareId::from(783), ArpHardwareId::IRDA); + + assert_eq!(ArpHardwareId::from(784), ArpHardwareId::FCPP); + assert_eq!(ArpHardwareId::from(785), ArpHardwareId::FCAL); + assert_eq!(ArpHardwareId::from(786), ArpHardwareId::FCPL); + assert_eq!(ArpHardwareId::from(787), ArpHardwareId::FCFABRIC); + + assert_eq!(ArpHardwareId::from(800), ArpHardwareId::IEEE802_TR); + assert_eq!(ArpHardwareId::from(801), ArpHardwareId::IEEE80211); + assert_eq!(ArpHardwareId::from(802), ArpHardwareId::IEEE80211_PRISM); + assert_eq!(ArpHardwareId::from(803), ArpHardwareId::IEEE80211_RADIOTAP); + assert_eq!(ArpHardwareId::from(804), ArpHardwareId::IEEE802154); + assert_eq!(ArpHardwareId::from(805), ArpHardwareId::IEEE802154_MONITOR); + + assert_eq!(ArpHardwareId::from(820), ArpHardwareId::PHONET); + assert_eq!(ArpHardwareId::from(821), ArpHardwareId::PHONET_PIPE); + assert_eq!(ArpHardwareId::from(822), ArpHardwareId::CAIF); + assert_eq!(ArpHardwareId::from(823), ArpHardwareId::IP6GRE); + assert_eq!(ArpHardwareId::from(824), ArpHardwareId::NETLINK); + assert_eq!(ArpHardwareId::from(825), ArpHardwareId::IPV6LOWPAN); + assert_eq!(ArpHardwareId::from(826), ArpHardwareId::VSOCKMON); + + assert_eq!(ArpHardwareId::from(0xFFFF), ArpHardwareId::VOID); + assert_eq!(ArpHardwareId::from(0xFFFE), ArpHardwareId::NONE); + } + + + #[test] + fn dbg() { + let pairs = &[ + (ArpHardwareId::NETROM, "0 (from KA9Q: NET/ROM pseudo)"), + (ArpHardwareId::ETHER, "1 (Ethernet 10Mbps)"), + (ArpHardwareId::EETHER, "2 (Experimental Ethernet)"), + (ArpHardwareId::AX25, "3 (AX.25 Level 2)"), + (ArpHardwareId::PRONET, "4 (PROnet token ring)"), + (ArpHardwareId::CHAOS, "5 (Chaosnet)"), + (ArpHardwareId::IEEE802, "6 (IEEE 802.2 Ethernet/TR/TB)"), + (ArpHardwareId::ARCNET, "7 (ARCnet)"), + (ArpHardwareId::APPLETLK, "8 (APPLEtalk)"), + (ArpHardwareId::DLCI, "15 (Frame Relay DLCI)"), + (ArpHardwareId::ATM, "19 (ATM)"), + (ArpHardwareId::METRICOM, "23 (Metricom STRIP (new IANA id))"), + (ArpHardwareId::IEEE1394, "24 (IEEE 1394 IPv4 - RFC 2734)"), + (ArpHardwareId::EUI64, "27 (EUI-64)"), + (ArpHardwareId::INFINIBAND, "32 (InfiniBand)"), + (ArpHardwareId::SLIP, "256 (SLIP)"), + (ArpHardwareId::CSLIP, "257 (CSLIP)"), + (ArpHardwareId::SLIP6, "258 (SLIP6)"), + (ArpHardwareId::CSLIP6, "259 (CSLIP6)"), + (ArpHardwareId::RSRVD, "260 (Notional KISS type)"), + (ArpHardwareId::ADAPT, "264 (ADAPT)"), + (ArpHardwareId::ROSE, "270 (ROSE)"), + (ArpHardwareId::X25, "271 (CCITT X.25)"), + (ArpHardwareId::HWX25, "272 (Boards with X.25 in firmware)"), + (ArpHardwareId::CAN, "280 (Controller Area Network)"), + (ArpHardwareId::PPP, "512 (PPP)"), + (ArpHardwareId::CISCO_HDLC, "513 (Cisco HDLC)"), + (ArpHardwareId::LAPB, "516 (LAPB)"), + (ArpHardwareId::DDCMP, "517 (Digital's DDCMP protocol)"), + (ArpHardwareId::RAWHDLC, "518 (Raw HDLC)"), + (ArpHardwareId::RAWIP, "519 (Raw IP)"), + (ArpHardwareId::TUNNEL, "768 (IPIP tunnel)"), + (ArpHardwareId::TUNNEL6, "769 (IP6IP6 tunnel)"), + (ArpHardwareId::FRAD, "770 (Frame Relay Access Device)"), + (ArpHardwareId::SKIP, "771 (SKIP vif)"), + (ArpHardwareId::LOOPBACK, "772 (Loopback device)"), + (ArpHardwareId::LOCALTLK, "773 (Localtalk device)"), + (ArpHardwareId::FDDI, "774 (Fiber Distributed Data Interface)"), + (ArpHardwareId::BIF, "775 (AP1000 BIF)"), + (ArpHardwareId::SIT, "776 (sit0 device - IPv6-in-IPv4)"), + (ArpHardwareId::IPDDP, "777 (IP over DDP tunneller)"), + (ArpHardwareId::IPGRE, "778 (GRE over IP)"), + (ArpHardwareId::PIMREG, "779 (PIMSM register interface)"), + (ArpHardwareId::HIPPI, "780 (High Performance Parallel Interface)"), + (ArpHardwareId::ASH, "781 (Nexus 64Mbps Ash)"), + (ArpHardwareId::ECONET, "782 (Acorn Econet)"), + (ArpHardwareId::IRDA, "783 (Linux-IrDA)"), + (ArpHardwareId::FCPP, "784 (Point to point fibrechannel)"), + (ArpHardwareId::FCAL, "785 (Fibrechannel arbitrated loop)"), + (ArpHardwareId::FCPL, "786 (Fibrechannel public loop)"), + (ArpHardwareId::FCFABRIC, "787 (Fibrechannel fabric)"), + (ArpHardwareId::IEEE802_TR, "800 (Magic type ident for TR)"), + (ArpHardwareId::IEEE80211, "801 (IEEE 802.11)"), + (ArpHardwareId::IEEE80211_PRISM, "802 (IEEE 802.11 + Prism2 header)"), + (ArpHardwareId::IEEE80211_RADIOTAP, "803 (IEEE 802.11 + radiotap header)"), + (ArpHardwareId::IEEE802154, "804 (IEEE 802.15.4)"), + (ArpHardwareId::IEEE802154_MONITOR, "805 (IEEE 802.15.4 network monitor)"), + (ArpHardwareId::PHONET, "820 (PhoNet media type)"), + (ArpHardwareId::PHONET_PIPE, "821 (PhoNet pipe header)"), + (ArpHardwareId::CAIF, "822 (CAIF media type)"), + (ArpHardwareId::IP6GRE, "823 (GRE over IPv6)"), + (ArpHardwareId::NETLINK, "824 (Netlink header)"), + (ArpHardwareId::IPV6LOWPAN, "825 (IPv6 over LoWPAN)"), + (ArpHardwareId::VSOCKMON, "826 (Vsock monitor header)"), + (ArpHardwareId::VOID, "0xFFFF (Void type, nothing is known)"), + (ArpHardwareId::NONE, "0xFFFE (zero header length)"), + (ArpHardwareId::from(0x1234), "0x1234"), + ]; + + for (ether_type, str_value) in pairs { + assert_eq!(str_value, &format!("{:?}", ether_type)); + } + } + + #[test] + fn default() { + let value: ArpHardwareId = Default::default(); + assert_eq!(ArpHardwareId(0), value); + } + + #[test] + fn clone_eq() { + let values = &[ + ArpHardwareId::NETROM, + ArpHardwareId::ETHER, + ArpHardwareId::EETHER, + ArpHardwareId::AX25, + ArpHardwareId::PRONET, + ArpHardwareId::CHAOS, + ArpHardwareId::IEEE802, + ArpHardwareId::ARCNET, + ArpHardwareId::APPLETLK, + ArpHardwareId::DLCI, + ArpHardwareId::ATM, + ArpHardwareId::METRICOM, + ArpHardwareId::IEEE1394, + ArpHardwareId::EUI64, + ArpHardwareId::INFINIBAND, + ArpHardwareId::SLIP, + ArpHardwareId::CSLIP, + ArpHardwareId::SLIP6, + ArpHardwareId::CSLIP6, + ArpHardwareId::RSRVD, + ArpHardwareId::ADAPT, + ArpHardwareId::ROSE, + ArpHardwareId::X25, + ArpHardwareId::HWX25, + ArpHardwareId::CAN, + ArpHardwareId::PPP, + ArpHardwareId::CISCO_HDLC, + ArpHardwareId::LAPB, + ArpHardwareId::DDCMP, + ArpHardwareId::RAWHDLC, + ArpHardwareId::RAWIP, + ArpHardwareId::TUNNEL, + ArpHardwareId::TUNNEL6, + ArpHardwareId::FRAD, + ArpHardwareId::SKIP, + ArpHardwareId::LOOPBACK, + ArpHardwareId::LOCALTLK, + ArpHardwareId::FDDI, + ArpHardwareId::BIF, + ArpHardwareId::SIT, + ArpHardwareId::IPDDP, + ArpHardwareId::IPGRE, + ArpHardwareId::PIMREG, + ArpHardwareId::HIPPI, + ArpHardwareId::ASH, + ArpHardwareId::ECONET, + ArpHardwareId::IRDA, + ArpHardwareId::FCPP, + ArpHardwareId::FCAL, + ArpHardwareId::FCPL, + ArpHardwareId::FCFABRIC, + ArpHardwareId::IEEE802_TR, + ArpHardwareId::IEEE80211, + ArpHardwareId::IEEE80211_PRISM, + ArpHardwareId::IEEE80211_RADIOTAP, + ArpHardwareId::IEEE802154, + ArpHardwareId::IEEE802154_MONITOR, + ArpHardwareId::PHONET, + ArpHardwareId::PHONET_PIPE, + ArpHardwareId::CAIF, + ArpHardwareId::IP6GRE, + ArpHardwareId::NETLINK, + ArpHardwareId::IPV6LOWPAN, + ArpHardwareId::VSOCKMON, + ArpHardwareId::VOID, + ArpHardwareId::NONE, + ]; + + // clone + for v in values { + assert_eq!(v, &v.clone()); + } + + // eq + for (a_pos, a) in values.iter().enumerate() { + for (b_pos, b) in values.iter().enumerate() { + assert_eq!(a_pos == b_pos, a == b); + assert_eq!(a_pos != b_pos, a != b); + } + } + } +} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 74cd242a..69a0b74c 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -1,4 +1,4 @@ -pub mod arphrd_type; +pub mod arp_hardware_id; pub mod double_vlan_header; pub mod double_vlan_header_slice; pub mod double_vlan_slice; From 0df5e66c1c55122fec130482fbbc5dd763d02e6e Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Thu, 25 Apr 2024 21:17:46 +0200 Subject: [PATCH 05/21] make linux sll packet type more consistent with the pcap and kernel definitions --- README.md | 6 +- etherparse/src/lib.rs | 2 +- etherparse/src/link/linux_sll_header.rs | 4 +- etherparse/src/link/linux_sll_packet_type.rs | 182 ++++++++++++++++++ etherparse/src/link/linux_sll_type.rs | 190 ------------------- etherparse/src/link/mod.rs | 2 +- 6 files changed, 190 insertions(+), 196 deletions(-) create mode 100644 etherparse/src/link/linux_sll_packet_type.rs delete mode 100644 etherparse/src/link/linux_sll_type.rs diff --git a/README.md b/README.md index 72a4b27d..2c3788a5 100644 --- a/README.md +++ b/README.md @@ -228,9 +228,11 @@ Read the documentations of the different methods for a more details: * [Internet Control Message Protocol version 6 (ICMPv6) Parameters](https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml) * Multicast Listener Discovery (MLD) for IPv6 [RFC 2710](https://datatracker.ietf.org/doc/html/rfc2710) * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) -* [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) +* [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) on tcpdump +* LINUX_SLL [header definition](https://github.com/the-tcpdump-group/libpcap/blob/a932566fa1f6df16176ac702b1762ea1cd9ed9a3/pcap/sll.h) on libpcap +* [Linux packet types definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel * Address Resolution Protocol (ARP) Parameters [Harware Types](https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2) -* Arp hardware identifiers definitions on the Linux kernel [if_arp.h](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) +* [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel ## License Licensed under either of Apache License, Version 2.0 or MIT license at your option. The corresponding license texts can be found in the LICENSE-APACHE file and the LICENSE-MIT file. diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 28bb7a6d..781968ca 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -304,7 +304,7 @@ pub use crate::link::ethernet2_header_slice::*; pub use crate::link::ethernet2_slice::*; pub use crate::link::link_slice::*; pub use crate::link::linux_sll_header::*; -pub use crate::link::linux_sll_type::*; +pub use crate::link::linux_sll_packet_type::*; pub use crate::link::single_vlan_header::*; pub use crate::link::single_vlan_header_slice::*; pub use crate::link::single_vlan_slice::*; diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index 3e46a851..c155f3fa 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -1,6 +1,6 @@ use crate::EtherType; -use super::{arp_hardware_id::ArpHardwareId, linux_sll_type::LinuxSllType}; +use super::{arp_hardware_id::ArpHardwareId, linux_sll_packet_type::LinuxSllPacketType}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum LinuxSllProtocolType { @@ -29,7 +29,7 @@ pub enum LinuxSllProtocolType { #[derive(Clone, Debug, Eq, PartialEq)] pub struct LinuxSllHeader { /// Type of the captured packet - pub packet_type: LinuxSllType, + pub packet_type: LinuxSllPacketType, /// ARPHRD_ value for the link-layer device type pub arp_hrd_type: ArpHardwareId, /// The size of the adress that is valid diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs new file mode 100644 index 00000000..0dc93c5b --- /dev/null +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -0,0 +1,182 @@ +use core::hint::unreachable_unchecked; + +use crate::err::{self, ValueTooBigError}; + +/// Represents an "Packet type", indicating the direction where it was sent, +/// used inside a SLL header +/// +/// You can convert `u16` in the valid range to an `LinuxSllType` and the +/// other way around +/// +/// ``` +/// use etherparse::LinuxSllPacketType; +/// +/// // Convert to LinuxSllPacketType using the try_from & try_into trait +/// let link_type: LinuxSllPacketType = 1_u16.try_into().unwrap(); +/// assert_eq!(LinuxSllPacketType::BROADCAST, link_type); +/// +/// // convert to u16 using the from & into trait +/// let num: u16 = LinuxSllPacketType::BROADCAST.into(); +/// assert_eq!(1, num); +/// ``` +#[derive(Clone, Copy, Eq, PartialEq, Default)] +pub struct LinuxSllPacketType(u16); + +impl LinuxSllPacketType { + // Numbers sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + pub const HOST: LinuxSllPacketType = Self(0); + pub const BROADCAST: LinuxSllPacketType = Self(1); + pub const MULTICAST: LinuxSllPacketType = Self(2); + pub const OTHERHOST: LinuxSllPacketType = Self(3); + pub const OUTGOING: LinuxSllPacketType = Self(4); + pub const LOOPBACK: LinuxSllPacketType = Self(5); + pub const USER: LinuxSllPacketType = Self(6); + pub const KERNEL: LinuxSllPacketType = Self(7); + + pub const MAX_VAL: u16 = 7; +} + +impl TryFrom for LinuxSllPacketType { + type Error = ValueTooBigError; + + fn try_from(value: u16) -> Result { + match value { + 0 => Ok(LinuxSllPacketType::HOST), + 1 => Ok(LinuxSllPacketType::BROADCAST), + 2 => Ok(LinuxSllPacketType::MULTICAST), + 3 => Ok(LinuxSllPacketType::OTHERHOST), + 4 => Ok(LinuxSllPacketType::OUTGOING), + 5 => Ok(LinuxSllPacketType::LOOPBACK), + 6 => Ok(LinuxSllPacketType::USER), + 7 => Ok(LinuxSllPacketType::KERNEL), + LinuxSllPacketType::MAX_VAL..=u16::MAX => Err(ValueTooBigError { + actual: value, + max_allowed: LinuxSllPacketType::MAX_VAL, + value_type: err::ValueType::LinuxSllType, + }), + } + } +} + +impl From for u16 { + #[inline] + fn from(val: LinuxSllPacketType) -> Self { + val.0 + } +} + +impl core::fmt::Debug for LinuxSllPacketType { + // Descriptions sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.0 { + 0 => write!(f, "0 (Sent to us)"), + 1 => write!(f, "1 (Sent to all)"), + 2 => write!(f, "2 (Sent to group)"), + 3 => write!(f, "3 (Sent to someone else)"), + 4 => write!(f, "4 (Sent by us)"), + 5 => write!(f, "5 (MC/BRD frame looped back)"), + 6 => write!(f, "6 (Sent to user space)"), + 7 => write!(f, "7 (Sent to kernel space)"), + LinuxSllPacketType::MAX_VAL..=u16::MAX => { + // SAFETY: + // Safe because values over MAX_VAL are never constructed + unsafe { unreachable_unchecked() } + } + } + } +} + +#[cfg(test)] +mod test { + use alloc::format; + + use super::*; + use crate::err::{self, ValueTooBigError}; + + #[test] + fn to_u16() { + assert_eq!(0, u16::from(LinuxSllPacketType::HOST)); + assert_eq!(1, u16::from(LinuxSllPacketType::BROADCAST)); + assert_eq!(2, u16::from(LinuxSllPacketType::MULTICAST)); + assert_eq!(3, u16::from(LinuxSllPacketType::OTHERHOST)); + assert_eq!(4, u16::from(LinuxSllPacketType::OUTGOING)); + assert_eq!(5, u16::from(LinuxSllPacketType::LOOPBACK)); + assert_eq!(6, u16::from(LinuxSllPacketType::USER)); + assert_eq!(7, u16::from(LinuxSllPacketType::KERNEL)); + } + + #[test] + fn try_from_u16() { + assert_eq!(LinuxSllPacketType::try_from(0), Ok(LinuxSllPacketType::HOST)); + assert_eq!(LinuxSllPacketType::try_from(1), Ok(LinuxSllPacketType::BROADCAST)); + assert_eq!(LinuxSllPacketType::try_from(2), Ok(LinuxSllPacketType::MULTICAST)); + assert_eq!(LinuxSllPacketType::try_from(3), Ok(LinuxSllPacketType::OTHERHOST)); + assert_eq!(LinuxSllPacketType::try_from(4), Ok(LinuxSllPacketType::OUTGOING)); + assert_eq!(LinuxSllPacketType::try_from(5), Ok(LinuxSllPacketType::LOOPBACK)); + assert_eq!(LinuxSllPacketType::try_from(6), Ok(LinuxSllPacketType::USER)); + assert_eq!(LinuxSllPacketType::try_from(7), Ok(LinuxSllPacketType::KERNEL)); + assert_eq!(LinuxSllPacketType::try_from(8), Err(ValueTooBigError { + actual: 8, + max_allowed: LinuxSllPacketType::MAX_VAL, + value_type: err::ValueType::LinuxSllType, + })); + assert_eq!(LinuxSllPacketType::try_from(123), Err(ValueTooBigError { + actual: 123, + max_allowed: LinuxSllPacketType::MAX_VAL, + value_type: err::ValueType::LinuxSllType, + })); + } + + #[test] + fn dbg() { + let pairs = &[ + (LinuxSllPacketType::HOST, "0 (Sent to us)"), + (LinuxSllPacketType::BROADCAST, "1 (Sent to all)"), + (LinuxSllPacketType::MULTICAST, "2 (Sent to group)"), + (LinuxSllPacketType::OTHERHOST, "3 (Sent to someone else)"), + (LinuxSllPacketType::OUTGOING, "4 (Sent by us)"), + (LinuxSllPacketType::LOOPBACK, "5 (MC/BRD frame looped back)"), + (LinuxSllPacketType::USER, "6 (Sent to user space)"), + (LinuxSllPacketType::KERNEL, "7 (Sent to kernel space)"), + ]; + + for (ether_type, str_value) in pairs { + assert_eq!(str_value, &format!("{:?}", ether_type)); + } + } + + #[test] + fn default() { + let value: LinuxSllPacketType = Default::default(); + assert_eq!(LinuxSllPacketType::HOST, value); + } + + #[test] + fn clone_eq() { + let values = &[ + LinuxSllPacketType::HOST, + LinuxSllPacketType::BROADCAST, + LinuxSllPacketType::MULTICAST, + LinuxSllPacketType::OTHERHOST, + LinuxSllPacketType::OUTGOING, + LinuxSllPacketType::LOOPBACK, + LinuxSllPacketType::USER, + LinuxSllPacketType::KERNEL, + ]; + + // clone + for v in values { + assert_eq!(v, &v.clone()); + } + + // eq + for (a_pos, a) in values.iter().enumerate() { + for (b_pos, b) in values.iter().enumerate() { + assert_eq!(a_pos == b_pos, a == b); + assert_eq!(a_pos != b_pos, a != b); + } + } + } +} diff --git a/etherparse/src/link/linux_sll_type.rs b/etherparse/src/link/linux_sll_type.rs deleted file mode 100644 index 6784642d..00000000 --- a/etherparse/src/link/linux_sll_type.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::err::{self, ValueTooBigError}; - -/// Represents the type of direction that the packet contained in the -/// LINUX_SLL packet -/// -/// You can convert `u16` in the valid range to an `LinuxSllType` and the -/// other way around -/// -/// ``` -/// use etherparse::LinuxSllType; -/// -/// // Convert to LinuxSllType using the try_from & try_into trait -/// let link_type: LinuxSllType = 1_u16.try_into().unwrap(); -/// assert_eq!(LinuxSllType::BroadcastByOther, link_type); -/// -/// // convert to u16 using the from & into trait -/// let num: u16 = LinuxSllType::BroadcastByOther.into(); -/// assert_eq!(1, num); -/// ``` -/// -#[derive(Clone, Copy, Eq, PartialEq, Default)] -pub enum LinuxSllType { - /// The packet was specifically sent by other to the one that captured the - /// packet - #[default] - UnicastByOtherToReceiver, - /// The packet was multicasted by somebody else - BroadcastByOther, - /// The packet was broadcasted by somebody else - MulticastByOther, - /// The packet was sent by other to another - UnicastByOtherToOther, - /// The packet was sent by the one that captured the packet - SentByUs, -} - -impl LinuxSllType { - /// Asociated u16 value of `LinuxSllType::UnicastByOtherToReceiver` - pub const UNICAST_BY_OTHER_TO_US: u16 = 0; - /// Asociated u16 value of `LinuxSllType::BroadcastByOther` - pub const BROADCAST_BY_OTHER: u16 = 1; - /// Asociated u16 value of `LinuxSllType::MulticastByOther` - pub const MULTICAST_BY_OTHER: u16 = 2; - /// Asociated u16 value of `LinuxSllType::UnicastByOtherToOther` - pub const UNICAST_BY_OTHER_TO_OTHER: u16 = 3; - /// Asociated u16 value of `LinuxSllType::UnicastByOtherToOther` - pub const SENT_BY_US: u16 = 4; - /// Maximum associated value - pub const MAX_U16: u16 = 4; -} - -impl TryFrom for LinuxSllType { - type Error = ValueTooBigError; - - fn try_from(value: u16) -> Result { - match value { - LinuxSllType::UNICAST_BY_OTHER_TO_US => Ok(LinuxSllType::UnicastByOtherToReceiver), - LinuxSllType::BROADCAST_BY_OTHER => Ok(LinuxSllType::BroadcastByOther), - LinuxSllType::MULTICAST_BY_OTHER => Ok(LinuxSllType::MulticastByOther), - LinuxSllType::UNICAST_BY_OTHER_TO_OTHER => Ok(LinuxSllType::UnicastByOtherToOther), - LinuxSllType::SENT_BY_US => Ok(LinuxSllType::SentByUs), - LinuxSllType::MAX_U16..=u16::MAX => Err(ValueTooBigError { - actual: value, - max_allowed: LinuxSllType::MAX_U16, - value_type: err::ValueType::LinuxSllType, - }), - } - } -} - -impl From for u16 { - #[inline] - fn from(value: LinuxSllType) -> Self { - match value { - LinuxSllType::UnicastByOtherToReceiver => LinuxSllType::UNICAST_BY_OTHER_TO_US, - LinuxSllType::BroadcastByOther => LinuxSllType::BROADCAST_BY_OTHER, - LinuxSllType::MulticastByOther => LinuxSllType::MULTICAST_BY_OTHER, - LinuxSllType::UnicastByOtherToOther => LinuxSllType::UNICAST_BY_OTHER_TO_OTHER, - LinuxSllType::SentByUs => LinuxSllType::SENT_BY_US, - } - } -} - -impl core::fmt::Debug for LinuxSllType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - LinuxSllType::UnicastByOtherToReceiver => write!(f, "Unicast by other to receiver ({})", u16::from(*self)), - LinuxSllType::BroadcastByOther => write!(f, "Broadcast by other ({})", u16::from(*self)), - LinuxSllType::MulticastByOther => write!(f, "Multicast by other to receiver ({})", u16::from(*self)), - LinuxSllType::UnicastByOtherToOther => write!(f, "Unicast by other to other ({})", u16::from(*self)), - LinuxSllType::SentByUs => write!(f, "Sent by us ({})", u16::from(*self)), - } - } -} - -#[cfg(test)] -mod test { - use alloc::format; - - use super::*; - use crate::err::{self, ValueTooBigError}; - - #[test] - fn to_u16() { - assert_eq!(0, u16::from(LinuxSllType::UnicastByOtherToReceiver)); - assert_eq!(1, u16::from(LinuxSllType::BroadcastByOther)); - assert_eq!(2, u16::from(LinuxSllType::MulticastByOther)); - assert_eq!(3, u16::from(LinuxSllType::UnicastByOtherToOther)); - assert_eq!(4, u16::from(LinuxSllType::SentByUs)); - } - - #[test] - fn try_from_u16() { - assert_eq!(LinuxSllType::try_from(0), Ok(LinuxSllType::UnicastByOtherToReceiver)); - assert_eq!(LinuxSllType::try_from(1), Ok(LinuxSllType::BroadcastByOther)); - assert_eq!(LinuxSllType::try_from(2), Ok(LinuxSllType::MulticastByOther)); - assert_eq!(LinuxSllType::try_from(3), Ok(LinuxSllType::UnicastByOtherToOther)); - assert_eq!(LinuxSllType::try_from(4), Ok(LinuxSllType::SentByUs)); - assert_eq!(LinuxSllType::try_from(5), Err(ValueTooBigError { - actual: 5, - max_allowed: LinuxSllType::MAX_U16, - value_type: err::ValueType::LinuxSllType, - })); - assert_eq!(LinuxSllType::try_from(123), Err(ValueTooBigError { - actual: 123, - max_allowed: LinuxSllType::MAX_U16, - value_type: err::ValueType::LinuxSllType, - })); - } - - #[test] - fn dbg() { - let pairs = &[ - ( - LinuxSllType::UnicastByOtherToReceiver, - "Unicast by other to receiver (0)", - ), - ( - LinuxSllType::BroadcastByOther, - "Broadcast by other (1)", - ), - ( - LinuxSllType::MulticastByOther, - "Multicast by other to receiver (2)" - ), - ( - LinuxSllType::UnicastByOtherToOther, - "Unicast by other to other (3)" - ), - ( - LinuxSllType::SentByUs, - "Sent by us (4)" - ), - ]; - - for (ether_type, str_value) in pairs { - assert_eq!(str_value, &format!("{:?}", ether_type)); - } - } - - #[test] - fn default() { - let value: LinuxSllType = Default::default(); - assert_eq!(LinuxSllType::UnicastByOtherToReceiver, value); - } - - #[test] - fn clone_eq() { - let values = &[ - LinuxSllType::UnicastByOtherToReceiver, - LinuxSllType::BroadcastByOther, - LinuxSllType::MulticastByOther, - LinuxSllType::UnicastByOtherToOther, - LinuxSllType::SentByUs, - ]; - - // clone - for v in values { - assert_eq!(v, &v.clone()); - } - - // eq - for (a_pos, a) in values.iter().enumerate() { - for (b_pos, b) in values.iter().enumerate() { - assert_eq!(a_pos == b_pos, a == b); - assert_eq!(a_pos != b_pos, a != b); - } - } - } -} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 69a0b74c..7a5b54fa 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -8,7 +8,7 @@ pub mod ethernet2_header; pub mod ethernet2_header_slice; pub mod ethernet2_slice; pub mod linux_sll_header; -pub mod linux_sll_type; +pub mod linux_sll_packet_type; pub mod link_slice; pub mod single_vlan_header; pub mod single_vlan_header_slice; From 3bb335b1c7638935ce460ba4e3cc243ac4acd5f2 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Fri, 26 Apr 2024 12:06:56 +0200 Subject: [PATCH 06/21] combine used non standard linux ether types into its own type --- etherparse/src/lib.rs | 1 + .../src/link/linux_nonstandard_ether_type.rs | 316 ++++++++++++++++++ etherparse/src/link/linux_sll_header.rs | 27 +- etherparse/src/link/mod.rs | 1 + 4 files changed, 327 insertions(+), 18 deletions(-) create mode 100644 etherparse/src/link/linux_nonstandard_ether_type.rs diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 781968ca..dc5f0c89 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -303,6 +303,7 @@ pub use crate::link::ethernet2_header::*; pub use crate::link::ethernet2_header_slice::*; pub use crate::link::ethernet2_slice::*; pub use crate::link::link_slice::*; +pub use crate::link::linux_nonstandard_ether_type::*; pub use crate::link::linux_sll_header::*; pub use crate::link::linux_sll_packet_type::*; pub use crate::link::single_vlan_header::*; diff --git a/etherparse/src/link/linux_nonstandard_ether_type.rs b/etherparse/src/link/linux_nonstandard_ether_type.rs new file mode 100644 index 00000000..32cefd3e --- /dev/null +++ b/etherparse/src/link/linux_nonstandard_ether_type.rs @@ -0,0 +1,316 @@ +/// Represents an non standard ethertype. These are defined in the Linux +/// kernel with ids under 1500 so they don't clash with the standard ones. +/// +/// You can convert any valid `u16` value to an `LinuxNonstandardEtherType` and +/// the other way around. +/// +/// ``` +/// use etherparse::LinuxNonstandardEtherType; +/// +/// // Convert to LinuxNonstandardEtherType using the from & into trait +/// let link_type: LinuxNonstandardEtherType = 0x0001.try_into().unwrap(); +/// assert_eq!(LinuxNonstandardEtherType::N802_3, link_type); +/// +/// // convert to u16 using the from & into trait +/// let num: u16 = LinuxNonstandardEtherType::N802_3.try_into().unwrap(); +/// assert_eq!(0x0001, num); +/// ``` +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct LinuxNonstandardEtherType(u16); + +impl LinuxNonstandardEtherType { + // Numbers sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_ether.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + pub const N802_3: LinuxNonstandardEtherType = Self(0x0001); + pub const AX25: LinuxNonstandardEtherType = Self(0x0002); + pub const ALL: LinuxNonstandardEtherType = Self(0x0003); + pub const N802_2: LinuxNonstandardEtherType = Self(0x0004); + pub const SNAP: LinuxNonstandardEtherType = Self(0x0005); + pub const DDCMP: LinuxNonstandardEtherType = Self(0x0006); + pub const WAN_PPP: LinuxNonstandardEtherType = Self(0x0007); + pub const PPP_MP: LinuxNonstandardEtherType = Self(0x0008); + pub const LOCALTALK: LinuxNonstandardEtherType = Self(0x0009); + pub const CAN: LinuxNonstandardEtherType = Self(0x000C); + pub const CANFD: LinuxNonstandardEtherType = Self(0x000D); + pub const CANXL: LinuxNonstandardEtherType = Self(0x000E); + pub const PPPTALK: LinuxNonstandardEtherType = Self(0x0010); + pub const TR_802_2: LinuxNonstandardEtherType = Self(0x0011); + pub const MOBITEX: LinuxNonstandardEtherType = Self(0x0015); + pub const CONTROL: LinuxNonstandardEtherType = Self(0x0016); + pub const IRDA: LinuxNonstandardEtherType = Self(0x0017); + pub const ECONET: LinuxNonstandardEtherType = Self(0x0018); + pub const HDLC: LinuxNonstandardEtherType = Self(0x0019); + pub const ARCNET: LinuxNonstandardEtherType = Self(0x001A); + pub const DSA: LinuxNonstandardEtherType = Self(0x001B); + pub const TRAILER: LinuxNonstandardEtherType = Self(0x001C); + pub const PHONET: LinuxNonstandardEtherType = Self(0x00F5); + pub const IEEE802154: LinuxNonstandardEtherType = Self(0x00F6); + pub const CAIF: LinuxNonstandardEtherType = Self(0x00F7); + pub const XDSA: LinuxNonstandardEtherType = Self(0x00F8); + pub const MAP: LinuxNonstandardEtherType = Self(0x00F9); + pub const MCTP: LinuxNonstandardEtherType = Self(0x00FA); +} + +impl Default for LinuxNonstandardEtherType { + fn default() -> Self { + Self::N802_3 + } +} + +impl TryFrom for LinuxNonstandardEtherType { + type Error = (); + + fn try_from(value: u16) -> Result { + match value { + 0x0000 => Err(()), + 0x0001 => Ok(LinuxNonstandardEtherType::N802_3), + 0x0002 => Ok(LinuxNonstandardEtherType::AX25), + 0x0003 => Ok(LinuxNonstandardEtherType::ALL), + 0x0004 => Ok(LinuxNonstandardEtherType::N802_2), + 0x0005 => Ok(LinuxNonstandardEtherType::SNAP), + 0x0006 => Ok(LinuxNonstandardEtherType::DDCMP), + 0x0007 => Ok(LinuxNonstandardEtherType::WAN_PPP), + 0x0008 => Ok(LinuxNonstandardEtherType::PPP_MP), + 0x0009 => Ok(LinuxNonstandardEtherType::LOCALTALK), + 0x000A..=0x000B => Err(()), + 0x000C => Ok(LinuxNonstandardEtherType::CAN), + 0x000D => Ok(LinuxNonstandardEtherType::CANFD), + 0x000E => Ok(LinuxNonstandardEtherType::CANXL), + 0x000F => Err(()), + 0x0010 => Ok(LinuxNonstandardEtherType::PPPTALK), + 0x0011 => Ok(LinuxNonstandardEtherType::TR_802_2), + 0x0012..=0x0014 => Err(()), + 0x0015 => Ok(LinuxNonstandardEtherType::MOBITEX), + 0x0016 => Ok(LinuxNonstandardEtherType::CONTROL), + 0x0017 => Ok(LinuxNonstandardEtherType::IRDA), + 0x0018 => Ok(LinuxNonstandardEtherType::ECONET), + 0x0019 => Ok(LinuxNonstandardEtherType::HDLC), + 0x001A => Ok(LinuxNonstandardEtherType::ARCNET), + 0x001B => Ok(LinuxNonstandardEtherType::DSA), + 0x001C => Ok(LinuxNonstandardEtherType::TRAILER), + 0x001D..=0x00F4 => Err(()), + 0x00F5 => Ok(LinuxNonstandardEtherType::PHONET), + 0x00F6 => Ok(LinuxNonstandardEtherType::IEEE802154), + 0x00F7 => Ok(LinuxNonstandardEtherType::CAIF), + 0x00F8 => Ok(LinuxNonstandardEtherType::XDSA), + 0x00F9 => Ok(LinuxNonstandardEtherType::MAP), + 0x00FA => Ok(LinuxNonstandardEtherType::MCTP), + 0x00FB..=u16::MAX => Err(()), + } + } +} + +impl From for u16 { + #[inline] + fn from(val: LinuxNonstandardEtherType) -> Self { + val.0 + } +} + +impl core::fmt::Debug for LinuxNonstandardEtherType { + // Descriptions sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_ether.h?id=e33c4963bf536900f917fb65a687724d5539bc21 + + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + LinuxNonstandardEtherType(0x0000) => write!(f, "{:#06X} (Unknown)", self.0), + LinuxNonstandardEtherType::N802_3 => write!(f, "{:#06X} (Dummy type for 802.3 frames)", self.0), + LinuxNonstandardEtherType::AX25 => write!(f, "{:#06X} (Dummy protocol id for AX.25)", self.0), + LinuxNonstandardEtherType::ALL => write!(f, "{:#06X} (Every packet)", self.0), + LinuxNonstandardEtherType::N802_2 => write!(f, "{:#06X} (802.2 frames)", self.0), + LinuxNonstandardEtherType::SNAP => write!(f, "{:#06X} (SNAP: Internal only)", self.0), + LinuxNonstandardEtherType::DDCMP => write!(f, "{:#06X} (DEC DDCMP: Internal only)", self.0), + LinuxNonstandardEtherType::WAN_PPP => write!(f, "{:#06X} (Dummy type for WAN PPP frames)", self.0), + LinuxNonstandardEtherType::PPP_MP => write!(f, "{:#06X} (Dummy type for PPP MP frames)", self.0), + LinuxNonstandardEtherType::LOCALTALK => write!(f, "{:#06X} (Localtalk pseudo type)", self.0), + LinuxNonstandardEtherType(0x000A..=0x000B) => write!(f, "{:#06X} (Unknown)", self.0), + LinuxNonstandardEtherType::CAN => write!(f, "{:#06X} (CAN: Controller Area Network)", self.0), + LinuxNonstandardEtherType::CANFD => write!(f, "{:#06X} (CANFD: CAN flexible data rate)", self.0), + LinuxNonstandardEtherType::CANXL => write!(f, "{:#06X} (CANXL: eXtended frame Length)", self.0), + LinuxNonstandardEtherType(0x000F) => write!(f, "{:#06X} (Unknown)", self.0), + LinuxNonstandardEtherType::PPPTALK => write!(f, "{:#06X} (Dummy type for Atalk over PPP)", self.0), + LinuxNonstandardEtherType::TR_802_2 => write!(f, "{:#06X} (802.2 frames)", self.0), + LinuxNonstandardEtherType(0x0012..=0x0014) => write!(f, "{:#06X} (Unknown)", self.0), + LinuxNonstandardEtherType::MOBITEX => write!(f, "{:#06X} (Mobitex)", self.0), + LinuxNonstandardEtherType::CONTROL => write!(f, "{:#06X} (Card specific control frames)", self.0), + LinuxNonstandardEtherType::IRDA => write!(f, "{:#06X} (Linux-IrDA)", self.0), + LinuxNonstandardEtherType::ECONET => write!(f, "{:#06X} (Acorn Econet)", self.0), + LinuxNonstandardEtherType::HDLC => write!(f, "{:#06X} (HDLC frames)", self.0), + LinuxNonstandardEtherType::ARCNET => write!(f, "{:#06X} (1A for ArcNet)", self.0), + LinuxNonstandardEtherType::DSA => write!(f, "{:#06X} (Distributed Switch Arch)", self.0), + LinuxNonstandardEtherType::TRAILER => write!(f, "{:#06X} (Trailer switch tagging)", self.0), + LinuxNonstandardEtherType(0x001D..=0x00F4) => write!(f, "{:#06X} (Unknown)", self.0), + LinuxNonstandardEtherType::PHONET => write!(f, "{:#06X} (Nokia Phonet frame)", self.0), + LinuxNonstandardEtherType::IEEE802154 => write!(f, "{:#06X} (IEEE802.15.4 frame)", self.0), + LinuxNonstandardEtherType::CAIF => write!(f, "{:#06X} (ST-Ericsson CAIF protocol)", self.0), + LinuxNonstandardEtherType::XDSA => write!(f, "{:#06X} (Multiplexed DSA protocol)", self.0), + LinuxNonstandardEtherType::MAP => write!(f, "{:#06X} (Qualcomm multiplexing and aggregation protocol)", self.0), + LinuxNonstandardEtherType::MCTP => write!(f, "{:#06X} (Management component transport protocol packets)", self.0), + LinuxNonstandardEtherType(0x00FB..=u16::MAX) => write!(f, "{:#06X} (Unknown)", self.0), + } + } +} + +#[cfg(test)] +mod test { + use alloc::format; + use super::*; + + #[test] + fn to_u16() { + assert_eq!(0x0001, u16::from(LinuxNonstandardEtherType::N802_3)); + assert_eq!(0x0002, u16::from(LinuxNonstandardEtherType::AX25)); + assert_eq!(0x0003, u16::from(LinuxNonstandardEtherType::ALL)); + assert_eq!(0x0004, u16::from(LinuxNonstandardEtherType::N802_2)); + assert_eq!(0x0005, u16::from(LinuxNonstandardEtherType::SNAP)); + assert_eq!(0x0006, u16::from(LinuxNonstandardEtherType::DDCMP)); + assert_eq!(0x0007, u16::from(LinuxNonstandardEtherType::WAN_PPP)); + assert_eq!(0x0008, u16::from(LinuxNonstandardEtherType::PPP_MP)); + assert_eq!(0x0009, u16::from(LinuxNonstandardEtherType::LOCALTALK)); + assert_eq!(0x000C, u16::from(LinuxNonstandardEtherType::CAN)); + assert_eq!(0x000D, u16::from(LinuxNonstandardEtherType::CANFD)); + assert_eq!(0x000E, u16::from(LinuxNonstandardEtherType::CANXL)); + assert_eq!(0x0010, u16::from(LinuxNonstandardEtherType::PPPTALK)); + assert_eq!(0x0011, u16::from(LinuxNonstandardEtherType::TR_802_2)); + assert_eq!(0x0015, u16::from(LinuxNonstandardEtherType::MOBITEX)); + assert_eq!(0x0016, u16::from(LinuxNonstandardEtherType::CONTROL)); + assert_eq!(0x0017, u16::from(LinuxNonstandardEtherType::IRDA)); + assert_eq!(0x0018, u16::from(LinuxNonstandardEtherType::ECONET)); + assert_eq!(0x0019, u16::from(LinuxNonstandardEtherType::HDLC)); + assert_eq!(0x001A, u16::from(LinuxNonstandardEtherType::ARCNET)); + assert_eq!(0x001B, u16::from(LinuxNonstandardEtherType::DSA)); + assert_eq!(0x001C, u16::from(LinuxNonstandardEtherType::TRAILER)); + assert_eq!(0x00F5, u16::from(LinuxNonstandardEtherType::PHONET)); + assert_eq!(0x00F6, u16::from(LinuxNonstandardEtherType::IEEE802154)); + assert_eq!(0x00F7, u16::from(LinuxNonstandardEtherType::CAIF)); + assert_eq!(0x00F8, u16::from(LinuxNonstandardEtherType::XDSA)); + assert_eq!(0x00F9, u16::from(LinuxNonstandardEtherType::MAP)); + assert_eq!(0x00FA, u16::from(LinuxNonstandardEtherType::MCTP)); + } + + #[test] + fn try_from_u16() { + assert_eq!(LinuxNonstandardEtherType::try_from(0x0001), Ok(LinuxNonstandardEtherType::N802_3)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0002), Ok(LinuxNonstandardEtherType::AX25)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0003), Ok(LinuxNonstandardEtherType::ALL)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0004), Ok(LinuxNonstandardEtherType::N802_2)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0005), Ok(LinuxNonstandardEtherType::SNAP)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0006), Ok(LinuxNonstandardEtherType::DDCMP)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0007), Ok(LinuxNonstandardEtherType::WAN_PPP)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0008), Ok(LinuxNonstandardEtherType::PPP_MP)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0009), Ok(LinuxNonstandardEtherType::LOCALTALK)); + /* 0x00A..=0x00B */ + assert_eq!(LinuxNonstandardEtherType::try_from(0x000C), Ok(LinuxNonstandardEtherType::CAN)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x000D), Ok(LinuxNonstandardEtherType::CANFD)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x000E), Ok(LinuxNonstandardEtherType::CANXL)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0010), Ok(LinuxNonstandardEtherType::PPPTALK)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0011), Ok(LinuxNonstandardEtherType::TR_802_2)); + /* 0x0012..=0x0014 */ + assert_eq!(LinuxNonstandardEtherType::try_from(0x0015), Ok(LinuxNonstandardEtherType::MOBITEX)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0016), Ok(LinuxNonstandardEtherType::CONTROL)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0017), Ok(LinuxNonstandardEtherType::IRDA)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0018), Ok(LinuxNonstandardEtherType::ECONET)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x0019), Ok(LinuxNonstandardEtherType::HDLC)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x001A), Ok(LinuxNonstandardEtherType::ARCNET)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x001B), Ok(LinuxNonstandardEtherType::DSA)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x001C), Ok(LinuxNonstandardEtherType::TRAILER)); + /* 0x001D..=0x00F4 */ + assert_eq!(LinuxNonstandardEtherType::try_from(0x00F5), Ok(LinuxNonstandardEtherType::PHONET)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x00F6), Ok(LinuxNonstandardEtherType::IEEE802154)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x00F7), Ok(LinuxNonstandardEtherType::CAIF)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x00F8), Ok(LinuxNonstandardEtherType::XDSA)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x00F9), Ok(LinuxNonstandardEtherType::MAP)); + assert_eq!(LinuxNonstandardEtherType::try_from(0x00FA), Ok(LinuxNonstandardEtherType::MCTP)); + /* 0x00FB..=u16::MAX */ + } + + #[test] + fn dbg() { + let pairs = &[ + (LinuxNonstandardEtherType::N802_3, "0x0001 (Dummy type for 802.3 frames)"), + (LinuxNonstandardEtherType::AX25, "0x0002 (Dummy protocol id for AX.25)"), + (LinuxNonstandardEtherType::ALL, "0x0003 (Every packet)"), + (LinuxNonstandardEtherType::N802_2, "0x0004 (802.2 frames)"), + (LinuxNonstandardEtherType::SNAP, "0x0005 (SNAP: Internal only)"), + (LinuxNonstandardEtherType::DDCMP, "0x0006 (DEC DDCMP: Internal only)"), + (LinuxNonstandardEtherType::WAN_PPP, "0x0007 (Dummy type for WAN PPP frames)"), + (LinuxNonstandardEtherType::PPP_MP, "0x0008 (Dummy type for PPP MP frames)"), + (LinuxNonstandardEtherType::LOCALTALK, "0x0009 (Localtalk pseudo type)"), + (LinuxNonstandardEtherType::CAN, "0x000C (CAN: Controller Area Network)"), + (LinuxNonstandardEtherType::CANFD, "0x000D (CANFD: CAN flexible data rate)"), + (LinuxNonstandardEtherType::CANXL, "0x000E (CANXL: eXtended frame Length)"), + (LinuxNonstandardEtherType::PPPTALK, "0x0010 (Dummy type for Atalk over PPP)"), + (LinuxNonstandardEtherType::TR_802_2, "0x0011 (802.2 frames)"), + (LinuxNonstandardEtherType::MOBITEX, "0x0015 (Mobitex)"), + (LinuxNonstandardEtherType::CONTROL, "0x0016 (Card specific control frames)"), + (LinuxNonstandardEtherType::IRDA, "0x0017 (Linux-IrDA)"), + (LinuxNonstandardEtherType::ECONET, "0x0018 (Acorn Econet)"), + (LinuxNonstandardEtherType::HDLC, "0x0019 (HDLC frames)"), + (LinuxNonstandardEtherType::ARCNET, "0x001A (1A for ArcNet)"), + (LinuxNonstandardEtherType::DSA, "0x001B (Distributed Switch Arch)"), + (LinuxNonstandardEtherType::TRAILER, "0x001C (Trailer switch tagging)"), + (LinuxNonstandardEtherType::PHONET, "0x00F5 (Nokia Phonet frame)"), + (LinuxNonstandardEtherType::IEEE802154, "0x00F6 (IEEE802.15.4 frame)"), + (LinuxNonstandardEtherType::CAIF, "0x00F7 (ST-Ericsson CAIF protocol)"), + (LinuxNonstandardEtherType::XDSA, "0x00F8 (Multiplexed DSA protocol)"), + (LinuxNonstandardEtherType::MAP, "0x00F9 (Qualcomm multiplexing and aggregation protocol)"), + (LinuxNonstandardEtherType::MCTP, "0x00FA (Management component transport protocol packets)"), + ]; + + for (ether_type, str_value) in pairs { + assert_eq!(str_value, &format!("{:?}", ether_type)); + } + } + + #[test] + fn default() { + let value: LinuxNonstandardEtherType = Default::default(); + assert_eq!(LinuxNonstandardEtherType::N802_3, value); + } + + #[test] + fn clone_eq() { + let values = &[ + LinuxNonstandardEtherType::N802_3, + LinuxNonstandardEtherType::AX25, + LinuxNonstandardEtherType::ALL, + LinuxNonstandardEtherType::N802_2, + LinuxNonstandardEtherType::SNAP, + LinuxNonstandardEtherType::DDCMP, + LinuxNonstandardEtherType::WAN_PPP, + LinuxNonstandardEtherType::PPP_MP, + LinuxNonstandardEtherType::LOCALTALK, + LinuxNonstandardEtherType::CAN, + LinuxNonstandardEtherType::CANFD, + LinuxNonstandardEtherType::CANXL, + LinuxNonstandardEtherType::PPPTALK, + LinuxNonstandardEtherType::TR_802_2, + LinuxNonstandardEtherType::MOBITEX, + LinuxNonstandardEtherType::CONTROL, + LinuxNonstandardEtherType::IRDA, + LinuxNonstandardEtherType::ECONET, + LinuxNonstandardEtherType::HDLC, + LinuxNonstandardEtherType::ARCNET, + LinuxNonstandardEtherType::DSA, + LinuxNonstandardEtherType::TRAILER, + LinuxNonstandardEtherType::PHONET, + LinuxNonstandardEtherType::IEEE802154, + LinuxNonstandardEtherType::CAIF, + LinuxNonstandardEtherType::XDSA, + LinuxNonstandardEtherType::MAP, + LinuxNonstandardEtherType::MCTP, + ]; + + // clone + for v in values { + assert_eq!(v, &v.clone()); + } + + // eq + for (a_pos, a) in values.iter().enumerate() { + for (b_pos, b) in values.iter().enumerate() { + assert_eq!(a_pos == b_pos, a == b); + assert_eq!(a_pos != b_pos, a != b); + } + } + } +} diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index c155f3fa..c623b900 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -1,28 +1,19 @@ -use crate::EtherType; +use crate::{EtherType, LinuxNonstandardEtherType}; use super::{arp_hardware_id::ArpHardwareId, linux_sll_packet_type::LinuxSllPacketType}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum LinuxSllProtocolType { - /// The protocol type does not have relevant information - Ignored, - /// Netlink protocol type for the associated Netlink payload + /// The protocol type should be ignored + Ignored(u16), + /// Netlink protocol type of the encapsulated payload NetlinkProtocolType(u16), - /// Generic Routing Encapsulation protocol type + /// Generic Routing Encapsulation protocol type for the encapsulated payload GenericRoutingEncapsulationProtocolType(u16), - /// The associated payload is a Novell 802.3 frame without an 802.2 LLC header - Novel802_3Frame, - /// The protocol type value is "0x0003", which is possibly an error on the - /// capture, but it is not known the specific cause - Unknown, - /// The associated payload begins with a 802.2 LLC header. - LLC, - /// The associated payload is a CAN bus frame - CANBusFrame, - /// The associated payload is a CAN FD (CAN with Flexible Data-Rate) frame - CANFDFrame, - /// The associated payload's ether type - EtherType(EtherType) + /// EtherType of the encapsulated payload + EtherType(EtherType), + /// Non-standard ether types of the encapsulated payload + LinuxNonstandardEtherType(LinuxNonstandardEtherType), } /// Linux SLL Header diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 7a5b54fa..c637a1b8 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -7,6 +7,7 @@ pub mod ether_type_impl; pub mod ethernet2_header; pub mod ethernet2_header_slice; pub mod ethernet2_slice; +pub mod linux_nonstandard_ether_type; pub mod linux_sll_header; pub mod linux_sll_packet_type; pub mod link_slice; From 1fa846d82a0e36f00a12f1bd1dd368b55afb48c8 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sat, 27 Apr 2024 13:56:59 +0200 Subject: [PATCH 07/21] move sll protocol type to its own source file and add construction from arphwd+type --- etherparse/src/lib.rs | 1 + etherparse/src/link/linux_sll_header.rs | 18 +---- .../src/link/linux_sll_protocol_type.rs | 67 +++++++++++++++++++ etherparse/src/link/mod.rs | 1 + 4 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 etherparse/src/link/linux_sll_protocol_type.rs diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index dc5f0c89..f2f24923 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -306,6 +306,7 @@ pub use crate::link::link_slice::*; pub use crate::link::linux_nonstandard_ether_type::*; pub use crate::link::linux_sll_header::*; pub use crate::link::linux_sll_packet_type::*; +pub use crate::link::linux_sll_protocol_type::*; pub use crate::link::single_vlan_header::*; pub use crate::link::single_vlan_header_slice::*; pub use crate::link::single_vlan_slice::*; diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index c623b900..d88f96f5 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -1,20 +1,4 @@ -use crate::{EtherType, LinuxNonstandardEtherType}; - -use super::{arp_hardware_id::ArpHardwareId, linux_sll_packet_type::LinuxSllPacketType}; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum LinuxSllProtocolType { - /// The protocol type should be ignored - Ignored(u16), - /// Netlink protocol type of the encapsulated payload - NetlinkProtocolType(u16), - /// Generic Routing Encapsulation protocol type for the encapsulated payload - GenericRoutingEncapsulationProtocolType(u16), - /// EtherType of the encapsulated payload - EtherType(EtherType), - /// Non-standard ether types of the encapsulated payload - LinuxNonstandardEtherType(LinuxNonstandardEtherType), -} +use crate::{ArpHardwareId, LinuxSllPacketType, LinuxSllProtocolType}; /// Linux SLL Header #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs new file mode 100644 index 00000000..e5649ea5 --- /dev/null +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -0,0 +1,67 @@ +use crate::{ArpHardwareId, EtherType, LinuxNonstandardEtherType}; + +/// Represents the "protcol type" field in a Linux Cooked Capture v1 packet. It +/// is represented as an enum due to the meaning of the inner value depending +/// on the associated arp_hardware_id field. +/// +/// You can convert pairs of ArpHardwareId and its associated u16 value with ` +/// LinuxSllProtocolType::try_from()`, an Err(_) is returned if the relation is +/// not defined or known. +/// +/// ``` +/// use etherparse::LinuxNonstandardEtherType; +/// +/// // Convert to LinuxNonstandardEtherType using the from & into trait +/// let link_type: LinuxNonstandardEtherType = 0x0001.try_into().unwrap(); +/// assert_eq!(LinuxNonstandardEtherType::N802_3, link_type); +/// +/// // convert to u16 using the from & into trait +/// let num: u16 = LinuxNonstandardEtherType::N802_3.try_into().unwrap(); +/// assert_eq!(0x0001, num); +/// ``` +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LinuxSllProtocolType { + /// The protocol type should be ignored + Ignored(u16), + /// Netlink protocol type of the encapsulated payload + NetlinkProtocolType(u16), + /// Generic Routing Encapsulation protocol type for the encapsulated payload + GenericRoutingEncapsulationProtocolType(u16), + /// EtherType of the encapsulated payload + EtherType(EtherType), + /// Non-standard ether types of the encapsulated payload + LinuxNonstandardEtherType(LinuxNonstandardEtherType), +} + +impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { + type Error = (); + + fn try_from((arp_hardware_id, protocol_type): (ArpHardwareId, u16)) -> Result { + match arp_hardware_id { + ArpHardwareId::NETLINK => Ok(LinuxSllProtocolType::NetlinkProtocolType(protocol_type)), + ArpHardwareId::IPGRE => Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(protocol_type)), + ArpHardwareId::IEEE80211_RADIOTAP => Ok(LinuxSllProtocolType::Ignored(protocol_type)), + ArpHardwareId::FRAD => Ok(LinuxSllProtocolType::Ignored(protocol_type)), + ArpHardwareId::ETHER => match LinuxNonstandardEtherType::try_from(protocol_type) { + Ok(v) => Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(v)), + Err(_) => Ok(LinuxSllProtocolType::EtherType(EtherType(protocol_type))) + }, + _ => Err(()) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn try_from_pair_arp_hardware_id_u16() { + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::NETLINK, 123)), Ok(LinuxSllProtocolType::NetlinkProtocolType(123))); + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::IPGRE, 123)), Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(123))); + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::IEEE80211_RADIOTAP, 123)), Ok(LinuxSllProtocolType::Ignored(123))); + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::FRAD, 123)), Ok(LinuxSllProtocolType::Ignored(123))); + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(LinuxNonstandardEtherType::N802_3))), Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType::N802_3))); + assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(EtherType::IPV4))), Ok(LinuxSllProtocolType::EtherType(EtherType::IPV4))); + } +} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index c637a1b8..4f86e906 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -10,6 +10,7 @@ pub mod ethernet2_slice; pub mod linux_nonstandard_ether_type; pub mod linux_sll_header; pub mod linux_sll_packet_type; +pub mod linux_sll_protocol_type; pub mod link_slice; pub mod single_vlan_header; pub mod single_vlan_header_slice; From c64a9eaa05b30f9bd642f8803a3706a26a44fa6a Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sat, 27 Apr 2024 14:03:33 +0200 Subject: [PATCH 08/21] add private LinuxSllPacketType::FIRST_INVALID to be able to match against it so clippy does not complain about overlaps --- etherparse/src/link/linux_sll_packet_type.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs index 0dc93c5b..f591d08f 100644 --- a/etherparse/src/link/linux_sll_packet_type.rs +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -35,6 +35,7 @@ impl LinuxSllPacketType { pub const KERNEL: LinuxSllPacketType = Self(7); pub const MAX_VAL: u16 = 7; + const FIRST_INVALID: u16 = LinuxSllPacketType::MAX_VAL+1; } impl TryFrom for LinuxSllPacketType { @@ -50,7 +51,7 @@ impl TryFrom for LinuxSllPacketType { 5 => Ok(LinuxSllPacketType::LOOPBACK), 6 => Ok(LinuxSllPacketType::USER), 7 => Ok(LinuxSllPacketType::KERNEL), - LinuxSllPacketType::MAX_VAL..=u16::MAX => Err(ValueTooBigError { + LinuxSllPacketType::FIRST_INVALID..=u16::MAX => Err(ValueTooBigError { actual: value, max_allowed: LinuxSllPacketType::MAX_VAL, value_type: err::ValueType::LinuxSllType, @@ -79,9 +80,9 @@ impl core::fmt::Debug for LinuxSllPacketType { 5 => write!(f, "5 (MC/BRD frame looped back)"), 6 => write!(f, "6 (Sent to user space)"), 7 => write!(f, "7 (Sent to kernel space)"), - LinuxSllPacketType::MAX_VAL..=u16::MAX => { + LinuxSllPacketType::FIRST_INVALID..=u16::MAX => { // SAFETY: - // Safe because values over MAX_VAL are never constructed + // Safe because values over MAX_VAL/FIRST_INVALID are never constructed unsafe { unreachable_unchecked() } } } From 45795a9d49bfa8a0c7967bc4995e304cc838a60f Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sat, 27 Apr 2024 21:08:15 +0200 Subject: [PATCH 09/21] add LinuxSllHeader and LinuxSllHeaderSlice, with their associated errors, tests and utilities --- etherparse/src/err/layer.rs | 4 + etherparse/src/err/linux_sll/header_error.rs | 97 ++++++ .../src/err/linux_sll/header_read_error.rs | 142 ++++++++ .../src/err/linux_sll/header_slice_error.rs | 149 +++++++++ etherparse/src/err/linux_sll/mod.rs | 10 + etherparse/src/err/mod.rs | 1 + etherparse/src/err/read_error.rs | 94 +++++- etherparse/src/helpers.rs | 21 ++ etherparse/src/lib.rs | 1 + etherparse/src/link/arp_hardware_id.rs | 12 +- etherparse/src/link/linux_sll_header.rs | 312 +++++++++++++++++- etherparse/src/link/linux_sll_header_slice.rs | 214 ++++++++++++ etherparse/src/link/linux_sll_packet_type.rs | 24 +- .../src/link/linux_sll_protocol_type.rs | 30 +- etherparse/src/link/mod.rs | 1 + etherparse/src/test_gens/mod.rs | 51 +++ 16 files changed, 1135 insertions(+), 28 deletions(-) create mode 100644 etherparse/src/err/linux_sll/header_error.rs create mode 100644 etherparse/src/err/linux_sll/header_read_error.rs create mode 100644 etherparse/src/err/linux_sll/header_slice_error.rs create mode 100644 etherparse/src/err/linux_sll/mod.rs create mode 100644 etherparse/src/link/linux_sll_header_slice.rs diff --git a/etherparse/src/err/layer.rs b/etherparse/src/err/layer.rs index fc0b7454..5b46d47f 100644 --- a/etherparse/src/err/layer.rs +++ b/etherparse/src/err/layer.rs @@ -1,6 +1,8 @@ /// Layers on which an error can occur. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Layer { + /// Error occurred in the Linux Cooked Capture v1 (SLL) header. + LinuxSllHeader, /// Error occurred in the ethernet 2 header. Ethernet2Header, /// Payload identified by an ether type number (e.g. after an ethernet 2 header). @@ -50,6 +52,7 @@ impl Layer { pub fn error_title(&self) -> &'static str { use Layer::*; match self { + LinuxSllHeader => "Linux Cooked Capture v1 Error", Ethernet2Header => "Ethernet 2 Header Error", EtherPayload => "Payload with Ether Type Error", VlanHeader => "VLAN Header Error", @@ -79,6 +82,7 @@ impl core::fmt::Display for Layer { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { use Layer::*; match self { + LinuxSllHeader => write!(f, "Linux Cooked Capture v1 header"), Ethernet2Header => write!(f, "Ethernet 2 header"), EtherPayload => write!(f, "Ether type payload"), VlanHeader => write!(f, "VLAN header"), diff --git a/etherparse/src/err/linux_sll/header_error.rs b/etherparse/src/err/linux_sll/header_error.rs new file mode 100644 index 00000000..7d0d399b --- /dev/null +++ b/etherparse/src/err/linux_sll/header_error.rs @@ -0,0 +1,97 @@ +use crate::ArpHardwareId; + +/// Errors in an Linux Cooked Capture header encountered while decoding it. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum HeaderError { + /// Error when the "packet byte" field is not one of the known ones + UnsupportedPacketTypeField{ + // The unexpected packet type number in the SLL header + packet_type: u16 + }, + /// Error when the arp hardware type field is not one of the known ones + UnsupportedArpHardwareId{ + arp_hardware_type: ArpHardwareId + }, +} + +impl core::fmt::Display for HeaderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use HeaderError::*; + match self { + UnsupportedPacketTypeField { packet_type } => write!(f, "Linux cooked capture v1 (SLL) Header Error: Encountered '{}' as the packet type, but its not supported.", packet_type), + UnsupportedArpHardwareId { arp_hardware_type } => write!(f, "Linux cooked capture v1 (SLL) Header Error: Encountered '{}' as the ARP harware type, but its not supported.", arp_hardware_type), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for HeaderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use HeaderError::*; + match self { + UnsupportedPacketTypeField { packet_type: _ } => None, + UnsupportedArpHardwareId { arp_hardware_type: _ } => None, + } + } +} + +#[cfg(test)] +mod tests { + use super::{HeaderError::*, *}; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn debug() { + assert_eq!( + "UnsupportedPacketTypeField { packet_type: 6 }", + format!("{:?}", UnsupportedPacketTypeField { packet_type: 6 }) + ); + } + + #[test] + fn clone_eq_hash() { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 6 }; + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + assert_eq!( + "Linux cooked capture v1 (SLL) Header Error: Encountered '6' as the packet type, but its not supported.", + format!("{}", UnsupportedPacketTypeField{ packet_type: 6 }) + ); + assert_eq!( + "Linux cooked capture v1 (SLL) Header Error: Encountered '1 (Ethernet 10Mbps)' as the ARP harware type, but its not supported.", + format!("{}", UnsupportedArpHardwareId{ arp_hardware_type: ArpHardwareId::ETHER }) + ); + } + + #[cfg(feature = "std")] + #[test] + fn source() { + let values = [ + UnsupportedPacketTypeField { packet_type: 6 }, + UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }, + ]; + for v in values { + assert!(v.source().is_none()); + } + } +} diff --git a/etherparse/src/err/linux_sll/header_read_error.rs b/etherparse/src/err/linux_sll/header_read_error.rs new file mode 100644 index 00000000..0a75b592 --- /dev/null +++ b/etherparse/src/err/linux_sll/header_read_error.rs @@ -0,0 +1,142 @@ +use super::HeaderError; + +/// Error when decoding Linux Cooked Capture v1 (SLL) headers via a +/// `std::io::Read` source. +/// +/// Requires crate feature `std`. +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[derive(Debug)] +pub enum HeaderReadError { + /// IO error was encountered while reading header. + Io(std::io::Error), + + /// Error caused by the contents of the header. + Content(HeaderError), +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl HeaderReadError { + /// Returns the `std::io::Error` value if the `HeaderReadError` is `Io`. + /// Otherwise `None` is returned. + #[inline] + pub fn io_error(self) -> Option { + use HeaderReadError::*; + match self { + Io(value) => Some(value), + _ => None, + } + } + + /// Returns the `err::linux_sll::HeaderError` value if the `HeaderReadError` is `Content`. + /// Otherwise `None` is returned. + #[inline] + pub fn content_error(self) -> Option { + use HeaderReadError::*; + match self { + Content(value) => Some(value), + _ => None, + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl core::fmt::Display for HeaderReadError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use HeaderReadError::*; + match self { + Io(err) => write!(f, "Linux Cooked Capture v1 (SLL) Header IO Error: {}", err), + Content(value) => value.fmt(f), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for HeaderReadError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use HeaderReadError::*; + match self { + Io(err) => Some(err), + Content(err) => Some(err), + } + } +} + +#[cfg(all(test, feature = "std"))] +mod test { + use super::{HeaderReadError::*, *}; + use alloc::format; + + #[test] + fn debug() { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 1 }; + assert_eq!( + format!("Content({:?})", err.clone()), + format!("{:?}", Content(err)) + ); + } + + #[test] + fn fmt() { + { + let err = std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + ); + assert_eq!( + format!("Linux Cooked Capture v1 (SLL) Header IO Error: {}", err), + format!("{}", Io(err)) + ); + } + { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 1 }; + assert_eq!(format!("{}", &err), format!("{}", Content(err.clone()))); + } + } + + #[test] + fn source() { + use std::error::Error; + assert!(Io(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )) + .source() + .is_some()); + assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) + .source() + .is_some()); + } + + #[test] + fn io_error() { + assert!(Io(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )) + .io_error() + .is_some()); + assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) + .io_error() + .is_none()); + } + + #[test] + fn content_error() { + assert_eq!( + None, + Io(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )) + .content_error() + ); + { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 1 }; + assert_eq!(Some(err.clone()), Content(err.clone()).content_error()); + } + } +} diff --git a/etherparse/src/err/linux_sll/header_slice_error.rs b/etherparse/src/err/linux_sll/header_slice_error.rs new file mode 100644 index 00000000..9accd33a --- /dev/null +++ b/etherparse/src/err/linux_sll/header_slice_error.rs @@ -0,0 +1,149 @@ +use super::HeaderError; +use crate::err::LenError; + +/// Error when decoding Linux Cooked Capture v1 (SLL) header from a slice. +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub enum HeaderSliceError { + /// Error when an length error is encountered (e.g. unexpected + /// end of slice). + Len(LenError), + + /// Error caused by the contents of the header. + Content(HeaderError), +} + +impl HeaderSliceError { + /// Adds an offset value to all slice length related fields. + #[inline] + pub const fn add_slice_offset(self, offset: usize) -> Self { + use HeaderSliceError::*; + match self { + Len(err) => Len(err.add_offset(offset)), + Content(err) => Content(err), + } + } +} + +impl core::fmt::Display for HeaderSliceError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use HeaderSliceError::*; + match self { + Len(err) => err.fmt(f), + Content(err) => err.fmt(f), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for HeaderSliceError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use HeaderSliceError::*; + match self { + Len(err) => Some(err), + Content(err) => Some(err), + } + } +} + +#[cfg(test)] +mod tests { + use super::{HeaderSliceError::*, *}; + use crate::{ + err::{Layer, LenError}, + LenSource, + }; + use alloc::format; + use std::{ + collections::hash_map::DefaultHasher, + error::Error, + hash::{Hash, Hasher}, + }; + + #[test] + fn add_slice_offset() { + assert_eq!( + Len(LenError { + required_len: 1, + layer: Layer::LinuxSllHeader, + len: 2, + len_source: LenSource::Slice, + layer_start_offset: 3 + }) + .add_slice_offset(200), + Len(LenError { + required_len: 1, + layer: Layer::LinuxSllHeader, + len: 2, + len_source: LenSource::Slice, + layer_start_offset: 203 + }) + ); + assert_eq!( + Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) + .add_slice_offset(200), + Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) + ); + } + + #[test] + fn debug() { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 0 }; + assert_eq!( + format!("Content({:?})", err.clone()), + format!("{:?}", Content(err)) + ); + } + + #[test] + fn clone_eq_hash() { + let err = Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }); + assert_eq!(err, err.clone()); + let hash_a = { + let mut hasher = DefaultHasher::new(); + err.hash(&mut hasher); + hasher.finish() + }; + let hash_b = { + let mut hasher = DefaultHasher::new(); + err.clone().hash(&mut hasher); + hasher.finish() + }; + assert_eq!(hash_a, hash_b); + } + + #[test] + fn fmt() { + { + let err = LenError { + required_len: 1, + layer: Layer::LinuxSllHeader, + len: 2, + len_source: LenSource::Slice, + layer_start_offset: 3, + }; + assert_eq!(format!("{}", &err), format!("{}", Len(err))); + } + { + let err = HeaderError::UnsupportedPacketTypeField { packet_type: 0 }; + assert_eq!(format!("{}", &err), format!("{}", Content(err.clone()))); + } + } + + #[cfg(feature = "std")] + #[test] + fn source() { + assert!(Len(LenError { + required_len: 1, + layer: Layer::LinuxSllHeader, + len: 2, + len_source: LenSource::Slice, + layer_start_offset: 3 + }) + .source() + .is_some()); + assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) + .source() + .is_some()); + } +} diff --git a/etherparse/src/err/linux_sll/mod.rs b/etherparse/src/err/linux_sll/mod.rs new file mode 100644 index 00000000..bf4f0e84 --- /dev/null +++ b/etherparse/src/err/linux_sll/mod.rs @@ -0,0 +1,10 @@ +mod header_error; +pub use header_error::*; + +#[cfg(feature = "std")] +mod header_read_error; +#[cfg(feature = "std")] +pub use header_read_error::*; + +mod header_slice_error; +pub use header_slice_error::*; diff --git a/etherparse/src/err/mod.rs b/etherparse/src/err/mod.rs index 81f50718..b2965b2a 100644 --- a/etherparse/src/err/mod.rs +++ b/etherparse/src/err/mod.rs @@ -7,6 +7,7 @@ pub mod ip_auth; pub mod ip_exts; pub mod ipv4; pub mod ipv4_exts; +pub mod linux_sll; pub mod ipv6; pub mod ipv6_exts; pub mod packet; diff --git a/etherparse/src/err/read_error.rs b/etherparse/src/err/read_error.rs index 7918f963..8378cd08 100644 --- a/etherparse/src/err/read_error.rs +++ b/etherparse/src/err/read_error.rs @@ -31,6 +31,9 @@ pub enum ReadError { /// Error while parsing a IPv6 extension header. Ipv6Exts(ipv6_exts::HeaderError), + /// Error while parsing a Linux Cooked Capture v1 (SLL) + LinuxSll(linux_sll::HeaderError), + /// Error while parsing a TCP extension header. Tcp(tcp::HeaderError), } @@ -85,6 +88,12 @@ impl ReadError { _ => None, } } + pub fn linux_sll(&self) -> Option<&linux_sll::HeaderError> { + match self { + ReadError::LinuxSll(err) => Some(err), + _ => None, + } + } pub fn tcp(&self) -> Option<&tcp::HeaderError> { match self { ReadError::Tcp(err) => Some(err), @@ -105,6 +114,7 @@ impl core::fmt::Display for ReadError { Ipv4(err) => err.fmt(f), Ipv6(err) => err.fmt(f), Ipv6Exts(err) => err.fmt(f), + LinuxSll(err) => err.fmt(f), Tcp(err) => err.fmt(f), } } @@ -123,6 +133,7 @@ impl std::error::Error for ReadError { ReadError::Ipv4(err) => Some(err), ReadError::Ipv6(err) => Some(err), ReadError::Ipv6Exts(err) => Some(err), + ReadError::LinuxSll(err) => Some(err), ReadError::Tcp(err) => Some(err), } } @@ -370,6 +381,36 @@ impl From for ReadError { } } +// linux sll error conversions +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl From for ReadError { + fn from(value: linux_sll::HeaderError) -> Self { + ReadError::LinuxSll(value) + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl From for ReadError { + fn from(value: linux_sll::HeaderReadError) -> Self { + use linux_sll::HeaderReadError::*; + match value { + Io(err) => ReadError::Io(err), + Content(err) => ReadError::LinuxSll(err), + } + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl From for ReadError { + fn from(value: linux_sll::HeaderSliceError) -> Self { + use linux_sll::HeaderSliceError::*; + match value { + Len(err) => ReadError::Len(err), + Content(err) => ReadError::LinuxSll(err), + } + } +} + // packet error conversions #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl From for ReadError { @@ -429,7 +470,7 @@ mod tests { #[test] fn debug_source() { - let test_values: [(&str, ReadError); 8] = [ + let test_values: [(&str, ReadError); 9] = [ ( "Len", Len(LenError { @@ -465,6 +506,10 @@ mod tests { "Ipv6Exts", Ipv6Exts(ipv6_exts::HeaderError::HopByHopNotAtStart), ), + ( + "LinuxSll", + LinuxSll(linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }), + ), ( "Tcp", Tcp(tcp::HeaderError::DataOffsetTooSmall { data_offset: 1 }), @@ -489,7 +534,7 @@ mod tests { #[test] fn display_source() { - let test_values: [ReadError; 8] = [ + let test_values: [ReadError; 9] = [ Len(LenError { required_len: 0, len: 0, @@ -507,6 +552,7 @@ mod tests { Ipv4(ipv4::HeaderError::UnexpectedVersion { version_number: 1 }), Ipv6(ipv6::HeaderError::UnexpectedVersion { version_number: 1 }), Ipv6Exts(ipv6_exts::HeaderError::HopByHopNotAtStart), + LinuxSll(linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }), Tcp(tcp::HeaderError::DataOffsetTooSmall { data_offset: 1 }), ]; for value in &test_values { @@ -540,6 +586,7 @@ mod tests { let ipv6_error = || ipv6::HeaderError::UnexpectedVersion { version_number: 1 }; let ip_auth_error = || ip_auth::HeaderError::ZeroPayloadLen; let ipv6_exts_error = || ipv6_exts::HeaderError::HopByHopNotAtStart; + let linux_sll_error = || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; let tcp_error = || tcp::HeaderError::DataOffsetTooSmall { data_offset: 1 }; // io @@ -580,6 +627,13 @@ mod tests { ); assert_eq!(IpAuth(ip_auth_error()).ipv6_exts(), None); + // linux_sll + assert_eq!( + LinuxSll(linux_sll_error()).linux_sll(), + Some(&linux_sll_error()) + ); + assert_eq!(IpAuth(ip_auth_error()).linux_sll(), None); + // tcp assert_eq!(Tcp(tcp_error()).tcp(), Some(&tcp_error())); assert_eq!(IpAuth(ip_auth_error()).tcp(), None); @@ -893,6 +947,42 @@ mod tests { ); } + // linux_sll errors + { + let header_error = || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; + assert_eq!( + &header_error(), + ReadError::from(header_error()).linux_sll().unwrap() + ); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderReadError::Content(header_error())) + .linux_sll() + .unwrap() + ); + assert!(ReadError::from(linux_sll::HeaderReadError::Io(io_error())) + .io() + .is_some()); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + assert_eq!( + &len_error(), + ReadError::from(linux_sll::HeaderSliceError::Len(len_error())) + .len() + .unwrap() + ); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + } + // packet error { let ip_error = || ip::HeaderError::UnsupportedIpVersion { version_number: 0 }; diff --git a/etherparse/src/helpers.rs b/etherparse/src/helpers.rs index ac4d6ef7..fc821ca1 100644 --- a/etherparse/src/helpers.rs +++ b/etherparse/src/helpers.rs @@ -53,6 +53,27 @@ pub(crate) unsafe fn get_unchecked_6_byte_array(ptr: *const u8) -> [u8; 6] { ] } +/// Helper function for reading a 8 byte fixed-size array. +/// +/// # Safety +/// +/// It is in the responsibility of the caller to ensure there are at least 6 +/// bytes accessable via the ptr. If this is not the case undefined behavior +/// will be triggered. +#[inline] +pub(crate) unsafe fn get_unchecked_8_byte_array(ptr: *const u8) -> [u8; 8] { + [ + *ptr, + *ptr.add(1), + *ptr.add(2), + *ptr.add(3), + *ptr.add(4), + *ptr.add(5), + *ptr.add(6), + *ptr.add(7), + ] +} + /// Helper function for reading a 16 byte fixed-size array. /// /// # Safety diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index f2f24923..046af0e1 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -304,6 +304,7 @@ pub use crate::link::ethernet2_header_slice::*; pub use crate::link::ethernet2_slice::*; pub use crate::link::link_slice::*; pub use crate::link::linux_nonstandard_ether_type::*; +pub use crate::link::linux_sll_header_slice::*; pub use crate::link::linux_sll_header::*; pub use crate::link::linux_sll_packet_type::*; pub use crate::link::linux_sll_protocol_type::*; diff --git a/etherparse/src/link/arp_hardware_id.rs b/etherparse/src/link/arp_hardware_id.rs index eba7d40f..efddd955 100644 --- a/etherparse/src/link/arp_hardware_id.rs +++ b/etherparse/src/link/arp_hardware_id.rs @@ -19,7 +19,7 @@ /// ``` /// -#[derive(Clone, Eq, PartialEq, Default)] +#[derive(Clone, Copy, Eq, PartialEq, Default, Hash)] pub struct ArpHardwareId(pub u16); impl ArpHardwareId { @@ -108,7 +108,7 @@ impl From for u16 { } } -impl core::fmt::Debug for ArpHardwareId { +impl core::fmt::Display for ArpHardwareId { // Names sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -184,6 +184,11 @@ impl core::fmt::Debug for ArpHardwareId { } } +impl core::fmt::Debug for ArpHardwareId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Display::fmt(&self, f) + } +} #[cfg(test)] mod test { @@ -344,7 +349,7 @@ mod test { #[test] - fn dbg() { + fn display_dbg() { let pairs = &[ (ArpHardwareId::NETROM, "0 (from KA9Q: NET/ROM pseudo)"), (ArpHardwareId::ETHER, "1 (Ethernet 10Mbps)"), @@ -416,6 +421,7 @@ mod test { ]; for (ether_type, str_value) in pairs { + assert_eq!(str_value, &format!("{}", ether_type)); assert_eq!(str_value, &format!("{:?}", ether_type)); } } diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index d88f96f5..23a13bdb 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -1,6 +1,6 @@ -use crate::{ArpHardwareId, LinuxSllPacketType, LinuxSllProtocolType}; +use crate::{err, ArpHardwareId, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSllProtocolType}; -/// Linux SLL Header +/// Linux Cooked Capture v1 (SLL) Header #[derive(Clone, Debug, Eq, PartialEq)] pub struct LinuxSllHeader { /// Type of the captured packet @@ -17,3 +17,311 @@ pub struct LinuxSllHeader { /// The protocol type of the encapsulated packet pub protocol_type: LinuxSllProtocolType, } + +impl LinuxSllHeader { + /// Serialized size of an SLL header in bytes/octets. + pub const LEN: usize = 16; + + /// Read an SLL header from a slice and return the header & unused parts of the slice. + #[inline] + pub fn from_slice(slice: &[u8]) -> Result<(LinuxSllHeader, &[u8]), err::ReadError> { + Ok(( + LinuxSllHeaderSlice::from_slice(slice)?.to_header()?, + &slice[LinuxSllHeader::LEN..], + )) + } + + /// Read an SLL header from a static sized byte array. + #[inline] + pub fn from_bytes(bytes: [u8; 16]) -> Result { + let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]]))?; + let arp_hrd_type = ArpHardwareId::from(u16::from_be_bytes([bytes[2], bytes[3]])); + let sender_address_valid_length = u16::from_be_bytes([bytes[4], bytes[5]]); + let sender_address = [bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13]]; + let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]])))?; + + Ok(LinuxSllHeader { + packet_type, + arp_hrd_type, + sender_address_valid_length, + sender_address, + protocol_type, + }) + } + + /// Reads an SLL header from the current position of the read argument. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + pub fn read( + reader: &mut T, + ) -> Result { + let buffer = { + let mut buffer = [0; LinuxSllHeader::LEN]; + reader.read_exact(&mut buffer)?; + buffer + }; + + Ok( + // SAFETY: Safe as the buffer contains exactly the needed LinuxSllHeader::LEN bytes. + unsafe { LinuxSllHeaderSlice::from_slice_unchecked(&buffer) }.to_header()?, + ) + } + + /// Serialize the header to a given slice. Returns the unused part of the slice. + pub fn write_to_slice<'a>( + &self, + slice: &'a mut [u8], + ) -> Result<&'a mut [u8], err::SliceWriteSpaceError> { + // length check + if slice.len() < LinuxSllHeader::LEN { + Err(err::SliceWriteSpaceError { + required_len: LinuxSllHeader::LEN, + len: slice.len(), + layer: err::Layer::LinuxSllHeader, + layer_start_offset: 0, + }) + } else { + slice[..LinuxSllHeader::LEN].copy_from_slice(&self.to_bytes()); + Ok(&mut slice[LinuxSllHeader::LEN..]) + } + } + + /// Writes a given Sll header to the current position of the write argument. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + #[inline] + pub fn write(&self, writer: &mut T) -> Result<(), std::io::Error> { + writer.write_all(&self.to_bytes()) + } + + /// Length of the serialized header in bytes. + #[inline] + pub fn header_len(&self) -> usize { + Self::LEN + } + + /// Returns the serialized form of the header as a statically + /// sized byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; Self::LEN] { + let packet_type_be = u16::from(self.packet_type).to_be_bytes(); + let arp_hrd_type_be = u16::from(self.arp_hrd_type).to_be_bytes(); + let sender_address_valid_length_be = self.sender_address_valid_length.to_be_bytes(); + let sender_address_be = self.sender_address; + let protocol_type_be = u16::from(self.protocol_type).to_be_bytes(); + + [ + packet_type_be[0], + packet_type_be[1], + arp_hrd_type_be[0], + arp_hrd_type_be[1], + sender_address_valid_length_be[0], + sender_address_valid_length_be[1], + sender_address_be[0], + sender_address_be[1], + sender_address_be[2], + sender_address_be[3], + sender_address_be[4], + sender_address_be[5], + sender_address_be[6], + sender_address_be[7], + protocol_type_be[0], + protocol_type_be[1], + ] + } +} + + +#[cfg(test)] +mod test { + use super::*; + use crate::{test_gens::*, LenSource}; + use alloc::{borrow::ToOwned, format, vec::Vec}; + use proptest::prelude::*; + use std::io::{Cursor, ErrorKind}; + + proptest! { + #[test] + fn from_slice( + input in linux_sll_any(), + dummy_data in proptest::collection::vec(any::(), 0..20) + ) { + // serialize + let mut buffer: Vec = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len()); + input.write(&mut buffer).unwrap(); + buffer.extend(&dummy_data[..]); + + // calls with a valid result + { + let (result, rest) = LinuxSllHeader::from_slice(&buffer[..]).unwrap(); + assert_eq!(input, result); + assert_eq!(&buffer[16..], rest); + } + + // call with not enough data in the slice + for len in 0..=13 { + assert_eq!( + LinuxSllHeader::from_slice(&buffer[..len]).unwrap_err().len().unwrap().to_owned(), + err::LenError{ + required_len: LinuxSllHeader::LEN, + len: len, + len_source: LenSource::Slice, + layer: err::Layer::LinuxSllHeader, + layer_start_offset: 0, + } + ); + } + } + } + + proptest! { + #[test] + fn from_bytes(input in linux_sll_any()) { + assert_eq!( + input, + LinuxSllHeader::from_bytes(input.to_bytes()).unwrap() + ); + } + } + + proptest! { + #[test] + fn read( + input in linux_sll_any(), + dummy_data in proptest::collection::vec(any::(), 0..20) + ) { + // normal read + let mut buffer = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len()); + input.write(&mut buffer).unwrap(); + buffer.extend(&dummy_data[..]); + + // calls with a valid result + { + let mut cursor = Cursor::new(&buffer); + let result = LinuxSllHeader::read(&mut cursor).unwrap(); + assert_eq!(input, result); + assert_eq!(cursor.position(), u64::try_from(LinuxSllHeader::LEN).unwrap()); + } + + // unexpected eof + for len in 0..=13 { + let mut cursor = Cursor::new(&buffer[0..len]); + assert_eq!( + LinuxSllHeader::read(&mut cursor) + .unwrap_err() + .io().unwrap() + .kind(), + ErrorKind::UnexpectedEof + ); + } + } + } + + proptest! { + #[test] + fn write_to_slice(input in linux_sll_any()) { + // normal write + { + let mut buffer: [u8;LinuxSllHeader::LEN] = [0;LinuxSllHeader::LEN]; + input.write_to_slice(&mut buffer).unwrap(); + assert_eq!(buffer, input.to_bytes()); + } + // len to small + for len in 0..14 { + let mut buffer: [u8;LinuxSllHeader::LEN] = [0;LinuxSllHeader::LEN]; + assert_eq!( + err::SliceWriteSpaceError { + required_len: LinuxSllHeader::LEN, + len, + layer: err::Layer::LinuxSllHeader, + layer_start_offset: 0, + }, + input.write_to_slice(&mut buffer[..len]).unwrap_err() + ); + } + } + } + + proptest! { + #[test] + fn write(input in linux_sll_any()) { + // successful write + { + let mut buffer: Vec = Vec::with_capacity(LinuxSllHeader::LEN); + input.write(&mut buffer).unwrap(); + assert_eq!(&buffer[..], &input.to_bytes()); + } + + // not enough memory for write (unexpected eof) + for len in 0..8 { + let mut buffer = [0u8;8]; + let mut writer = Cursor::new(&mut buffer[..len]); + assert!(input.write(&mut writer).is_err()); + } + } + } + + proptest! { + #[test] + fn header_len(input in linux_sll_any()) { + assert_eq!(input.header_len(), LinuxSllHeader::LEN); + } + } + + proptest! { + #[test] + fn to_bytes(input in linux_sll_any()) { + let packet_type_be = u16::from(input.packet_type).to_be_bytes(); + let arp_hrd_type_be = u16::from(input.arp_hrd_type).to_be_bytes(); + let sender_address_valid_length_be = input.sender_address_valid_length.to_be_bytes(); + let sender_address_be = input.sender_address; + let protocol_type_be = u16::from(input.protocol_type).to_be_bytes(); + + assert_eq!( + input.to_bytes(), + [ + packet_type_be[0], + packet_type_be[1], + arp_hrd_type_be[0], + arp_hrd_type_be[1], + sender_address_valid_length_be[0], + sender_address_valid_length_be[1], + sender_address_be[0], + sender_address_be[1], + sender_address_be[2], + sender_address_be[3], + sender_address_be[4], + sender_address_be[5], + sender_address_be[6], + sender_address_be[7], + protocol_type_be[0], + protocol_type_be[1], + ] + ); + } + } + + proptest! { + #[test] + fn clone_eq(input in linux_sll_any()) { + assert_eq!(input, input.clone()); + } + } + + proptest! { + #[test] + fn dbg(input in linux_sll_any()) { + assert_eq!( + &format!( + "LinuxSllHeader {{ packet_type: {:?}, arp_hrd_type: {:?}, sender_address_valid_length: {:?}, sender_address: {:?}, protocol_type: {:?} }}", + input.packet_type, + input.arp_hrd_type, + input.sender_address_valid_length, + input.sender_address, + input.protocol_type, + ), + &format!("{:?}", input) + ); + } + } +} diff --git a/etherparse/src/link/linux_sll_header_slice.rs b/etherparse/src/link/linux_sll_header_slice.rs new file mode 100644 index 00000000..79eb9cf1 --- /dev/null +++ b/etherparse/src/link/linux_sll_header_slice.rs @@ -0,0 +1,214 @@ +use crate::*; +use core::{cmp::min, slice::from_raw_parts}; + +///A slice containing an Linux Cooked Capture (SLL) header of a network package. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinuxSllHeaderSlice<'a> { + pub(crate) slice: &'a [u8], +} + +impl<'a> LinuxSllHeaderSlice<'a> { + /// Creates a SLL header slice from an other slice. + pub fn from_slice(slice: &'a [u8]) -> Result, err::LenError> { + //check length + if slice.len() < LinuxSllHeader::LEN { + return Err(err::LenError { + required_len: LinuxSllHeader::LEN, + len: slice.len(), + len_source: LenSource::Slice, + layer: err::Layer::LinuxSllHeader, + layer_start_offset: 0, + }); + } + + //all done + Ok(LinuxSllHeaderSlice { + // SAFETY: + // Safe as slice length is checked to be at least + // LinuxSllHeader::LEN (16) before this. + slice: unsafe { from_raw_parts(slice.as_ptr(), LinuxSllHeader::LEN) }, + }) + } + + /// Converts the given slice into a SLL header slice WITHOUT any checks to + /// ensure that the data present is an sll header or that the slice length + /// is matching the header length. + /// + /// If you are not sure what this means, use [`LinuxSllHeaderSlice::from_slice`] + /// instead. + /// + /// # Safety + /// + /// The caller must ensured that the given slice has the length of + /// [`LinuxSllHeader::LEN`] + #[inline] + #[cfg(feature = "std")] + pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> LinuxSllHeaderSlice { + debug_assert!(slice.len() == LinuxSllHeader::LEN); + LinuxSllHeaderSlice { slice } + } + + /// Returns the slice containing the SLL header + #[inline] + pub fn slice(&self) -> &'a [u8] { + self.slice + } + + /// Try read the packet type field. + #[inline] + pub fn packet_type(&self) -> Result { + // SAFETY: + // Safe as the contructor checks that the slice has + // at least the length of LinuxSllHeader::LEN (16). + let packet_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr()) }; + + LinuxSllPacketType::try_from(packet_type_raw) + } + + /// Try read the arp hardware type field + #[inline] + pub fn arp_hardware_type(&self) -> ArpHardwareId { + // SAFETY: + // Safe as the contructor checks that the slice has + // at least the length of LinuxSllHeader::LEN (16). + let arp_hardware_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) }; + + ArpHardwareId::from(arp_hardware_type_raw) + } + + /// Read the link layer address length field. + #[inline] + pub fn sender_address_valid_length(&self) -> u16 { + // SAFETY: + // Safe as the contructor checks that the slice has + // at least the length of LinuxSllHeader::LEN (16). + unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) } + } + + /// Read the link layer address field. Only the first + /// `LinuxSllHeaderSlice::link_layer_address_length` bytes are meaningful + #[inline] + pub fn sender_address_full(&self) -> [u8; 8] { + // SAFETY: + // Safe as the contructor checks that the slice has + // at least the length of LinuxSllHeader::LEN (16). + unsafe { get_unchecked_8_byte_array(self.slice.as_ptr().add(6)) } + } + + /// Get the meaningful bytes of the slice of the link layer address + #[inline] + pub fn sender_address(&self) -> &'a [u8] { + let length = self.sender_address_valid_length() as usize; + &self.slice[6..min(length, 8)] + } + + /// Try read the protocol type field + #[inline] + pub fn protocol_type(&self) -> Result { + let arp_harware_type = self.arp_hardware_type(); + // SAFETY: + // Safe as the contructor checks that the slice has + // at least the length of LinuxSllHeader::LEN (16). + let protocol_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(14)) }; + + LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)) + } + + /// Try decode all the fields and copy the results to a [`LinuxSllHeader`] struct + pub fn to_header(&self) -> Result { + Ok(LinuxSllHeader { + packet_type: self.packet_type()?, + arp_hrd_type: self.arp_hardware_type(), + sender_address_valid_length: self.sender_address_valid_length(), + sender_address: self.sender_address_full(), + protocol_type: self.protocol_type()? + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::test_gens::*; + use alloc::{format, vec::Vec}; + use proptest::prelude::*; + + proptest! { + #[test] + fn from_slice( + input in linux_sll_any(), + dummy_data in proptest::collection::vec(any::(), 0..20) + ) { + // serialize + let mut buffer: Vec = Vec::with_capacity(LinuxSllHeader::LEN + dummy_data.len()); + input.write(&mut buffer).unwrap(); + buffer.extend(&dummy_data[..]); + + // calls with a valid result + { + let result = LinuxSllHeaderSlice::from_slice(&buffer[..]).unwrap(); + assert_eq!(&buffer[..LinuxSllHeader::LEN], result.slice()); + } + + // call with not enough data in the slice + for len in 0..=13 { + assert_eq!( + LinuxSllHeaderSlice::from_slice(&buffer[..len]), + Err(err::LenError{ + required_len: LinuxSllHeader::LEN, + len: len, + len_source: LenSource::Slice, + layer: err::Layer::LinuxSllHeader, + layer_start_offset: 0, + }) + ); + } + } + } + + proptest! { + #[test] + fn getters(input in linux_sll_any()) { + let buffer = input.to_bytes(); + let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); + assert_eq!(input.packet_type, slice.packet_type().unwrap()); + assert_eq!(input.arp_hrd_type, slice.arp_hardware_type()); + assert_eq!(input.sender_address_valid_length, slice.sender_address_valid_length()); + assert_eq!(input.sender_address, slice.sender_address_full()); + assert_eq!(input.protocol_type, slice.protocol_type().unwrap()); + } + } + + proptest! { + #[test] + fn to_header(input in linux_sll_any()) { + let buffer = input.to_bytes(); + let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); + assert_eq!(input, slice.to_header().unwrap()); + } + } + + proptest! { + #[test] + fn clone_eq(input in linux_sll_any()) { + let buffer = input.to_bytes(); + let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); + assert_eq!(slice, slice.clone()); + } + } + + proptest! { + #[test] + fn dbg(input in linux_sll_any()) { + let buffer = input.to_bytes(); + let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); + assert_eq!( + &format!( + "LinuxSllHeaderSlice {{ slice: {:?} }}", + slice.slice() + ), + &format!("{:?}", slice) + ); + } + } +} diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs index f591d08f..81724684 100644 --- a/etherparse/src/link/linux_sll_packet_type.rs +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -1,6 +1,6 @@ use core::hint::unreachable_unchecked; -use crate::err::{self, ValueTooBigError}; +use crate::err::{self}; /// Represents an "Packet type", indicating the direction where it was sent, /// used inside a SLL header @@ -39,7 +39,7 @@ impl LinuxSllPacketType { } impl TryFrom for LinuxSllPacketType { - type Error = ValueTooBigError; + type Error = err::linux_sll::HeaderError; fn try_from(value: u16) -> Result { match value { @@ -51,10 +51,8 @@ impl TryFrom for LinuxSllPacketType { 5 => Ok(LinuxSllPacketType::LOOPBACK), 6 => Ok(LinuxSllPacketType::USER), 7 => Ok(LinuxSllPacketType::KERNEL), - LinuxSllPacketType::FIRST_INVALID..=u16::MAX => Err(ValueTooBigError { - actual: value, - max_allowed: LinuxSllPacketType::MAX_VAL, - value_type: err::ValueType::LinuxSllType, + LinuxSllPacketType::FIRST_INVALID..=u16::MAX => Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField{ + packet_type: value }), } } @@ -94,7 +92,7 @@ mod test { use alloc::format; use super::*; - use crate::err::{self, ValueTooBigError}; + use crate::err::{self}; #[test] fn to_u16() { @@ -118,16 +116,8 @@ mod test { assert_eq!(LinuxSllPacketType::try_from(5), Ok(LinuxSllPacketType::LOOPBACK)); assert_eq!(LinuxSllPacketType::try_from(6), Ok(LinuxSllPacketType::USER)); assert_eq!(LinuxSllPacketType::try_from(7), Ok(LinuxSllPacketType::KERNEL)); - assert_eq!(LinuxSllPacketType::try_from(8), Err(ValueTooBigError { - actual: 8, - max_allowed: LinuxSllPacketType::MAX_VAL, - value_type: err::ValueType::LinuxSllType, - })); - assert_eq!(LinuxSllPacketType::try_from(123), Err(ValueTooBigError { - actual: 123, - max_allowed: LinuxSllPacketType::MAX_VAL, - value_type: err::ValueType::LinuxSllType, - })); + assert_eq!(LinuxSllPacketType::try_from(8), Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 8 })); + assert_eq!(LinuxSllPacketType::try_from(123), Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 })); } #[test] diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs index e5649ea5..88aa91d2 100644 --- a/etherparse/src/link/linux_sll_protocol_type.rs +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -1,4 +1,4 @@ -use crate::{ArpHardwareId, EtherType, LinuxNonstandardEtherType}; +use crate::{err, ArpHardwareId, EtherType, LinuxNonstandardEtherType}; /// Represents the "protcol type" field in a Linux Cooked Capture v1 packet. It /// is represented as an enum due to the meaning of the inner value depending @@ -19,7 +19,7 @@ use crate::{ArpHardwareId, EtherType, LinuxNonstandardEtherType}; /// let num: u16 = LinuxNonstandardEtherType::N802_3.try_into().unwrap(); /// assert_eq!(0x0001, num); /// ``` -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum LinuxSllProtocolType { /// The protocol type should be ignored Ignored(u16), @@ -33,8 +33,18 @@ pub enum LinuxSllProtocolType { LinuxNonstandardEtherType(LinuxNonstandardEtherType), } +impl LinuxSllProtocolType { + pub const SUPPORTED_ARPHWD: [ArpHardwareId; 5] = [ + ArpHardwareId::NETLINK, + ArpHardwareId::IPGRE, + ArpHardwareId::IEEE80211_RADIOTAP, + ArpHardwareId::FRAD, + ArpHardwareId::ETHER + ]; +} + impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { - type Error = (); + type Error = err::linux_sll::HeaderError; fn try_from((arp_hardware_id, protocol_type): (ArpHardwareId, u16)) -> Result { match arp_hardware_id { @@ -46,7 +56,19 @@ impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { Ok(v) => Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(v)), Err(_) => Ok(LinuxSllProtocolType::EtherType(EtherType(protocol_type))) }, - _ => Err(()) + _ => Err(err::linux_sll::HeaderError::UnsupportedArpHardwareId{arp_hardware_type: arp_hardware_id}) + } + } +} + +impl From for u16 { + fn from(value: LinuxSllProtocolType) -> u16 { + match value { + LinuxSllProtocolType::Ignored(value) => value, + LinuxSllProtocolType::NetlinkProtocolType(value) => value, + LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(value) => value, + LinuxSllProtocolType::EtherType(value) => value.into(), + LinuxSllProtocolType::LinuxNonstandardEtherType(value) => value.into(), } } } diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 4f86e906..896d0ded 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -8,6 +8,7 @@ pub mod ethernet2_header; pub mod ethernet2_header_slice; pub mod ethernet2_slice; pub mod linux_nonstandard_ether_type; +pub mod linux_sll_header_slice; pub mod linux_sll_header; pub mod linux_sll_packet_type; pub mod linux_sll_protocol_type; diff --git a/etherparse/src/test_gens/mod.rs b/etherparse/src/test_gens/mod.rs index 2d5488b7..73a70b7b 100644 --- a/etherparse/src/test_gens/mod.rs +++ b/etherparse/src/test_gens/mod.rs @@ -98,6 +98,57 @@ prop_compose! { } } +prop_compose! { + pub fn linux_sll_packet_type_any() + (value in 0..=LinuxSllPacketType::MAX_VAL) + -> LinuxSllPacketType + { + LinuxSllPacketType::try_from(value).unwrap() + } +} + +prop_compose! { + pub fn linux_sll_arphrd() + (index in 0..=(LinuxSllProtocolType::SUPPORTED_ARPHWD.len()-1)) + -> ArpHardwareId + { + LinuxSllProtocolType::SUPPORTED_ARPHWD[index] + } +} + +prop_compose! { + pub fn linux_sll_sender_adress_any() + (mut sender_address in prop::collection::vec(any::(), 0..8)) + -> (u16, [u8; 8]) + { + let size = sender_address.len().try_into().unwrap(); + sender_address.resize(8, 0); + let mut v: [u8; 8] = [0u8;8]; + v.copy_from_slice(&sender_address); + + (size, v) + } +} + +prop_compose! { + pub fn linux_sll_any() + (packet_type in linux_sll_packet_type_any(), + arp_hrd_type in linux_sll_arphrd(), + (sender_address_valid_length, sender_address) in linux_sll_sender_adress_any(), + protocol_num in any::() + ) + -> LinuxSllHeader + { + LinuxSllHeader { + packet_type, + arp_hrd_type, + sender_address_valid_length, + sender_address, + protocol_type: LinuxSllProtocolType::try_from((arp_hrd_type, protocol_num)).unwrap() + } + } +} + pub static ETHERNET_KNOWN_ETHER_TYPES: &'static [EtherType] = &[ ether_type::IPV4, ether_type::IPV6, From bb03503ef1873e386ccfa8c12a9136243aa244c2 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 13:18:02 +0200 Subject: [PATCH 10/21] add LinkHeader enum --- etherparse/src/lib.rs | 1 + etherparse/src/link/link_header.rs | 242 +++++++++++++++++++++++++++++ etherparse/src/link/mod.rs | 1 + 3 files changed, 244 insertions(+) create mode 100644 etherparse/src/link/link_header.rs diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 046af0e1..adf7c1da 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -302,6 +302,7 @@ pub use crate::link::ether_type_impl::*; pub use crate::link::ethernet2_header::*; pub use crate::link::ethernet2_header_slice::*; pub use crate::link::ethernet2_slice::*; +pub use crate::link::link_header::*; pub use crate::link::link_slice::*; pub use crate::link::linux_nonstandard_ether_type::*; pub use crate::link::linux_sll_header_slice::*; diff --git a/etherparse/src/link/link_header.rs b/etherparse/src/link/link_header.rs new file mode 100644 index 00000000..e183c34b --- /dev/null +++ b/etherparse/src/link/link_header.rs @@ -0,0 +1,242 @@ +use crate::{Ethernet2Header, LinuxSllHeader}; + +/// The possible headers on the link layer +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LinkHeader { + LinuxSll(LinuxSllHeader), + Ethernet2(Ethernet2Header), +} + +impl LinkHeader { + /// Returns `Option::Some` containing the `Ethernet2Header` if self has the + /// value Ethernet2. Otherwise `Option::None` is returned. + pub fn ethernet2(self) -> Option { + use crate::LinkHeader::*; + if let Ethernet2(value) = self { + Some(value) + } else { + None + } + + } + + /// Returns `Option::Some` containing the `Ethernet2Header` if self has the + /// value Ethernet2. Otherwise `Option::None` is returned. + pub fn mut_ethernet2(&mut self) -> Option<&mut Ethernet2Header> { + use crate::LinkHeader::*; + if let Ethernet2(value) = self { + Some(value) + } else { + None + } + + } + + /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the + /// value LinuxSll. Otherwise `Option::None` is returned. + pub fn linux_sll(self) -> Option { + use crate::LinkHeader::*; + if let LinuxSll(value) = self { + Some(value) + } else { + None + } + } + + /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the + /// value LinuxSll. Otherwise `Option::None` is returned. + pub fn mut_linux_sll(&mut self) -> Option<&mut LinuxSllHeader> { + use crate::LinkHeader::*; + if let LinuxSll(value) = self { + Some(value) + } else { + None + } + } + + /// Returns the size of the link header + pub fn header_len(&self) -> usize { + use crate::LinkHeader::*; + match self { + Ethernet2(_) => Ethernet2Header::LEN, + LinuxSll(_) => LinuxSllHeader::LEN, + } + } + + /// Write the link header to the given writer. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + pub fn write(&self, writer: &mut T) -> Result<(), std::io::Error> { + use crate::LinkHeader::*; + match self { + Ethernet2(value) => value.write(writer), + LinuxSll(value) => value.write(writer), + } + } +} + + +#[cfg(test)] +mod test { + use crate::{test_gens::*, *}; + use alloc::{format, vec::Vec}; + use proptest::prelude::*; + use std::io::Cursor; + use super::*; + + proptest! { + #[test] + fn debug( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any(), + ) { + assert_eq!( + format!("Ethernet2({:?})", ethernet2), + format!("{:?}", LinkHeader::Ethernet2(ethernet2.clone())), + ); + assert_eq!( + format!("LinuxSll({:?})", linux_sll), + format!("{:?}", LinkHeader::LinuxSll(linux_sll.clone())), + ); + } + } + + proptest! { + #[test] + fn clone_eq( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any(), + ) { + let values = [ + LinkHeader::Ethernet2(ethernet2), + LinkHeader::LinuxSll(linux_sll), + ]; + for value in values { + assert_eq!(value.clone(), value); + } + } + } + + proptest! { + #[test] + fn ethernet2( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + assert_eq!(Some(ethernet2.clone()), LinkHeader::Ethernet2(ethernet2).ethernet2()); + assert_eq!(None, LinkHeader::LinuxSll(linux_sll).ethernet2()); + } + + } + proptest! { + #[test] + fn mut_ethernet2( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + assert_eq!(Some(&mut ethernet2.clone()), LinkHeader::Ethernet2(ethernet2).mut_ethernet2()); + assert_eq!(None, LinkHeader::LinuxSll(linux_sll).mut_ethernet2()); + } + } + + proptest! { + #[test] + fn linux_sll( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + assert_eq!(Some(linux_sll.clone()), LinkHeader::LinuxSll(linux_sll).linux_sll()); + assert_eq!(None, LinkHeader::Ethernet2(ethernet2).linux_sll()); + } + + } + proptest! { + #[test] + fn mut_linux_sll( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + assert_eq!(Some(&mut linux_sll.clone()), LinkHeader::LinuxSll(linux_sll).mut_linux_sll()); + assert_eq!(None, LinkHeader::Ethernet2(ethernet2).mut_linux_sll()); + } + } + + proptest! { + #[test] + fn header_size( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + assert_eq!( + LinkHeader::Ethernet2(ethernet2).header_len(), + Ethernet2Header::LEN + ); + assert_eq!( + LinkHeader::LinuxSll(linux_sll.clone()).header_len(), + LinuxSllHeader::LEN + ); + } + } + + + proptest! { + #[test] + fn write( + ethernet2 in ethernet_2_any(), + linux_sll in linux_sll_any() + ) { + // ethernet2 + { + //write + { + let result_input = { + let mut buffer = Vec::new(); + ethernet2.write(&mut buffer).unwrap(); + buffer + }; + let result_transport = { + let mut buffer = Vec::new(); + LinkHeader::Ethernet2(ethernet2.clone()).write(&mut buffer).unwrap(); + buffer + }; + assert_eq!(result_input, result_transport); + } + //trigger an error + { + let mut a: [u8;0] = []; + assert!( + LinkHeader::Ethernet2(ethernet2.clone()) + .write(&mut Cursor::new(&mut a[..])) + .is_err() + ); + } + } + // linux_sll + { + //write + { + let result_input = { + let mut buffer = Vec::new(); + linux_sll.write(&mut buffer).unwrap(); + buffer + }; + let result_transport = { + let mut buffer = Vec::new(); + LinkHeader::LinuxSll(linux_sll.clone()).write(&mut buffer).unwrap(); + buffer + }; + assert_eq!(result_input, result_transport); + } + //trigger an error + { + let mut a: [u8;0] = []; + assert!( + LinkHeader::LinuxSll(linux_sll.clone()) + .write(&mut Cursor::new(&mut a[..])) + .is_err() + ); + } + } + } + } +} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 896d0ded..aba277c9 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -12,6 +12,7 @@ pub mod linux_sll_header_slice; pub mod linux_sll_header; pub mod linux_sll_packet_type; pub mod linux_sll_protocol_type; +pub mod link_header; pub mod link_slice; pub mod single_vlan_header; pub mod single_vlan_header_slice; From 857278d7931fcf4e767343427ee7d831aa7f1e13 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 14:13:59 +0200 Subject: [PATCH 11/21] use LinkHeader enum instead of a direct Ethernet2Header --- etherparse/src/compositions_tests.rs | 18 +++--- etherparse/src/lax_packet_headers.rs | 6 +- etherparse/src/lax_sliced_packet.rs | 2 +- etherparse/src/link/link_slice.rs | 6 +- .../src/link/linux_sll_protocol_type.rs | 14 +++++ etherparse/src/packet_builder.rs | 61 ++++++++++--------- etherparse/src/packet_headers.rs | 6 +- etherparse/src/sliced_packet.rs | 4 +- etherparse/src/test_packet.rs | 7 ++- 9 files changed, 73 insertions(+), 51 deletions(-) diff --git a/etherparse/src/compositions_tests.rs b/etherparse/src/compositions_tests.rs index 9d1d377b..ecd1fcf6 100644 --- a/etherparse/src/compositions_tests.rs +++ b/etherparse/src/compositions_tests.rs @@ -6,7 +6,7 @@ use proptest::prelude::*; #[derive(Clone, Debug, Eq, PartialEq)] struct ComponentTest { - link: Option, + link: Option, vlan: Option, ip: Option, transport: Option, @@ -142,13 +142,13 @@ impl ComponentTest { // PacketHeaders::from_ether_type ether_down.assert_headers( - PacketHeaders::from_ether_type(test.link.as_ref().unwrap().ether_type, &buffer[..]) + PacketHeaders::from_ether_type(test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..]) .unwrap(), ); // SlicedPacket::from_ether_type ether_down.assert_sliced_packet( - SlicedPacket::from_ether_type(test.link.as_ref().unwrap().ether_type, &buffer[..]) + SlicedPacket::from_ether_type(test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..]) .unwrap(), ); @@ -156,12 +156,12 @@ impl ComponentTest { for len in ether_down.invalid_ser_lengths() { if let Some(len) = len { assert!(PacketHeaders::from_ether_type( - test.link.as_ref().unwrap().ether_type, + test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..len] ) .is_err()); assert!(SlicedPacket::from_ether_type( - test.link.as_ref().unwrap().ether_type, + test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..len] ) .is_err()); @@ -290,7 +290,7 @@ impl ComponentTest { self.link, match result.link.as_ref() { Some(l) => match l { - LinkSlice::Ethernet2(e) => Some(e.to_header()), + LinkSlice::Ethernet2(e) => Some(LinkHeader::Ethernet2(e.to_header())), LinkSlice::EtherPayload(_) => None, }, None => None, @@ -608,7 +608,7 @@ proptest! { link: Some({ let mut result = eth.clone(); result.ether_type = ether_type; - result + LinkHeader::Ethernet2(result) }), vlan: None, ip: None, @@ -639,11 +639,11 @@ fn test_packet_slicing_panics() { transport: None, }; ComponentTest { - link: Some(Ethernet2Header { + link: Some(LinkHeader::Ethernet2(Ethernet2Header { source: [0; 6], destination: [0; 6], ether_type: 0.into(), - }), + })), vlan: None, ip: None, transport: None, diff --git a/etherparse/src/lax_packet_headers.rs b/etherparse/src/lax_packet_headers.rs index d492241a..30a9aa41 100644 --- a/etherparse/src/lax_packet_headers.rs +++ b/etherparse/src/lax_packet_headers.rs @@ -16,7 +16,7 @@ use crate::{ #[derive(Clone, Debug, Eq, PartialEq)] pub struct LaxPacketHeaders<'a> { /// Ethernet II header if present. - pub link: Option, + pub link: Option, /// Single or double vlan headers if present. pub vlan: Option, @@ -127,7 +127,7 @@ impl<'a> LaxPacketHeaders<'a> { pub fn from_ethernet(slice: &'a [u8]) -> Result, err::LenError> { let (ethernet, rest) = Ethernet2Header::from_slice(slice)?; let mut result = Self::from_ether_type(ethernet.ether_type, rest); - result.link = Some(ethernet); + result.link = Some(LinkHeader::Ethernet2(ethernet)); if let Some((SliceError::Len(l), _)) = result.stop_err.as_mut() { l.layer_start_offset += Ethernet2Header::LEN; } @@ -636,7 +636,7 @@ mod test { ether_type: 0.into(), }; let test = TestPacket { - link: Some(eth.clone()), + link: Some(LinkHeader::Ethernet2(eth.clone())), vlan: None, net: None, transport: None, diff --git a/etherparse/src/lax_sliced_packet.rs b/etherparse/src/lax_sliced_packet.rs index 42f05a75..d5584fa4 100644 --- a/etherparse/src/lax_sliced_packet.rs +++ b/etherparse/src/lax_sliced_packet.rs @@ -516,7 +516,7 @@ mod test { ether_type: 0.into(), }; let test = TestPacket { - link: Some(eth.clone()), + link: Some(LinkHeader::Ethernet2(eth.clone())), vlan: None, net: None, transport: None, diff --git a/etherparse/src/link/link_slice.rs b/etherparse/src/link/link_slice.rs index 99b7b4c1..863659f7 100644 --- a/etherparse/src/link/link_slice.rs +++ b/etherparse/src/link/link_slice.rs @@ -13,10 +13,10 @@ pub enum LinkSlice<'a> { impl<'a> LinkSlice<'a> { /// Convert the link slice to a header (currently just the /// ethernet2 header as this is the only value it can take). - pub fn to_header(&self) -> Option { + pub fn to_header(&self) -> Option { use LinkSlice::*; match self { - Ethernet2(slice) => Some(slice.to_header()), + Ethernet2(slice) => Some(LinkHeader::Ethernet2(slice.to_header())), EtherPayload(_) => None, } } @@ -68,7 +68,7 @@ mod test { ); assert_eq!( slice.to_header(), - Some(eth.clone()) + Some(LinkHeader::Ethernet2(eth.clone())) ); } { diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs index 88aa91d2..3f589df8 100644 --- a/etherparse/src/link/linux_sll_protocol_type.rs +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -41,6 +41,20 @@ impl LinuxSllProtocolType { ArpHardwareId::FRAD, ArpHardwareId::ETHER ]; + + pub fn change_value(&mut self, value: u16) { + *self = match *self { + LinuxSllProtocolType::Ignored(_) => LinuxSllProtocolType::Ignored(value), + LinuxSllProtocolType::NetlinkProtocolType(_) => LinuxSllProtocolType::NetlinkProtocolType(value), + LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(_) => LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(value), + LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType (_) => { + match LinuxNonstandardEtherType::try_from(value) { + Ok(v) => LinuxSllProtocolType::LinuxNonstandardEtherType(v), + Err(_) => LinuxSllProtocolType::EtherType(EtherType(value)) + } + } + } + } } impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { diff --git a/etherparse/src/packet_builder.rs b/etherparse/src/packet_builder.rs index a2b058aa..477fc573 100644 --- a/etherparse/src/packet_builder.rs +++ b/etherparse/src/packet_builder.rs @@ -129,11 +129,11 @@ impl PacketBuilder { pub fn ethernet2(source: [u8; 6], destination: [u8; 6]) -> PacketBuilderStep { PacketBuilderStep { state: PacketImpl { - ethernet2_header: Some(Ethernet2Header { + link_header: Some(LinkHeader::Ethernet2(Ethernet2Header { source, destination, ether_type: EtherType(0), //the type identifier - }), + })), vlan_header: None, ip_header: None, transport_header: None, @@ -175,7 +175,7 @@ impl PacketBuilder { ) -> PacketBuilderStep { PacketBuilderStep { state: PacketImpl { - ethernet2_header: None, + link_header: None, vlan_header: None, ip_header: None, transport_header: None, @@ -222,7 +222,7 @@ impl PacketBuilder { ) -> PacketBuilderStep { PacketBuilderStep { state: PacketImpl { - ethernet2_header: None, + link_header: None, vlan_header: None, ip_header: None, transport_header: None, @@ -299,7 +299,7 @@ impl PacketBuilder { pub fn ip(ip_header: IpHeaders) -> PacketBuilderStep { PacketBuilderStep { state: PacketImpl { - ethernet2_header: None, + link_header: None, vlan_header: None, ip_header: None, transport_header: None, @@ -311,7 +311,7 @@ impl PacketBuilder { } struct PacketImpl { - ethernet2_header: Option, + link_header: Option, ip_header: Option, vlan_header: Option, transport_header: Option, @@ -1566,19 +1566,24 @@ fn final_write( } }; - //ethernetII header - if let Some(mut eth) = builder.state.ethernet2_header { - eth.ether_type = { - use crate::VlanHeader::*; - //determine the ether type depending on if there is a vlan tagging header - match builder.state.vlan_header { - Some(Single(_)) => ether_type::VLAN_TAGGED_FRAME, - Some(Double(_)) => ether_type::PROVIDER_BRIDGING, - //if no vlan header exists, the id is purely defined by the ip type - None => ip_ether_type, + //link header + if let Some(link) = builder.state.link_header { + match link { + LinkHeader::Ethernet2(mut eth) => { + eth.ether_type = { + use crate::VlanHeader::*; + //determine the ether type depending on if there is a vlan tagging header + match builder.state.vlan_header { + Some(Single(_)) => ether_type::VLAN_TAGGED_FRAME, + Some(Double(_)) => ether_type::PROVIDER_BRIDGING, + //if no vlan header exists, the id is purely defined by the ip type + None => ip_ether_type, + } + }; + eth.write(writer).map_err(Io)?; } - }; - eth.write(writer).map_err(Io)?; + LinkHeader::LinuxSll(mut linux_sll) => todo!() + } } //write the vlan header if it exists @@ -1737,8 +1742,8 @@ fn final_size(builder: &PacketBuilderStep, payload_size: usize) -> usize { use crate::IpHeaders::*; use crate::TransportHeader::*; use crate::VlanHeader::*; - (match builder.state.ethernet2_header { - Some(_) => Ethernet2Header::LEN, + (match builder.state.link_header { + Some(ref header) => header.header_len(), None => 0, }) + match builder.state.vlan_header { Some(Single(_)) => SingleVlanHeader::LEN, @@ -1769,7 +1774,7 @@ mod white_box_tests { 0, PacketBuilderStep:: { state: PacketImpl { - ethernet2_header: None, + link_header: None, ip_header: None, vlan_header: None, transport_header: None @@ -1787,7 +1792,7 @@ mod white_box_tests { final_write( PacketBuilderStep:: { state: PacketImpl { - ethernet2_header: None, + link_header: None, ip_header: None, vlan_header: None, transport_header: None, @@ -2984,11 +2989,11 @@ mod test { // check the packets could be decoded assert_eq!( - Some(Ethernet2Header{ + Some(LinkHeader::Ethernet2(Ethernet2Header{ source: [1,2,3,4,5,6], destination: [7,8,9,10,11,12], ether_type: ether_type::IPV4 - }), + })), actual.link ); assert_eq!( @@ -3203,11 +3208,11 @@ mod test { // check the packets could be decoded assert_eq!( - Some(Ethernet2Header{ + Some(LinkHeader::Ethernet2(Ethernet2Header{ source: [1,2,3,4,5,6], destination: [7,8,9,10,11,12], ether_type: ether_type::IPV6 - }), + })), actual.link ); assert_eq!( @@ -3330,11 +3335,11 @@ mod test { // check the packets could be decoded assert_eq!( - Some(Ethernet2Header{ + Some(LinkHeader::Ethernet2(Ethernet2Header{ source: [1,2,3,4,5,6], destination: [7,8,9,10,11,12], ether_type: ether_type::IPV6 - }), + })), actual.link ); assert_eq!( diff --git a/etherparse/src/packet_headers.rs b/etherparse/src/packet_headers.rs index 516b5ad2..5ab033e3 100644 --- a/etherparse/src/packet_headers.rs +++ b/etherparse/src/packet_headers.rs @@ -15,7 +15,7 @@ use super::*; #[derive(Clone, Debug, Eq, PartialEq)] pub struct PacketHeaders<'a> { /// Ethernet II header if present. - pub link: Option, + pub link: Option, /// Single or double vlan headers if present. pub vlan: Option, /// IPv4 or IPv6 header and IP extension headers if present. @@ -76,7 +76,7 @@ impl<'a> PacketHeaders<'a> { match &mut result { // inject ethernet header into the result - Ok(result) => result.link = Some(ethernet), + Ok(result) => result.link = Some(LinkHeader::Ethernet2(ethernet)), // add the ethernet header to the overall offset in case there is a length error Err(Len(err)) => err.layer_start_offset += Ethernet2Header::LEN, _ => {} @@ -487,7 +487,7 @@ mod test { ether_type: 0.into(), }; let test = TestPacket { - link: Some(eth.clone()), + link: Some(LinkHeader::Ethernet2(eth.clone())), vlan: None, net: None, transport: None, diff --git a/etherparse/src/sliced_packet.rs b/etherparse/src/sliced_packet.rs index ae3b6aed..388eaaa2 100644 --- a/etherparse/src/sliced_packet.rs +++ b/etherparse/src/sliced_packet.rs @@ -519,7 +519,7 @@ mod test { ether_type: 0.into(), }; let test = TestPacket { - link: Some(eth.clone()), + link: Some(LinkHeader::Ethernet2(eth.clone())), vlan: None, net: None, transport: None, @@ -1203,7 +1203,7 @@ mod test { test.link, match result.link.as_ref() { Some(s) => match s { - LinkSlice::Ethernet2(e) => Some(e.to_header()), + LinkSlice::Ethernet2(e) => Some(LinkHeader::Ethernet2(e.to_header())), LinkSlice::EtherPayload(_) => None, }, None => None, diff --git a/etherparse/src/test_packet.rs b/etherparse/src/test_packet.rs index ae4ed43f..aac354f4 100644 --- a/etherparse/src/test_packet.rs +++ b/etherparse/src/test_packet.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; #[derive(Clone)] pub(crate) struct TestPacket { - pub link: Option, + pub link: Option, pub vlan: Option, pub net: Option, pub transport: Option, @@ -57,7 +57,10 @@ impl TestPacket { } } } else if let Some(link) = &mut self.link { - link.ether_type = ether_type; + match link { + LinkHeader::Ethernet2(ethernet) => ethernet.ether_type = ether_type, + LinkHeader::LinuxSll(linux_sll) => linux_sll.protocol_type.change_value(ether_type.0), + } } } From 19d8f5a671b9b99236688570f6a27669143c72c5 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 16:36:24 +0200 Subject: [PATCH 12/21] add PacketBuilder::linux_sll and PacketBuilderStep::ip[_, v4, v6] --- etherparse/src/packet_builder.rs | 453 ++++++++++++++++++++++++++++++- 1 file changed, 448 insertions(+), 5 deletions(-) diff --git a/etherparse/src/packet_builder.rs b/etherparse/src/packet_builder.rs index 477fc573..3f82e18e 100644 --- a/etherparse/src/packet_builder.rs +++ b/etherparse/src/packet_builder.rs @@ -44,6 +44,7 @@ use std::{io, marker}; /// /// * Starting Options: /// * [`PacketBuilder::ethernet2`] +/// * [`PacketBuilder::linux_sll`] /// * [`PacketBuilder::ip`] /// * [`PacketBuilder::ipv4`] /// * [`PacketBuilder::ipv6`] @@ -54,6 +55,10 @@ use std::{io, marker}; /// * [`PacketBuilderStep::ip`] /// * [`PacketBuilderStep::ipv4`] /// * [`PacketBuilderStep::ipv6`] +/// * Options after a Linux Cooked Capture v1 (SLL) was added: +/// * [`PacketBuilderStep::ip`] +/// * [`PacketBuilderStep::ipv4`] +/// * [`PacketBuilderStep::ipv6`] /// * Options after an Vlan header was added: /// * [`PacketBuilderStep::ip`] /// * [`PacketBuilderStep::ipv4`] @@ -142,6 +147,57 @@ impl PacketBuilder { } } + /// Start an packet with an Linux Cooked Catpure (v1) header. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// # use etherparse::{PacketBuilder, LinuxSllPacketType}; + /// # + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// .ipv4([192,168,1,1], //source ip + /// [192,168,1,2], //destination ip + /// 20) //time to life + /// .udp(21, //source port + /// 1234); //destination port + /// + /// //payload of the udp packet + /// let payload = [1,2,3,4,5,6,7,8]; + /// + /// //get some memory to store the result + /// let mut result = Vec::::with_capacity( + /// builder.size(payload.len())); + /// + /// //serialize + /// builder.write(&mut result, &payload).unwrap(); + /// ``` + pub fn linux_sll( + packet_type: LinuxSllPacketType, + sender_address_valid_length: u16, + sender_address: [u8; 8], + ) -> PacketBuilderStep { + PacketBuilderStep { + state: PacketImpl { + link_header: Some(LinkHeader::LinuxSll(LinuxSllHeader { + packet_type, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length, + sender_address, + protocol_type: LinuxSllProtocolType::EtherType(EtherType(0)) // Will be overwitten when writing depending on the net layer + })), + vlan_header: None, + ip_header: None, + transport_header: None, + }, + _marker: marker::PhantomData:: {}, + } + } + /// Starts a packet with an IPv4 header. /// /// # Example @@ -633,6 +689,152 @@ impl PacketBuilderStep { } } +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl PacketBuilderStep { + /// Add an ip header (length, protocol/next_header & checksum fields will be overwritten based on the rest of the packet). + /// + /// # Example IPv4 + /// ``` + /// # use etherparse::*; + /// # + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// //payload_len, protocol & checksum will be replaced during write + /// .ip(IpHeaders::Ipv4( + /// Ipv4Header::new( + /// 0, //payload_len will be replaced during write + /// 12, //time_to_live + /// ip_number::UDP, //will be replaced during write + /// [0,1,2,3], //source + /// [4,5,6,7] //destination + /// ).unwrap(), + /// Default::default() // IPv4 extension headers (default is none) + /// )); + /// ``` + /// + /// # Example IPv6 + /// ``` + /// # use etherparse::*; + /// # + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// .ip(IpHeaders::Ipv6( + /// Ipv6Header{ + /// traffic_class: 0, + /// flow_label: 0.try_into().unwrap(), + /// hop_limit: 4, + /// source: [0;16], + /// destination: [0;16], + /// // payload_length & next_header will be replaced during write + /// ..Default::default() + /// }, + /// Default::default() // IPv6 extension headers (default is none) + /// )); + /// ``` + pub fn ip(self, ip_header: IpHeaders) -> PacketBuilderStep { + //use the method from the Ethernet2Header implementation + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + .ip(ip_header) + } + + /// Add an IPv6 header + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// # use etherparse::{PacketBuilder, LinuxSllPacketType, ArpHardwareId, LinuxSllProtocolType, EtherType}; + /// # + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// .ipv6( + /// //source + /// [11,12,13,14,15,16,17,18,19,10,21,22,23,24,25,26], + /// //destination + /// [31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46], + /// //hop_limit + /// 47) + /// .udp(21, //source port + /// 1234); //destination port + /// + /// //payload of the udp packet + /// let payload = [1,2,3,4,5,6,7,8]; + /// + /// //get some memory to store the result + /// let mut result = Vec::::with_capacity( + /// builder.size(payload.len())); + /// + /// //serialize + /// builder.write(&mut result, &payload).unwrap(); + /// ``` + pub fn ipv6( + self, + source: [u8; 16], + destination: [u8; 16], + hop_limit: u8, + ) -> PacketBuilderStep { + //use the method from the Ethernet2Header implementation + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + .ipv6(source, destination, hop_limit) + } + + /// Add an IPv4 header + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// # use etherparse::{PacketBuilder, LinuxSllPacketType, ArpHardwareId, LinuxSllProtocolType, EtherType}; + /// # + /// let builder = PacketBuilder:: + /// linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// 6, //sender address valid length + /// [1,2,3,4,5,6,0,0]) //sender address with padding + /// .ipv4([192,168,1,1], //source ip + /// [192,168,1,2], //destination ip + /// 20) //time to life + /// .udp(21, //source port + /// 1234); //destination port + /// + /// //payload of the udp packet + /// let payload = [1,2,3,4,5,6,7,8]; + /// + /// //get some memory to store the result + /// let mut result = Vec::::with_capacity( + /// builder.size(payload.len())); + /// + /// //serialize + /// builder.write(&mut result, &payload).unwrap(); + /// ``` + pub fn ipv4( + self, + source: [u8; 4], + destination: [u8; 4], + time_to_live: u8, + ) -> PacketBuilderStep { + //use the method from the Ethernet2Header implementation + PacketBuilderStep { + state: self.state, + _marker: marker::PhantomData:: {}, + } + .ipv4(source, destination, time_to_live) + } +} + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl PacketBuilderStep { ///Add an ip header (length, protocol/next_header & checksum fields will be overwritten based on the rest of the packet). @@ -1582,7 +1784,14 @@ fn final_write( }; eth.write(writer).map_err(Io)?; } - LinkHeader::LinuxSll(mut linux_sll) => todo!() + LinkHeader::LinuxSll(mut linux_sll) => { + // Assumes that next layers are ether based. If more types of + // layers are supported, this should be updated + debug_assert_eq!(linux_sll.arp_hrd_type, ArpHardwareId::ETHER); + + linux_sll.protocol_type.change_value(ip_ether_type.into()); + linux_sll.write(writer).map_err(Io)?; + } } } @@ -1872,6 +2081,66 @@ mod test { assert_eq!(actual_payload, in_payload); } + #[test] + fn linuxsll_ipv4_udp() { + //generate + let in_payload = [24, 25, 26, 27]; + let mut serialized = Vec::new(); + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .ipv4([13, 14, 15, 16], [17, 18, 19, 20], 21) + .udp(22, 23) + .write(&mut serialized, &in_payload) + .unwrap(); + + //check the deserialized size + let expected_ip_size: usize = UdpHeader::LEN + in_payload.len(); + assert_eq!( + expected_ip_size + LinuxSllHeader::LEN + Ipv4Header::MIN_LEN, + serialized.len() + ); + + //deserialize and check that everything is as expected + use std::io::Cursor; + //deserialize each part of the message and check it + let mut cursor = Cursor::new(&serialized); + + //ethernet 2 header + assert_eq!( + LinuxSllHeader::read(&mut cursor).unwrap(), + LinuxSllHeader { + packet_type: LinuxSllPacketType::OUTGOING, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length: 6, + sender_address: [7, 8, 9, 10, 11, 12, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV4) + } + ); + + //ip header + let ip_actual = Ipv4Header::read(&mut cursor).unwrap(); + let mut ip_expected = Ipv4Header::new( + expected_ip_size as u16, + 21, //ttl + ip_number::UDP, + [13, 14, 15, 16], + [17, 18, 19, 20], + ) + .unwrap(); + ip_expected.header_checksum = ip_expected.calc_header_checksum(); + assert_eq!(ip_actual, ip_expected); + + //udp header + let udp_actual = UdpHeader::read(&mut cursor).unwrap(); + let udp_expected = + UdpHeader::with_ipv4_checksum(22, 23, &ip_expected, &in_payload).unwrap(); + assert_eq!(udp_actual, udp_expected); + + //payload + let mut actual_payload: [u8; 4] = [0; 4]; + cursor.read_exact(&mut actual_payload).unwrap(); + assert_eq!(actual_payload, in_payload); + } + #[test] fn ipv4() { let auth_ext = IpAuthHeader::new(0.into(), 1, 2, &[3, 4, 5, 6]).unwrap(); @@ -2270,6 +2539,78 @@ mod test { assert_eq!(actual_payload, in_payload); } + #[test] + fn udp_builder_linuxsll_ipv6_udp() { + //generate + let in_payload = [50, 51, 52, 53]; + let mut serialized = Vec::new(); + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .ipv6( + [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 21, 22, 23, 24, 25, 26, + ], + [ + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + ], + 47, + ) + .udp(48, 49) + .write(&mut serialized, &in_payload) + .unwrap(); + + //check the deserialized size + assert_eq!( + LinuxSllHeader::LEN + Ipv6Header::LEN + UdpHeader::LEN + in_payload.len(), + serialized.len() + ); + + //deserialize and check that everything is as expected + use std::io::Cursor; + use std::io::Read; + //deserialize each part of the message and check it + let mut cursor = Cursor::new(&serialized); + + //ethernet 2 header + assert_eq!( + LinuxSllHeader::read(&mut cursor).unwrap(), + LinuxSllHeader { + packet_type: LinuxSllPacketType::OUTGOING, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length: 6, + sender_address: [7, 8, 9, 10, 11, 12, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV6) + } + ); + + //ip header + let ip_actual = Ipv6Header::read(&mut cursor).unwrap(); + let ip_expected = Ipv6Header { + traffic_class: 0, + flow_label: Ipv6FlowLabel::ZERO, + payload_length: (UdpHeader::LEN + in_payload.len()) as u16, + next_header: ip_number::UDP, + hop_limit: 47, + source: [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 21, 22, 23, 24, 25, 26, + ], + destination: [ + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + ], + }; + assert_eq!(ip_actual, ip_expected); + + //udp header + let udp_actual = UdpHeader::read(&mut cursor).unwrap(); + let udp_expected = + UdpHeader::with_ipv6_checksum(48, 49, &ip_expected, &in_payload).unwrap(); + assert_eq!(udp_actual, udp_expected); + + //payload + let mut actual_payload: [u8; 4] = [0; 4]; + cursor.read_exact(&mut actual_payload).unwrap(); + assert_eq!(actual_payload, in_payload); + } + #[test] fn udp_builder_eth_single_vlan_ipv4_udp() { //generate @@ -2519,6 +2860,86 @@ mod test { assert_eq!(actual_payload, in_payload); } + #[test] + fn udp_builder_linuxsll_ip_udp() { + //generate + let in_payload = [50, 51, 52, 53]; + let mut serialized = Vec::new(); + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .ip(IpHeaders::Ipv6( + Ipv6Header { + traffic_class: 1, + flow_label: 2.try_into().unwrap(), + payload_length: (UdpHeader::LEN + in_payload.len()) as u16, + next_header: ip_number::UDP, + hop_limit: 47, + source: [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 21, 22, 23, 24, 25, 26, + ], + destination: [ + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + ], + }, + Default::default(), + )) + .udp(48, 49) + .write(&mut serialized, &in_payload) + .unwrap(); + + //check the deserialized size + assert_eq!( + LinuxSllHeader::LEN + Ipv6Header::LEN + UdpHeader::LEN + in_payload.len(), + serialized.len() + ); + + //deserialize and check that everything is as expected + use std::io::Cursor; + use std::io::Read; + + //deserialize each part of the message and check it + let mut cursor = Cursor::new(&serialized); + + //ethernet 2 header + assert_eq!( + LinuxSllHeader::read(&mut cursor).unwrap(), + LinuxSllHeader { + packet_type: LinuxSllPacketType::OUTGOING, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length: 6, + sender_address: [7, 8, 9, 10, 11, 12, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV6) + } + ); + + //ip header + let ip_actual = Ipv6Header::read(&mut cursor).unwrap(); + let ip_expected = Ipv6Header { + traffic_class: 1, + flow_label: 2.try_into().unwrap(), + payload_length: (UdpHeader::LEN + in_payload.len()) as u16, + next_header: ip_number::UDP, + hop_limit: 47, + source: [ + 11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 21, 22, 23, 24, 25, 26, + ], + destination: [ + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + ], + }; + assert_eq!(ip_actual, ip_expected); + + //udp header + let udp_actual = UdpHeader::read(&mut cursor).unwrap(); + let udp_expected = + UdpHeader::with_ipv6_checksum(48, 49, &ip_expected, &in_payload).unwrap(); + assert_eq!(udp_actual, udp_expected); + + //payload + let mut actual_payload: [u8; 4] = [0; 4]; + cursor.read_exact(&mut actual_payload).unwrap(); + assert_eq!(actual_payload, in_payload); + } + #[test] fn udp_builder_eth_vlan_ip_udp() { //generate @@ -2866,7 +3287,7 @@ mod test { #[test] fn size() { - //ipv4 no vlan + //ipv4 no vlan ethernet assert_eq!( Ethernet2Header::LEN + Ipv4Header::MIN_LEN + UdpHeader::LEN + 123, PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]) @@ -2875,7 +3296,7 @@ mod test { .size(123) ); - //ipv6 no vlan + //ipv6 no vlan ethernet assert_eq!( Ethernet2Header::LEN + Ipv6Header::LEN + UdpHeader::LEN + 123, PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]) @@ -2888,7 +3309,29 @@ mod test { .size(123) ); - //ipv4 single vlan + //ipv4 linux_sll + assert_eq!( + LinuxSllHeader::LEN + Ipv4Header::MIN_LEN + UdpHeader::LEN + 123, + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .ipv4([13, 14, 15, 16], [17, 18, 19, 20], 21) + .udp(22, 23) + .size(123) + ); + + //ipv6 linux_sll + assert_eq!( + LinuxSllHeader::LEN + Ipv6Header::LEN + UdpHeader::LEN + 123, + PacketBuilder::linux_sll(LinuxSllPacketType::OUTGOING, 6, [7, 8, 9, 10, 11, 12, 0, 0]) + .ipv6( + [11, 12, 13, 14, 15, 16, 17, 18, 19, 10, 21, 22, 23, 24, 25, 26], + [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46], + 47, + ) + .udp(22, 23) + .size(123) + ); + + //ipv4 single vlan ethernet assert_eq!( Ethernet2Header::LEN + SingleVlanHeader::LEN @@ -2902,7 +3345,7 @@ mod test { .size(123) ); - //ipv6 double vlan + //ipv6 double vlan ethernet assert_eq!( Ethernet2Header::LEN + DoubleVlanHeader::LEN + Ipv6Header::LEN + UdpHeader::LEN + 123, PacketBuilder::ethernet2([1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]) From ed889ad3d890a1edb3dd480fe6467304743af3e4 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 17:12:03 +0200 Subject: [PATCH 13/21] update documentation with the added methods and references --- README.md | 3 +++ etherparse/src/lib.rs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 2c3788a5..14f2d39f 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ It is also possible just to parse headers. Have a look at the documentation for following \[NAME\]HeaderSlice.from_slice methods, if you want to just slice the header: * [`Ethernet2HeaderSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2HeaderSlice.html#method.from_slice) +* [`LinuxSllHeaderSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeaderSlice.html#method.from_slice) * [`SingleVlanHeaderSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeaderSlice.html#method.from_slice) * [`DoubleVlanHeaderSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeaderSlice.html#method.from_slice) * [`Ipv4HeaderSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4HeaderSlice.html#method.from_slice) @@ -133,6 +134,7 @@ following \[NAME\]HeaderSlice.from_slice methods, if you want to just slice the And for deserialization into the corresponding header structs have a look at: * [`Ethernet2Header::read`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Header.html#method.read) & [`Ethernet2Header::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Header.html#method.from_slice) +* [`LinuxSllHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.read) & [`LinuxSllHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.from_slice) * [`SingleVlanHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.read) & [`SingleVlanHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.from_slice) * [`DoubleVlanHeader::read`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.read) & [`DoubleVlanHeader::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.from_slice) * [`IpHeaders::read`](https://docs.rs/etherparse/~0/etherparse/enum.IpHeaders.html#method.read) & [`IpHeaders::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.IpHeaders.html#method.from_slice) @@ -189,6 +191,7 @@ Alternatively it is possible to manually build a packet ([example](etherparse/ex Read the documentations of the different methods for a more details: * [`Ethernet2Header::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Header.html#method.to_bytes) & [`Ethernet2Header::write`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Header.html#method.write) +* [`LinuxSllHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.to_bytes) & [`LinuxSllHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllHeader.html#method.write) * [`SingleVlanHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.to_bytes) & [`SingleVlanHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanHeader.html#method.write) * [`DoubleVlanHeader::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.to_bytes) & [`DoubleVlanHeader::write`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanHeader.html#method.write) * [`Ipv4Header::to_bytes`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.to_bytes) & [`Ipv4Header::write`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.write) & [`Ipv4Header::write_raw`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Header.html#method.write_raw) diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index adf7c1da..4255768b 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -142,6 +142,7 @@ //! following \[NAME\]HeaderSlice.from_slice methods, if you want to just slice the header: //! //! * [`Ethernet2HeaderSlice::from_slice`] +//! * [`LinuxSllHeaderSlice::from_slice`] //! * [`SingleVlanHeaderSlice::from_slice`] //! * [`DoubleVlanHeaderSlice::from_slice`] //! * [`Ipv4HeaderSlice::from_slice`] @@ -157,6 +158,7 @@ //! And for deserialization into the corresponding header structs have a look at: //! //! * [`Ethernet2Header::read`] & [`Ethernet2Header::from_slice`] +//! * [`LinuxSllHeader::read`] & [`LinuxSllHeader::from_slice`] //! * [`SingleVlanHeader::read`] & [`SingleVlanHeader::from_slice`] //! * [`DoubleVlanHeader::read`] & [`DoubleVlanHeader::from_slice`] //! * [`IpHeaders::read`] & [`IpHeaders::from_slice`] @@ -220,6 +222,7 @@ //! Read the documentations of the different methods for a more details: //! //! * [`Ethernet2Header::to_bytes`] & [`Ethernet2Header::write`] +//! * [`LinuxSllHeader::to_bytes`] & [`LinuxSllHeader::write`] //! * [`SingleVlanHeader::to_bytes`] & [`SingleVlanHeader::write`] //! * [`DoubleVlanHeader::to_bytes`] & [`DoubleVlanHeader::write`] //! * [`Ipv4Header::to_bytes`] & [`Ipv4Header::write`] & [`Ipv4Header::write_raw`] @@ -260,6 +263,11 @@ //! * [Internet Control Message Protocol version 6 (ICMPv6) Parameters](https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml) //! * Multicast Listener Discovery (MLD) for IPv6 [RFC 2710](https://datatracker.ietf.org/doc/html/rfc2710) //! * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) +//! * [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) on tcpdump +//! * LINUX_SLL [header definition](https://github.com/the-tcpdump-group/libpcap/blob/a932566fa1f6df16176ac702b1762ea1cd9ed9a3/pcap/sll.h) on libpcap +//! * [Linux packet types definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel +//! * Address Resolution Protocol (ARP) Parameters [Harware Types](https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2) +//! * [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel // # Reason for 'bool_comparison' disable: // From 4bbd19028233e13ee31ac636abbc617dfa236db5 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 21:57:13 +0200 Subject: [PATCH 14/21] add LinuxSllSlice --- README.md | 1 + etherparse/src/lib.rs | 3 + etherparse/src/link/linux_sll_header.rs | 4 +- etherparse/src/link/linux_sll_header_slice.rs | 79 ++++-- .../src/link/linux_sll_payload_slice.rs | 45 ++++ etherparse/src/link/linux_sll_slice.rs | 245 ++++++++++++++++++ etherparse/src/link/mod.rs | 2 + 7 files changed, 353 insertions(+), 26 deletions(-) create mode 100644 etherparse/src/link/linux_sll_payload_slice.rs create mode 100644 etherparse/src/link/linux_sll_slice.rs diff --git a/README.md b/README.md index 14f2d39f..70dd8081 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ In case you want to parse cut off packets (e.g. packets returned in in ICMP mess It is also possible to only slice one packet layer: * [`Ethernet2Slice::from_slice_without_fcs`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Slice.html#method.from_slice_without_fcs) & [`Ethernet2Slice::from_slice_with_crc32_fcs`](https://docs.rs/etherparse/~0/etherparse/struct.Ethernet2Slice.html#method.from_slice_with_crc32_fcs) +* [`LinuxSllSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LinuxSllSlice.html#method.from_slice) * [`SingleVlanSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.SingleVlanSlice.html#method.from_slice) & [`DoubleVlanSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.DoubleVlanSlice.html#method.from_slice) * [`IpSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.IpSlice.html#method.from_slice) & [`LaxIpSlice::from_slice`](https://docs.rs/etherparse/~0/etherparse/enum.LaxIpSlice.html#method.from_slice) * [`Ipv4Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.Ipv4Slice.html#method.from_slice) & [`LaxIpv4Slice::from_slice`](https://docs.rs/etherparse/~0/etherparse/struct.LaxIpv4Slice.html#method.from_slice) diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 4255768b..6e8cf021 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -122,6 +122,7 @@ //! It is also possible to only slice one packet layer: //! //! * [`Ethernet2Slice::from_slice_without_fcs`] & [`Ethernet2Slice::from_slice_with_crc32_fcs`] +//! * [`LinuxSllSlice::from_slice`] //! * [`SingleVlanSlice::from_slice`] & [`DoubleVlanSlice::from_slice`] //! * [`IpSlice::from_slice`] & [`LaxIpSlice::from_slice`] //! * [`Ipv4Slice::from_slice`] & [`LaxIpv4Slice::from_slice`] @@ -316,7 +317,9 @@ pub use crate::link::linux_nonstandard_ether_type::*; pub use crate::link::linux_sll_header_slice::*; pub use crate::link::linux_sll_header::*; pub use crate::link::linux_sll_packet_type::*; +pub use crate::link::linux_sll_payload_slice::*; pub use crate::link::linux_sll_protocol_type::*; +pub use crate::link::linux_sll_slice::*; pub use crate::link::single_vlan_header::*; pub use crate::link::single_vlan_header_slice::*; pub use crate::link::single_vlan_slice::*; diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index 23a13bdb..a151bbab 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -26,7 +26,7 @@ impl LinuxSllHeader { #[inline] pub fn from_slice(slice: &[u8]) -> Result<(LinuxSllHeader, &[u8]), err::ReadError> { Ok(( - LinuxSllHeaderSlice::from_slice(slice)?.to_header()?, + LinuxSllHeaderSlice::from_slice(slice)?.to_header(), &slice[LinuxSllHeader::LEN..], )) } @@ -63,7 +63,7 @@ impl LinuxSllHeader { Ok( // SAFETY: Safe as the buffer contains exactly the needed LinuxSllHeader::LEN bytes. - unsafe { LinuxSllHeaderSlice::from_slice_unchecked(&buffer) }.to_header()?, + unsafe { LinuxSllHeaderSlice::from_slice_unchecked(&buffer) }.to_header(), ) } diff --git a/etherparse/src/link/linux_sll_header_slice.rs b/etherparse/src/link/linux_sll_header_slice.rs index 79eb9cf1..47e6eb65 100644 --- a/etherparse/src/link/linux_sll_header_slice.rs +++ b/etherparse/src/link/linux_sll_header_slice.rs @@ -4,21 +4,48 @@ use core::{cmp::min, slice::from_raw_parts}; ///A slice containing an Linux Cooked Capture (SLL) header of a network package. #[derive(Clone, Debug, Eq, PartialEq)] pub struct LinuxSllHeaderSlice<'a> { - pub(crate) slice: &'a [u8], + slice: &'a [u8], } impl<'a> LinuxSllHeaderSlice<'a> { /// Creates a SLL header slice from an other slice. - pub fn from_slice(slice: &'a [u8]) -> Result, err::LenError> { + pub fn from_slice(slice: &'a [u8]) -> Result, err::linux_sll::HeaderSliceError> { //check length if slice.len() < LinuxSllHeader::LEN { - return Err(err::LenError { + return Err(err::linux_sll::HeaderSliceError::Len(err::LenError { required_len: LinuxSllHeader::LEN, len: slice.len(), len_source: LenSource::Slice, layer: err::Layer::LinuxSllHeader, layer_start_offset: 0, - }); + })); + } + + // check valid packet type + + // SAFETY: + // Safe as it is checked at the start of the function that the + // length of the slice is at least LinuxSllHeader::LEN (16). + let packet_type_val = unsafe { get_unchecked_be_u16(slice.as_ptr()) }; + if let Err(err) = LinuxSllPacketType::try_from(packet_type_val) { + return Err(err::linux_sll::HeaderSliceError::Content(err)); + } + + // check supported ArpHardwareId + + // SAFETY: + // Safe as it is checked at the start of the function that the + // length of the slice is at least LinuxSllHeader::LEN (16). + let arp_hardware_id = unsafe { get_unchecked_be_u16(slice.as_ptr().add(2)) }; + let arp_hardware_id = ArpHardwareId::from(arp_hardware_id); + + // SAFETY: + // Safe as it is checked at the start of the function that the + // length of the slice is at least LinuxSllHeader::LEN (16). + let protocol_type = unsafe { get_unchecked_be_u16(slice.as_ptr().add(14)) }; + + if let Err(err) = LinuxSllProtocolType::try_from((arp_hardware_id, protocol_type)) { + return Err(err::linux_sll::HeaderSliceError::Content(err)); } //all done @@ -40,7 +67,7 @@ impl<'a> LinuxSllHeaderSlice<'a> { /// # Safety /// /// The caller must ensured that the given slice has the length of - /// [`LinuxSllHeader::LEN`] + /// [`LinuxSllHeader::LEN`] and the fields are valid #[inline] #[cfg(feature = "std")] pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> LinuxSllHeaderSlice { @@ -54,18 +81,20 @@ impl<'a> LinuxSllHeaderSlice<'a> { self.slice } - /// Try read the packet type field. + /// Read the packet type field. #[inline] - pub fn packet_type(&self) -> Result { + pub fn packet_type(&self) -> LinuxSllPacketType { // SAFETY: // Safe as the contructor checks that the slice has // at least the length of LinuxSllHeader::LEN (16). let packet_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr()) }; - LinuxSllPacketType::try_from(packet_type_raw) + // SAFETY: + // Safe as the constructor checks that the packet type is valid + unsafe { LinuxSllPacketType::try_from(packet_type_raw).unwrap_unchecked() } } - /// Try read the arp hardware type field + /// Read the arp hardware type field #[inline] pub fn arp_hardware_type(&self) -> ArpHardwareId { // SAFETY: @@ -99,30 +128,32 @@ impl<'a> LinuxSllHeaderSlice<'a> { #[inline] pub fn sender_address(&self) -> &'a [u8] { let length = self.sender_address_valid_length() as usize; - &self.slice[6..min(length, 8)] + &self.slice[6..min(6+length,6+ 8)] } - /// Try read the protocol type field + /// Read the protocol type field #[inline] - pub fn protocol_type(&self) -> Result { + pub fn protocol_type(&self) -> LinuxSllProtocolType { let arp_harware_type = self.arp_hardware_type(); // SAFETY: // Safe as the contructor checks that the slice has // at least the length of LinuxSllHeader::LEN (16). let protocol_type_raw = unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(14)) }; - LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)) + // SAFETY: + // Safe as the constructor checks that the arphwd + protocol are supported + unsafe { LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)).unwrap_unchecked() } } - /// Try decode all the fields and copy the results to a [`LinuxSllHeader`] struct - pub fn to_header(&self) -> Result { - Ok(LinuxSllHeader { - packet_type: self.packet_type()?, + /// Decode all the fields and copy the results to a [`LinuxSllHeader`] struct + pub fn to_header(&self) -> LinuxSllHeader { + LinuxSllHeader { + packet_type: self.packet_type(), arp_hrd_type: self.arp_hardware_type(), sender_address_valid_length: self.sender_address_valid_length(), sender_address: self.sender_address_full(), - protocol_type: self.protocol_type()? - }) + protocol_type: self.protocol_type() + } } } @@ -154,13 +185,13 @@ mod test { for len in 0..=13 { assert_eq!( LinuxSllHeaderSlice::from_slice(&buffer[..len]), - Err(err::LenError{ + Err(err::linux_sll::HeaderSliceError::Len(err::LenError{ required_len: LinuxSllHeader::LEN, len: len, len_source: LenSource::Slice, layer: err::Layer::LinuxSllHeader, layer_start_offset: 0, - }) + })) ); } } @@ -171,11 +202,11 @@ mod test { fn getters(input in linux_sll_any()) { let buffer = input.to_bytes(); let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); - assert_eq!(input.packet_type, slice.packet_type().unwrap()); + assert_eq!(input.packet_type, slice.packet_type()); assert_eq!(input.arp_hrd_type, slice.arp_hardware_type()); assert_eq!(input.sender_address_valid_length, slice.sender_address_valid_length()); assert_eq!(input.sender_address, slice.sender_address_full()); - assert_eq!(input.protocol_type, slice.protocol_type().unwrap()); + assert_eq!(input.protocol_type, slice.protocol_type()); } } @@ -184,7 +215,7 @@ mod test { fn to_header(input in linux_sll_any()) { let buffer = input.to_bytes(); let slice = LinuxSllHeaderSlice::from_slice(&buffer).unwrap(); - assert_eq!(input, slice.to_header().unwrap()); + assert_eq!(input, slice.to_header()); } } diff --git a/etherparse/src/link/linux_sll_payload_slice.rs b/etherparse/src/link/linux_sll_payload_slice.rs new file mode 100644 index 00000000..23ee3c65 --- /dev/null +++ b/etherparse/src/link/linux_sll_payload_slice.rs @@ -0,0 +1,45 @@ +use crate::LinuxSllProtocolType; + + +/// Payload of Linux Cooked Capture v1 (SLL) packet +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinuxSllPayloadSlice<'a> { + /// Identifying content of the payload. + pub protocol_type: LinuxSllProtocolType, + + /// Payload + pub payload: &'a [u8], +} + + +#[cfg(test)] +mod test { + use crate::EtherType; + + use super::*; + use alloc::format; + + #[test] + fn debug() { + let s = LinuxSllPayloadSlice { + protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV4), + payload: &[], + }; + assert_eq!( + format!( + "LinuxSllPayloadSlice {{ protocol_type: {:?}, payload: {:?} }}", + s.protocol_type, s.payload + ), + format!("{:?}", s) + ); + } + + #[test] + fn clone_eq() { + let s = LinuxSllPayloadSlice { + protocol_type: LinuxSllProtocolType::EtherType(EtherType::IPV4), + payload: &[], + }; + assert_eq!(s.clone(), s); + } +} diff --git a/etherparse/src/link/linux_sll_slice.rs b/etherparse/src/link/linux_sll_slice.rs new file mode 100644 index 00000000..e3b490a0 --- /dev/null +++ b/etherparse/src/link/linux_sll_slice.rs @@ -0,0 +1,245 @@ +use crate::{err::{self, Layer}, ArpHardwareId, LenSource, LinuxSllHeader, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSllPayloadSlice, LinuxSllProtocolType}; + +/// Slice containing a Linux Cooked Capture v1 (SLL) header & payload. +#[derive(Clone, Eq, PartialEq)] +pub struct LinuxSllSlice<'a> { + header_slice: LinuxSllHeaderSlice<'a>, + header_and_payload_slice: &'a [u8], +} + +impl<'a> LinuxSllSlice<'a> { + /// Try creating a [`LinuxSllSlice`] from a slice containing the + /// header & payload + pub fn from_slice(slice: &'a [u8]) -> Result, err::linux_sll::HeaderSliceError> { + // check length + if slice.len() < LinuxSllHeader::LEN { + return Err(err::linux_sll::HeaderSliceError::Len(err::LenError { + required_len: LinuxSllHeader::LEN, + len: slice.len(), + len_source: LenSource::Slice, + layer: Layer::LinuxSllHeader, + layer_start_offset: 0, + })); + } + + // extract header + match LinuxSllHeaderSlice::from_slice(&slice[0..LinuxSllHeader::LEN]) { + Err(err) => Err(err), + Ok(header_slice) => Ok(LinuxSllSlice{header_slice, header_and_payload_slice: slice}) + } + } + + /// Returns the slice containing the Linux Cooked Capture v1 (SLL) header & + /// payload. + #[inline] + pub fn slice(&self) -> &'a [u8] { + self.header_and_payload_slice + } + + /// Read the packet type field from the header + #[inline] + pub fn packet_type(&self) -> LinuxSllPacketType { + self.header_slice.packet_type() + } + + /// Read the arp hardware type field from the header + #[inline] + pub fn arp_hardware_type(&self) -> ArpHardwareId { + self.header_slice.arp_hardware_type() + } + + /// Read the link layer address length field from the header + #[inline] + pub fn sender_address_valid_length(&self) -> u16 { + self.header_slice.sender_address_valid_length() + } + + /// Read the link layer address field from the header. Only the first + /// `LinuxSllSlice::link_layer_address_length` bytes are meaningful + #[inline] + pub fn sender_address_full(&self) -> [u8; 8] { + self.header_slice.sender_address_full() + } + + /// Get the meaningful bytes of the slice of the link layer address from + /// the header + #[inline] + pub fn sender_address(&self) -> &'a [u8] { + self.header_slice.sender_address() + } + + /// Read the protocol type field from the header + #[inline] + pub fn protocol_type(&self) -> LinuxSllProtocolType { + self.header_slice.protocol_type() + } + + /// Decode all the header fields and copy the results to a + /// [`LinuxSllHeader`] struct + pub fn to_header(&self) -> LinuxSllHeader { + LinuxSllHeader { + packet_type: self.packet_type(), + arp_hrd_type: self.arp_hardware_type(), + sender_address_valid_length: self.sender_address_valid_length(), + sender_address: self.sender_address_full(), + protocol_type: self.protocol_type(), + } + } + + /// Slice only containing the header + pub fn header_slice(&self) -> &[u8] { + self.header_slice.slice() + } + + /// Returns the slice containing the Ethernet II payload & ether type + /// identifying it's content type. + #[inline] + pub fn payload(&self) -> LinuxSllPayloadSlice<'a> { + LinuxSllPayloadSlice { + protocol_type: self.protocol_type(), + payload: self.payload_slice(), + } + } + + /// Slice only containing the payload + #[inline] + pub fn payload_slice(&self) -> &'a [u8] { + // SAFETY: Safe as the slice length was verified to be at least + // LinuxSllHeader::LEN by "from_slice". + unsafe { + core::slice::from_raw_parts( + self.header_and_payload_slice.as_ptr().add(LinuxSllHeader::LEN), + self.header_and_payload_slice.len() - LinuxSllHeader::LEN, + ) + } + } + + /// Length of the header in bytes (equal to [`crate::LinuxSllHeader::LEN`]) + #[inline] + pub const fn header_len(&self) -> usize { + LinuxSllHeader::LEN + } +} + +impl<'a> core::fmt::Debug for LinuxSllSlice<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LinuxSllSlice") + .field("header", &self.to_header()) + .field("payload", &self.payload()) + .finish() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::test_gens::*; + use alloc::{format, vec::Vec}; + use proptest::prelude::*; + + + proptest! { + #[test] + fn debug_clone_eq( + linux_sll in linux_sll_any() + ) { + let payload: [u8;8] = [1,2,3,4,5,6,7,8]; + let mut data = Vec::with_capacity( + linux_sll.header_len() + + payload.len() + ); + data.extend_from_slice(&linux_sll.to_bytes()); + data.extend_from_slice(&payload); + + // decode packet + let slice = LinuxSllSlice::from_slice(&data).unwrap(); + + // check debug output + prop_assert_eq!( + format!("{:?}", slice), + format!( + "LinuxSllSlice {{ header: {:?}, payload: {:?} }}", + slice.to_header(), + slice.payload(), + ) + ); + prop_assert_eq!(slice.clone(), slice); + } + } + + proptest! { + #[test] + fn getters(linux_sll in linux_sll_any()) { + let payload: [u8;8] = [1,2,3,4,5,6,7,8]; + let mut data = Vec::with_capacity( + linux_sll.header_len() + + payload.len() + ); + data.extend_from_slice(&linux_sll.to_bytes()); + data.extend_from_slice(&payload); + + let slice = LinuxSllSlice::from_slice(&data).unwrap(); + assert_eq!(linux_sll.packet_type, slice.packet_type()); + assert_eq!(linux_sll.arp_hrd_type, slice.arp_hardware_type()); + assert_eq!(linux_sll.sender_address_valid_length, slice.sender_address_valid_length()); + assert_eq!(linux_sll.sender_address, slice.sender_address_full()); + assert_eq!(linux_sll.protocol_type, slice.protocol_type()); + assert_eq!(&payload, slice.payload_slice()); + assert_eq!( + LinuxSllPayloadSlice{ + payload: &payload, + protocol_type: linux_sll.protocol_type, + }, + slice.payload() + ); + assert_eq!(linux_sll, slice.to_header()); + assert_eq!(&data, slice.slice()); + assert_eq!(&data[..LinuxSllHeader::LEN], slice.header_slice()); + } + } + + proptest! { + #[test] + fn from_slice(linux_sll in linux_sll_any()) { + + let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10]; + let data = { + let mut data = Vec::with_capacity( + linux_sll.header_len() + + payload.len() + ); + data.extend_from_slice(&linux_sll.to_bytes()); + data.extend_from_slice(&payload); + data + }; + + // normal decode + { + let slice = LinuxSllSlice::from_slice(&data).unwrap(); + assert_eq!(slice.to_header(), linux_sll); + assert_eq!(slice.payload_slice(), &payload); + } + + // decode without payload + { + let slice = LinuxSllSlice::from_slice(&data[..LinuxSllHeader::LEN]).unwrap(); + assert_eq!(slice.to_header(), linux_sll); + assert_eq!(slice.payload_slice(), &[]); + } + + // length error + for len in 0..LinuxSllHeader::LEN { + assert_eq!( + LinuxSllSlice::from_slice(&data[..len]).unwrap_err(), + err::linux_sll::HeaderSliceError::Len(err::LenError{ + required_len: LinuxSllHeader::LEN, + len, + len_source: LenSource::Slice, + layer: Layer::LinuxSllHeader, + layer_start_offset: 0 + }) + ); + } + } + } +} diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index aba277c9..9e041f79 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -11,7 +11,9 @@ pub mod linux_nonstandard_ether_type; pub mod linux_sll_header_slice; pub mod linux_sll_header; pub mod linux_sll_packet_type; +pub mod linux_sll_payload_slice; pub mod linux_sll_protocol_type; +pub mod linux_sll_slice; pub mod link_header; pub mod link_slice; pub mod single_vlan_header; From 9ece217163ed96f62efe24e4daeb624f189b55e7 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Sun, 28 Apr 2024 23:31:11 +0200 Subject: [PATCH 15/21] add linux sll to link slice --- etherparse/examples/read_by_slicing.rs | 8 ++ etherparse/src/compositions_tests.rs | 2 + etherparse/src/lax_sliced_packet.rs | 12 ++- etherparse/src/link/link_slice.rs | 98 ++++++++++++++++--- .../src/link/linux_nonstandard_ether_type.rs | 2 +- .../src/link/linux_sll_payload_slice.rs | 33 ++++++- etherparse/src/sliced_packet.rs | 26 ++++- 7 files changed, 162 insertions(+), 19 deletions(-) diff --git a/etherparse/examples/read_by_slicing.rs b/etherparse/examples/read_by_slicing.rs index f203d12b..dcf2bb07 100644 --- a/etherparse/examples/read_by_slicing.rs +++ b/etherparse/examples/read_by_slicing.rs @@ -44,9 +44,17 @@ fn main() { value.source(), value.destination() ), + Some(LinuxSll(value)) => println!( + " LinuxSll (packet type: {:?}, source address: {:?})", + value.packet_type(), + value.sender_address(), + ), Some(EtherPayload(payload)) => { println!(" EtherPayload (ether type {:?})", payload.ether_type) } + Some(LinuxSllPayload(payload)) => { + println!(" LinuxSllPayload (protocol type {:?})", payload.protocol_type) + } None => {} } diff --git a/etherparse/src/compositions_tests.rs b/etherparse/src/compositions_tests.rs index ecd1fcf6..043dce67 100644 --- a/etherparse/src/compositions_tests.rs +++ b/etherparse/src/compositions_tests.rs @@ -291,7 +291,9 @@ impl ComponentTest { match result.link.as_ref() { Some(l) => match l { LinkSlice::Ethernet2(e) => Some(LinkHeader::Ethernet2(e.to_header())), + LinkSlice::LinuxSll(e) => Some(LinkHeader::LinuxSll(e.to_header())), LinkSlice::EtherPayload(_) => None, + LinkSlice::LinuxSllPayload(_) => None, }, None => None, } diff --git a/etherparse/src/lax_sliced_packet.rs b/etherparse/src/lax_sliced_packet.rs index d5584fa4..8818a355 100644 --- a/etherparse/src/lax_sliced_packet.rs +++ b/etherparse/src/lax_sliced_packet.rs @@ -232,10 +232,18 @@ impl<'a> LaxSlicedPacket<'a> { VlanSlice::SingleVlan(s) => Some(s.payload()), VlanSlice::DoubleVlan(s) => Some(s.payload()), } - } else if let Some(eth) = self.link.as_ref() { - match eth { + } else if let Some(link) = self.link.as_ref() { + match link { LinkSlice::Ethernet2(e) => Some(e.payload()), + LinkSlice::LinuxSll(e) => match e.protocol_type() { + LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.payload()).ok()?), + _ => None + } LinkSlice::EtherPayload(e) => Some(e.clone()), + LinkSlice::LinuxSllPayload(e) => match e.protocol_type { + LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.clone()).ok()?), + _ => None + } } } else { None diff --git a/etherparse/src/link/link_slice.rs b/etherparse/src/link/link_slice.rs index 863659f7..755e16dc 100644 --- a/etherparse/src/link/link_slice.rs +++ b/etherparse/src/link/link_slice.rs @@ -1,32 +1,53 @@ use crate::*; -/// A slice containing the link layer header (currently only Ethernet II is supported). +/// 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 (currently just the - /// ethernet2 header as this is the only value it can take). + /// Convert the link slice to a header pub fn to_header(&self) -> Option { 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> { + 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 payload (slice + ether type number). - pub fn payload(&self) -> EtherPayloadSlice<'a> { + /// Returns the link layer sll payload (slice + link layer protocol type). + pub fn sll_payload(&self) -> LinuxSllPayloadSlice<'a> { use LinkSlice::*; match self { - Ethernet2(s) => s.payload().clone(), - EtherPayload(p) => p.clone(), + Ethernet2(s) => LinuxSllPayloadSlice::from(s.payload().clone()), + LinuxSll(s) => s.payload().clone(), + EtherPayload(p) => LinuxSllPayloadSlice::from(p.clone()), + LinuxSllPayload(p) => p.clone() } } } @@ -60,7 +81,10 @@ mod test { proptest! { #[test] - fn to_header(ref eth in ethernet_2_unknown()) { + 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( @@ -71,6 +95,16 @@ mod test { 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, @@ -81,12 +115,25 @@ mod test { None ); } + { + let slice = LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice { + protocol_type: LinuxSllProtocolType::EtherType(ether_type::IPV4), + payload: &[] + }); + assert_eq!( + slice.to_header(), + None + ); + } } } proptest! { #[test] - fn payload(ref eth in ethernet_2_unknown()) { + 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()); @@ -96,21 +143,48 @@ mod test { Ethernet2Slice::from_slice_without_fcs(&bytes).unwrap() ); assert_eq!( - slice.payload(), + slice.ether_payload().unwrap(), EtherPayloadSlice{ ether_type: eth.ether_type, payload: &p } ); } { - let p = [1,2,3,4]; let slice = LinkSlice::EtherPayload(EtherPayloadSlice { ether_type: eth.ether_type, payload: &p }); assert_eq!( - slice.payload(), + 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());} + } + } } } } diff --git a/etherparse/src/link/linux_nonstandard_ether_type.rs b/etherparse/src/link/linux_nonstandard_ether_type.rs index 32cefd3e..42d419c5 100644 --- a/etherparse/src/link/linux_nonstandard_ether_type.rs +++ b/etherparse/src/link/linux_nonstandard_ether_type.rs @@ -16,7 +16,7 @@ /// assert_eq!(0x0001, num); /// ``` #[derive(Clone, Copy, Eq, PartialEq)] -pub struct LinuxNonstandardEtherType(u16); +pub struct LinuxNonstandardEtherType(pub(crate) u16); impl LinuxNonstandardEtherType { // Numbers sourced from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_ether.h?id=e33c4963bf536900f917fb65a687724d5539bc21 diff --git a/etherparse/src/link/linux_sll_payload_slice.rs b/etherparse/src/link/linux_sll_payload_slice.rs index 23ee3c65..e9bf4d59 100644 --- a/etherparse/src/link/linux_sll_payload_slice.rs +++ b/etherparse/src/link/linux_sll_payload_slice.rs @@ -1,5 +1,4 @@ -use crate::LinuxSllProtocolType; - +use crate::{EtherPayloadSlice, EtherType, LinuxSllProtocolType}; /// Payload of Linux Cooked Capture v1 (SLL) packet #[derive(Clone, Debug, Eq, PartialEq)] @@ -11,6 +10,36 @@ pub struct LinuxSllPayloadSlice<'a> { pub payload: &'a [u8], } +impl<'a> From> for LinuxSllPayloadSlice<'a> { + fn from(value: EtherPayloadSlice<'a>) -> LinuxSllPayloadSlice<'a> { + LinuxSllPayloadSlice { + protocol_type: LinuxSllProtocolType::EtherType(value.ether_type), + payload: value.payload + } + } +} + +impl<'a> TryFrom> for EtherPayloadSlice<'a> { + type Error = (); + + fn try_from(value: LinuxSllPayloadSlice<'a>) -> Result, Self::Error> { + match value.protocol_type { + LinuxSllProtocolType::LinuxNonstandardEtherType(nonstandard_ether_type) => { + Ok(EtherPayloadSlice { + ether_type: EtherType(nonstandard_ether_type.into()), + payload: value.payload + }) + }, + LinuxSllProtocolType::EtherType(ether_type) => { + Ok(EtherPayloadSlice { + ether_type, + payload: value.payload + }) + }, + _ => Err(()) + } + } +} #[cfg(test)] mod test { diff --git a/etherparse/src/sliced_packet.rs b/etherparse/src/sliced_packet.rs index 388eaaa2..b3b475c7 100644 --- a/etherparse/src/sliced_packet.rs +++ b/etherparse/src/sliced_packet.rs @@ -228,7 +228,19 @@ impl<'a> SlicedPacket<'a> { use LinkSlice::*; match link { Ethernet2(eth) => Some(eth.ether_type()), + LinkSlice::LinuxSll(e) => match e.protocol_type() { + LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { + Some(EtherType(v)) + } + _ => None + } EtherPayload(e) => Some(e.ether_type), + LinkSlice::LinuxSllPayload(e) => match e.protocol_type { + LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { + Some(EtherType(v)) + } + _ => None + } } } else { None @@ -246,10 +258,18 @@ impl<'a> SlicedPacket<'a> { VlanSlice::SingleVlan(s) => Some(s.payload()), VlanSlice::DoubleVlan(s) => Some(s.payload()), } - } else if let Some(eth) = self.link.as_ref() { - match eth { + } else if let Some(link) = self.link.as_ref() { + match link { LinkSlice::Ethernet2(e) => Some(e.payload()), + LinkSlice::LinuxSll(e) => match e.protocol_type() { + LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.payload()).ok()?), + _ => None + } LinkSlice::EtherPayload(e) => Some(e.clone()), + LinkSlice::LinuxSllPayload(e) => match e.protocol_type { + LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.clone()).ok()?), + _ => None + } } } else { None @@ -1204,7 +1224,9 @@ mod test { match result.link.as_ref() { Some(s) => match s { LinkSlice::Ethernet2(e) => Some(LinkHeader::Ethernet2(e.to_header())), + LinkSlice::LinuxSll(e) => Some(LinkHeader::LinuxSll(e.to_header())), LinkSlice::EtherPayload(_) => None, + LinkSlice::LinuxSllPayload(_) => None, }, None => None, } From 0f4603e25f90bab5683cef49ea31e62b83ee0721 Mon Sep 17 00:00:00 2001 From: Raul Rabadan Arroyo Date: Mon, 29 Apr 2024 20:03:26 +0200 Subject: [PATCH 16/21] add SlicedPacket::from_linux_sll --- README.md | 1 + .../proptest-regressions/sliced_packet.txt | 7 + etherparse/src/err/from_slice_error.rs | 68 ++++++++- etherparse/src/err/packet/slice_error.rs | 19 +++ etherparse/src/err/read_error.rs | 56 ++++++- etherparse/src/lib.rs | 1 + etherparse/src/sliced_packet.rs | 144 +++++++++++++++++- etherparse/src/sliced_packet_cursor.rs | 24 +++ 8 files changed, 313 insertions(+), 7 deletions(-) create mode 100644 etherparse/proptest-regressions/sliced_packet.txt diff --git a/README.md b/README.md index 70dd8081..52b22e91 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ This is the faster option if your code is not interested in all fields of all th Depending from which point downward you want to slice a package check out the functions: * [`SlicedPacket::from_ethernet`](https://docs.rs/etherparse/~0/etherparse/struct.SlicedPacket.html#method.from_ethernet) for parsing from an Ethernet II header downwards +* [`SlicedPacket::from_linux_sll`](https://docs.rs/etherparse/~0/etherparse/struct.SlicedPacket.html#method.from_linux_sll) for parsing from a Linux Cooked Capture v1 (SLL) downwards * [`SlicedPacket::from_ether_type`](https://docs.rs/etherparse/~0/etherparse/struct.SlicedPacket.html#method.from_ether_type) for parsing a slice starting after an Ethernet II header * [`SlicedPacket::from_ip`](https://docs.rs/etherparse/~0/etherparse/struct.SlicedPacket.html#method.from_ip) for parsing from an IPv4 or IPv6 downwards diff --git a/etherparse/proptest-regressions/sliced_packet.txt b/etherparse/proptest-regressions/sliced_packet.txt new file mode 100644 index 00000000..c09057b8 --- /dev/null +++ b/etherparse/proptest-regressions/sliced_packet.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc b196b71d1fd361e0dc02078dcedaa8e67bb496f2cb76ceddd1fa51ce90c70f6d # shrinks to ref eth = Ethernet2Header { source: [0, 0, 0, 0, 0, 0], destination: [0, 0, 0, 0, 0, 0], ether_type: 0x0000 }, ref linux_sll = LinuxSllHeader { packet_type: 0 (Sent to us), arp_hrd_type: 824 (Netlink header), sender_address_valid_length: 0, sender_address: [0, 0, 0, 0, 0, 0, 0, 0], protocol_type: NetlinkProtocolType(0) }, ref vlan_outer = SingleVlanHeader { pcp: VlanPcp(0), drop_eligible_indicator: false, vlan_id: VlanId(0), ether_type: 0x0000 }, ref vlan_inner = SingleVlanHeader { pcp: VlanPcp(0), drop_eligible_indicator: false, vlan_id: VlanId(0), ether_type: 0x0000 }, ref ipv4 = Ipv4Header { dscp: Ipv4Dscp(0), ecn: Ipv4Ecn(0), total_len: 60781, identification: 0, dont_fragment: false, more_fragments: false, fragment_offset: IpFragOffset(0), time_to_live: 0, protocol: 253 (Use for experimentation and testing), header_checksum: 128, source: [0, 0, 0, 0], destination: [0, 0, 0, 0], options: [] }, ref udp = UdpHeader { source_port: 24402, destination_port: 23948, length: 49051, checksum: 43062 } diff --git a/etherparse/src/err/from_slice_error.rs b/etherparse/src/err/from_slice_error.rs index aa307ec4..47d5339d 100644 --- a/etherparse/src/err/from_slice_error.rs +++ b/etherparse/src/err/from_slice_error.rs @@ -9,6 +9,9 @@ pub enum FromSliceError { /// not enough data being available). Len(LenError), + /// Error when decoding an Linux SLL header. + LinuxSll(linux_sll::HeaderError), + /// Error while parsing a double vlan header. DoubleVlan(double_vlan::HeaderError), @@ -38,6 +41,12 @@ impl FromSliceError { _ => None, } } + pub fn linux_sll(&self) -> Option<&linux_sll::HeaderError> { + match self { + FromSliceError::LinuxSll(err) => Some(err), + _ => None, + } + } pub fn double_vlan(&self) -> Option<&double_vlan::HeaderError> { match self { FromSliceError::DoubleVlan(err) => Some(err), @@ -87,6 +96,7 @@ impl core::fmt::Display for FromSliceError { use FromSliceError::*; match self { Len(err) => err.fmt(f), + LinuxSll(err) => err.fmt(f), DoubleVlan(err) => err.fmt(f), Ip(err) => err.fmt(f), IpAuth(err) => err.fmt(f), @@ -104,6 +114,7 @@ impl std::error::Error for FromSliceError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { FromSliceError::Len(err) => Some(err), + FromSliceError::LinuxSll(err) => Some(err), FromSliceError::DoubleVlan(err) => Some(err), FromSliceError::Ip(err) => Some(err), FromSliceError::IpAuth(err) => Some(err), @@ -123,6 +134,25 @@ impl From for FromSliceError { } } +// linux sll conversions + +impl From for FromSliceError { + fn from(value: linux_sll::HeaderError) -> Self { + FromSliceError::LinuxSll(value) + } +} + +impl From for FromSliceError { + fn from(value: linux_sll::HeaderSliceError) -> Self { + use linux_sll::HeaderSliceError::*; + match value { + Len(err) => FromSliceError::Len(err), + Content(err) => FromSliceError::LinuxSll(err), + } + } +} + + // double vlan error conversions impl From for FromSliceError { @@ -280,6 +310,7 @@ impl From for FromSliceError { use packet::SliceError::*; match value { Len(err) => FromSliceError::Len(err), + LinuxSll(err) => FromSliceError::LinuxSll(err), Ip(err) => FromSliceError::Ip(err), Ipv4(err) => FromSliceError::Ipv4(err), Ipv6(err) => FromSliceError::Ipv6(err), @@ -310,7 +341,7 @@ impl From for FromSliceError { #[cfg(test)] mod tests { - use crate::{EtherType, LenSource}; + use crate::{ArpHardwareId, EtherType, LenSource}; use super::{FromSliceError::*, *}; use core::hash::{Hash, Hasher}; @@ -395,7 +426,7 @@ mod tests { #[test] fn display_source() { - let test_values: [FromSliceError; 8] = [ + let test_values: [FromSliceError; 9] = [ Len(LenError { required_len: 0, len: 0, @@ -403,6 +434,7 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }), + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), }), @@ -431,6 +463,7 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }; + let linux_sll_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; let double_vlan_error = || double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(1), }; @@ -445,6 +478,10 @@ mod tests { assert_eq!(Len(len_error()).len(), Some(&len_error())); assert_eq!(Ipv4(ipv4_error()).len(), None); + // linux_sll + assert_eq!(LinuxSll(linux_sll_error()).linux_sll(), Some(&linux_sll_error())); + assert_eq!(Ipv4(ipv4_error()).linux_sll(), None); + // double_vlan assert_eq!( DoubleVlan(double_vlan_error()).double_vlan(), @@ -498,6 +535,33 @@ mod tests { FromSliceError::from(len_error()).len().unwrap() ); + // linux sll + { + let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; + assert_eq!( + &header_error(), + FromSliceError::from(header_error()).linux_sll().unwrap() + ); + assert_eq!( + &header_error(), + FromSliceError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + assert_eq!( + &len_error(), + FromSliceError::from(linux_sll::HeaderSliceError::Len(len_error())) + .len() + .unwrap() + ); + assert_eq!( + &header_error(), + FromSliceError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + } + // double vlan errors { let header_error = || double_vlan::HeaderError::NonVlanEtherType { diff --git a/etherparse/src/err/packet/slice_error.rs b/etherparse/src/err/packet/slice_error.rs index 374304f5..4f115188 100644 --- a/etherparse/src/err/packet/slice_error.rs +++ b/etherparse/src/err/packet/slice_error.rs @@ -6,6 +6,8 @@ use crate::*; pub enum SliceError { /// Length related errors (e.g. not enough data in slice). Len(err::LenError), + /// Error when decoding an Linux SLL header. + LinuxSll(err::linux_sll::HeaderError), /// Error when decoding starting at an IP header (v4 or v6). Ip(err::ip::HeaderError), /// Error when decoding an IPv4 header. @@ -26,6 +28,7 @@ impl core::fmt::Display for SliceError { match self { Len(err) => err.fmt(f), + LinuxSll(err) => err.fmt(f), Ip(err) => err.fmt(f), Ipv4(err) => err.fmt(f), Ipv6(err) => err.fmt(f), @@ -43,6 +46,7 @@ impl std::error::Error for SliceError { use SliceError::*; match self { Len(err) => Some(err), + LinuxSll(err) => Some(err), Ip(err) => Some(err), Ipv4(err) => Some(err), Ipv6(err) => Some(err), @@ -104,6 +108,15 @@ mod tests { assert_eq!(format!("{}", err), format!("{}", Len(err))); } + // Linux SLL Header + { + let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ADAPT }; + assert_eq!( + format!("{}", err), + format!("{}", err::packet::SliceError::LinuxSll(err)) + ); + } + // IpHeader { let err = err::ip::HeaderError::UnsupportedIpVersion { version_number: 1 }; @@ -159,6 +172,12 @@ mod tests { assert!(Len(err).source().is_some()); } + // IpHeaders + { + let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; + assert!(LinuxSll(err).source().is_some()); + } + // IpHeaders { let err = err::ip::HeaderError::UnsupportedIpVersion { version_number: 1 }; diff --git a/etherparse/src/err/read_error.rs b/etherparse/src/err/read_error.rs index 8378cd08..3292f505 100644 --- a/etherparse/src/err/read_error.rs +++ b/etherparse/src/err/read_error.rs @@ -418,6 +418,7 @@ impl From for ReadError { use packet::SliceError::*; match value { Len(err) => ReadError::Len(err), + LinuxSll(err) => ReadError::LinuxSll(err), Ip(err) => ReadError::Ip(err), Ipv4(err) => ReadError::Ipv4(err), Ipv6(err) => ReadError::Ipv6(err), @@ -460,7 +461,7 @@ impl From for ReadError { #[cfg(test)] mod tests { - use crate::EtherType; + use crate::{ArpHardwareId, EtherType}; use crate::{ err::{ReadError::*, *}, LenSource, @@ -470,7 +471,7 @@ mod tests { #[test] fn debug_source() { - let test_values: [(&str, ReadError); 9] = [ + let test_values: [(&str, ReadError); 10] = [ ( "Len", Len(LenError { @@ -481,6 +482,10 @@ mod tests { layer_start_offset: 0, }), ), + ( + "LinuxSll", + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }) + ), ( "DoubleVlan", DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { @@ -534,7 +539,7 @@ mod tests { #[test] fn display_source() { - let test_values: [ReadError; 9] = [ + let test_values: [ReadError; 10] = [ Len(LenError { required_len: 0, len: 0, @@ -542,6 +547,7 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }), + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), }), @@ -597,6 +603,10 @@ mod tests { assert_eq!(Len(len_error()).len(), Some(&len_error())); assert_eq!(Ipv4(ipv4_error()).len(), None); + // linux sll + assert_eq!(LinuxSll(linux_sll_error()).linux_sll(), Some(&linux_sll_error())); + assert_eq!(Ipv4(ipv4_error()).linux_sll(), None); + // double_vlan assert_eq!( DoubleVlan(double_vlan_error()).double_vlan(), @@ -657,6 +667,46 @@ mod tests { assert!(ReadError::from(io_error()).io().is_some()); assert_eq!(&len_error(), ReadError::from(len_error()).len().unwrap()); + // linux sll + { + let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER + }; + assert_eq!( + &header_error(), + ReadError::from(header_error()).linux_sll().unwrap() + ); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderReadError::Content(header_error())) + .linux_sll() + .unwrap() + ); + assert!( + ReadError::from(linux_sll::HeaderReadError::Io(io_error())) + .io() + .is_some() + ); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + assert_eq!( + &len_error(), + ReadError::from(linux_sll::HeaderSliceError::Len(len_error())) + .len() + .unwrap() + ); + assert_eq!( + &header_error(), + ReadError::from(linux_sll::HeaderSliceError::Content(header_error())) + .linux_sll() + .unwrap() + ); + } + // double vlan errors { let header_error = || double_vlan::HeaderError::NonVlanEtherType { diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 6e8cf021..4897431b 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -65,6 +65,7 @@ //! Depending from which point downward you want to slice a package check out the functions: //! //! * [`SlicedPacket::from_ethernet`] for parsing from an Ethernet II header downwards +//! * [`SlicedPacket::from_linux_sll`] for parsing from a Linux Cooked Capture v1 (SLL) downwards //! * [`SlicedPacket::from_ether_type`] for parsing a slice starting after an Ethernet II header //! * [`SlicedPacket::from_ip`] for parsing from an IPv4 or IPv6 downwards //! diff --git a/etherparse/src/sliced_packet.rs b/etherparse/src/sliced_packet.rs index b3b475c7..346dad41 100644 --- a/etherparse/src/sliced_packet.rs +++ b/etherparse/src/sliced_packet.rs @@ -94,6 +94,48 @@ impl<'a> SlicedPacket<'a> { SlicedPacketCursor::new(data).slice_ethernet2() } + /// Separates a network packet slice into different slices containing the + /// headers from the Linux Cooked Capture v1 (SLL) header downwards. + /// + /// The result is returned as a [`SlicedPacket`] struct. This function + /// assumes the given data starts with a Linux Cooked Capture v1 (SLL) + /// header. + /// + /// # Examples + /// + /// Basic usage: + /// + ///``` + /// # use etherparse::{SlicedPacket, PacketBuilder, LinuxSllPacketType}; + /// # let builder = PacketBuilder:: + /// # linux_sll(LinuxSllPacketType::OTHERHOST, //packet type + /// # 6, //sender address valid length + /// # [1,2,3,4,5,6,0,0]) //sender address with padding + /// # .ipv4([192,168,1,1], //source ip + /// # [192,168,1,2], //destination ip + /// # 20) //time to life + /// # .udp(21, //source port + /// # 1234); //destination port + /// # //payload of the udp packet + /// # let payload = [1,2,3,4,5,6,7,8]; + /// # //get some memory to store the serialized data + /// # let mut packet = Vec::::with_capacity( + /// # builder.size(payload.len())); + /// # builder.write(&mut packet, &payload).unwrap(); + /// match SlicedPacket::from_linux_sll(&packet) { + /// Err(value) => println!("Err {:?}", value), + /// Ok(value) => { + /// println!("link: {:?}", value.link); + /// println!("vlan: {:?}", value.vlan); + /// println!("net: {:?}", value.net); + /// println!("transport: {:?}", value.transport); + /// } + /// } + /// ``` + pub fn from_linux_sll(data: &'a [u8]) -> Result { + SlicedPacketCursor::new(data).slice_linux_sll() + } + /// Separates a network packet slice into different slices containing the headers using /// the given `ether_type` number to identify the first header. /// @@ -392,6 +434,51 @@ mod test { ); } + // only linux_sll payload + { + let payload = [1, 2, 3, 4]; + let mut buf = Vec::with_capacity(LinuxSllHeader::LEN + 4); + buf.extend_from_slice( + &LinuxSllHeader { + packet_type: LinuxSllPacketType::HOST, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length: 6, + sender_address: [1, 2, 3, 4, 5, 6, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN) + } + .to_bytes(), + ); + buf.extend_from_slice(&payload); + assert_eq!( + SlicedPacket::from_linux_sll(&buf).unwrap().ether_payload(), + Some(EtherPayloadSlice { + ether_type: EtherType::WAKE_ON_LAN, + payload: &payload + }) + ); + } + + // ether type payload + { + let payload = [1, 2, 3, 4]; + assert_eq!( + SlicedPacket { + link: Some(LinkSlice::LinuxSllPayload(LinuxSllPayloadSlice { + protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN), + payload: &payload + })), + vlan: None, + net: None, + transport: None, + } + .ether_payload(), + Some(EtherPayloadSlice { + ether_type: EtherType::WAKE_ON_LAN, + payload: &payload + }) + ); + } + // single vlan header { let payload = [1, 2, 3, 4]; @@ -564,6 +651,39 @@ mod test { } } } + + // linux_sll + { + let linux_sll = LinuxSllHeader { + packet_type: LinuxSllPacketType::HOST, + arp_hrd_type: ArpHardwareId::ETHER, + sender_address_valid_length: 6, + sender_address: [1, 2, 3, 4, 5, 6, 0, 0], + protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN) + }; + let test = TestPacket { + link: Some(LinkHeader::LinuxSll(linux_sll.clone())), + vlan: None, + net: None, + transport: None, + }; + + // eth len error + { + let data = test.to_vec(&[]); + for len in 0..data.len() { + let err = LenError { + required_len: linux_sll.header_len(), + len, + len_source: LenSource::Slice, + layer: Layer::LinuxSllHeader, + layer_start_offset: 0, + }; + + from_slice_assert_err(&test, &data[..len], SliceError::Len(err.clone())); + } + } + } } fn from_x_slice_vlan_variants(base: &TestPacket) { @@ -1331,8 +1451,11 @@ mod test { /// data. fn from_slice_assert_err(test: &TestPacket, data: &[u8], err: SliceError) { // from_ethernet_slice - if test.link.is_some() { - assert_eq!(err.clone(), SlicedPacket::from_ethernet(&data).unwrap_err()); + if let Some(ref header) = test.link { + match header { + LinkHeader::Ethernet2(_) => assert_eq!(err.clone(), SlicedPacket::from_ethernet(&data).unwrap_err()), + LinkHeader::LinuxSll(_) => assert_eq!(err.clone(), SlicedPacket::from_linux_sll(&data).unwrap_err()), + } } // from_ether_type (vlan at start) if test.link.is_none() && test.vlan.is_some() { @@ -1367,6 +1490,7 @@ mod test { #[test] fn payload_ether_type( ref eth in ethernet_2_unknown(), + ref linux_sll in linux_sll_any(), ref vlan_outer in vlan_single_unknown(), ref vlan_inner in vlan_single_unknown(), ref ipv4 in ipv4_unknown(), @@ -1386,6 +1510,22 @@ mod test { assert_eq!(None, s.payload_ether_type()); } + // only linux sll + { + let mut serialized = Vec::with_capacity(linux_sll.header_len()); + eth.write(&mut serialized).unwrap(); + let ether_type = match linux_sll.protocol_type { + LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => Some(EtherType(v)), + _ => None, + }; + if let Ok(s) = SlicedPacket::from_linux_sll(&serialized) { + assert_eq!( + ether_type, + s.payload_ether_type() + ); + } + } + // only ethernet { let mut serialized = Vec::with_capacity(eth.header_len()); diff --git a/etherparse/src/sliced_packet_cursor.rs b/etherparse/src/sliced_packet_cursor.rs index b8bcc355..3ae3d34d 100644 --- a/etherparse/src/sliced_packet_cursor.rs +++ b/etherparse/src/sliced_packet_cursor.rs @@ -55,6 +55,30 @@ impl<'a> SlicedPacketCursor<'a> { } } + pub fn slice_linux_sll(mut self) -> Result, err::packet::SliceError> { + use err::packet::SliceError::*; + + let result = LinuxSllSlice::from_slice(self.slice) + .map_err(|err| match err { + err::linux_sll::HeaderSliceError::Len(len) => Len(len.add_offset(self.offset)), + err::linux_sll::HeaderSliceError::Content(content) => err::packet::SliceError::LinuxSll(content), + })?; + + //cache the protocol type for later + let protocol_type = result.protocol_type(); + + //set the new data + self.move_by(result.header_len()); + self.result.link = Some(LinkSlice::LinuxSll(result)); + + //continue parsing (if required) + match protocol_type { + LinuxSllProtocolType::EtherType(EtherType::IPV4) => self.slice_ipv4(), + LinuxSllProtocolType::EtherType(EtherType::IPV6) => self.slice_ipv6(), + _ => Ok(self.result), + } + } + pub fn slice_vlan(mut self) -> Result, err::packet::SliceError> { use err::packet::SliceError::*; use ether_type::*; From 34f3e4528664a469fa9a92e4292f0cbd8d78a640 Mon Sep 17 00:00:00 2001 From: Julian Schmid Date: Thu, 2 May 2024 07:45:15 +0200 Subject: [PATCH 17/21] Minor fixes for non-std support --- etherparse/src/link/linux_sll_header.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index a151bbab..9ff650b8 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -24,7 +24,7 @@ impl LinuxSllHeader { /// Read an SLL header from a slice and return the header & unused parts of the slice. #[inline] - pub fn from_slice(slice: &[u8]) -> Result<(LinuxSllHeader, &[u8]), err::ReadError> { + pub fn from_slice(slice: &[u8]) -> Result<(LinuxSllHeader, &[u8]), err::linux_sll::HeaderSliceError> { Ok(( LinuxSllHeaderSlice::from_slice(slice)?.to_header(), &slice[LinuxSllHeader::LEN..], @@ -34,11 +34,13 @@ impl LinuxSllHeader { /// Read an SLL header from a static sized byte array. #[inline] pub fn from_bytes(bytes: [u8; 16]) -> Result { - let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]]))?; + use err::linux_sll::HeaderSliceError::Content; + + let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]])).map_err(Content)?; let arp_hrd_type = ArpHardwareId::from(u16::from_be_bytes([bytes[2], bytes[3]])); let sender_address_valid_length = u16::from_be_bytes([bytes[4], bytes[5]]); let sender_address = [bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13]]; - let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]])))?; + let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]]))).map_err(Content)?; Ok(LinuxSllHeader { packet_type, From 3a5e3d8ba62577b141ea3eb797acc377f690f4e1 Mon Sep 17 00:00:00 2001 From: Julian Schmid Date: Thu, 2 May 2024 20:28:46 +0200 Subject: [PATCH 18/21] Resolved test compiler error --- etherparse/src/link/linux_sll_header.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index 9ff650b8..713f7699 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -163,14 +163,14 @@ mod test { // call with not enough data in the slice for len in 0..=13 { assert_eq!( - LinuxSllHeader::from_slice(&buffer[..len]).unwrap_err().len().unwrap().to_owned(), - err::LenError{ + LinuxSllHeader::from_slice(&buffer[..len]).unwrap_err(), + err::linux_sll::HeaderSliceError::Len(err::LenError{ required_len: LinuxSllHeader::LEN, len: len, len_source: LenSource::Slice, layer: err::Layer::LinuxSllHeader, layer_start_offset: 0, - } + }) ); } } From 41cdb2aa5c710ddb19154d9343aa5cdb9762759a Mon Sep 17 00:00:00 2001 From: Julian Schmid Date: Thu, 2 May 2024 20:33:13 +0200 Subject: [PATCH 19/21] Resolved compiler warnings --- etherparse/src/err/double_vlan/header_slice_error.rs | 2 +- etherparse/src/err/ip/headers_read_error.rs | 2 +- etherparse/src/err/ip/headers_slice_error.rs | 2 +- etherparse/src/err/ip/lax_header_slice_error.rs | 2 +- etherparse/src/err/ip_auth/header_slice_error.rs | 2 +- etherparse/src/err/ip_exts/headers_slice_error.rs | 2 +- etherparse/src/err/ipv4/header_slice_error.rs | 2 +- etherparse/src/err/ipv4/slice_error.rs | 2 +- etherparse/src/err/ipv6/header_slice_error.rs | 2 +- etherparse/src/err/ipv6/slice_error.rs | 2 +- etherparse/src/err/ipv6_exts/header_slice_error.rs | 2 +- etherparse/src/err/layer.rs | 2 +- etherparse/src/err/len_error.rs | 1 - etherparse/src/err/linux_sll/header_slice_error.rs | 2 +- etherparse/src/err/packet/slice_error.rs | 2 +- etherparse/src/err/slice_write_space_error.rs | 1 - etherparse/src/err/tcp/header_slice_error.rs | 2 +- etherparse/src/err/value_too_big_error.rs | 2 +- etherparse/src/lax_packet_headers.rs | 1 - etherparse/src/lax_sliced_packet.rs | 2 +- etherparse/src/len_source.rs | 2 +- etherparse/src/link/linux_sll_header.rs | 2 +- etherparse/src/link/linux_sll_packet_type.rs | 2 -- etherparse/src/link/linux_sll_payload_slice.rs | 2 -- etherparse/src/net/ipv4_slice.rs | 2 +- etherparse/src/net/ipv6_slice.rs | 1 - etherparse/src/net/lax_ipv4_slice.rs | 2 +- etherparse/src/net/lax_ipv6_slice.rs | 1 - etherparse/src/packet_headers.rs | 2 +- etherparse/src/transport/transport_slice.rs | 1 - 30 files changed, 22 insertions(+), 32 deletions(-) diff --git a/etherparse/src/err/double_vlan/header_slice_error.rs b/etherparse/src/err/double_vlan/header_slice_error.rs index 88b8ebe5..f0e3a51d 100644 --- a/etherparse/src/err/double_vlan/header_slice_error.rs +++ b/etherparse/src/err/double_vlan/header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ip/headers_read_error.rs b/etherparse/src/err/ip/headers_read_error.rs index a0d51f98..051df5e5 100644 --- a/etherparse/src/err/ip/headers_read_error.rs +++ b/etherparse/src/err/ip/headers_read_error.rs @@ -85,7 +85,7 @@ impl std::error::Error for HeaderReadError { mod test { use super::{super::HeaderError::*, super::HeadersError::*, HeaderReadError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ip/headers_slice_error.rs b/etherparse/src/err/ip/headers_slice_error.rs index 3cb6dbe0..ac141527 100644 --- a/etherparse/src/err/ip/headers_slice_error.rs +++ b/etherparse/src/err/ip/headers_slice_error.rs @@ -54,7 +54,7 @@ mod tests { *, }; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ip/lax_header_slice_error.rs b/etherparse/src/err/ip/lax_header_slice_error.rs index f248cd1f..6cc6aac6 100644 --- a/etherparse/src/err/ip/lax_header_slice_error.rs +++ b/etherparse/src/err/ip/lax_header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for LaxHeaderSliceError { mod tests { use super::{super::HeaderError::*, LaxHeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ip_auth/header_slice_error.rs b/etherparse/src/err/ip_auth/header_slice_error.rs index e6d75ee4..61436657 100644 --- a/etherparse/src/err/ip_auth/header_slice_error.rs +++ b/etherparse/src/err/ip_auth/header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ip_exts/headers_slice_error.rs b/etherparse/src/err/ip_exts/headers_slice_error.rs index 5882566b..77ea0e81 100644 --- a/etherparse/src/err/ip_exts/headers_slice_error.rs +++ b/etherparse/src/err/ip_exts/headers_slice_error.rs @@ -58,7 +58,7 @@ impl std::error::Error for HeadersSliceError { mod tests { use super::{HeadersSliceError::*, *}; use crate::{ - err::{ipv6_exts::HeaderError::*, Layer, LenError}, + err::{ipv6_exts::HeaderError::*, Layer}, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ipv4/header_slice_error.rs b/etherparse/src/err/ipv4/header_slice_error.rs index 20c6c03a..fd563e6c 100644 --- a/etherparse/src/err/ipv4/header_slice_error.rs +++ b/etherparse/src/err/ipv4/header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ipv4/slice_error.rs b/etherparse/src/err/ipv4/slice_error.rs index d4fbf920..d698fb8f 100644 --- a/etherparse/src/err/ipv4/slice_error.rs +++ b/etherparse/src/err/ipv4/slice_error.rs @@ -41,7 +41,7 @@ impl std::error::Error for SliceError { mod tests { use super::{super::HeaderError, SliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ipv6/header_slice_error.rs b/etherparse/src/err/ipv6/header_slice_error.rs index d6ed5873..355d5b75 100644 --- a/etherparse/src/err/ipv6/header_slice_error.rs +++ b/etherparse/src/err/ipv6/header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ipv6/slice_error.rs b/etherparse/src/err/ipv6/slice_error.rs index d30e0854..091a060e 100644 --- a/etherparse/src/err/ipv6/slice_error.rs +++ b/etherparse/src/err/ipv6/slice_error.rs @@ -41,7 +41,7 @@ impl std::error::Error for SliceError { mod tests { use super::{super::HeaderError, SliceError::*, *}; use crate::{ - err::{ip_auth, Layer, LenError}, + err::{ip_auth, Layer}, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/ipv6_exts/header_slice_error.rs b/etherparse/src/err/ipv6_exts/header_slice_error.rs index 18039d18..92f15e69 100644 --- a/etherparse/src/err/ipv6_exts/header_slice_error.rs +++ b/etherparse/src/err/ipv6_exts/header_slice_error.rs @@ -68,7 +68,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/layer.rs b/etherparse/src/err/layer.rs index 5b46d47f..16e2ce2c 100644 --- a/etherparse/src/err/layer.rs +++ b/etherparse/src/err/layer.rs @@ -113,7 +113,7 @@ mod test { use super::Layer::*; use alloc::format; use std::{ - cmp::{Ord, Ordering}, + cmp::Ordering, collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; diff --git a/etherparse/src/err/len_error.rs b/etherparse/src/err/len_error.rs index 0a3cc61b..bf60e152 100644 --- a/etherparse/src/err/len_error.rs +++ b/etherparse/src/err/len_error.rs @@ -148,7 +148,6 @@ impl std::error::Error for LenError { #[cfg(test)] mod test { use super::*; - use crate::err::Layer; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/linux_sll/header_slice_error.rs b/etherparse/src/err/linux_sll/header_slice_error.rs index 9accd33a..87e8f484 100644 --- a/etherparse/src/err/linux_sll/header_slice_error.rs +++ b/etherparse/src/err/linux_sll/header_slice_error.rs @@ -50,7 +50,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/packet/slice_error.rs b/etherparse/src/err/packet/slice_error.rs index 4f115188..7651171b 100644 --- a/etherparse/src/err/packet/slice_error.rs +++ b/etherparse/src/err/packet/slice_error.rs @@ -60,7 +60,7 @@ impl std::error::Error for SliceError { #[cfg(test)] mod tests { use super::{SliceError::*, *}; - use crate::{err::Layer, LenSource}; + use crate::err::Layer; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/slice_write_space_error.rs b/etherparse/src/err/slice_write_space_error.rs index aaaeb352..15bed005 100644 --- a/etherparse/src/err/slice_write_space_error.rs +++ b/etherparse/src/err/slice_write_space_error.rs @@ -54,7 +54,6 @@ impl std::error::Error for SliceWriteSpaceError { #[cfg(test)] mod test { use super::*; - use crate::err::Layer; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/tcp/header_slice_error.rs b/etherparse/src/err/tcp/header_slice_error.rs index 7b092990..e0113a11 100644 --- a/etherparse/src/err/tcp/header_slice_error.rs +++ b/etherparse/src/err/tcp/header_slice_error.rs @@ -49,7 +49,7 @@ impl std::error::Error for HeaderSliceError { mod tests { use super::{HeaderSliceError::*, *}; use crate::{ - err::{Layer, LenError}, + err::Layer, LenSource, }; use alloc::format; diff --git a/etherparse/src/err/value_too_big_error.rs b/etherparse/src/err/value_too_big_error.rs index 18cc9970..bedbf95d 100644 --- a/etherparse/src/err/value_too_big_error.rs +++ b/etherparse/src/err/value_too_big_error.rs @@ -45,7 +45,7 @@ mod test { collections::hash_map::DefaultHasher, error::Error, format, - hash::{Hash, Hasher}, + hash::Hasher, }; #[test] diff --git a/etherparse/src/lax_packet_headers.rs b/etherparse/src/lax_packet_headers.rs index 30a9aa41..3b0685af 100644 --- a/etherparse/src/lax_packet_headers.rs +++ b/etherparse/src/lax_packet_headers.rs @@ -569,7 +569,6 @@ impl<'a> LaxPacketHeaders<'a> { #[cfg(test)] mod test { use super::*; - use crate::err::{packet::SliceError, Layer, LenError}; use crate::test_packet::TestPacket; const VLAN_ETHER_TYPES: [EtherType; 3] = [ diff --git a/etherparse/src/lax_sliced_packet.rs b/etherparse/src/lax_sliced_packet.rs index 8818a355..be1fe146 100644 --- a/etherparse/src/lax_sliced_packet.rs +++ b/etherparse/src/lax_sliced_packet.rs @@ -268,7 +268,7 @@ impl<'a> LaxSlicedPacket<'a> { #[cfg(test)] mod test { use super::*; - use crate::err::{packet::SliceError, Layer, LenError}; + use crate::err::{packet::SliceError, LenError}; use crate::test_packet::TestPacket; const VLAN_ETHER_TYPES: [EtherType; 3] = [ diff --git a/etherparse/src/len_source.rs b/etherparse/src/len_source.rs index 649d98f9..45d00393 100644 --- a/etherparse/src/len_source.rs +++ b/etherparse/src/len_source.rs @@ -19,7 +19,7 @@ mod test { use super::LenSource::*; use alloc::format; use std::{ - cmp::{Ord, Ordering}, + cmp::Ordering, collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index 713f7699..bec9c157 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -138,7 +138,7 @@ impl LinuxSllHeader { mod test { use super::*; use crate::{test_gens::*, LenSource}; - use alloc::{borrow::ToOwned, format, vec::Vec}; + use alloc::{format, vec::Vec}; use proptest::prelude::*; use std::io::{Cursor, ErrorKind}; diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs index 81724684..f7a3fec1 100644 --- a/etherparse/src/link/linux_sll_packet_type.rs +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -90,9 +90,7 @@ impl core::fmt::Debug for LinuxSllPacketType { #[cfg(test)] mod test { use alloc::format; - use super::*; - use crate::err::{self}; #[test] fn to_u16() { diff --git a/etherparse/src/link/linux_sll_payload_slice.rs b/etherparse/src/link/linux_sll_payload_slice.rs index e9bf4d59..26b1b7a0 100644 --- a/etherparse/src/link/linux_sll_payload_slice.rs +++ b/etherparse/src/link/linux_sll_payload_slice.rs @@ -43,8 +43,6 @@ impl<'a> TryFrom> for EtherPayloadSlice<'a> { #[cfg(test)] mod test { - use crate::EtherType; - use super::*; use alloc::format; diff --git a/etherparse/src/net/ipv4_slice.rs b/etherparse/src/net/ipv4_slice.rs index 57fb05b9..e22a566a 100644 --- a/etherparse/src/net/ipv4_slice.rs +++ b/etherparse/src/net/ipv4_slice.rs @@ -154,7 +154,7 @@ impl<'a> Ipv4Slice<'a> { #[cfg(test)] mod test { use super::*; - use crate::{ip_number, test_gens::*, Ipv4Header}; + use crate::test_gens::*; use alloc::{format, vec::Vec}; use proptest::prelude::*; diff --git a/etherparse/src/net/ipv6_slice.rs b/etherparse/src/net/ipv6_slice.rs index 6ee99b9d..68eaac33 100644 --- a/etherparse/src/net/ipv6_slice.rs +++ b/etherparse/src/net/ipv6_slice.rs @@ -251,7 +251,6 @@ mod test { use crate::{ ip_number::{AUTH, IGMP, UDP}, test_gens::*, - Ipv6FragmentHeader, }; use alloc::{format, vec::Vec}; use proptest::prelude::*; diff --git a/etherparse/src/net/lax_ipv4_slice.rs b/etherparse/src/net/lax_ipv4_slice.rs index 0cd1a3d1..2c73f58c 100644 --- a/etherparse/src/net/lax_ipv4_slice.rs +++ b/etherparse/src/net/lax_ipv4_slice.rs @@ -234,7 +234,7 @@ impl<'a> LaxIpv4Slice<'a> { #[cfg(test)] mod test { use super::*; - use crate::{err::LenError, ip_number::AUTH, test_gens::*, IpHeaders, Ipv4Header}; + use crate::{err::LenError, ip_number::AUTH, test_gens::*}; use alloc::{format, vec::Vec}; use proptest::prelude::*; diff --git a/etherparse/src/net/lax_ipv6_slice.rs b/etherparse/src/net/lax_ipv6_slice.rs index c5c10468..a9403feb 100644 --- a/etherparse/src/net/lax_ipv6_slice.rs +++ b/etherparse/src/net/lax_ipv6_slice.rs @@ -184,7 +184,6 @@ mod test { err::{Layer, LenError}, ip_number::{AUTH, IGMP, UDP}, test_gens::*, - Ipv6FragmentHeader, }; use alloc::{format, vec::Vec}; use proptest::prelude::*; diff --git a/etherparse/src/packet_headers.rs b/etherparse/src/packet_headers.rs index 5ab033e3..7e58a152 100644 --- a/etherparse/src/packet_headers.rs +++ b/etherparse/src/packet_headers.rs @@ -419,7 +419,7 @@ fn read_transport( #[cfg(test)] mod test { use super::*; - use crate::err::{packet::SliceError, LenError}; + use crate::err::{packet::SliceError}; use crate::test_packet::TestPacket; const VLAN_ETHER_TYPES: [EtherType; 3] = [ diff --git a/etherparse/src/transport/transport_slice.rs b/etherparse/src/transport/transport_slice.rs index 619bfe50..a7b46b51 100644 --- a/etherparse/src/transport/transport_slice.rs +++ b/etherparse/src/transport/transport_slice.rs @@ -15,7 +15,6 @@ pub enum TransportSlice<'a> { #[cfg(test)] mod test { use super::*; - use crate::{TcpHeader, UdpHeader}; use alloc::{format, vec::Vec}; #[test] From 3c712ec96b1bd3bf9172474eedb5ab87184cc88c Mon Sep 17 00:00:00 2001 From: Julian Schmid Date: Thu, 2 May 2024 20:49:55 +0200 Subject: [PATCH 20/21] Resolved no std compile error --- etherparse/src/link/linux_sll_header.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index bec9c157..dd340bba 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -33,14 +33,12 @@ impl LinuxSllHeader { /// Read an SLL header from a static sized byte array. #[inline] - pub fn from_bytes(bytes: [u8; 16]) -> Result { - use err::linux_sll::HeaderSliceError::Content; - - let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]])).map_err(Content)?; + pub fn from_bytes(bytes: [u8; 16]) -> Result { + let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]]))?; let arp_hrd_type = ArpHardwareId::from(u16::from_be_bytes([bytes[2], bytes[3]])); let sender_address_valid_length = u16::from_be_bytes([bytes[4], bytes[5]]); let sender_address = [bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13]]; - let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]]))).map_err(Content)?; + let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]])))?; Ok(LinuxSllHeader { packet_type, From 1e764964ac3f5010998975d83892c0bcc71afd98 Mon Sep 17 00:00:00 2001 From: Julian Schmid Date: Thu, 2 May 2024 20:50:10 +0200 Subject: [PATCH 21/21] Applied rust fmt --- etherparse/examples/read_by_slicing.rs | 5 +- etherparse/src/compositions_tests.rs | 14 +- .../src/err/double_vlan/header_slice_error.rs | 5 +- etherparse/src/err/from_slice_error.rs | 22 +- etherparse/src/err/ip/headers_read_error.rs | 5 +- etherparse/src/err/ip/headers_slice_error.rs | 5 +- .../src/err/ip/lax_header_slice_error.rs | 5 +- .../src/err/ip_auth/header_slice_error.rs | 5 +- etherparse/src/err/ipv4/header_slice_error.rs | 5 +- etherparse/src/err/ipv4/slice_error.rs | 5 +- etherparse/src/err/ipv6/header_slice_error.rs | 5 +- .../src/err/ipv6_exts/header_slice_error.rs | 5 +- etherparse/src/err/linux_sll/header_error.rs | 18 +- .../src/err/linux_sll/header_read_error.rs | 18 +- .../src/err/linux_sll/header_slice_error.rs | 15 +- etherparse/src/err/mod.rs | 2 +- etherparse/src/err/packet/slice_error.rs | 8 +- etherparse/src/err/read_error.rs | 35 +- etherparse/src/err/tcp/header_slice_error.rs | 5 +- etherparse/src/err/value_too_big_error.rs | 7 +- etherparse/src/err/value_type.rs | 2 +- etherparse/src/lax_sliced_packet.rs | 18 +- etherparse/src/lib.rs | 6 +- etherparse/src/link/arp_hardware_id.rs | 39 ++- etherparse/src/link/link_header.rs | 14 +- etherparse/src/link/link_slice.rs | 8 +- .../src/link/linux_nonstandard_ether_type.rs | 320 ++++++++++++++---- etherparse/src/link/linux_sll_header.rs | 22 +- etherparse/src/link/linux_sll_header_slice.rs | 24 +- etherparse/src/link/linux_sll_packet_type.rs | 64 +++- .../src/link/linux_sll_payload_slice.rs | 18 +- .../src/link/linux_sll_protocol_type.rs | 68 +++- etherparse/src/link/linux_sll_slice.rs | 36 +- etherparse/src/link/mod.rs | 6 +- etherparse/src/packet_builder.rs | 8 +- etherparse/src/packet_headers.rs | 2 +- etherparse/src/sliced_packet.rs | 57 ++-- etherparse/src/sliced_packet_cursor.rs | 11 +- etherparse/src/test_gens/mod.rs | 2 +- etherparse/src/test_packet.rs | 4 +- 40 files changed, 609 insertions(+), 314 deletions(-) diff --git a/etherparse/examples/read_by_slicing.rs b/etherparse/examples/read_by_slicing.rs index dcf2bb07..f9299daa 100644 --- a/etherparse/examples/read_by_slicing.rs +++ b/etherparse/examples/read_by_slicing.rs @@ -53,7 +53,10 @@ fn main() { println!(" EtherPayload (ether type {:?})", payload.ether_type) } Some(LinuxSllPayload(payload)) => { - println!(" LinuxSllPayload (protocol type {:?})", payload.protocol_type) + println!( + " LinuxSllPayload (protocol type {:?})", + payload.protocol_type + ) } None => {} } diff --git a/etherparse/src/compositions_tests.rs b/etherparse/src/compositions_tests.rs index 043dce67..d85f8705 100644 --- a/etherparse/src/compositions_tests.rs +++ b/etherparse/src/compositions_tests.rs @@ -142,14 +142,20 @@ impl ComponentTest { // PacketHeaders::from_ether_type ether_down.assert_headers( - PacketHeaders::from_ether_type(test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..]) - .unwrap(), + PacketHeaders::from_ether_type( + test.link.clone().unwrap().ethernet2().unwrap().ether_type, + &buffer[..], + ) + .unwrap(), ); // SlicedPacket::from_ether_type ether_down.assert_sliced_packet( - SlicedPacket::from_ether_type(test.link.clone().unwrap().ethernet2().unwrap().ether_type, &buffer[..]) - .unwrap(), + SlicedPacket::from_ether_type( + test.link.clone().unwrap().ethernet2().unwrap().ether_type, + &buffer[..], + ) + .unwrap(), ); // create unexpected end of slice errors for the different headers diff --git a/etherparse/src/err/double_vlan/header_slice_error.rs b/etherparse/src/err/double_vlan/header_slice_error.rs index f0e3a51d..7b78eea5 100644 --- a/etherparse/src/err/double_vlan/header_slice_error.rs +++ b/etherparse/src/err/double_vlan/header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/from_slice_error.rs b/etherparse/src/err/from_slice_error.rs index 47d5339d..a1f8ba01 100644 --- a/etherparse/src/err/from_slice_error.rs +++ b/etherparse/src/err/from_slice_error.rs @@ -96,7 +96,7 @@ impl core::fmt::Display for FromSliceError { use FromSliceError::*; match self { Len(err) => err.fmt(f), - LinuxSll(err) => err.fmt(f), + LinuxSll(err) => err.fmt(f), DoubleVlan(err) => err.fmt(f), Ip(err) => err.fmt(f), IpAuth(err) => err.fmt(f), @@ -152,7 +152,6 @@ impl From for FromSliceError { } } - // double vlan error conversions impl From for FromSliceError { @@ -434,7 +433,9 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }), - LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }), + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), }), @@ -463,7 +464,9 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }; - let linux_sll_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; + let linux_sll_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }; let double_vlan_error = || double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(1), }; @@ -479,8 +482,11 @@ mod tests { assert_eq!(Ipv4(ipv4_error()).len(), None); // linux_sll - assert_eq!(LinuxSll(linux_sll_error()).linux_sll(), Some(&linux_sll_error())); - assert_eq!(Ipv4(ipv4_error()).linux_sll(), None); + assert_eq!( + LinuxSll(linux_sll_error()).linux_sll(), + Some(&linux_sll_error()) + ); + assert_eq!(Ipv4(ipv4_error()).linux_sll(), None); // double_vlan assert_eq!( @@ -537,7 +543,9 @@ mod tests { // linux sll { - let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; + let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }; assert_eq!( &header_error(), FromSliceError::from(header_error()).linux_sll().unwrap() diff --git a/etherparse/src/err/ip/headers_read_error.rs b/etherparse/src/err/ip/headers_read_error.rs index 051df5e5..9874ccc1 100644 --- a/etherparse/src/err/ip/headers_read_error.rs +++ b/etherparse/src/err/ip/headers_read_error.rs @@ -84,10 +84,7 @@ impl std::error::Error for HeaderReadError { #[cfg(all(test, feature = "std"))] mod test { use super::{super::HeaderError::*, super::HeadersError::*, HeaderReadError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; #[test] diff --git a/etherparse/src/err/ip/headers_slice_error.rs b/etherparse/src/err/ip/headers_slice_error.rs index ac141527..1682b7ff 100644 --- a/etherparse/src/err/ip/headers_slice_error.rs +++ b/etherparse/src/err/ip/headers_slice_error.rs @@ -53,10 +53,7 @@ mod tests { HeadersSliceError::*, *, }; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ip/lax_header_slice_error.rs b/etherparse/src/err/ip/lax_header_slice_error.rs index 6cc6aac6..ed6bc2be 100644 --- a/etherparse/src/err/ip/lax_header_slice_error.rs +++ b/etherparse/src/err/ip/lax_header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for LaxHeaderSliceError { #[cfg(test)] mod tests { use super::{super::HeaderError::*, LaxHeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ip_auth/header_slice_error.rs b/etherparse/src/err/ip_auth/header_slice_error.rs index 61436657..8512f991 100644 --- a/etherparse/src/err/ip_auth/header_slice_error.rs +++ b/etherparse/src/err/ip_auth/header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ipv4/header_slice_error.rs b/etherparse/src/err/ipv4/header_slice_error.rs index fd563e6c..27d64fbf 100644 --- a/etherparse/src/err/ipv4/header_slice_error.rs +++ b/etherparse/src/err/ipv4/header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ipv4/slice_error.rs b/etherparse/src/err/ipv4/slice_error.rs index d698fb8f..3e5948a3 100644 --- a/etherparse/src/err/ipv4/slice_error.rs +++ b/etherparse/src/err/ipv4/slice_error.rs @@ -40,10 +40,7 @@ impl std::error::Error for SliceError { #[cfg(test)] mod tests { use super::{super::HeaderError, SliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ipv6/header_slice_error.rs b/etherparse/src/err/ipv6/header_slice_error.rs index 355d5b75..d4918331 100644 --- a/etherparse/src/err/ipv6/header_slice_error.rs +++ b/etherparse/src/err/ipv6/header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/ipv6_exts/header_slice_error.rs b/etherparse/src/err/ipv6_exts/header_slice_error.rs index 92f15e69..6473369b 100644 --- a/etherparse/src/err/ipv6_exts/header_slice_error.rs +++ b/etherparse/src/err/ipv6_exts/header_slice_error.rs @@ -67,10 +67,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/linux_sll/header_error.rs b/etherparse/src/err/linux_sll/header_error.rs index 7d0d399b..2fb504df 100644 --- a/etherparse/src/err/linux_sll/header_error.rs +++ b/etherparse/src/err/linux_sll/header_error.rs @@ -4,14 +4,12 @@ use crate::ArpHardwareId; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum HeaderError { /// Error when the "packet byte" field is not one of the known ones - UnsupportedPacketTypeField{ + UnsupportedPacketTypeField { // The unexpected packet type number in the SLL header - packet_type: u16 + packet_type: u16, }, /// Error when the arp hardware type field is not one of the known ones - UnsupportedArpHardwareId{ - arp_hardware_type: ArpHardwareId - }, + UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId }, } impl core::fmt::Display for HeaderError { @@ -31,7 +29,9 @@ impl std::error::Error for HeaderError { use HeaderError::*; match self { UnsupportedPacketTypeField { packet_type: _ } => None, - UnsupportedArpHardwareId { arp_hardware_type: _ } => None, + UnsupportedArpHardwareId { + arp_hardware_type: _, + } => None, } } } @@ -70,7 +70,7 @@ mod tests { }; assert_eq!(hash_a, hash_b); } - + #[test] fn fmt() { assert_eq!( @@ -88,7 +88,9 @@ mod tests { fn source() { let values = [ UnsupportedPacketTypeField { packet_type: 6 }, - UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }, + UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }, ]; for v in values { assert!(v.source().is_none()); diff --git a/etherparse/src/err/linux_sll/header_read_error.rs b/etherparse/src/err/linux_sll/header_read_error.rs index 0a75b592..a7d1ebcc 100644 --- a/etherparse/src/err/linux_sll/header_read_error.rs +++ b/etherparse/src/err/linux_sll/header_read_error.rs @@ -1,6 +1,6 @@ use super::HeaderError; -/// Error when decoding Linux Cooked Capture v1 (SLL) headers via a +/// Error when decoding Linux Cooked Capture v1 (SLL) headers via a /// `std::io::Read` source. /// /// Requires crate feature `std`. @@ -106,9 +106,11 @@ mod test { )) .source() .is_some()); - assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) - .source() - .is_some()); + assert!( + Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) + .source() + .is_some() + ); } #[test] @@ -119,9 +121,11 @@ mod test { )) .io_error() .is_some()); - assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) - .io_error() - .is_none()); + assert!( + Content(HeaderError::UnsupportedPacketTypeField { packet_type: 1 }) + .io_error() + .is_none() + ); } #[test] diff --git a/etherparse/src/err/linux_sll/header_slice_error.rs b/etherparse/src/err/linux_sll/header_slice_error.rs index 87e8f484..134c4a5b 100644 --- a/etherparse/src/err/linux_sll/header_slice_error.rs +++ b/etherparse/src/err/linux_sll/header_slice_error.rs @@ -49,10 +49,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, @@ -81,7 +78,7 @@ mod tests { ); assert_eq!( Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) - .add_slice_offset(200), + .add_slice_offset(200), Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) ); } @@ -142,8 +139,10 @@ mod tests { }) .source() .is_some()); - assert!(Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) - .source() - .is_some()); + assert!( + Content(HeaderError::UnsupportedPacketTypeField { packet_type: 0 }) + .source() + .is_some() + ); } } diff --git a/etherparse/src/err/mod.rs b/etherparse/src/err/mod.rs index b2965b2a..27d97d18 100644 --- a/etherparse/src/err/mod.rs +++ b/etherparse/src/err/mod.rs @@ -7,9 +7,9 @@ pub mod ip_auth; pub mod ip_exts; pub mod ipv4; pub mod ipv4_exts; -pub mod linux_sll; pub mod ipv6; pub mod ipv6_exts; +pub mod linux_sll; pub mod packet; pub mod tcp; diff --git a/etherparse/src/err/packet/slice_error.rs b/etherparse/src/err/packet/slice_error.rs index 7651171b..13261566 100644 --- a/etherparse/src/err/packet/slice_error.rs +++ b/etherparse/src/err/packet/slice_error.rs @@ -110,7 +110,9 @@ mod tests { // Linux SLL Header { - let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ADAPT }; + let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ADAPT, + }; assert_eq!( format!("{}", err), format!("{}", err::packet::SliceError::LinuxSll(err)) @@ -174,7 +176,9 @@ mod tests { // IpHeaders { - let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }; + let err = err::linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }; assert!(LinuxSll(err).source().is_some()); } diff --git a/etherparse/src/err/read_error.rs b/etherparse/src/err/read_error.rs index 3292f505..77e3e2a4 100644 --- a/etherparse/src/err/read_error.rs +++ b/etherparse/src/err/read_error.rs @@ -461,11 +461,11 @@ impl From for ReadError { #[cfg(test)] mod tests { - use crate::{ArpHardwareId, EtherType}; use crate::{ err::{ReadError::*, *}, LenSource, }; + use crate::{ArpHardwareId, EtherType}; use std::error::Error; use std::format; @@ -484,7 +484,9 @@ mod tests { ), ( "LinuxSll", - LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }) + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }), ), ( "DoubleVlan", @@ -547,7 +549,9 @@ mod tests { layer: Layer::Icmpv4, layer_start_offset: 0, }), - LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { arp_hardware_type: ArpHardwareId::ETHER }), + LinuxSll(linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, + }), DoubleVlan(double_vlan::HeaderError::NonVlanEtherType { unexpected_ether_type: EtherType(123), }), @@ -592,7 +596,8 @@ mod tests { let ipv6_error = || ipv6::HeaderError::UnexpectedVersion { version_number: 1 }; let ip_auth_error = || ip_auth::HeaderError::ZeroPayloadLen; let ipv6_exts_error = || ipv6_exts::HeaderError::HopByHopNotAtStart; - let linux_sll_error = || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; + let linux_sll_error = + || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; let tcp_error = || tcp::HeaderError::DataOffsetTooSmall { data_offset: 1 }; // io @@ -604,7 +609,10 @@ mod tests { assert_eq!(Ipv4(ipv4_error()).len(), None); // linux sll - assert_eq!(LinuxSll(linux_sll_error()).linux_sll(), Some(&linux_sll_error())); + assert_eq!( + LinuxSll(linux_sll_error()).linux_sll(), + Some(&linux_sll_error()) + ); assert_eq!(Ipv4(ipv4_error()).linux_sll(), None); // double_vlan @@ -643,7 +651,7 @@ mod tests { Some(&linux_sll_error()) ); assert_eq!(IpAuth(ip_auth_error()).linux_sll(), None); - + // tcp assert_eq!(Tcp(tcp_error()).tcp(), Some(&tcp_error())); assert_eq!(IpAuth(ip_auth_error()).tcp(), None); @@ -669,8 +677,8 @@ mod tests { // linux sll { - let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { - arp_hardware_type: ArpHardwareId::ETHER + let header_error = || linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: ArpHardwareId::ETHER, }; assert_eq!( &header_error(), @@ -682,11 +690,9 @@ mod tests { .linux_sll() .unwrap() ); - assert!( - ReadError::from(linux_sll::HeaderReadError::Io(io_error())) - .io() - .is_some() - ); + assert!(ReadError::from(linux_sll::HeaderReadError::Io(io_error())) + .io() + .is_some()); assert_eq!( &header_error(), ReadError::from(linux_sll::HeaderSliceError::Content(header_error())) @@ -999,7 +1005,8 @@ mod tests { // linux_sll errors { - let header_error = || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; + let header_error = + || linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }; assert_eq!( &header_error(), ReadError::from(header_error()).linux_sll().unwrap() diff --git a/etherparse/src/err/tcp/header_slice_error.rs b/etherparse/src/err/tcp/header_slice_error.rs index e0113a11..c6f0859d 100644 --- a/etherparse/src/err/tcp/header_slice_error.rs +++ b/etherparse/src/err/tcp/header_slice_error.rs @@ -48,10 +48,7 @@ impl std::error::Error for HeaderSliceError { #[cfg(test)] mod tests { use super::{HeaderSliceError::*, *}; - use crate::{ - err::Layer, - LenSource, - }; + use crate::{err::Layer, LenSource}; use alloc::format; use std::{ collections::hash_map::DefaultHasher, diff --git a/etherparse/src/err/value_too_big_error.rs b/etherparse/src/err/value_too_big_error.rs index bedbf95d..021c7d59 100644 --- a/etherparse/src/err/value_too_big_error.rs +++ b/etherparse/src/err/value_too_big_error.rs @@ -41,12 +41,7 @@ where #[cfg(test)] mod test { use super::*; - use std::{ - collections::hash_map::DefaultHasher, - error::Error, - format, - hash::Hasher, - }; + use std::{collections::hash_map::DefaultHasher, error::Error, format, hash::Hasher}; #[test] fn fmt() { diff --git a/etherparse/src/err/value_type.rs b/etherparse/src/err/value_type.rs index d2153ff3..b5d8405a 100644 --- a/etherparse/src/err/value_type.rs +++ b/etherparse/src/err/value_type.rs @@ -38,7 +38,7 @@ pub enum ValueType { /// Variable length data of an ICMPv6 packet. Icmpv6PayloadLength, /// Packet type of a Linux Cooked Capture v1 (SLL) - LinuxSllType + LinuxSllType, } impl core::fmt::Display for ValueType { diff --git a/etherparse/src/lax_sliced_packet.rs b/etherparse/src/lax_sliced_packet.rs index be1fe146..451f330a 100644 --- a/etherparse/src/lax_sliced_packet.rs +++ b/etherparse/src/lax_sliced_packet.rs @@ -236,14 +236,20 @@ impl<'a> LaxSlicedPacket<'a> { match link { LinkSlice::Ethernet2(e) => Some(e.payload()), LinkSlice::LinuxSll(e) => match e.protocol_type() { - LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.payload()).ok()?), - _ => None - } + LinuxSllProtocolType::EtherType(_) + | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => { + Some(EtherPayloadSlice::try_from(e.payload()).ok()?) + } + _ => None, + }, LinkSlice::EtherPayload(e) => Some(e.clone()), LinkSlice::LinuxSllPayload(e) => match e.protocol_type { - LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.clone()).ok()?), - _ => None - } + LinuxSllProtocolType::EtherType(_) + | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => { + Some(EtherPayloadSlice::try_from(e.clone()).ok()?) + } + _ => None, + }, } } else { None diff --git a/etherparse/src/lib.rs b/etherparse/src/lib.rs index 4897431b..996d4251 100644 --- a/etherparse/src/lib.rs +++ b/etherparse/src/lib.rs @@ -267,9 +267,9 @@ //! * Neighbor Discovery for IP version 6 (IPv6) [RFC 4861](https://datatracker.ietf.org/doc/html/rfc4861) //! * [LINKTYPE_LINUX_SLL](https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html) on tcpdump //! * LINUX_SLL [header definition](https://github.com/the-tcpdump-group/libpcap/blob/a932566fa1f6df16176ac702b1762ea1cd9ed9a3/pcap/sll.h) on libpcap -//! * [Linux packet types definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel +//! * [Linux packet types definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_packet.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel //! * Address Resolution Protocol (ARP) Parameters [Harware Types](https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2) -//! * [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel +//! * [Arp hardware identifiers definitions](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if_arp.h?id=e33c4963bf536900f917fb65a687724d5539bc21) on the Linux kernel // # Reason for 'bool_comparison' disable: // @@ -315,8 +315,8 @@ pub use crate::link::ethernet2_slice::*; pub use crate::link::link_header::*; pub use crate::link::link_slice::*; pub use crate::link::linux_nonstandard_ether_type::*; -pub use crate::link::linux_sll_header_slice::*; pub use crate::link::linux_sll_header::*; +pub use crate::link::linux_sll_header_slice::*; pub use crate::link::linux_sll_packet_type::*; pub use crate::link::linux_sll_payload_slice::*; pub use crate::link::linux_sll_protocol_type::*; diff --git a/etherparse/src/link/arp_hardware_id.rs b/etherparse/src/link/arp_hardware_id.rs index efddd955..2f89ce48 100644 --- a/etherparse/src/link/arp_hardware_id.rs +++ b/etherparse/src/link/arp_hardware_id.rs @@ -91,7 +91,6 @@ impl ArpHardwareId { pub const VSOCKMON: ArpHardwareId = Self(826); pub const VOID: ArpHardwareId = Self(0xFFFF); pub const NONE: ArpHardwareId = Self(0xFFFE); - } impl From for ArpHardwareId { @@ -288,7 +287,7 @@ mod test { assert_eq!(ArpHardwareId::from(24), ArpHardwareId::IEEE1394); assert_eq!(ArpHardwareId::from(27), ArpHardwareId::EUI64); assert_eq!(ArpHardwareId::from(32), ArpHardwareId::INFINIBAND); - + assert_eq!(ArpHardwareId::from(256), ArpHardwareId::SLIP); assert_eq!(ArpHardwareId::from(257), ArpHardwareId::CSLIP); assert_eq!(ArpHardwareId::from(258), ArpHardwareId::SLIP6); @@ -305,7 +304,7 @@ mod test { assert_eq!(ArpHardwareId::from(517), ArpHardwareId::DDCMP); assert_eq!(ArpHardwareId::from(518), ArpHardwareId::RAWHDLC); assert_eq!(ArpHardwareId::from(519), ArpHardwareId::RAWIP); - + assert_eq!(ArpHardwareId::from(768), ArpHardwareId::TUNNEL); assert_eq!(ArpHardwareId::from(769), ArpHardwareId::TUNNEL6); assert_eq!(ArpHardwareId::from(770), ArpHardwareId::FRAD); @@ -322,19 +321,19 @@ mod test { assert_eq!(ArpHardwareId::from(781), ArpHardwareId::ASH); assert_eq!(ArpHardwareId::from(782), ArpHardwareId::ECONET); assert_eq!(ArpHardwareId::from(783), ArpHardwareId::IRDA); - + assert_eq!(ArpHardwareId::from(784), ArpHardwareId::FCPP); assert_eq!(ArpHardwareId::from(785), ArpHardwareId::FCAL); assert_eq!(ArpHardwareId::from(786), ArpHardwareId::FCPL); assert_eq!(ArpHardwareId::from(787), ArpHardwareId::FCFABRIC); - + assert_eq!(ArpHardwareId::from(800), ArpHardwareId::IEEE802_TR); assert_eq!(ArpHardwareId::from(801), ArpHardwareId::IEEE80211); assert_eq!(ArpHardwareId::from(802), ArpHardwareId::IEEE80211_PRISM); assert_eq!(ArpHardwareId::from(803), ArpHardwareId::IEEE80211_RADIOTAP); assert_eq!(ArpHardwareId::from(804), ArpHardwareId::IEEE802154); assert_eq!(ArpHardwareId::from(805), ArpHardwareId::IEEE802154_MONITOR); - + assert_eq!(ArpHardwareId::from(820), ArpHardwareId::PHONET); assert_eq!(ArpHardwareId::from(821), ArpHardwareId::PHONET_PIPE); assert_eq!(ArpHardwareId::from(822), ArpHardwareId::CAIF); @@ -342,12 +341,11 @@ mod test { assert_eq!(ArpHardwareId::from(824), ArpHardwareId::NETLINK); assert_eq!(ArpHardwareId::from(825), ArpHardwareId::IPV6LOWPAN); assert_eq!(ArpHardwareId::from(826), ArpHardwareId::VSOCKMON); - + assert_eq!(ArpHardwareId::from(0xFFFF), ArpHardwareId::VOID); assert_eq!(ArpHardwareId::from(0xFFFE), ArpHardwareId::NONE); } - #[test] fn display_dbg() { let pairs = &[ @@ -388,13 +386,19 @@ mod test { (ArpHardwareId::SKIP, "771 (SKIP vif)"), (ArpHardwareId::LOOPBACK, "772 (Loopback device)"), (ArpHardwareId::LOCALTLK, "773 (Localtalk device)"), - (ArpHardwareId::FDDI, "774 (Fiber Distributed Data Interface)"), + ( + ArpHardwareId::FDDI, + "774 (Fiber Distributed Data Interface)", + ), (ArpHardwareId::BIF, "775 (AP1000 BIF)"), (ArpHardwareId::SIT, "776 (sit0 device - IPv6-in-IPv4)"), (ArpHardwareId::IPDDP, "777 (IP over DDP tunneller)"), (ArpHardwareId::IPGRE, "778 (GRE over IP)"), (ArpHardwareId::PIMREG, "779 (PIMSM register interface)"), - (ArpHardwareId::HIPPI, "780 (High Performance Parallel Interface)"), + ( + ArpHardwareId::HIPPI, + "780 (High Performance Parallel Interface)", + ), (ArpHardwareId::ASH, "781 (Nexus 64Mbps Ash)"), (ArpHardwareId::ECONET, "782 (Acorn Econet)"), (ArpHardwareId::IRDA, "783 (Linux-IrDA)"), @@ -404,10 +408,19 @@ mod test { (ArpHardwareId::FCFABRIC, "787 (Fibrechannel fabric)"), (ArpHardwareId::IEEE802_TR, "800 (Magic type ident for TR)"), (ArpHardwareId::IEEE80211, "801 (IEEE 802.11)"), - (ArpHardwareId::IEEE80211_PRISM, "802 (IEEE 802.11 + Prism2 header)"), - (ArpHardwareId::IEEE80211_RADIOTAP, "803 (IEEE 802.11 + radiotap header)"), + ( + ArpHardwareId::IEEE80211_PRISM, + "802 (IEEE 802.11 + Prism2 header)", + ), + ( + ArpHardwareId::IEEE80211_RADIOTAP, + "803 (IEEE 802.11 + radiotap header)", + ), (ArpHardwareId::IEEE802154, "804 (IEEE 802.15.4)"), - (ArpHardwareId::IEEE802154_MONITOR, "805 (IEEE 802.15.4 network monitor)"), + ( + ArpHardwareId::IEEE802154_MONITOR, + "805 (IEEE 802.15.4 network monitor)", + ), (ArpHardwareId::PHONET, "820 (PhoNet media type)"), (ArpHardwareId::PHONET_PIPE, "821 (PhoNet pipe header)"), (ArpHardwareId::CAIF, "822 (CAIF media type)"), diff --git a/etherparse/src/link/link_header.rs b/etherparse/src/link/link_header.rs index e183c34b..1c5caa2f 100644 --- a/etherparse/src/link/link_header.rs +++ b/etherparse/src/link/link_header.rs @@ -8,7 +8,7 @@ pub enum LinkHeader { } impl LinkHeader { - /// Returns `Option::Some` containing the `Ethernet2Header` if self has the + /// Returns `Option::Some` containing the `Ethernet2Header` if self has the /// value Ethernet2. Otherwise `Option::None` is returned. pub fn ethernet2(self) -> Option { use crate::LinkHeader::*; @@ -17,10 +17,9 @@ impl LinkHeader { } else { None } - } - /// Returns `Option::Some` containing the `Ethernet2Header` if self has the + /// Returns `Option::Some` containing the `Ethernet2Header` if self has the /// value Ethernet2. Otherwise `Option::None` is returned. pub fn mut_ethernet2(&mut self) -> Option<&mut Ethernet2Header> { use crate::LinkHeader::*; @@ -29,10 +28,9 @@ impl LinkHeader { } else { None } - } - /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the + /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the /// value LinuxSll. Otherwise `Option::None` is returned. pub fn linux_sll(self) -> Option { use crate::LinkHeader::*; @@ -43,7 +41,7 @@ impl LinkHeader { } } - /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the + /// Returns `Option::Some` containing the `LinuxSllHeader` if self has the /// value LinuxSll. Otherwise `Option::None` is returned. pub fn mut_linux_sll(&mut self) -> Option<&mut LinuxSllHeader> { use crate::LinkHeader::*; @@ -75,14 +73,13 @@ impl LinkHeader { } } - #[cfg(test)] mod test { + use super::*; use crate::{test_gens::*, *}; use alloc::{format, vec::Vec}; use proptest::prelude::*; use std::io::Cursor; - use super::*; proptest! { #[test] @@ -178,7 +175,6 @@ mod test { } } - proptest! { #[test] fn write( diff --git a/etherparse/src/link/link_slice.rs b/etherparse/src/link/link_slice.rs index 755e16dc..3257e6c4 100644 --- a/etherparse/src/link/link_slice.rs +++ b/etherparse/src/link/link_slice.rs @@ -1,6 +1,6 @@ use crate::*; -/// A slice containing the link layer header (currently only Ethernet II and +/// A slice containing the link layer header (currently only Ethernet II and /// SLL are supported). #[derive(Clone, Debug, Eq, PartialEq)] pub enum LinkSlice<'a> { @@ -36,7 +36,7 @@ impl<'a> LinkSlice<'a> { 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()?) + LinuxSllPayload(p) => Some(EtherPayloadSlice::try_from(p.clone()).ok()?), } } @@ -46,8 +46,8 @@ impl<'a> LinkSlice<'a> { match self { Ethernet2(s) => LinuxSllPayloadSlice::from(s.payload().clone()), LinuxSll(s) => s.payload().clone(), - EtherPayload(p) => LinuxSllPayloadSlice::from(p.clone()), - LinuxSllPayload(p) => p.clone() + EtherPayload(p) => LinuxSllPayloadSlice::from(p.clone()), + LinuxSllPayload(p) => p.clone(), } } } diff --git a/etherparse/src/link/linux_nonstandard_ether_type.rs b/etherparse/src/link/linux_nonstandard_ether_type.rs index 42d419c5..24f151c2 100644 --- a/etherparse/src/link/linux_nonstandard_ether_type.rs +++ b/etherparse/src/link/linux_nonstandard_ether_type.rs @@ -1,4 +1,4 @@ -/// Represents an non standard ethertype. These are defined in the Linux +/// Represents an non standard ethertype. These are defined in the Linux /// kernel with ids under 1500 so they don't clash with the standard ones. /// /// You can convert any valid `u16` value to an `LinuxNonstandardEtherType` and @@ -113,38 +113,78 @@ impl core::fmt::Debug for LinuxNonstandardEtherType { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { LinuxNonstandardEtherType(0x0000) => write!(f, "{:#06X} (Unknown)", self.0), - LinuxNonstandardEtherType::N802_3 => write!(f, "{:#06X} (Dummy type for 802.3 frames)", self.0), - LinuxNonstandardEtherType::AX25 => write!(f, "{:#06X} (Dummy protocol id for AX.25)", self.0), + LinuxNonstandardEtherType::N802_3 => { + write!(f, "{:#06X} (Dummy type for 802.3 frames)", self.0) + } + LinuxNonstandardEtherType::AX25 => { + write!(f, "{:#06X} (Dummy protocol id for AX.25)", self.0) + } LinuxNonstandardEtherType::ALL => write!(f, "{:#06X} (Every packet)", self.0), LinuxNonstandardEtherType::N802_2 => write!(f, "{:#06X} (802.2 frames)", self.0), LinuxNonstandardEtherType::SNAP => write!(f, "{:#06X} (SNAP: Internal only)", self.0), - LinuxNonstandardEtherType::DDCMP => write!(f, "{:#06X} (DEC DDCMP: Internal only)", self.0), - LinuxNonstandardEtherType::WAN_PPP => write!(f, "{:#06X} (Dummy type for WAN PPP frames)", self.0), - LinuxNonstandardEtherType::PPP_MP => write!(f, "{:#06X} (Dummy type for PPP MP frames)", self.0), - LinuxNonstandardEtherType::LOCALTALK => write!(f, "{:#06X} (Localtalk pseudo type)", self.0), + LinuxNonstandardEtherType::DDCMP => { + write!(f, "{:#06X} (DEC DDCMP: Internal only)", self.0) + } + LinuxNonstandardEtherType::WAN_PPP => { + write!(f, "{:#06X} (Dummy type for WAN PPP frames)", self.0) + } + LinuxNonstandardEtherType::PPP_MP => { + write!(f, "{:#06X} (Dummy type for PPP MP frames)", self.0) + } + LinuxNonstandardEtherType::LOCALTALK => { + write!(f, "{:#06X} (Localtalk pseudo type)", self.0) + } LinuxNonstandardEtherType(0x000A..=0x000B) => write!(f, "{:#06X} (Unknown)", self.0), - LinuxNonstandardEtherType::CAN => write!(f, "{:#06X} (CAN: Controller Area Network)", self.0), - LinuxNonstandardEtherType::CANFD => write!(f, "{:#06X} (CANFD: CAN flexible data rate)", self.0), - LinuxNonstandardEtherType::CANXL => write!(f, "{:#06X} (CANXL: eXtended frame Length)", self.0), + LinuxNonstandardEtherType::CAN => { + write!(f, "{:#06X} (CAN: Controller Area Network)", self.0) + } + LinuxNonstandardEtherType::CANFD => { + write!(f, "{:#06X} (CANFD: CAN flexible data rate)", self.0) + } + LinuxNonstandardEtherType::CANXL => { + write!(f, "{:#06X} (CANXL: eXtended frame Length)", self.0) + } LinuxNonstandardEtherType(0x000F) => write!(f, "{:#06X} (Unknown)", self.0), - LinuxNonstandardEtherType::PPPTALK => write!(f, "{:#06X} (Dummy type for Atalk over PPP)", self.0), + LinuxNonstandardEtherType::PPPTALK => { + write!(f, "{:#06X} (Dummy type for Atalk over PPP)", self.0) + } LinuxNonstandardEtherType::TR_802_2 => write!(f, "{:#06X} (802.2 frames)", self.0), LinuxNonstandardEtherType(0x0012..=0x0014) => write!(f, "{:#06X} (Unknown)", self.0), LinuxNonstandardEtherType::MOBITEX => write!(f, "{:#06X} (Mobitex)", self.0), - LinuxNonstandardEtherType::CONTROL => write!(f, "{:#06X} (Card specific control frames)", self.0), + LinuxNonstandardEtherType::CONTROL => { + write!(f, "{:#06X} (Card specific control frames)", self.0) + } LinuxNonstandardEtherType::IRDA => write!(f, "{:#06X} (Linux-IrDA)", self.0), LinuxNonstandardEtherType::ECONET => write!(f, "{:#06X} (Acorn Econet)", self.0), LinuxNonstandardEtherType::HDLC => write!(f, "{:#06X} (HDLC frames)", self.0), LinuxNonstandardEtherType::ARCNET => write!(f, "{:#06X} (1A for ArcNet)", self.0), - LinuxNonstandardEtherType::DSA => write!(f, "{:#06X} (Distributed Switch Arch)", self.0), - LinuxNonstandardEtherType::TRAILER => write!(f, "{:#06X} (Trailer switch tagging)", self.0), + LinuxNonstandardEtherType::DSA => { + write!(f, "{:#06X} (Distributed Switch Arch)", self.0) + } + LinuxNonstandardEtherType::TRAILER => { + write!(f, "{:#06X} (Trailer switch tagging)", self.0) + } LinuxNonstandardEtherType(0x001D..=0x00F4) => write!(f, "{:#06X} (Unknown)", self.0), LinuxNonstandardEtherType::PHONET => write!(f, "{:#06X} (Nokia Phonet frame)", self.0), - LinuxNonstandardEtherType::IEEE802154 => write!(f, "{:#06X} (IEEE802.15.4 frame)", self.0), - LinuxNonstandardEtherType::CAIF => write!(f, "{:#06X} (ST-Ericsson CAIF protocol)", self.0), - LinuxNonstandardEtherType::XDSA => write!(f, "{:#06X} (Multiplexed DSA protocol)", self.0), - LinuxNonstandardEtherType::MAP => write!(f, "{:#06X} (Qualcomm multiplexing and aggregation protocol)", self.0), - LinuxNonstandardEtherType::MCTP => write!(f, "{:#06X} (Management component transport protocol packets)", self.0), + LinuxNonstandardEtherType::IEEE802154 => { + write!(f, "{:#06X} (IEEE802.15.4 frame)", self.0) + } + LinuxNonstandardEtherType::CAIF => { + write!(f, "{:#06X} (ST-Ericsson CAIF protocol)", self.0) + } + LinuxNonstandardEtherType::XDSA => { + write!(f, "{:#06X} (Multiplexed DSA protocol)", self.0) + } + LinuxNonstandardEtherType::MAP => write!( + f, + "{:#06X} (Qualcomm multiplexing and aggregation protocol)", + self.0 + ), + LinuxNonstandardEtherType::MCTP => write!( + f, + "{:#06X} (Management component transport protocol packets)", + self.0 + ), LinuxNonstandardEtherType(0x00FB..=u16::MAX) => write!(f, "{:#06X} (Unknown)", self.0), } } @@ -152,8 +192,8 @@ impl core::fmt::Debug for LinuxNonstandardEtherType { #[cfg(test)] mod test { - use alloc::format; use super::*; + use alloc::format; #[test] fn to_u16() { @@ -189,71 +229,215 @@ mod test { #[test] fn try_from_u16() { - assert_eq!(LinuxNonstandardEtherType::try_from(0x0001), Ok(LinuxNonstandardEtherType::N802_3)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0002), Ok(LinuxNonstandardEtherType::AX25)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0003), Ok(LinuxNonstandardEtherType::ALL)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0004), Ok(LinuxNonstandardEtherType::N802_2)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0005), Ok(LinuxNonstandardEtherType::SNAP)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0006), Ok(LinuxNonstandardEtherType::DDCMP)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0007), Ok(LinuxNonstandardEtherType::WAN_PPP)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0008), Ok(LinuxNonstandardEtherType::PPP_MP)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0009), Ok(LinuxNonstandardEtherType::LOCALTALK)); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0001), + Ok(LinuxNonstandardEtherType::N802_3) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0002), + Ok(LinuxNonstandardEtherType::AX25) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0003), + Ok(LinuxNonstandardEtherType::ALL) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0004), + Ok(LinuxNonstandardEtherType::N802_2) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0005), + Ok(LinuxNonstandardEtherType::SNAP) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0006), + Ok(LinuxNonstandardEtherType::DDCMP) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0007), + Ok(LinuxNonstandardEtherType::WAN_PPP) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0008), + Ok(LinuxNonstandardEtherType::PPP_MP) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0009), + Ok(LinuxNonstandardEtherType::LOCALTALK) + ); /* 0x00A..=0x00B */ - assert_eq!(LinuxNonstandardEtherType::try_from(0x000C), Ok(LinuxNonstandardEtherType::CAN)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x000D), Ok(LinuxNonstandardEtherType::CANFD)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x000E), Ok(LinuxNonstandardEtherType::CANXL)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0010), Ok(LinuxNonstandardEtherType::PPPTALK)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0011), Ok(LinuxNonstandardEtherType::TR_802_2)); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x000C), + Ok(LinuxNonstandardEtherType::CAN) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x000D), + Ok(LinuxNonstandardEtherType::CANFD) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x000E), + Ok(LinuxNonstandardEtherType::CANXL) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0010), + Ok(LinuxNonstandardEtherType::PPPTALK) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0011), + Ok(LinuxNonstandardEtherType::TR_802_2) + ); /* 0x0012..=0x0014 */ - assert_eq!(LinuxNonstandardEtherType::try_from(0x0015), Ok(LinuxNonstandardEtherType::MOBITEX)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0016), Ok(LinuxNonstandardEtherType::CONTROL)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0017), Ok(LinuxNonstandardEtherType::IRDA)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0018), Ok(LinuxNonstandardEtherType::ECONET)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x0019), Ok(LinuxNonstandardEtherType::HDLC)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x001A), Ok(LinuxNonstandardEtherType::ARCNET)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x001B), Ok(LinuxNonstandardEtherType::DSA)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x001C), Ok(LinuxNonstandardEtherType::TRAILER)); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0015), + Ok(LinuxNonstandardEtherType::MOBITEX) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0016), + Ok(LinuxNonstandardEtherType::CONTROL) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0017), + Ok(LinuxNonstandardEtherType::IRDA) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0018), + Ok(LinuxNonstandardEtherType::ECONET) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x0019), + Ok(LinuxNonstandardEtherType::HDLC) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x001A), + Ok(LinuxNonstandardEtherType::ARCNET) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x001B), + Ok(LinuxNonstandardEtherType::DSA) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x001C), + Ok(LinuxNonstandardEtherType::TRAILER) + ); /* 0x001D..=0x00F4 */ - assert_eq!(LinuxNonstandardEtherType::try_from(0x00F5), Ok(LinuxNonstandardEtherType::PHONET)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x00F6), Ok(LinuxNonstandardEtherType::IEEE802154)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x00F7), Ok(LinuxNonstandardEtherType::CAIF)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x00F8), Ok(LinuxNonstandardEtherType::XDSA)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x00F9), Ok(LinuxNonstandardEtherType::MAP)); - assert_eq!(LinuxNonstandardEtherType::try_from(0x00FA), Ok(LinuxNonstandardEtherType::MCTP)); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00F5), + Ok(LinuxNonstandardEtherType::PHONET) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00F6), + Ok(LinuxNonstandardEtherType::IEEE802154) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00F7), + Ok(LinuxNonstandardEtherType::CAIF) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00F8), + Ok(LinuxNonstandardEtherType::XDSA) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00F9), + Ok(LinuxNonstandardEtherType::MAP) + ); + assert_eq!( + LinuxNonstandardEtherType::try_from(0x00FA), + Ok(LinuxNonstandardEtherType::MCTP) + ); /* 0x00FB..=u16::MAX */ } #[test] fn dbg() { let pairs = &[ - (LinuxNonstandardEtherType::N802_3, "0x0001 (Dummy type for 802.3 frames)"), - (LinuxNonstandardEtherType::AX25, "0x0002 (Dummy protocol id for AX.25)"), + ( + LinuxNonstandardEtherType::N802_3, + "0x0001 (Dummy type for 802.3 frames)", + ), + ( + LinuxNonstandardEtherType::AX25, + "0x0002 (Dummy protocol id for AX.25)", + ), (LinuxNonstandardEtherType::ALL, "0x0003 (Every packet)"), (LinuxNonstandardEtherType::N802_2, "0x0004 (802.2 frames)"), - (LinuxNonstandardEtherType::SNAP, "0x0005 (SNAP: Internal only)"), - (LinuxNonstandardEtherType::DDCMP, "0x0006 (DEC DDCMP: Internal only)"), - (LinuxNonstandardEtherType::WAN_PPP, "0x0007 (Dummy type for WAN PPP frames)"), - (LinuxNonstandardEtherType::PPP_MP, "0x0008 (Dummy type for PPP MP frames)"), - (LinuxNonstandardEtherType::LOCALTALK, "0x0009 (Localtalk pseudo type)"), - (LinuxNonstandardEtherType::CAN, "0x000C (CAN: Controller Area Network)"), - (LinuxNonstandardEtherType::CANFD, "0x000D (CANFD: CAN flexible data rate)"), - (LinuxNonstandardEtherType::CANXL, "0x000E (CANXL: eXtended frame Length)"), - (LinuxNonstandardEtherType::PPPTALK, "0x0010 (Dummy type for Atalk over PPP)"), + ( + LinuxNonstandardEtherType::SNAP, + "0x0005 (SNAP: Internal only)", + ), + ( + LinuxNonstandardEtherType::DDCMP, + "0x0006 (DEC DDCMP: Internal only)", + ), + ( + LinuxNonstandardEtherType::WAN_PPP, + "0x0007 (Dummy type for WAN PPP frames)", + ), + ( + LinuxNonstandardEtherType::PPP_MP, + "0x0008 (Dummy type for PPP MP frames)", + ), + ( + LinuxNonstandardEtherType::LOCALTALK, + "0x0009 (Localtalk pseudo type)", + ), + ( + LinuxNonstandardEtherType::CAN, + "0x000C (CAN: Controller Area Network)", + ), + ( + LinuxNonstandardEtherType::CANFD, + "0x000D (CANFD: CAN flexible data rate)", + ), + ( + LinuxNonstandardEtherType::CANXL, + "0x000E (CANXL: eXtended frame Length)", + ), + ( + LinuxNonstandardEtherType::PPPTALK, + "0x0010 (Dummy type for Atalk over PPP)", + ), (LinuxNonstandardEtherType::TR_802_2, "0x0011 (802.2 frames)"), (LinuxNonstandardEtherType::MOBITEX, "0x0015 (Mobitex)"), - (LinuxNonstandardEtherType::CONTROL, "0x0016 (Card specific control frames)"), + ( + LinuxNonstandardEtherType::CONTROL, + "0x0016 (Card specific control frames)", + ), (LinuxNonstandardEtherType::IRDA, "0x0017 (Linux-IrDA)"), (LinuxNonstandardEtherType::ECONET, "0x0018 (Acorn Econet)"), (LinuxNonstandardEtherType::HDLC, "0x0019 (HDLC frames)"), (LinuxNonstandardEtherType::ARCNET, "0x001A (1A for ArcNet)"), - (LinuxNonstandardEtherType::DSA, "0x001B (Distributed Switch Arch)"), - (LinuxNonstandardEtherType::TRAILER, "0x001C (Trailer switch tagging)"), - (LinuxNonstandardEtherType::PHONET, "0x00F5 (Nokia Phonet frame)"), - (LinuxNonstandardEtherType::IEEE802154, "0x00F6 (IEEE802.15.4 frame)"), - (LinuxNonstandardEtherType::CAIF, "0x00F7 (ST-Ericsson CAIF protocol)"), - (LinuxNonstandardEtherType::XDSA, "0x00F8 (Multiplexed DSA protocol)"), - (LinuxNonstandardEtherType::MAP, "0x00F9 (Qualcomm multiplexing and aggregation protocol)"), - (LinuxNonstandardEtherType::MCTP, "0x00FA (Management component transport protocol packets)"), + ( + LinuxNonstandardEtherType::DSA, + "0x001B (Distributed Switch Arch)", + ), + ( + LinuxNonstandardEtherType::TRAILER, + "0x001C (Trailer switch tagging)", + ), + ( + LinuxNonstandardEtherType::PHONET, + "0x00F5 (Nokia Phonet frame)", + ), + ( + LinuxNonstandardEtherType::IEEE802154, + "0x00F6 (IEEE802.15.4 frame)", + ), + ( + LinuxNonstandardEtherType::CAIF, + "0x00F7 (ST-Ericsson CAIF protocol)", + ), + ( + LinuxNonstandardEtherType::XDSA, + "0x00F8 (Multiplexed DSA protocol)", + ), + ( + LinuxNonstandardEtherType::MAP, + "0x00F9 (Qualcomm multiplexing and aggregation protocol)", + ), + ( + LinuxNonstandardEtherType::MCTP, + "0x00FA (Management component transport protocol packets)", + ), ]; for (ether_type, str_value) in pairs { diff --git a/etherparse/src/link/linux_sll_header.rs b/etherparse/src/link/linux_sll_header.rs index dd340bba..ec1a1ba9 100644 --- a/etherparse/src/link/linux_sll_header.rs +++ b/etherparse/src/link/linux_sll_header.rs @@ -9,9 +9,9 @@ pub struct LinuxSllHeader { pub arp_hrd_type: ArpHardwareId, /// The size of the adress that is valid pub sender_address_valid_length: u16, - /// The link-layer adress of the sender of the packet, with the meaningful - /// bytes specified by `sender_address_valid_length`. If the original is - /// larger, the value on the packet is truncated to the first 8 bytes. If + /// The link-layer adress of the sender of the packet, with the meaningful + /// bytes specified by `sender_address_valid_length`. If the original is + /// larger, the value on the packet is truncated to the first 8 bytes. If /// the original is smaller, the remaining bytes will be filled with 0s. pub sender_address: [u8; 8], /// The protocol type of the encapsulated packet @@ -24,7 +24,9 @@ impl LinuxSllHeader { /// Read an SLL header from a slice and return the header & unused parts of the slice. #[inline] - pub fn from_slice(slice: &[u8]) -> Result<(LinuxSllHeader, &[u8]), err::linux_sll::HeaderSliceError> { + pub fn from_slice( + slice: &[u8], + ) -> Result<(LinuxSllHeader, &[u8]), err::linux_sll::HeaderSliceError> { Ok(( LinuxSllHeaderSlice::from_slice(slice)?.to_header(), &slice[LinuxSllHeader::LEN..], @@ -37,8 +39,13 @@ impl LinuxSllHeader { let packet_type = LinuxSllPacketType::try_from(u16::from_be_bytes([bytes[0], bytes[1]]))?; let arp_hrd_type = ArpHardwareId::from(u16::from_be_bytes([bytes[2], bytes[3]])); let sender_address_valid_length = u16::from_be_bytes([bytes[4], bytes[5]]); - let sender_address = [bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13]]; - let protocol_type = LinuxSllProtocolType::try_from((arp_hrd_type, u16::from_be_bytes([bytes[14], bytes[15]])))?; + let sender_address = [ + bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], + ]; + let protocol_type = LinuxSllProtocolType::try_from(( + arp_hrd_type, + u16::from_be_bytes([bytes[14], bytes[15]]), + ))?; Ok(LinuxSllHeader { packet_type, @@ -131,7 +138,6 @@ impl LinuxSllHeader { } } - #[cfg(test)] mod test { use super::*; @@ -276,7 +282,7 @@ mod test { let sender_address_valid_length_be = input.sender_address_valid_length.to_be_bytes(); let sender_address_be = input.sender_address; let protocol_type_be = u16::from(input.protocol_type).to_be_bytes(); - + assert_eq!( input.to_bytes(), [ diff --git a/etherparse/src/link/linux_sll_header_slice.rs b/etherparse/src/link/linux_sll_header_slice.rs index 47e6eb65..274cbab0 100644 --- a/etherparse/src/link/linux_sll_header_slice.rs +++ b/etherparse/src/link/linux_sll_header_slice.rs @@ -9,7 +9,9 @@ pub struct LinuxSllHeaderSlice<'a> { impl<'a> LinuxSllHeaderSlice<'a> { /// Creates a SLL header slice from an other slice. - pub fn from_slice(slice: &'a [u8]) -> Result, err::linux_sll::HeaderSliceError> { + pub fn from_slice( + slice: &'a [u8], + ) -> Result, err::linux_sll::HeaderSliceError> { //check length if slice.len() < LinuxSllHeader::LEN { return Err(err::linux_sll::HeaderSliceError::Len(err::LenError { @@ -36,13 +38,13 @@ impl<'a> LinuxSllHeaderSlice<'a> { // SAFETY: // Safe as it is checked at the start of the function that the // length of the slice is at least LinuxSllHeader::LEN (16). - let arp_hardware_id = unsafe { get_unchecked_be_u16(slice.as_ptr().add(2)) }; + let arp_hardware_id = unsafe { get_unchecked_be_u16(slice.as_ptr().add(2)) }; let arp_hardware_id = ArpHardwareId::from(arp_hardware_id); // SAFETY: // Safe as it is checked at the start of the function that the // length of the slice is at least LinuxSllHeader::LEN (16). - let protocol_type = unsafe { get_unchecked_be_u16(slice.as_ptr().add(14)) }; + let protocol_type = unsafe { get_unchecked_be_u16(slice.as_ptr().add(14)) }; if let Err(err) = LinuxSllProtocolType::try_from((arp_hardware_id, protocol_type)) { return Err(err::linux_sll::HeaderSliceError::Content(err)); @@ -57,8 +59,8 @@ impl<'a> LinuxSllHeaderSlice<'a> { }) } - /// Converts the given slice into a SLL header slice WITHOUT any checks to - /// ensure that the data present is an sll header or that the slice length + /// Converts the given slice into a SLL header slice WITHOUT any checks to + /// ensure that the data present is an sll header or that the slice length /// is matching the header length. /// /// If you are not sure what this means, use [`LinuxSllHeaderSlice::from_slice`] @@ -114,7 +116,7 @@ impl<'a> LinuxSllHeaderSlice<'a> { unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) } } - /// Read the link layer address field. Only the first + /// Read the link layer address field. Only the first /// `LinuxSllHeaderSlice::link_layer_address_length` bytes are meaningful #[inline] pub fn sender_address_full(&self) -> [u8; 8] { @@ -124,11 +126,11 @@ impl<'a> LinuxSllHeaderSlice<'a> { unsafe { get_unchecked_8_byte_array(self.slice.as_ptr().add(6)) } } - /// Get the meaningful bytes of the slice of the link layer address + /// Get the meaningful bytes of the slice of the link layer address #[inline] pub fn sender_address(&self) -> &'a [u8] { let length = self.sender_address_valid_length() as usize; - &self.slice[6..min(6+length,6+ 8)] + &self.slice[6..min(6 + length, 6 + 8)] } /// Read the protocol type field @@ -142,7 +144,9 @@ impl<'a> LinuxSllHeaderSlice<'a> { // SAFETY: // Safe as the constructor checks that the arphwd + protocol are supported - unsafe { LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)).unwrap_unchecked() } + unsafe { + LinuxSllProtocolType::try_from((arp_harware_type, protocol_type_raw)).unwrap_unchecked() + } } /// Decode all the fields and copy the results to a [`LinuxSllHeader`] struct @@ -152,7 +156,7 @@ impl<'a> LinuxSllHeaderSlice<'a> { arp_hrd_type: self.arp_hardware_type(), sender_address_valid_length: self.sender_address_valid_length(), sender_address: self.sender_address_full(), - protocol_type: self.protocol_type() + protocol_type: self.protocol_type(), } } } diff --git a/etherparse/src/link/linux_sll_packet_type.rs b/etherparse/src/link/linux_sll_packet_type.rs index f7a3fec1..78c62a3c 100644 --- a/etherparse/src/link/linux_sll_packet_type.rs +++ b/etherparse/src/link/linux_sll_packet_type.rs @@ -2,10 +2,10 @@ use core::hint::unreachable_unchecked; use crate::err::{self}; -/// Represents an "Packet type", indicating the direction where it was sent, +/// Represents an "Packet type", indicating the direction where it was sent, /// used inside a SLL header /// -/// You can convert `u16` in the valid range to an `LinuxSllType` and the +/// You can convert `u16` in the valid range to an `LinuxSllType` and the /// other way around /// /// ``` @@ -35,7 +35,7 @@ impl LinuxSllPacketType { pub const KERNEL: LinuxSllPacketType = Self(7); pub const MAX_VAL: u16 = 7; - const FIRST_INVALID: u16 = LinuxSllPacketType::MAX_VAL+1; + const FIRST_INVALID: u16 = LinuxSllPacketType::MAX_VAL + 1; } impl TryFrom for LinuxSllPacketType { @@ -51,9 +51,9 @@ impl TryFrom for LinuxSllPacketType { 5 => Ok(LinuxSllPacketType::LOOPBACK), 6 => Ok(LinuxSllPacketType::USER), 7 => Ok(LinuxSllPacketType::KERNEL), - LinuxSllPacketType::FIRST_INVALID..=u16::MAX => Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField{ - packet_type: value - }), + LinuxSllPacketType::FIRST_INVALID..=u16::MAX => { + Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: value }) + } } } } @@ -89,8 +89,8 @@ impl core::fmt::Debug for LinuxSllPacketType { #[cfg(test)] mod test { - use alloc::format; use super::*; + use alloc::format; #[test] fn to_u16() { @@ -106,16 +106,46 @@ mod test { #[test] fn try_from_u16() { - assert_eq!(LinuxSllPacketType::try_from(0), Ok(LinuxSllPacketType::HOST)); - assert_eq!(LinuxSllPacketType::try_from(1), Ok(LinuxSllPacketType::BROADCAST)); - assert_eq!(LinuxSllPacketType::try_from(2), Ok(LinuxSllPacketType::MULTICAST)); - assert_eq!(LinuxSllPacketType::try_from(3), Ok(LinuxSllPacketType::OTHERHOST)); - assert_eq!(LinuxSllPacketType::try_from(4), Ok(LinuxSllPacketType::OUTGOING)); - assert_eq!(LinuxSllPacketType::try_from(5), Ok(LinuxSllPacketType::LOOPBACK)); - assert_eq!(LinuxSllPacketType::try_from(6), Ok(LinuxSllPacketType::USER)); - assert_eq!(LinuxSllPacketType::try_from(7), Ok(LinuxSllPacketType::KERNEL)); - assert_eq!(LinuxSllPacketType::try_from(8), Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 8 })); - assert_eq!(LinuxSllPacketType::try_from(123), Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 })); + assert_eq!( + LinuxSllPacketType::try_from(0), + Ok(LinuxSllPacketType::HOST) + ); + assert_eq!( + LinuxSllPacketType::try_from(1), + Ok(LinuxSllPacketType::BROADCAST) + ); + assert_eq!( + LinuxSllPacketType::try_from(2), + Ok(LinuxSllPacketType::MULTICAST) + ); + assert_eq!( + LinuxSllPacketType::try_from(3), + Ok(LinuxSllPacketType::OTHERHOST) + ); + assert_eq!( + LinuxSllPacketType::try_from(4), + Ok(LinuxSllPacketType::OUTGOING) + ); + assert_eq!( + LinuxSllPacketType::try_from(5), + Ok(LinuxSllPacketType::LOOPBACK) + ); + assert_eq!( + LinuxSllPacketType::try_from(6), + Ok(LinuxSllPacketType::USER) + ); + assert_eq!( + LinuxSllPacketType::try_from(7), + Ok(LinuxSllPacketType::KERNEL) + ); + assert_eq!( + LinuxSllPacketType::try_from(8), + Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 8 }) + ); + assert_eq!( + LinuxSllPacketType::try_from(123), + Err(err::linux_sll::HeaderError::UnsupportedPacketTypeField { packet_type: 123 }) + ); } #[test] diff --git a/etherparse/src/link/linux_sll_payload_slice.rs b/etherparse/src/link/linux_sll_payload_slice.rs index 26b1b7a0..3c39c2a9 100644 --- a/etherparse/src/link/linux_sll_payload_slice.rs +++ b/etherparse/src/link/linux_sll_payload_slice.rs @@ -14,7 +14,7 @@ impl<'a> From> for LinuxSllPayloadSlice<'a> { fn from(value: EtherPayloadSlice<'a>) -> LinuxSllPayloadSlice<'a> { LinuxSllPayloadSlice { protocol_type: LinuxSllProtocolType::EtherType(value.ether_type), - payload: value.payload + payload: value.payload, } } } @@ -27,16 +27,14 @@ impl<'a> TryFrom> for EtherPayloadSlice<'a> { LinuxSllProtocolType::LinuxNonstandardEtherType(nonstandard_ether_type) => { Ok(EtherPayloadSlice { ether_type: EtherType(nonstandard_ether_type.into()), - payload: value.payload + payload: value.payload, }) - }, - LinuxSllProtocolType::EtherType(ether_type) => { - Ok(EtherPayloadSlice { - ether_type, - payload: value.payload - }) - }, - _ => Err(()) + } + LinuxSllProtocolType::EtherType(ether_type) => Ok(EtherPayloadSlice { + ether_type, + payload: value.payload, + }), + _ => Err(()), } } } diff --git a/etherparse/src/link/linux_sll_protocol_type.rs b/etherparse/src/link/linux_sll_protocol_type.rs index 3f589df8..da259b6e 100644 --- a/etherparse/src/link/linux_sll_protocol_type.rs +++ b/etherparse/src/link/linux_sll_protocol_type.rs @@ -1,8 +1,8 @@ use crate::{err, ArpHardwareId, EtherType, LinuxNonstandardEtherType}; /// Represents the "protcol type" field in a Linux Cooked Capture v1 packet. It -/// is represented as an enum due to the meaning of the inner value depending -/// on the associated arp_hardware_id field. +/// is represented as an enum due to the meaning of the inner value depending +/// on the associated arp_hardware_id field. /// /// You can convert pairs of ArpHardwareId and its associated u16 value with ` /// LinuxSllProtocolType::try_from()`, an Err(_) is returned if the relation is @@ -39,18 +39,23 @@ impl LinuxSllProtocolType { ArpHardwareId::IPGRE, ArpHardwareId::IEEE80211_RADIOTAP, ArpHardwareId::FRAD, - ArpHardwareId::ETHER + ArpHardwareId::ETHER, ]; pub fn change_value(&mut self, value: u16) { *self = match *self { LinuxSllProtocolType::Ignored(_) => LinuxSllProtocolType::Ignored(value), - LinuxSllProtocolType::NetlinkProtocolType(_) => LinuxSllProtocolType::NetlinkProtocolType(value), - LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(_) => LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(value), - LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType (_) => { + LinuxSllProtocolType::NetlinkProtocolType(_) => { + LinuxSllProtocolType::NetlinkProtocolType(value) + } + LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(_) => { + LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(value) + } + LinuxSllProtocolType::EtherType(_) + | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => { match LinuxNonstandardEtherType::try_from(value) { Ok(v) => LinuxSllProtocolType::LinuxNonstandardEtherType(v), - Err(_) => LinuxSllProtocolType::EtherType(EtherType(value)) + Err(_) => LinuxSllProtocolType::EtherType(EtherType(value)), } } } @@ -60,17 +65,23 @@ impl LinuxSllProtocolType { impl TryFrom<(ArpHardwareId, u16)> for LinuxSllProtocolType { type Error = err::linux_sll::HeaderError; - fn try_from((arp_hardware_id, protocol_type): (ArpHardwareId, u16)) -> Result { + fn try_from( + (arp_hardware_id, protocol_type): (ArpHardwareId, u16), + ) -> Result { match arp_hardware_id { ArpHardwareId::NETLINK => Ok(LinuxSllProtocolType::NetlinkProtocolType(protocol_type)), - ArpHardwareId::IPGRE => Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(protocol_type)), + ArpHardwareId::IPGRE => { + Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(protocol_type)) + } ArpHardwareId::IEEE80211_RADIOTAP => Ok(LinuxSllProtocolType::Ignored(protocol_type)), ArpHardwareId::FRAD => Ok(LinuxSllProtocolType::Ignored(protocol_type)), ArpHardwareId::ETHER => match LinuxNonstandardEtherType::try_from(protocol_type) { Ok(v) => Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(v)), - Err(_) => Ok(LinuxSllProtocolType::EtherType(EtherType(protocol_type))) + Err(_) => Ok(LinuxSllProtocolType::EtherType(EtherType(protocol_type))), }, - _ => Err(err::linux_sll::HeaderError::UnsupportedArpHardwareId{arp_hardware_type: arp_hardware_id}) + _ => Err(err::linux_sll::HeaderError::UnsupportedArpHardwareId { + arp_hardware_type: arp_hardware_id, + }), } } } @@ -93,11 +104,34 @@ mod test { #[test] fn try_from_pair_arp_hardware_id_u16() { - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::NETLINK, 123)), Ok(LinuxSllProtocolType::NetlinkProtocolType(123))); - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::IPGRE, 123)), Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(123))); - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::IEEE80211_RADIOTAP, 123)), Ok(LinuxSllProtocolType::Ignored(123))); - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::FRAD, 123)), Ok(LinuxSllProtocolType::Ignored(123))); - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(LinuxNonstandardEtherType::N802_3))), Ok(LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType::N802_3))); - assert_eq!(LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(EtherType::IPV4))), Ok(LinuxSllProtocolType::EtherType(EtherType::IPV4))); + assert_eq!( + LinuxSllProtocolType::try_from((ArpHardwareId::NETLINK, 123)), + Ok(LinuxSllProtocolType::NetlinkProtocolType(123)) + ); + assert_eq!( + LinuxSllProtocolType::try_from((ArpHardwareId::IPGRE, 123)), + Ok(LinuxSllProtocolType::GenericRoutingEncapsulationProtocolType(123)) + ); + assert_eq!( + LinuxSllProtocolType::try_from((ArpHardwareId::IEEE80211_RADIOTAP, 123)), + Ok(LinuxSllProtocolType::Ignored(123)) + ); + assert_eq!( + LinuxSllProtocolType::try_from((ArpHardwareId::FRAD, 123)), + Ok(LinuxSllProtocolType::Ignored(123)) + ); + assert_eq!( + LinuxSllProtocolType::try_from(( + ArpHardwareId::ETHER, + u16::from(LinuxNonstandardEtherType::N802_3) + )), + Ok(LinuxSllProtocolType::LinuxNonstandardEtherType( + LinuxNonstandardEtherType::N802_3 + )) + ); + assert_eq!( + LinuxSllProtocolType::try_from((ArpHardwareId::ETHER, u16::from(EtherType::IPV4))), + Ok(LinuxSllProtocolType::EtherType(EtherType::IPV4)) + ); } } diff --git a/etherparse/src/link/linux_sll_slice.rs b/etherparse/src/link/linux_sll_slice.rs index e3b490a0..9c2f2191 100644 --- a/etherparse/src/link/linux_sll_slice.rs +++ b/etherparse/src/link/linux_sll_slice.rs @@ -1,4 +1,8 @@ -use crate::{err::{self, Layer}, ArpHardwareId, LenSource, LinuxSllHeader, LinuxSllHeaderSlice, LinuxSllPacketType, LinuxSllPayloadSlice, LinuxSllProtocolType}; +use crate::{ + err::{self, Layer}, + ArpHardwareId, LenSource, LinuxSllHeader, LinuxSllHeaderSlice, LinuxSllPacketType, + LinuxSllPayloadSlice, LinuxSllProtocolType, +}; /// Slice containing a Linux Cooked Capture v1 (SLL) header & payload. #[derive(Clone, Eq, PartialEq)] @@ -10,7 +14,9 @@ pub struct LinuxSllSlice<'a> { impl<'a> LinuxSllSlice<'a> { /// Try creating a [`LinuxSllSlice`] from a slice containing the /// header & payload - pub fn from_slice(slice: &'a [u8]) -> Result, err::linux_sll::HeaderSliceError> { + pub fn from_slice( + slice: &'a [u8], + ) -> Result, err::linux_sll::HeaderSliceError> { // check length if slice.len() < LinuxSllHeader::LEN { return Err(err::linux_sll::HeaderSliceError::Len(err::LenError { @@ -25,8 +31,11 @@ impl<'a> LinuxSllSlice<'a> { // extract header match LinuxSllHeaderSlice::from_slice(&slice[0..LinuxSllHeader::LEN]) { Err(err) => Err(err), - Ok(header_slice) => Ok(LinuxSllSlice{header_slice, header_and_payload_slice: slice}) - } + Ok(header_slice) => Ok(LinuxSllSlice { + header_slice, + header_and_payload_slice: slice, + }), + } } /// Returns the slice containing the Linux Cooked Capture v1 (SLL) header & @@ -54,27 +63,27 @@ impl<'a> LinuxSllSlice<'a> { self.header_slice.sender_address_valid_length() } - /// Read the link layer address field from the header. Only the first + /// Read the link layer address field from the header. Only the first /// `LinuxSllSlice::link_layer_address_length` bytes are meaningful #[inline] pub fn sender_address_full(&self) -> [u8; 8] { self.header_slice.sender_address_full() } - /// Get the meaningful bytes of the slice of the link layer address from + /// Get the meaningful bytes of the slice of the link layer address from /// the header #[inline] - pub fn sender_address(&self) -> &'a [u8] { + pub fn sender_address(&self) -> &'a [u8] { self.header_slice.sender_address() } /// Read the protocol type field from the header #[inline] - pub fn protocol_type(&self) -> LinuxSllProtocolType { + pub fn protocol_type(&self) -> LinuxSllProtocolType { self.header_slice.protocol_type() } - /// Decode all the header fields and copy the results to a + /// Decode all the header fields and copy the results to a /// [`LinuxSllHeader`] struct pub fn to_header(&self) -> LinuxSllHeader { LinuxSllHeader { @@ -104,16 +113,18 @@ impl<'a> LinuxSllSlice<'a> { /// Slice only containing the payload #[inline] pub fn payload_slice(&self) -> &'a [u8] { - // SAFETY: Safe as the slice length was verified to be at least + // SAFETY: Safe as the slice length was verified to be at least // LinuxSllHeader::LEN by "from_slice". unsafe { core::slice::from_raw_parts( - self.header_and_payload_slice.as_ptr().add(LinuxSllHeader::LEN), + self.header_and_payload_slice + .as_ptr() + .add(LinuxSllHeader::LEN), self.header_and_payload_slice.len() - LinuxSllHeader::LEN, ) } } - + /// Length of the header in bytes (equal to [`crate::LinuxSllHeader::LEN`]) #[inline] pub const fn header_len(&self) -> usize { @@ -137,7 +148,6 @@ mod test { use alloc::{format, vec::Vec}; use proptest::prelude::*; - proptest! { #[test] fn debug_clone_eq( diff --git a/etherparse/src/link/mod.rs b/etherparse/src/link/mod.rs index 9e041f79..fab5b803 100644 --- a/etherparse/src/link/mod.rs +++ b/etherparse/src/link/mod.rs @@ -7,15 +7,15 @@ pub mod ether_type_impl; pub mod ethernet2_header; pub mod ethernet2_header_slice; pub mod ethernet2_slice; +pub mod link_header; +pub mod link_slice; pub mod linux_nonstandard_ether_type; -pub mod linux_sll_header_slice; pub mod linux_sll_header; +pub mod linux_sll_header_slice; pub mod linux_sll_packet_type; pub mod linux_sll_payload_slice; pub mod linux_sll_protocol_type; pub mod linux_sll_slice; -pub mod link_header; -pub mod link_slice; pub mod single_vlan_header; pub mod single_vlan_header_slice; pub mod single_vlan_slice; diff --git a/etherparse/src/packet_builder.rs b/etherparse/src/packet_builder.rs index 3f82e18e..ee92031d 100644 --- a/etherparse/src/packet_builder.rs +++ b/etherparse/src/packet_builder.rs @@ -177,8 +177,8 @@ impl PacketBuilder { /// builder.write(&mut result, &payload).unwrap(); /// ``` pub fn linux_sll( - packet_type: LinuxSllPacketType, - sender_address_valid_length: u16, + packet_type: LinuxSllPacketType, + sender_address_valid_length: u16, sender_address: [u8; 8], ) -> PacketBuilderStep { PacketBuilderStep { @@ -188,7 +188,7 @@ impl PacketBuilder { arp_hrd_type: ArpHardwareId::ETHER, sender_address_valid_length, sender_address, - protocol_type: LinuxSllProtocolType::EtherType(EtherType(0)) // Will be overwitten when writing depending on the net layer + protocol_type: LinuxSllProtocolType::EtherType(EtherType(0)), // Will be overwitten when writing depending on the net layer })), vlan_header: None, ip_header: None, @@ -1785,7 +1785,7 @@ fn final_write( eth.write(writer).map_err(Io)?; } LinkHeader::LinuxSll(mut linux_sll) => { - // Assumes that next layers are ether based. If more types of + // Assumes that next layers are ether based. If more types of // layers are supported, this should be updated debug_assert_eq!(linux_sll.arp_hrd_type, ArpHardwareId::ETHER); diff --git a/etherparse/src/packet_headers.rs b/etherparse/src/packet_headers.rs index 7e58a152..73e69e60 100644 --- a/etherparse/src/packet_headers.rs +++ b/etherparse/src/packet_headers.rs @@ -419,7 +419,7 @@ fn read_transport( #[cfg(test)] mod test { use super::*; - use crate::err::{packet::SliceError}; + use crate::err::packet::SliceError; use crate::test_packet::TestPacket; const VLAN_ETHER_TYPES: [EtherType; 3] = [ diff --git a/etherparse/src/sliced_packet.rs b/etherparse/src/sliced_packet.rs index 346dad41..b2eb30ac 100644 --- a/etherparse/src/sliced_packet.rs +++ b/etherparse/src/sliced_packet.rs @@ -94,10 +94,10 @@ impl<'a> SlicedPacket<'a> { SlicedPacketCursor::new(data).slice_ethernet2() } - /// Separates a network packet slice into different slices containing the + /// Separates a network packet slice into different slices containing the /// headers from the Linux Cooked Capture v1 (SLL) header downwards. /// - /// The result is returned as a [`SlicedPacket`] struct. This function + /// The result is returned as a [`SlicedPacket`] struct. This function /// assumes the given data starts with a Linux Cooked Capture v1 (SLL) /// header. /// @@ -271,18 +271,20 @@ impl<'a> SlicedPacket<'a> { match link { Ethernet2(eth) => Some(eth.ether_type()), LinkSlice::LinuxSll(e) => match e.protocol_type() { - LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { - Some(EtherType(v)) - } - _ => None - } + LinuxSllProtocolType::EtherType(EtherType(v)) + | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType( + v, + )) => Some(EtherType(v)), + _ => None, + }, EtherPayload(e) => Some(e.ether_type), LinkSlice::LinuxSllPayload(e) => match e.protocol_type { - LinuxSllProtocolType::EtherType(EtherType(v)) | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType(v)) => { - Some(EtherType(v)) - } - _ => None - } + LinuxSllProtocolType::EtherType(EtherType(v)) + | LinuxSllProtocolType::LinuxNonstandardEtherType(LinuxNonstandardEtherType( + v, + )) => Some(EtherType(v)), + _ => None, + }, } } else { None @@ -304,14 +306,20 @@ impl<'a> SlicedPacket<'a> { match link { LinkSlice::Ethernet2(e) => Some(e.payload()), LinkSlice::LinuxSll(e) => match e.protocol_type() { - LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.payload()).ok()?), - _ => None - } + LinuxSllProtocolType::EtherType(_) + | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => { + Some(EtherPayloadSlice::try_from(e.payload()).ok()?) + } + _ => None, + }, LinkSlice::EtherPayload(e) => Some(e.clone()), LinkSlice::LinuxSllPayload(e) => match e.protocol_type { - LinuxSllProtocolType::EtherType(_) | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => Some(EtherPayloadSlice::try_from(e.clone()).ok()?), - _ => None - } + LinuxSllProtocolType::EtherType(_) + | LinuxSllProtocolType::LinuxNonstandardEtherType(_) => { + Some(EtherPayloadSlice::try_from(e.clone()).ok()?) + } + _ => None, + }, } } else { None @@ -444,7 +452,7 @@ mod test { arp_hrd_type: ArpHardwareId::ETHER, sender_address_valid_length: 6, sender_address: [1, 2, 3, 4, 5, 6, 0, 0], - protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN) + protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN), } .to_bytes(), ); @@ -659,7 +667,7 @@ mod test { arp_hrd_type: ArpHardwareId::ETHER, sender_address_valid_length: 6, sender_address: [1, 2, 3, 4, 5, 6, 0, 0], - protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN) + protocol_type: LinuxSllProtocolType::EtherType(EtherType::WAKE_ON_LAN), }; let test = TestPacket { link: Some(LinkHeader::LinuxSll(linux_sll.clone())), @@ -1453,8 +1461,13 @@ mod test { // from_ethernet_slice if let Some(ref header) = test.link { match header { - LinkHeader::Ethernet2(_) => assert_eq!(err.clone(), SlicedPacket::from_ethernet(&data).unwrap_err()), - LinkHeader::LinuxSll(_) => assert_eq!(err.clone(), SlicedPacket::from_linux_sll(&data).unwrap_err()), + LinkHeader::Ethernet2(_) => { + assert_eq!(err.clone(), SlicedPacket::from_ethernet(&data).unwrap_err()) + } + LinkHeader::LinuxSll(_) => assert_eq!( + err.clone(), + SlicedPacket::from_linux_sll(&data).unwrap_err() + ), } } // from_ether_type (vlan at start) diff --git a/etherparse/src/sliced_packet_cursor.rs b/etherparse/src/sliced_packet_cursor.rs index 3ae3d34d..fb1a364e 100644 --- a/etherparse/src/sliced_packet_cursor.rs +++ b/etherparse/src/sliced_packet_cursor.rs @@ -58,11 +58,12 @@ impl<'a> SlicedPacketCursor<'a> { pub fn slice_linux_sll(mut self) -> Result, err::packet::SliceError> { use err::packet::SliceError::*; - let result = LinuxSllSlice::from_slice(self.slice) - .map_err(|err| match err { - err::linux_sll::HeaderSliceError::Len(len) => Len(len.add_offset(self.offset)), - err::linux_sll::HeaderSliceError::Content(content) => err::packet::SliceError::LinuxSll(content), - })?; + let result = LinuxSllSlice::from_slice(self.slice).map_err(|err| match err { + err::linux_sll::HeaderSliceError::Len(len) => Len(len.add_offset(self.offset)), + err::linux_sll::HeaderSliceError::Content(content) => { + err::packet::SliceError::LinuxSll(content) + } + })?; //cache the protocol type for later let protocol_type = result.protocol_type(); diff --git a/etherparse/src/test_gens/mod.rs b/etherparse/src/test_gens/mod.rs index 73a70b7b..c677a354 100644 --- a/etherparse/src/test_gens/mod.rs +++ b/etherparse/src/test_gens/mod.rs @@ -125,7 +125,7 @@ prop_compose! { sender_address.resize(8, 0); let mut v: [u8; 8] = [0u8;8]; v.copy_from_slice(&sender_address); - + (size, v) } } diff --git a/etherparse/src/test_packet.rs b/etherparse/src/test_packet.rs index aac354f4..13691d6f 100644 --- a/etherparse/src/test_packet.rs +++ b/etherparse/src/test_packet.rs @@ -59,7 +59,9 @@ impl TestPacket { } 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), + LinkHeader::LinuxSll(linux_sll) => { + linux_sll.protocol_type.change_value(ether_type.0) + } } } }