vmm/dumbo/tcp/
mod.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Provides functionality for handling incoming TCP connections.
5
6pub mod connection;
7mod endpoint;
8pub mod handler;
9
10use std::fmt::Debug;
11use std::num::Wrapping;
12
13use crate::dumbo::pdu::bytes::NetworkBytes;
14use crate::dumbo::pdu::tcp::{Flags as TcpFlags, TcpSegment};
15
16/// The largest possible window size (requires the window scaling option).
17pub const MAX_WINDOW_SIZE: u32 = 1_073_725_440;
18
19/// The default maximum segment size (MSS) value, used when no MSS information is carried
20/// over the initial handshake.
21pub const MSS_DEFAULT: u16 = 536;
22
23/// Describes whether a particular entity (a [`Connection`] for example) has segments to send.
24///
25/// [`Connection`]: connection/struct.Connection.html
26#[derive(Debug, PartialEq, Eq)]
27pub enum NextSegmentStatus {
28    /// At least one segment is available immediately.
29    Available,
30    /// There's nothing to send.
31    Nothing,
32    /// A retransmission timeout (RTO) will trigger after the specified point in time.
33    Timeout(u64),
34}
35
36/// Represents the configuration of the sequence number and `ACK` number fields for outgoing
37/// `RST` segments.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum RstConfig {
40    /// The `RST` segment will carry the specified sequence number, and will not have
41    /// the `ACK` flag set.
42    Seq(u32),
43    /// The `RST` segment will carry 0 as the sequence number, will have the `ACK` flag enabled,
44    /// and the `ACK` number will be set to the specified value.
45    Ack(u32),
46}
47
48impl RstConfig {
49    /// Creates a `RstConfig` in response to the given segment.
50    pub fn new<T: NetworkBytes + Debug>(s: &TcpSegment<T>) -> Self {
51        if s.flags_after_ns().intersects(TcpFlags::ACK) {
52            // If s contains an ACK number, we use that as the sequence number of the RST.
53            RstConfig::Seq(s.ack_number())
54        } else {
55            // Otherwise we try to guess a valid ACK number for the RST like this.
56            RstConfig::Ack(s.sequence_number().wrapping_add(s.payload_len().into()))
57        }
58    }
59
60    /// Returns the sequence number, acknowledgement number, and TCP flags (not counting `NS`) that
61    /// must be set on the outgoing `RST` segment.
62    pub fn seq_ack_tcp_flags(self) -> (u32, u32, TcpFlags) {
63        match self {
64            RstConfig::Seq(seq) => (seq, 0, TcpFlags::RST),
65            RstConfig::Ack(ack) => (0, ack, TcpFlags::RST | TcpFlags::ACK),
66        }
67    }
68}
69
70/// Returns true if `a` comes after `b` in the sequence number space, relative to the maximum
71/// possible window size.
72///
73/// Please note this is not a connex binary relation; in other words, given two sequence numbers,
74/// it's sometimes possible that `seq_after(a, b) || seq_after(b, a) == false`. This is why
75/// `seq_after(a, b)` can't be defined as simply `!seq_at_or_after(b, a)`.
76#[inline]
77pub fn seq_after(a: Wrapping<u32>, b: Wrapping<u32>) -> bool {
78    a != b && (a - b).0 < MAX_WINDOW_SIZE
79}
80
81/// Returns true if `a` comes after, or is at `b` in the sequence number space, relative to
82/// the maximum possible window size.
83///
84/// Please note this is not a connex binary relation; in other words, given two sequence numbers,
85/// it's sometimes possible that `seq_at_or_after(a, b) || seq_at_or_after(b, a) == false`. This
86/// is why `seq_after(a, b)` can't be defined as simply `!seq_at_or_after(b, a)`.
87#[inline]
88pub fn seq_at_or_after(a: Wrapping<u32>, b: Wrapping<u32>) -> bool {
89    (a - b).0 < MAX_WINDOW_SIZE
90}
91
92#[cfg(test)]
93mod tests {
94    use micro_http::{Request, Response, StatusCode, Version};
95
96    use super::*;
97
98    // In tcp tests, some of the functions require a callback parameter. Since we do not care,
99    // for the purpose of those tests, what that callback does, we need to provide a dummy one.
100    pub fn mock_callback(_request: Request) -> Response {
101        Response::new(Version::Http11, StatusCode::OK)
102    }
103
104    #[test]
105    fn test_rst_config() {
106        let mut buf = [0u8; 100];
107
108        let seq = 1234;
109        let ack = 5678;
110
111        let mut s = TcpSegment::write_segment::<[u8]>(
112            buf.as_mut(),
113            0,
114            0,
115            seq,
116            ack,
117            TcpFlags::empty(),
118            0,
119            None,
120            100,
121            None,
122            None,
123        )
124        .unwrap();
125
126        // The ACK flag isn't set, and the payload length is 0.
127        let cfg = RstConfig::new(&s);
128        assert_eq!(cfg, RstConfig::Ack(seq));
129        assert_eq!(
130            cfg.seq_ack_tcp_flags(),
131            (0, seq, TcpFlags::RST | TcpFlags::ACK)
132        );
133
134        // Let's set the ACK flag.
135        s.set_flags_after_ns(TcpFlags::ACK);
136        let cfg = RstConfig::new(&s);
137        assert_eq!(cfg, RstConfig::Seq(ack));
138        assert_eq!(cfg.seq_ack_tcp_flags(), (ack, 0, TcpFlags::RST));
139    }
140
141    #[test]
142    fn test_seq_at_or_after() {
143        let a = Wrapping(123);
144        let b = a + Wrapping(100);
145        let c = a + Wrapping(MAX_WINDOW_SIZE);
146
147        assert!(seq_at_or_after(a, a));
148        assert!(!seq_after(a, a));
149        assert!(seq_at_or_after(b, a));
150        assert!(seq_after(b, a));
151        assert!(!seq_at_or_after(a, b));
152        assert!(!seq_after(a, b));
153        assert!(!seq_at_or_after(c, a));
154        assert!(!seq_after(c, a));
155        assert!(seq_at_or_after(c, b));
156        assert!(seq_after(c, b));
157    }
158}