1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
//! TCP access and manipulation methods.

use crate::checksum::internet_checksum;
use crate::data_buffer::traits::{
    BufferAccess, BufferAccessMut, HeaderManipulation, HeaderMetadata, Layer,
};
use crate::internal_utils::grow_or_shrink_header_at_end;
use crate::tcp::SetDataOffsetError;
use crate::utility_traits::{PseudoHeaderChecksum, UpdateIpLength};
use core::ops::Range;
use core::ops::RangeInclusive;

pub(crate) const SOURCE_PORT: Range<usize> = 0..2;
pub(crate) const DESTINATION_PORT: Range<usize> = 2..4;
pub(crate) const SEQUENCE_NUMBER: Range<usize> = 4..8;
pub(crate) const ACKNOWLEDGEMENT_NUMBER: Range<usize> = 8..12;
pub(crate) const DATA_OFFSET_BYTE: usize = 12;
pub(crate) const _DATA_OFFSET_MASK: u8 = 0b1111_0000;
pub(crate) const DATA_OFFSET_SHIFT: usize = 4;
pub(crate) const RESERVED_BYTE: usize = 12;
pub(crate) const RESERVED_MASK: u8 = 0b0000_1111;
pub(crate) const FLAGS_BYTE: usize = 13;
pub(crate) const FLAGS_CWR_MASK: u8 = 0b1000_0000;
pub(crate) const FLAGS_CWR_SHIFT: usize = 7;
pub(crate) const FLAGS_ECE_MASK: u8 = 0b0100_0000;
pub(crate) const FLAGS_ECE_SHIFT: usize = 6;
pub(crate) const FLAGS_URG_MASK: u8 = 0b0010_0000;
pub(crate) const FLAGS_URG_SHIFT: usize = 5;
pub(crate) const FLAGS_ACK_MASK: u8 = 0b0001_0000;
pub(crate) const FLAGS_ACK_SHIFT: usize = 4;
pub(crate) const FLAGS_PSH_MASK: u8 = 0b0000_1000;
pub(crate) const FLAGS_PSH_SHIFT: usize = 3;
pub(crate) const FLAGS_RST_MASK: u8 = 0b0000_0100;
pub(crate) const FLAGS_RST_SHIFT: usize = 2;
pub(crate) const FLAGS_SYN_MASK: u8 = 0b0000_0010;
pub(crate) const FLAGS_SYN_SHIFT: usize = 1;
pub(crate) const FLAGS_FIN_MASK: u8 = 0b0000_0001;
pub(crate) const WINDOW_SIZE: Range<usize> = 14..16;
pub(crate) const CHECKSUM: Range<usize> = 16..18;
pub(crate) const URGENT_POINTER: Range<usize> = 18..20;
pub(crate) const OPTIONS_START: usize = 20;

pub(crate) const HEADER_MIN_LEN: usize = 20;

pub(crate) const DATA_OFFSET_RANGE: RangeInclusive<usize> = 5..=15;

pub(crate) const LAYER: Layer = Layer::Tcp;

// Length manipulating methods:
// - set_tcp_data_offset (has proof)

/// Methods available for [`DataBuffer`](crate::data_buffer::DataBuffer) containing a
/// [`Tcp`](crate::tcp::Tcp) header.
#[allow(private_bounds)]
pub trait TcpMethods: HeaderMetadata + PseudoHeaderChecksum + BufferAccess {
    /// Returns the TCP source port.
    #[inline]
    fn tcp_source_port(&self) -> u16 {
        u16::from_be_bytes(self.read_array(LAYER, SOURCE_PORT))
    }

    /// Returns the TCP destination port.
    #[inline]
    fn tcp_destination_port(&self) -> u16 {
        u16::from_be_bytes(self.read_array(LAYER, DESTINATION_PORT))
    }

    /// Returns the TCP sequence number.
    #[inline]
    fn tcp_sequence_number(&self) -> u32 {
        u32::from_be_bytes(self.read_array(LAYER, SEQUENCE_NUMBER))
    }

