1use super::flags::TcpFlags;
4use super::segment::{HEADER_LENGTH, TcpSegmentMut};
5use core::fmt;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum TcpSegmentBuildError {
10 MissingSourcePort,
12 MissingDestinationPort,
14 InvalidOptionsLength,
16 SegmentLengthTooLarge,
18 BufferTooShort {
20 required: usize,
22 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
45pub 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 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 pub fn source_port(mut self, value: u16) -> Self {
80 self.source_port = Some(value);
81 self
82 }
83
84 pub fn destination_port(mut self, value: u16) -> Self {
86 self.destination_port = Some(value);
87 self
88 }
89
90 pub fn options(mut self, value: &'b [u8]) -> Self {
92 self.options = value;
93 self
94 }
95
96 pub fn sequence_number(mut self, value: u32) -> Self {
98 self.sequence_number = value;
99 self
100 }
101
102 pub fn acknowledgment_number(mut self, value: u32) -> Self {
104 self.acknowledgment_number = value;
105 self
106 }
107
108 pub fn flags(mut self, value: TcpFlags) -> Self {
110 self.flags = value;
111 self
112 }
113
114 pub fn window_size(mut self, value: u16) -> Self {
116 self.window_size = value;
117 self
118 }
119
120 pub fn checksum(mut self, value: u16) -> Self {
122 self.checksum = value;
123 self
124 }
125
126 pub fn urgent_pointer(mut self, value: u16) -> Self {
128 self.urgent_pointer = value;
129 self
130 }
131
132 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}