| use crate::*; |
| |
| /// Deprecated use [`crate::NetSlice`] or [`crate::IpSlice`] instead. |
| #[cfg(feature = "std")] |
| #[deprecated( |
| since = "0.14.0", |
| note = "Deprecated use crate::NetSlice or crate::IpSlice instead" |
| )] |
| pub use NetSlice as InternetSlice; |
| |
| /// Slice containing the network headers & payloads (e.g. IPv4, IPv6, ARP). |
| #[derive(Clone, Debug, Eq, PartialEq)] |
| pub enum NetSlice<'a> { |
| /// The ipv4 header & the decoded extension headers. |
| Ipv4(Ipv4Slice<'a>), |
| /// The ipv6 header & the decoded extension headers. |
| Ipv6(Ipv6Slice<'a>), |
| /// The arp header & the decoded extension headers. |
| Arp(ArpPacketSlice<'a>), |
| } |
| |
| impl<'a> NetSlice<'a> { |
| /// Returns true if the NetSlice contains either IPv4 or IPv6. |
| #[inline] |
| pub fn is_ip(&self) -> bool { |
| use NetSlice::*; |
| matches!(self, Ipv4(_) | Ipv6(_)) |
| } |
| |
| /// Returns true if the NetSlice contains IPv4. |
| #[inline] |
| pub fn is_ipv4(&self) -> bool { |
| use NetSlice::*; |
| matches!(self, Ipv4(_)) |
| } |
| |
| /// Returns true if the NetSlice contains IPv6. |
| #[inline] |
| pub fn is_ipv6(&self) -> bool { |
| use NetSlice::*; |
| matches!(self, Ipv6(_)) |
| } |
| |
| /// Returns true if the NetSlice contains ARP. |
| #[inline] |
| pub fn is_arp(&self) -> bool { |
| use NetSlice::*; |
| matches!(self, Arp(_)) |
| } |
| |
| /// Returns references to the IPv4 slice if the slice contains an IPv4 values. |
| #[inline] |
| pub fn ipv4_ref(&self) -> Option<&Ipv4Slice<'a>> { |
| if let NetSlice::Ipv4(s) = self { |
| Some(s) |
| } else { |
| None |
| } |
| } |
| |
| /// Returns references to the IPv6 slice if the slice contains an IPv6 values. |
| #[inline] |
| pub fn ipv6_ref(&self) -> Option<&Ipv6Slice<'a>> { |
| if let NetSlice::Ipv6(s) = self { |
| Some(s) |
| } else { |
| None |
| } |
| } |
| |
| /// Returns references to the ARP packet slice if the slice contains an ARP values. |
| #[inline] |
| pub fn arp_ref(&self) -> Option<&ArpPacketSlice> { |
| if let NetSlice::Arp(arp) = self { |
| Some(arp) |
| } else { |
| None |
| } |
| } |
| |
| /// Returns a reference to ip payload if the net slice contains |
| /// an ipv4 or ipv6 slice. |
| #[inline] |
| pub fn ip_payload_ref(&self) -> Option<&IpPayloadSlice<'a>> { |
| match self { |
| NetSlice::Ipv4(s) => Some(&s.payload), |
| NetSlice::Ipv6(s) => Some(&s.payload), |
| NetSlice::Arp(_) => None, |
| } |
| } |
| } |
| |
| impl<'a> From<IpSlice<'a>> for NetSlice<'a> { |
| #[inline] |
| fn from(value: IpSlice<'a>) -> NetSlice<'a> { |
| match value { |
| IpSlice::Ipv4(ipv4) => NetSlice::Ipv4(ipv4), |
| IpSlice::Ipv6(ipv6) => NetSlice::Ipv6(ipv6), |
| } |
| } |
| } |
| |
| impl<'a> From<Ipv4Slice<'a>> for NetSlice<'a> { |
| #[inline] |
| fn from(value: Ipv4Slice<'a>) -> NetSlice<'a> { |
| NetSlice::Ipv4(value) |
| } |
| } |
| |
| impl<'a> From<Ipv6Slice<'a>> for NetSlice<'a> { |
| #[inline] |
| fn from(value: Ipv6Slice<'a>) -> NetSlice<'a> { |
| NetSlice::Ipv6(value) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use crate::*; |
| use alloc::{format, vec::Vec}; |
| |
| #[test] |
| fn debug() { |
| let bytes = Ipv6Header { |
| next_header: IpNumber::UDP, |
| ..Default::default() |
| } |
| .to_bytes(); |
| let s = Ipv6Slice::from_slice(&bytes).unwrap(); |
| let n = NetSlice::Ipv6(s.clone()); |
| assert_eq!(format!("{n:?}"), format!("Ipv6({s:?})")); |
| } |
| |
| #[test] |
| fn clone_eq() { |
| let bytes = Ipv6Header { |
| next_header: IpNumber::UDP, |
| ..Default::default() |
| } |
| .to_bytes(); |
| let s = NetSlice::Ipv6(Ipv6Slice::from_slice(&bytes).unwrap()); |
| assert_eq!(s, s.clone()) |
| } |
| |
| #[test] |
| fn ip_payload_ref_and_is_ip() { |
| // ipv4 |
| { |
| let payload = [1, 2, 3, 4]; |
| let bytes = { |
| let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); |
| bytes.extend_from_slice( |
| &(Ipv4Header { |
| total_len: Ipv4Header::MIN_LEN_U16 + 4, |
| protocol: IpNumber::UDP, |
| ..Default::default() |
| }) |
| .to_bytes(), |
| ); |
| bytes.extend_from_slice(&payload); |
| bytes |
| }; |
| let p = Ipv4Slice::from_slice(&bytes).unwrap(); |
| let s = NetSlice::Ipv4(p.clone()); |
| assert_eq!( |
| s.ip_payload_ref(), |
| Some(&IpPayloadSlice { |
| ip_number: IpNumber::UDP, |
| fragmented: false, |
| len_source: LenSource::Ipv4HeaderTotalLen, |
| payload: &payload |
| }) |
| ); |
| assert!(s.is_ip()); |
| assert!(s.is_ipv4()); |
| assert_eq!(false, s.is_ipv6()); |
| assert_eq!(false, s.is_arp()); |
| assert_eq!(Some(&p), s.ipv4_ref()); |
| assert_eq!(None, s.ipv6_ref()); |
| assert_eq!(None, s.arp_ref()); |
| } |
| // ipv6 |
| { |
| let payload = [1, 2, 3, 4]; |
| let bytes = { |
| let mut bytes = Vec::with_capacity(Ipv6Header::LEN + 4); |
| bytes.extend_from_slice( |
| &(Ipv6Header { |
| next_header: IpNumber::UDP, |
| payload_length: 4, |
| ..Default::default() |
| }) |
| .to_bytes(), |
| ); |
| bytes.extend_from_slice(&payload); |
| bytes |
| }; |
| let p = Ipv6Slice::from_slice(&bytes).unwrap(); |
| let s = NetSlice::Ipv6(p.clone()); |
| assert_eq!( |
| s.ip_payload_ref(), |
| Some(&IpPayloadSlice { |
| ip_number: IpNumber::UDP, |
| fragmented: false, |
| len_source: LenSource::Ipv6HeaderPayloadLen, |
| payload: &payload |
| }) |
| ); |
| assert!(s.is_ip()); |
| assert_eq!(false, s.is_ipv4()); |
| assert!(s.is_ipv6()); |
| assert_eq!(false, s.is_arp()); |
| assert_eq!(None, s.ipv4_ref()); |
| assert_eq!(Some(&p), s.ipv6_ref()); |
| assert_eq!(None, s.arp_ref()); |
| } |
| // arp |
| { |
| let arp = ArpPacket::new( |
| ArpHardwareId::ETHERNET, |
| EtherType::IPV4, |
| ArpOperation::REPLY, |
| &[0; 6], |
| &[0; 4], |
| &[0; 6], |
| &[0; 4], |
| ) |
| .unwrap(); |
| let bytes = arp.to_bytes(); |
| let p = ArpPacketSlice::from_slice(&bytes).unwrap(); |
| let s = NetSlice::Arp(p.clone()); |
| assert_eq!(None, s.ip_payload_ref()); |
| assert_eq!(false, s.is_ip()); |
| assert_eq!(false, s.is_ipv4()); |
| assert_eq!(false, s.is_ipv6()); |
| assert!(s.is_arp()); |
| assert_eq!(None, s.ipv4_ref()); |
| assert_eq!(None, s.ipv6_ref()); |
| assert_eq!(Some(&p), s.arp_ref()); |
| } |
| } |
| |
| #[test] |
| fn from() { |
| // IpSlice::Ipv4 |
| { |
| let payload = [1, 2, 3, 4]; |
| let bytes = { |
| let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); |
| bytes.extend_from_slice( |
| &(Ipv4Header { |
| total_len: Ipv4Header::MIN_LEN_U16 + 4, |
| protocol: IpNumber::UDP, |
| ..Default::default() |
| }) |
| .to_bytes(), |
| ); |
| bytes.extend_from_slice(&payload); |
| bytes |
| }; |
| let i = Ipv4Slice::from_slice(&bytes).unwrap(); |
| let actual: NetSlice = IpSlice::Ipv4(i.clone()).into(); |
| assert_eq!(NetSlice::Ipv4(i.clone()), actual); |
| } |
| // Ipv4Slice |
| { |
| let payload = [1, 2, 3, 4]; |
| let bytes = { |
| let mut bytes = Vec::with_capacity(Ipv4Header::MIN_LEN + 4); |
| bytes.extend_from_slice( |
| &(Ipv4Header { |
| total_len: Ipv4Header::MIN_LEN_U16 + 4, |
| protocol: IpNumber::UDP, |
| ..Default::default() |
| }) |
| .to_bytes(), |
| ); |
| bytes.extend_from_slice(&payload); |
| bytes |
| }; |
| let i = Ipv4Slice::from_slice(&bytes).unwrap(); |
| let actual: NetSlice = i.clone().into(); |
| assert_eq!(NetSlice::Ipv4(i.clone()), actual); |
| } |
| // IpSlice::Ipv6 |
| { |
| let payload = [1, 2, 3, 4]; |
| let bytes = { |
| let mut bytes = Vec::with_capacity(Ipv6Header::LEN + 4); |
| bytes.extend_from_slice( |
| &(Ipv6Header { |
| next_header: IpNumber::UDP, |
| payload_length: 4, |
| ..Default::default() |
| }) |
| .to_bytes(), |
| ); |
| bytes.extend_from_slice(&payload); |
| bytes |
| }; |
| let i = Ipv6Slice::from_slice(&bytes).unwrap(); |
| let actual: NetSlice = i.clone().into(); |
| assert_eq!(NetSlice::Ipv6(i.clone()), actual); |
| } |
| } |
| } |