    /// Returns the TCP acknowledgment number.
    #[inline]
    fn tcp_acknowledgment_number(&self) -> u32 {
        u32::from_be_bytes(self.read_array(LAYER, ACKNOWLEDGEMENT_NUMBER))
    }

    /// Returns the TCP data offset.
    #[inline]
    fn tcp_data_offset(&self) -> u8 {
        self.read_value(LAYER, DATA_OFFSET_BYTE) >> DATA_OFFSET_SHIFT
    }

    /// Returns the TCP reserved bits.
    #[inline]
    fn tcp_reserved_bits(&self) -> u8 {
        self.read_value(LAYER, RESERVED_BYTE) & RESERVED_MASK
    }

    /// Returns the TCP flags.
    #[inline]
    fn tcp_flags(&self) -> u8 {
        self.read_value(LAYER, FLAGS_BYTE)
    }

    /// Returns the TCP congestion window reduced flag.
    #[inline]
    fn tcp_congestion_window_reduced_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_CWR_MASK) != 0
    }

    /// Returns the TCP ECN echo flag.
    #[inline]
    fn tcp_ecn_echo_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_ECE_MASK) != 0
    }

    /// Returns the TCP urgent pointer flag.
    #[inline]
    fn tcp_urgent_pointer_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_URG_MASK) != 0
    }

    /// Returns the TCP acknowledgement flag.
    #[inline]
    fn tcp_acknowledgement_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_ACK_MASK) != 0
    }

    /// Returns the TCP push flag.
    #[inline]
    fn tcp_push_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_PSH_MASK) != 0
    }

    /// Returns the TCP reset flag.
    #[inline]
    fn tcp_reset_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_RST_MASK) != 0
    }

    /// Returns the TCP synchronize flag.
    #[inline]
    fn tcp_synchronize_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_SYN_MASK) != 0
    }

    /// Returns the TCP FIN flag.
    #[inline]
    fn tcp_fin_flag(&self) -> bool {
        (self.read_value(LAYER, FLAGS_BYTE) & FLAGS_FIN_MASK) != 0
    }

    /// Returns the TCP window size.
    #[inline]
    fn tcp_window_size(&self) -> u16 {
        u16::from_be_bytes(self.read_array(LAYER, WINDOW_SIZE))
    }

    /// Returns the TCP checksum.
    #[inline]
    fn tcp_checksum(&self) -> u16 {
        u16::from_be_bytes(self.read_array(LAYER, CHECKSUM))
    }

    /// Returns the TCP urgent pointer.
    #[inline]
    fn tcp_urgent_pointer(&self) -> u16 {
        u16::from_be_bytes(self.read_array(LAYER, URGENT_POINTER))
    }

    /// Returns the TCP options if present.
    #[inline]
    fn tcp_options(&self) -> Option<&[u8]> {
        let data_offset = usize::from(self.tcp_data_offset());
        if data_offset <= *DATA_OFFSET_RANGE.start() {
            None
        } else {
            Some(self.read_slice(LAYER, OPTIONS_START..data_offset * 4))
        }
    }

    /// Calculates and returns the TCP checksum.
    ///
    /// This takes lower layers into account.
    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
    /// the pseudo header will be included.
    /// If there is a [`NoPreviousHeader`](crate::no_previous_header::NoPreviousHeader) present,
    /// the pseudo header is set to zero.
    #[inline]
    fn tcp_calculate_checksum(&self) -> u16 {
        let checksum = self.pseudo_header_checksum();

        internet_checksum::<4>(checksum, self.data_buffer_starting_at_header(LAYER))
    }
}

