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}