mutnet/udp/
method_traits.rs

1//! UDP access and manipulation methods.
2
3use core::ops::Range;
4
5use crate::checksum::internet_checksum;
6use crate::data_buffer::{
7    BufferAccess, BufferAccessMut, HeaderManipulation, HeaderMetadata, Layer,
8};
9use crate::udp::SetLengthError;
10use crate::utility_traits::{PseudoHeaderChecksum, UpdateIpLength};
11
12pub(crate) const SOURCE_PORT: Range<usize> = 0..2;
13pub(crate) const DESTINATION_PORT: Range<usize> = 2..4;
14pub(crate) const LENGTH: Range<usize> = 4..6;
15pub(crate) const CHECKSUM: Range<usize> = 6..8;
16
17pub(crate) const HEADER_MIN_LEN: usize = 8;
18
19pub(crate) const LAYER: Layer = Layer::Udp;
20
21// Length manipulating methods:
22// - set_udp_length (has proof)
23
24/// Methods available for [`DataBuffer`](crate::data_buffer::DataBuffer) containing a
25/// [`Udp`](crate::udp::Udp) header.
26#[allow(private_bounds)]
27pub trait UdpMethods: HeaderMetadata + PseudoHeaderChecksum + BufferAccess {
28    /// Returns the UDP source port.
29    #[inline]
30    fn udp_source_port(&self) -> u16 {
31        u16::from_be_bytes(self.read_array(LAYER, SOURCE_PORT))
32    }
33
34    /// Returns the UDP destination port.
35    #[inline]
36    fn udp_destination_port(&self) -> u16 {
37        u16::from_be_bytes(self.read_array(LAYER, DESTINATION_PORT))
38    }
39
40    /// Returns the UDP length.
41    #[inline]
42    fn udp_length(&self) -> u16 {
43        u16::from_be_bytes(self.read_array(LAYER, LENGTH))
44    }
45
46    /// Returns the UDP checksum.
47    #[inline]
48    fn udp_checksum(&self) -> u16 {
49        u16::from_be_bytes(self.read_array(LAYER, CHECKSUM))
50    }
51
52    /// Calculates and returns the UDP checksum.
53    ///
54    /// This takes lower layers into account.
55    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
56    /// the pseudo header will be included.
57    /// If there is a [`NoPreviousHeader`](crate::no_previous_header::NoPreviousHeader) present,
58    /// the pseudo header is set to zero.
59    #[inline]
60    fn udp_calculate_checksum(&self) -> u16 {
61        let pseudo_header_checksum = self.pseudo_header_checksum();
62
63        let payload_end = usize::from(self.udp_length());
64        internet_checksum::<4>(
65            pseudo_header_checksum,
66            &self.data_buffer_starting_at_header(LAYER)[..payload_end],
67        )
68    }
69}
70
71/// Methods available for [`DataBuffer`](crate::data_buffer::DataBuffer) containing a
72/// [`Udp`](crate::udp::Udp) header and wrapping a mutable data buffer.
73#[allow(private_bounds)]
74pub trait UdpMethodsMut:
75    HeaderMetadata
76    + HeaderManipulation
77    + BufferAccessMut
78    + UdpMethods
79    + PseudoHeaderChecksum
80    + UpdateIpLength
81    + Sized
82{
83    /// Sets the UDP source port.
84    #[inline]
85    fn set_udp_source_port(&mut self, port: u16) {
86        self.write_slice(LAYER, SOURCE_PORT, &port.to_be_bytes());
87    }
88
89    /// Sets the UDP destination port.
90    #[inline]
91    fn set_udp_destination_port(&mut self, port: u16) {
92        self.write_slice(LAYER, DESTINATION_PORT, &port.to_be_bytes());
93    }
94
95    /// Sets the UDP length.
96    ///
97    /// This takes lower layers into account.
98    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
99    /// the length of that header will be updated accordingly.
100    ///
101    /// # Errors
102    /// Returns an error if:
103    /// - the provided `length` is smaller than eight.
104    /// - the `length` exceeds the available space.
105    #[inline]
106    fn set_udp_length(&mut self, length: u16) -> Result<(), SetLengthError> {
107        let length_usize = usize::from(length);
108
109        if length_usize < HEADER_MIN_LEN {
110            return Err(SetLengthError::LengthTooSmall {
111                length: length_usize,
112            });
113        }
114
115        let data_length = self.header_start_offset(LAYER) + length_usize;
116        self.set_data_length(data_length, self.buffer_length())?;
117
118        self.write_slice(LAYER, LENGTH, &length.to_be_bytes());
119        self.update_ip_length();
120        Ok(())
121    }
122
123    /// Sets the UDP checksum.
124    #[inline]
125    fn set_udp_checksum(&mut self, checksum: u16) {
126        self.write_slice(LAYER, CHECKSUM, &checksum.to_be_bytes());
127    }
128
129    /// Calculates and updates the UDP checksum.
130    ///
131    /// This takes lower layers into account.
132    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
133    /// the pseudo header will be included.
134    /// If there is a [`NoPreviousHeader`](crate::no_previous_header::NoPreviousHeader) present,
135    /// the pseudo header is set to zero.
136    #[inline]
137    fn update_udp_checksum(&mut self) {
138        self.write_slice(LAYER, CHECKSUM, &[0, 0]);
139        let checksum = self.udp_calculate_checksum();
140        self.write_slice(LAYER, CHECKSUM, &checksum.to_be_bytes());
141    }
142}