/// Methods available for [`DataBuffer`](crate::data_buffer::DataBuffer) containing a
/// [`Tcp`](crate::tcp::Tcp) header and wrapping a mutable data buffer.
#[allow(private_bounds)]
pub trait TcpMethodsMut:
    HeaderMetadata
    + HeaderManipulation
    + BufferAccessMut
    + TcpMethods
    + PseudoHeaderChecksum
    + UpdateIpLength
    + Sized
{
    /// Set the TCP source port.
    #[inline]
    fn set_tcp_source_port(&mut self, port: u16) {
        self.write_slice(LAYER, SOURCE_PORT, &port.to_be_bytes());
    }

    /// Set the TCP destination port.
    #[inline]
    fn set_tcp_destination_port(&mut self, port: u16) {
        self.write_slice(LAYER, DESTINATION_PORT, &port.to_be_bytes());
    }

    /// Set the TCP sequence number.
    #[inline]
    fn set_tcp_sequence_number(&mut self, sequence_number: u32) {
        self.write_slice(LAYER, SEQUENCE_NUMBER, &sequence_number.to_be_bytes());
    }

    /// Set the TCP acknowledgement number.
    #[inline]
    fn set_tcp_acknowledgement_number(&mut self, acknowledgement_number: u32) {
        self.write_slice(
            LAYER,
            ACKNOWLEDGEMENT_NUMBER,
            &acknowledgement_number.to_be_bytes(),
        );
    }

    /// Set the TCP data offset.
    ///
    /// This takes lower layers into account.
    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
    /// the length of that header will be updated accordingly.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - the provided `data_offset` is not within the valid bounds (5..=15).
    /// - there is not enough headroom available to accommodate the size change.
    #[inline]
    fn set_tcp_data_offset(&mut self, data_offset: u8) -> Result<(), SetDataOffsetError> {
        let new_data_offset_usize = usize::from(data_offset);
        if !DATA_OFFSET_RANGE.contains(&new_data_offset_usize) {
            return Err(SetDataOffsetError::InvalidDataOffset {
                data_offset: new_data_offset_usize,
            });
        }
        let current_data_offset_in_bytes = usize::from(self.tcp_data_offset()) * 4;
        let new_data_offset_in_bytes = new_data_offset_usize * 4;
        grow_or_shrink_header_at_end(
            self,
            current_data_offset_in_bytes,
            new_data_offset_in_bytes,
            LAYER,
        )?;

        let new_data_offset_byte = data_offset << DATA_OFFSET_SHIFT;
        self.write_value(LAYER, DATA_OFFSET_BYTE, new_data_offset_byte);
        self.update_ip_length();
        Ok(())
    }

    /// Set the TCP reserved bits.  
    #[inline]
    fn set_tcp_reserved_bits(&mut self, mut reserved_bits: u8) {
        reserved_bits &= RESERVED_MASK;
        reserved_bits |= self.read_value(LAYER, RESERVED_BYTE) & !RESERVED_MASK;
        self.write_value(LAYER, RESERVED_BYTE, reserved_bits);
    }

    /// Set the TCP flags.
    #[inline]
    fn set_tcp_flags(&mut self, flags: u8) {
        self.write_value(LAYER, FLAGS_BYTE, flags);
    }

    /// Set the TCP congestion window reduced flag.
    #[inline]
    fn set_tcp_congestion_window_reduced_flag(&mut self, congestion_window_reduced: bool) {
        let mut congestion_window_reduced = u8::from(congestion_window_reduced) << FLAGS_CWR_SHIFT;
        congestion_window_reduced |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_CWR_MASK;
        self.write_value(LAYER, FLAGS_BYTE, congestion_window_reduced);
    }

    /// Set the TCP ECN echo flag.
    #[inline]
    fn set_tcp_ecn_echo_flag(&mut self, ecn_echo: bool) {
        let mut ecn_echo = u8::from(ecn_echo) << FLAGS_ECE_SHIFT;
        ecn_echo |= self.data_buffer_starting_at_header_mut(LAYER)[FLAGS_BYTE] & !FLAGS_ECE_MASK;
        self.write_value(LAYER, FLAGS_BYTE, ecn_echo);
    }

    /// Set the TCP urgent pointer flag.
    #[inline]
    fn set_tcp_urgent_pointer_flag(&mut self, urgent_pointer: bool) {
        let mut urgent_pointer = u8::from(urgent_pointer) << FLAGS_URG_SHIFT;
        urgent_pointer |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_URG_MASK;
        self.write_value(LAYER, FLAGS_BYTE, urgent_pointer);
    }

    /// Set the TCP acknowledgement flag.
    #[inline]
    fn set_tcp_acknowledgement_flag(&mut self, acknowledgement: bool) {
        let mut acknowledgement = u8::from(acknowledgement) << FLAGS_ACK_SHIFT;
        acknowledgement |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_ACK_MASK;
        self.write_value(LAYER, FLAGS_BYTE, acknowledgement);
    }

    /// Set the TCP push flag.
    #[inline]
    fn set_tcp_push_flag(&mut self, push: bool) {
        let mut push = u8::from(push) << FLAGS_PSH_SHIFT;
        push |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_PSH_MASK;
        self.write_value(LAYER, FLAGS_BYTE, push);
    }

    /// Set the TCP reset flag.
    #[inline]
    fn set_tcp_reset_flag(&mut self, reset: bool) {
        let mut reset = u8::from(reset) << FLAGS_RST_SHIFT;
        reset |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_RST_MASK;
        self.write_value(LAYER, FLAGS_BYTE, reset);
    }

    /// Set the TCP synchronize flag.
    #[inline]
    fn set_tcp_synchronize_flag(&mut self, synchronize: bool) {
        let mut synchronize = u8::from(synchronize) << FLAGS_SYN_SHIFT;
        synchronize |= self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_SYN_MASK;
        self.write_value(LAYER, FLAGS_BYTE, synchronize);
    }

    /// Set the TCP FIN flag.
    #[inline]
    fn set_tcp_fin_flag(&mut self, fin: bool) {
        let fin_flag = self.read_value(LAYER, FLAGS_BYTE) & !FLAGS_FIN_MASK | u8::from(fin);
        self.write_value(LAYER, FLAGS_BYTE, fin_flag);
    }

    /// Set the TCP window size.
    #[inline]
    fn set_tcp_window_size(&mut self, window_size: u16) {
        self.write_slice(LAYER, WINDOW_SIZE, &window_size.to_be_bytes());
    }

    /// Set the TCP checksum.
    #[inline]
    fn set_tcp_checksum(&mut self, checksum: u16) {
        self.write_slice(LAYER, CHECKSUM, &checksum.to_be_bytes());
    }

    /// Set the TCP urgent pointer.
    #[inline]
    fn set_tcp_urgent_pointer(&mut self, urgent_pointer: u16) {
        self.write_slice(LAYER, URGENT_POINTER, &urgent_pointer.to_be_bytes());
    }

    /// Returns a mutable slice containing the TCP options or `None` if no options are present.
    #[inline]
    fn tcp_options_mut(&mut self) -> Option<&mut [u8]> {
        let data_offset_header = usize::from(self.tcp_data_offset());
        if data_offset_header <= *DATA_OFFSET_RANGE.start() {
            None
        } else {
            let data_offset_in_bytes = data_offset_header * 4;
            Some(self.get_slice_mut(LAYER, OPTIONS_START..data_offset_in_bytes))
        }
    }

    /// Calculates and replaces the TCP checksum.
    ///
    /// This takes lower layers into account.
    /// If there is an [`IPv4`](crate::ipv4::Ipv4) or [`IPv6`](crate::ipv6::Ipv6) layer present,
    /// the pseudo header will be included.
    /// If there is a [`NoPreviousHeader`](crate::no_previous_header::NoPreviousHeader) present,
    /// the pseudo header is set to zero.
    #[inline]
    fn update_tcp_checksum(&mut self) {
        self.write_slice(LAYER, CHECKSUM, &[0, 0]);
        let checksum = self.tcp_calculate_checksum();
        self.write_slice(LAYER, CHECKSUM, &checksum.to_be_bytes());
    }
}