Skip to main content

net_wire/ipv4/
dispatch.rs

1//! IPv4 concrete upper-layer dispatch.
2
3use super::packet::{Ipv4Packet, Ipv4PacketMut};
4use super::protocol::Ipv4Protocol;
5use crate::error::ParseError;
6#[cfg(feature = "icmpv4")]
7use crate::icmpv4::message::{Icmpv4Message, Icmpv4MessageMut};
8#[cfg(feature = "tcp")]
9use crate::tcp::segment::{TcpSegment, TcpSegmentMut};
10#[cfg(feature = "udp")]
11use crate::udp::datagram::{UdpDatagram, UdpDatagramMut};
12
13#[inline]
14fn is_non_atomic_fragment(flags_fragment_offset: u16) -> bool {
15    flags_fragment_offset & 0x2000 != 0 || flags_fragment_offset & 0x1fff != 0
16}
17
18impl<'a> Ipv4Packet<'a> {
19    /// Parses ICMPv4 only when this is an unfragmented ICMP packet.
20    #[cfg(feature = "icmpv4")]
21    #[inline]
22    pub fn icmpv4(&self) -> Result<Option<Icmpv4Message<'a>>, ParseError> {
23        if self.protocol() != Ipv4Protocol::ICMP
24            || is_non_atomic_fragment(self.flags_fragment_offset())
25        {
26            return Ok(None);
27        }
28        Icmpv4Message::parse(self.payload()).map(Some)
29    }
30
31    /// Parses UDP only when this is an unfragmented UDP packet.
32    #[cfg(feature = "udp")]
33    #[inline]
34    pub fn udp(&self) -> Result<Option<UdpDatagram<'a>>, ParseError> {
35        if self.protocol() != Ipv4Protocol::UDP
36            || is_non_atomic_fragment(self.flags_fragment_offset())
37        {
38            return Ok(None);
39        }
40        UdpDatagram::parse(self.payload()).map(Some)
41    }
42
43    /// Parses TCP only when this is an unfragmented TCP packet.
44    #[cfg(feature = "tcp")]
45    #[inline]
46    pub fn tcp(&self) -> Result<Option<TcpSegment<'a>>, ParseError> {
47        if self.protocol() != Ipv4Protocol::TCP
48            || is_non_atomic_fragment(self.flags_fragment_offset())
49        {
50            return Ok(None);
51        }
52        TcpSegment::parse(self.payload()).map(Some)
53    }
54}
55
56impl<'a> Ipv4PacketMut<'a> {
57    /// Parses mutable ICMPv4 only when this is an unfragmented ICMP packet.
58    #[cfg(feature = "icmpv4")]
59    #[inline]
60    pub fn icmpv4_mut(&mut self) -> Result<Option<Icmpv4MessageMut<'_>>, ParseError> {
61        if self.protocol() != Ipv4Protocol::ICMP
62            || is_non_atomic_fragment(self.flags_fragment_offset())
63        {
64            return Ok(None);
65        }
66        Icmpv4MessageMut::parse(self.payload_mut()).map(Some)
67    }
68
69    /// Parses mutable UDP only when this is an unfragmented UDP packet.
70    #[cfg(feature = "udp")]
71    #[inline]
72    pub fn udp_mut(&mut self) -> Result<Option<UdpDatagramMut<'_>>, ParseError> {
73        if self.protocol() != Ipv4Protocol::UDP
74            || is_non_atomic_fragment(self.flags_fragment_offset())
75        {
76            return Ok(None);
77        }
78        UdpDatagramMut::parse(self.payload_mut()).map(Some)
79    }
80
81    /// Parses mutable TCP only when this is an unfragmented TCP packet.
82    #[cfg(feature = "tcp")]
83    #[inline]
84    pub fn tcp_mut(&mut self) -> Result<Option<TcpSegmentMut<'_>>, ParseError> {
85        if self.protocol() != Ipv4Protocol::TCP
86            || is_non_atomic_fragment(self.flags_fragment_offset())
87        {
88            return Ok(None);
89        }
90        TcpSegmentMut::parse(self.payload_mut()).map(Some)
91    }
92}