|  | @@ -382,6 +382,9 @@ pub struct TcpSocket<'a> {
 | 
	
		
			
				|  |  |      /// ACK or window updates (ie, no data) won't be sent until expiry.
 | 
	
		
			
				|  |  |      ack_delay_timer: AckDelayTimer,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /// Used for rate-limiting: No more challenge ACKs will be sent until this instant.
 | 
	
		
			
				|  |  | +    challenge_ack_timer: Instant,
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /// Nagle's Algorithm enabled.
 | 
	
		
			
				|  |  |      nagle: bool,
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -443,6 +446,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |              local_rx_dup_acks: 0,
 | 
	
		
			
				|  |  |              ack_delay: Some(ACK_DELAY_DEFAULT),
 | 
	
		
			
				|  |  |              ack_delay_timer: AckDelayTimer::Idle,
 | 
	
		
			
				|  |  | +            challenge_ack_timer: Instant::from_secs(0),
 | 
	
		
			
				|  |  |              nagle: true,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              #[cfg(feature = "async")]
 | 
	
	
		
			
				|  | @@ -573,7 +577,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Set the keep-alive interval.
 | 
	
		
			
				|  |  |      ///
 | 
	
		
			
				|  |  | -    /// An idle socket with a keep-alive interval set will transmit a "challenge ACK" packet
 | 
	
		
			
				|  |  | +    /// An idle socket with a keep-alive interval set will transmit a "keep-alive ACK" packet
 | 
	
		
			
				|  |  |      /// every time it receives no communication during that interval. As a result, three things
 | 
	
		
			
				|  |  |      /// may happen:
 | 
	
		
			
				|  |  |      ///
 | 
	
	
		
			
				|  | @@ -666,6 +670,8 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |          self.remote_last_ts = None;
 | 
	
		
			
				|  |  |          self.ack_delay = Some(ACK_DELAY_DEFAULT);
 | 
	
		
			
				|  |  |          self.ack_delay_timer = AckDelayTimer::Idle;
 | 
	
		
			
				|  |  | +        self.challenge_ack_timer = Instant::from_secs(0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          self.nagle = true;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          #[cfg(feature = "async")]
 | 
	
	
		
			
				|  | @@ -1159,7 +1165,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |          // of why we sometimes send an RST and sometimes an RST|ACK
 | 
	
		
			
				|  |  |          reply_repr.control = TcpControl::Rst;
 | 
	
		
			
				|  |  |          reply_repr.seq_number = repr.ack_number.unwrap_or_default();
 | 
	
		
			
				|  |  | -        if repr.control == TcpControl::Syn {
 | 
	
		
			
				|  |  | +        if repr.control == TcpControl::Syn && repr.ack_number.is_none() {
 | 
	
		
			
				|  |  |              reply_repr.ack_number = Some(repr.seq_number + repr.segment_len());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1223,6 +1229,22 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |          (ip_reply_repr, reply_repr)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    fn challenge_ack_reply(
 | 
	
		
			
				|  |  | +        &mut self,
 | 
	
		
			
				|  |  | +        cx: &Context,
 | 
	
		
			
				|  |  | +        ip_repr: &IpRepr,
 | 
	
		
			
				|  |  | +        repr: &TcpRepr,
 | 
	
		
			
				|  |  | +    ) -> Option<(IpRepr, TcpRepr<'static>)> {
 | 
	
		
			
				|  |  | +        if cx.now < self.challenge_ack_timer {
 | 
	
		
			
				|  |  | +            return None;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Rate-limit to 1 per second max.
 | 
	
		
			
				|  |  | +        self.challenge_ack_timer = cx.now + Duration::from_secs(1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return Some(self.ack_reply(ip_repr, repr));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub(crate) fn accepts(&self, ip_repr: &IpRepr, repr: &TcpRepr) -> bool {
 | 
	
		
			
				|  |  |          if self.state == State::Closed {
 | 
	
		
			
				|  |  |              return false;
 | 
	
	
		
			
				|  | @@ -1279,17 +1301,10 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |          let control_len = (sent_syn as usize) + (sent_fin as usize);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // Reject unacceptable acknowledgements.
 | 
	
		
			
				|  |  | -        match (self.state, repr) {
 | 
	
		
			
				|  |  | +        match (self.state, repr.control, repr.ack_number) {
 | 
	
		
			
				|  |  |              // An RST received in response to initial SYN is acceptable if it acknowledges
 | 
	
		
			
				|  |  |              // the initial SYN.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                State::SynSent,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    control: TcpControl::Rst,
 | 
	
		
			
				|  |  | -                    ack_number: None,
 | 
	
		
			
				|  |  | -                    ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => {
 | 
	
		
			
				|  |  | +            (State::SynSent, TcpControl::Rst, None) => {
 | 
	
		
			
				|  |  |                  net_debug!(
 | 
	
		
			
				|  |  |                      "{}:{}:{}: unacceptable RST (expecting RST|ACK) \
 | 
	
		
			
				|  |  |                              in response to initial SYN",
 | 
	
	
		
			
				|  | @@ -1299,14 +1314,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                  );
 | 
	
		
			
				|  |  |                  return Err(Error::Dropped);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                State::SynSent,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    control: TcpControl::Rst,
 | 
	
		
			
				|  |  | -                    ack_number: Some(ack_number),
 | 
	
		
			
				|  |  | -                    ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => {
 | 
	
		
			
				|  |  | +            (State::SynSent, TcpControl::Rst, Some(ack_number)) => {
 | 
	
		
			
				|  |  |                  if ack_number != self.local_seq_no + 1 {
 | 
	
		
			
				|  |  |                      net_debug!(
 | 
	
		
			
				|  |  |                          "{}:{}:{}: unacceptable RST|ACK in response to initial SYN",
 | 
	
	
		
			
				|  | @@ -1318,35 +1326,13 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              // Any other RST need only have a valid sequence number.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                _,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    control: TcpControl::Rst,
 | 
	
		
			
				|  |  | -                    ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => (),
 | 
	
		
			
				|  |  | +            (_, TcpControl::Rst, _) => (),
 | 
	
		
			
				|  |  |              // The initial SYN cannot contain an acknowledgement.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                State::Listen,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    ack_number: None, ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => (),
 | 
	
		
			
				|  |  | -            // This case is handled above.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                State::Listen,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    ack_number: Some(_),
 | 
	
		
			
				|  |  | -                    ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => unreachable!(),
 | 
	
		
			
				|  |  | +            (State::Listen, _, None) => (),
 | 
	
		
			
				|  |  | +            // This case is handled in `accepts()`.
 | 
	
		
			
				|  |  | +            (State::Listen, _, Some(_)) => unreachable!(),
 | 
	
		
			
				|  |  |              // Every packet after the initial SYN must be an acknowledgement.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                _,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    ack_number: None, ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => {
 | 
	
		
			
				|  |  | +            (_, _, None) => {
 | 
	
		
			
				|  |  |                  net_debug!(
 | 
	
		
			
				|  |  |                      "{}:{}:{}: expecting an ACK",
 | 
	
		
			
				|  |  |                      self.meta.handle,
 | 
	
	
		
			
				|  | @@ -1356,14 +1342,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                  return Err(Error::Dropped);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              // SYN|ACK in the SYN-SENT state must have the exact ACK number.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                State::SynSent,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    control: TcpControl::Syn,
 | 
	
		
			
				|  |  | -                    ack_number: Some(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",
 | 
	
	
		
			
				|  | @@ -1371,28 +1350,33 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                          self.local_endpoint,
 | 
	
		
			
				|  |  |                          self.remote_endpoint
 | 
	
		
			
				|  |  |                      );
 | 
	
		
			
				|  |  | -                    return Err(Error::Dropped);
 | 
	
		
			
				|  |  | +                    return Ok(Some(Self::rst_reply(ip_repr, repr)));
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              // Anything else in the SYN-SENT state is invalid.
 | 
	
		
			
				|  |  | -            (State::SynSent, _) => {
 | 
	
		
			
				|  |  | +            (State::SynSent, _, _) => {
 | 
	
		
			
				|  |  |                  net_debug!(
 | 
	
		
			
				|  |  |                      "{}:{}:{}: expecting a SYN|ACK",
 | 
	
		
			
				|  |  |                      self.meta.handle,
 | 
	
		
			
				|  |  |                      self.local_endpoint,
 | 
	
		
			
				|  |  |                      self.remote_endpoint
 | 
	
		
			
				|  |  |                  );
 | 
	
		
			
				|  |  | -                self.abort();
 | 
	
		
			
				|  |  |                  return Err(Error::Dropped);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +            // 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 {
 | 
	
		
			
				|  |  | +                    net_debug!(
 | 
	
		
			
				|  |  | +                        "{}:{}:{}: unacceptable ACK in response to SYN|ACK",
 | 
	
		
			
				|  |  | +                        self.meta.handle,
 | 
	
		
			
				|  |  | +                        self.local_endpoint,
 | 
	
		
			
				|  |  | +                        self.remote_endpoint
 | 
	
		
			
				|  |  | +                    );
 | 
	
		
			
				|  |  | +                    return Ok(Some(Self::rst_reply(ip_repr, repr)));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |              // Every acknowledgement must be for transmitted but unacknowledged data.
 | 
	
		
			
				|  |  | -            (
 | 
	
		
			
				|  |  | -                _,
 | 
	
		
			
				|  |  | -                &TcpRepr {
 | 
	
		
			
				|  |  | -                    ack_number: Some(ack_number),
 | 
	
		
			
				|  |  | -                    ..
 | 
	
		
			
				|  |  | -                },
 | 
	
		
			
				|  |  | -            ) => {
 | 
	
		
			
				|  |  | +            (_, _, Some(ack_number)) => {
 | 
	
		
			
				|  |  |                  let unacknowledged = self.tx_buffer.len() + control_len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  // Acceptable ACK range (both inclusive)
 | 
	
	
		
			
				|  | @@ -1427,7 +1411,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                          ack_min,
 | 
	
		
			
				|  |  |                          ack_max
 | 
	
		
			
				|  |  |                      );
 | 
	
		
			
				|  |  | -                    return Ok(Some(self.ack_reply(ip_repr, repr)));
 | 
	
		
			
				|  |  | +                    return Ok(self.challenge_ack_reply(cx, ip_repr, repr));
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1493,7 +1477,7 @@ impl<'a> TcpSocket<'a> {
 | 
	
		
			
				|  |  |                          self.timer.set_for_close(cx.now);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    return Ok(Some(self.ack_reply(ip_repr, repr)));
 | 
	
		
			
				|  |  | +                    return Ok(self.challenge_ack_reply(cx, ip_repr, repr));
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -3067,7 +3051,13 @@ mod test {
 | 
	
		
			
				|  |  |                  ack_number: Some(LOCAL_SEQ), // wrong
 | 
	
		
			
				|  |  |                  ..SEND_TEMPL
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            Err(Error::Dropped)
 | 
	
		
			
				|  |  | +            Ok(Some(TcpRepr {
 | 
	
		
			
				|  |  | +                control: TcpControl::Rst,
 | 
	
		
			
				|  |  | +                seq_number: LOCAL_SEQ,
 | 
	
		
			
				|  |  | +                ack_number: None,
 | 
	
		
			
				|  |  | +                window_len: 0,
 | 
	
		
			
				|  |  | +                ..RECV_TEMPL
 | 
	
		
			
				|  |  | +            }))
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          assert_eq!(s.state, State::SynReceived);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -3092,11 +3082,11 @@ mod test {
 | 
	
		
			
				|  |  |                  ack_number: Some(LOCAL_SEQ + 2), // wrong
 | 
	
		
			
				|  |  |                  ..SEND_TEMPL
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            // TODO is this correct? probably not
 | 
	
		
			
				|  |  |              Ok(Some(TcpRepr {
 | 
	
		
			
				|  |  | -                control: TcpControl::None,
 | 
	
		
			
				|  |  | -                seq_number: LOCAL_SEQ + 1,
 | 
	
		
			
				|  |  | -                ack_number: Some(REMOTE_SEQ + 1),
 | 
	
		
			
				|  |  | +                control: TcpControl::Rst,
 | 
	
		
			
				|  |  | +                seq_number: LOCAL_SEQ + 2,
 | 
	
		
			
				|  |  | +                ack_number: None,
 | 
	
		
			
				|  |  | +                window_len: 0,
 | 
	
		
			
				|  |  |                  ..RECV_TEMPL
 | 
	
		
			
				|  |  |              }))
 | 
	
		
			
				|  |  |          );
 | 
	
	
		
			
				|  | @@ -3424,7 +3414,13 @@ mod test {
 | 
	
		
			
				|  |  |                  window_scale: Some(0),
 | 
	
		
			
				|  |  |                  ..SEND_TEMPL
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            Err(Error::Dropped)
 | 
	
		
			
				|  |  | +            Ok(Some(TcpRepr {
 | 
	
		
			
				|  |  | +                control: TcpControl::Rst,
 | 
	
		
			
				|  |  | +                seq_number: LOCAL_SEQ,
 | 
	
		
			
				|  |  | +                ack_number: None,
 | 
	
		
			
				|  |  | +                window_len: 0,
 | 
	
		
			
				|  |  | +                ..RECV_TEMPL
 | 
	
		
			
				|  |  | +            }))
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          assert_eq!(s.state, State::SynSent);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -3488,7 +3484,7 @@ mod test {
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  |              Err(Error::Dropped)
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  | -        assert_eq!(s.state, State::Closed);
 | 
	
		
			
				|  |  | +        assert_eq!(s.state, State::SynSent);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
	
		
			
				|  | @@ -3998,6 +3994,35 @@ mod test {
 | 
	
		
			
				|  |  |              }))
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          assert_eq!(s.remote_seq_no, REMOTE_SEQ + 1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Challenge ACKs are rate-limited, we don't get a second one immediately.
 | 
	
		
			
				|  |  | +        send!(
 | 
	
		
			
				|  |  | +            s,
 | 
	
		
			
				|  |  | +            time 100,
 | 
	
		
			
				|  |  | +            TcpRepr {
 | 
	
		
			
				|  |  | +                seq_number: REMOTE_SEQ + 1 + 256,
 | 
	
		
			
				|  |  | +                ack_number: Some(LOCAL_SEQ + 1),
 | 
	
		
			
				|  |  | +                ..SEND_TEMPL
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            Ok(None)
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // If we wait a bit, we do get a new one.
 | 
	
		
			
				|  |  | +        send!(
 | 
	
		
			
				|  |  | +            s,
 | 
	
		
			
				|  |  | +            time 2000,
 | 
	
		
			
				|  |  | +            TcpRepr {
 | 
	
		
			
				|  |  | +                seq_number: REMOTE_SEQ + 1 + 256,
 | 
	
		
			
				|  |  | +                ack_number: Some(LOCAL_SEQ + 1),
 | 
	
		
			
				|  |  | +                ..SEND_TEMPL
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            Ok(Some(TcpRepr {
 | 
	
		
			
				|  |  | +                seq_number: LOCAL_SEQ + 1,
 | 
	
		
			
				|  |  | +                ack_number: Some(REMOTE_SEQ + 1),
 | 
	
		
			
				|  |  | +                ..RECV_TEMPL
 | 
	
		
			
				|  |  | +            }))
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        assert_eq!(s.remote_seq_no, REMOTE_SEQ + 1);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
	
		
			
				|  | @@ -4176,6 +4201,7 @@ mod test {
 | 
	
		
			
				|  |  |          // See https://github.com/smoltcp-rs/smoltcp/issues/338
 | 
	
		
			
				|  |  |          send!(
 | 
	
		
			
				|  |  |              s,
 | 
	
		
			
				|  |  | +            time 2000,
 | 
	
		
			
				|  |  |              TcpRepr {
 | 
	
		
			
				|  |  |                  control: TcpControl::Rst,
 | 
	
		
			
				|  |  |                  seq_number: REMOTE_SEQ, // Wrong seq
 |