Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TCP simultaneous open #1001

Merged
merged 1 commit into from
Oct 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 140 additions & 8 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1508,18 +1508,17 @@ impl<'a> Socket<'a> {
(State::Listen, _, None) => (),
// This case is handled in `accepts()`.
(State::Listen, _, Some(_)) => unreachable!(),
// Every packet after the initial SYN must be an acknowledgement.
(_, _, None) => {
net_debug!("expecting an ACK");
return None;
}
// SYN|ACK in the SYN-SENT state must have the exact ACK number.
(State::SynSent, TcpControl::Syn, Some(ack_number)) => {
if ack_number != self.local_seq_no + 1 {
net_debug!("unacceptable SYN|ACK in response to initial SYN");
return Some(Self::rst_reply(ip_repr, repr));
}
}
// TCP simultaneous open.
// This is required by RFC 9293, which states "A TCP implementation MUST support
// simultaneous open attempts (MUST-10)."
(State::SynSent, TcpControl::Syn, None) => (),
// ACKs in the SYN-SENT state are invalid.
(State::SynSent, TcpControl::None, Some(ack_number)) => {
// If the sequence number matches, ignore it instead of RSTing.
Expand All @@ -1543,6 +1542,11 @@ impl<'a> Socket<'a> {
net_debug!("expecting a SYN|ACK");
return None;
}
// Every packet after the initial SYN must be an acknowledgement.
(_, _, None) => {
net_debug!("expecting an ACK");
return None;
}
// ACK in the SYN-RECEIVED state must have the exact ACK number, or we RST it.
(State::SynReceived, _, Some(ack_number)) => {
if ack_number != self.local_seq_no + 1 {
Expand Down Expand Up @@ -1722,7 +1726,10 @@ impl<'a> Socket<'a> {
(State::Listen, TcpControl::Rst) => return None,

// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
(State::SynReceived, TcpControl::Rst) => {
// Here we need to additionally check `listen_endpoint`, because we want to make sure
// that SYN-RECEIVED was actually converted from the LISTEN state (another possible
// reason is TCP simultaneous open).
(State::SynReceived, TcpControl::Rst) if self.listen_endpoint.port != 0 => {
tcp_trace!("received RST");
self.tuple = None;
self.set_state(State::Listen);
Expand Down Expand Up @@ -1789,8 +1796,13 @@ impl<'a> Socket<'a> {
}

// SYN|ACK packets in the SYN-SENT state change it to ESTABLISHED.
// SYN packets in the SYN-SENT state change it to SYN-RECEIVED.
(State::SynSent, TcpControl::Syn) => {
tcp_trace!("received SYN|ACK");
if repr.ack_number.is_some() {
tcp_trace!("received SYN|ACK");
} else {
tcp_trace!("received SYN");
}
if let Some(max_seg_size) = repr.max_seg_size {
if max_seg_size == 0 {
tcp_trace!("received SYNACK with zero MSS, ignoring");
Expand All @@ -1816,7 +1828,11 @@ impl<'a> Socket<'a> {
self.tsval_generator = None;
}

self.set_state(State::Established);
if repr.ack_number.is_some() {
self.set_state(State::Established);
} else {
self.set_state(State::SynReceived);
}
self.timer.set_for_idle(cx.now(), self.keep_alive);
}

Expand Down Expand Up @@ -2333,6 +2349,7 @@ impl<'a> Socket<'a> {
// We transmit a SYN|ACK in the SYN-RECEIVED state.
State::SynSent | State::SynReceived => {
repr.control = TcpControl::Syn;
repr.seq_number = self.local_seq_no;
// window len must NOT be scaled in SYNs.
repr.window_len = u16::try_from(self.rx_buffer.window()).unwrap_or(u16::MAX);
if self.state == State::SynSent {
Expand Down Expand Up @@ -3537,6 +3554,78 @@ mod test {
sanity!(s, socket_established());
}

#[test]
fn test_syn_sent_syn_received_ack() {
let mut s = socket_syn_sent();
recv!(
s,
[TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: None,
max_seg_size: Some(BASE_MSS),
window_scale: Some(0),
sack_permitted: true,
..RECV_TEMPL
}]
);

// A SYN packet changes the SYN-SENT state to SYN-RECEIVED.
send!(
s,
TcpRepr {
control: TcpControl::Syn,
seq_number: REMOTE_SEQ,
ack_number: None,
max_seg_size: Some(BASE_MSS - 80),
window_scale: Some(0),
..SEND_TEMPL
}
);
assert_eq!(s.state, State::SynReceived);

// The socket will then send a SYN|ACK packet.
recv!(
s,
[TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(BASE_MSS),
window_scale: Some(0),
..RECV_TEMPL
}]
);
recv_nothing!(s);

// The socket may retransmit the SYN|ACK packet.
recv!(
s,
time 1001,
Ok(TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(BASE_MSS),
window_scale: Some(0),
..RECV_TEMPL
})
);

// An ACK packet changes the SYN-RECEIVED state to ESTABLISHED.
send!(
s,
TcpRepr {
control: TcpControl::None,
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1),
..SEND_TEMPL
}
);
assert_eq!(s.state, State::Established);
sanity!(s, socket_established());
}

#[test]
fn test_syn_sent_syn_ack_not_incremented() {
let mut s = socket_syn_sent();
Expand Down Expand Up @@ -3573,6 +3662,49 @@ mod test {
assert_eq!(s.state, State::SynSent);
}

#[test]
fn test_syn_sent_syn_received_rst() {
let mut s = socket_syn_sent();
recv!(
s,
[TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: None,
max_seg_size: Some(BASE_MSS),
window_scale: Some(0),
sack_permitted: true,
..RECV_TEMPL
}]
);

// A SYN packet changes the SYN-SENT state to SYN-RECEIVED.
send!(
s,
TcpRepr {
control: TcpControl::Syn,
seq_number: REMOTE_SEQ,
ack_number: None,
max_seg_size: Some(BASE_MSS - 80),
window_scale: Some(0),
..SEND_TEMPL
}
);
assert_eq!(s.state, State::SynReceived);

// A RST packet changes the SYN-RECEIVED state to CLOSED.
send!(
s,
TcpRepr {
control: TcpControl::Rst,
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ),
..SEND_TEMPL
}
);
assert_eq!(s.state, State::Closed);
}

#[test]
fn test_syn_sent_rst() {
let mut s = socket_syn_sent();
Expand Down
Loading