Skip to main content

net_wire/tcp/
builder.rs

1//! TCP caller-buffer builder.
2
3use super::flags::TcpFlags;
4use super::segment::{HEADER_LENGTH, TcpSegmentMut};
5use core::fmt;
6
7/// Failure to construct a TCP segment in caller-provided storage.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum TcpSegmentBuildError {
10    /// The source port was not supplied.
11    MissingSourcePort,
12    /// The destination port was not supplied.
13    MissingDestinationPort,
14    /// Options are not a multiple of four octets or exceed forty octets.
15    InvalidOptionsLength,
16    /// The requested segment length cannot be represented as a `usize`.
17    SegmentLengthTooLarge,
18    /// The buffer cannot hold the requested segment.
19    BufferTooShort {
20        /// Required bytes.
21        required: usize,
22        /// Available bytes.
23        available: usize,
24    },
25}
26
27impl fmt::Display for TcpSegmentBuildError {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match self {
30            Self::MissingSourcePort => f.write_str("missing TCP source port"),
31            Self::MissingDestinationPort => f.write_str("missing TCP destination port"),
32            Self::InvalidOptionsLength => f.write_str("invalid TCP options length"),
33            Self::SegmentLengthTooLarge => f.write_str("TCP segment length exceeds platform limit"),
34            Self::BufferTooShort {
35                required,
36                available,
37            } => write!(
38                f,
39                "TCP buffer is too short: need {required} bytes, have {available}"
40            ),
41        }
42    }
43}
44
45/// Builds a TCP header in caller-owned storage.
46pub struct TcpSegmentBuilder<'a, 'b> {
47    buffer: &'a mut [u8],
48    payload_length: usize,
49    options: &'b [u8],
50    source_port: Option<u16>,
51    destination_port: Option<u16>,
52    sequence_number: u32,
53    acknowledgment_number: u32,
54    flags: TcpFlags,
55    window_size: u16,
56    checksum: u16,
57    urgent_pointer: u16,
58}
59
60impl<'a, 'b> TcpSegmentBuilder<'a, 'b> {
61    /// Starts a builder for `payload_length` bytes, which are left untouched.
62    pub fn new(buffer: &'a mut [u8], payload_length: usize) -> Self {
63        Self {
64            buffer,
65            payload_length,
66            options: &[],
67            source_port: None,
68            destination_port: None,
69            sequence_number: 0,
70            acknowledgment_number: 0,
71            flags: TcpFlags::new(0),
72            window_size: 0,
73            checksum: 0,
74            urgent_pointer: 0,
75        }
76    }
77
78    /// Supplies the source port.
79    pub fn source_port(mut self, value: u16) -> Self {
80        self.source_port = Some(value);
81        self
82    }
83
84    /// Supplies the destination port.
85    pub fn destination_port(mut self, value: u16) -> Self {
86        self.destination_port = Some(value);
87        self
88    }
89
90    /// Supplies copied header options.
91    pub fn options(mut self, value: &'b [u8]) -> Self {
92        self.options = value;
93        self
94    }
95
96    /// Supplies the sequence number.
97    pub fn sequence_number(mut self, value: u32) -> Self {
98        self.sequence_number = value;
99        self
100    }
101
102    /// Supplies the acknowledgment number.
103    pub fn acknowledgment_number(mut self, value: u32) -> Self {
104        self.acknowledgment_number = value;
105        self
106    }
107
108    /// Supplies flags.
109    pub fn flags(mut self, value: TcpFlags) -> Self {
110        self.flags = value;
111        self
112    }
113
114    /// Supplies the window size.
115    pub fn window_size(mut self, value: u16) -> Self {
116        self.window_size = value;
117        self
118    }
119
120    /// Supplies the checksum.
121    pub fn checksum(mut self, value: u16) -> Self {
122        self.checksum = value;
123        self
124    }
125
126    /// Supplies the urgent pointer.
127    pub fn urgent_pointer(mut self, value: u16) -> Self {
128        self.urgent_pointer = value;
129        self
130    }
131
132    /// Validates inputs and writes only the TCP header and options.
133    pub fn build(self) -> Result<TcpSegmentMut<'a>, TcpSegmentBuildError> {
134        let source_port = self
135            .source_port
136            .ok_or(TcpSegmentBuildError::MissingSourcePort)?;
137        let destination_port = self
138            .destination_port
139            .ok_or(TcpSegmentBuildError::MissingDestinationPort)?;
140        if self.options.len() > 40 || !self.options.len().is_multiple_of(4) {
141            return Err(TcpSegmentBuildError::InvalidOptionsLength);
142        }
143        let header_length = HEADER_LENGTH
144            .checked_add(self.options.len())
145            .ok_or(TcpSegmentBuildError::SegmentLengthTooLarge)?;
146        let segment_length = header_length
147            .checked_add(self.payload_length)
148            .ok_or(TcpSegmentBuildError::SegmentLengthTooLarge)?;
149        if self.buffer.len() < segment_length {
150            return Err(TcpSegmentBuildError::BufferTooShort {
151                required: segment_length,
152                available: self.buffer.len(),
153            });
154        }
155
156        let bytes = &mut self.buffer[..segment_length];
157        bytes[0..2].copy_from_slice(&source_port.to_be_bytes());
158        bytes[2..4].copy_from_slice(&destination_port.to_be_bytes());
159        bytes[4..8].copy_from_slice(&self.sequence_number.to_be_bytes());
160        bytes[8..12].copy_from_slice(&self.acknowledgment_number.to_be_bytes());
161        bytes[12] = u8::try_from(header_length / 4).expect("TCP header length fits") << 4;
162        bytes[13] = self.flags.raw();
163        bytes[14..16].copy_from_slice(&self.window_size.to_be_bytes());
164        bytes[16..18].copy_from_slice(&self.checksum.to_be_bytes());
165        bytes[18..20].copy_from_slice(&self.urgent_pointer.to_be_bytes());
166        bytes[HEADER_LENGTH..header_length].copy_from_slice(self.options);
167        Ok(TcpSegmentMut::from_validated(bytes))
168    }
169}