diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index 8c8911c7e..84d99abff 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -1508,11 +1508,6 @@ 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 { @@ -1520,6 +1515,10 @@ impl<'a> Socket<'a> { 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. @@ -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 { @@ -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); @@ -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"); @@ -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); } @@ -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 { @@ -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(); @@ -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();