|
@@ -5199,6 +5199,23 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/* Accept RST for rcv_nxt - 1 after a FIN.
|
|
|
+ * When tcp connections are abruptly terminated from Mac OSX (via ^C), a
|
|
|
+ * FIN is sent followed by a RST packet. The RST is sent with the same
|
|
|
+ * sequence number as the FIN, and thus according to RFC 5961 a challenge
|
|
|
+ * ACK should be sent. However, Mac OSX rate limits replies to challenge
|
|
|
+ * ACKs on the closed socket. In addition middleboxes can drop either the
|
|
|
+ * challenge ACK or a subsequent RST.
|
|
|
+ */
|
|
|
+static bool tcp_reset_check(const struct sock *sk, const struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
|
+
|
|
|
+ return unlikely(TCP_SKB_CB(skb)->seq == (tp->rcv_nxt - 1) &&
|
|
|
+ (1 << sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK |
|
|
|
+ TCPF_CLOSING));
|
|
|
+}
|
|
|
+
|
|
|
/* Does PAWS and seqno based validation of an incoming segment, flags will
|
|
|
* play significant role here.
|
|
|
*/
|
|
@@ -5237,20 +5254,25 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|
|
LINUX_MIB_TCPACKSKIPPEDSEQ,
|
|
|
&tp->last_oow_ack_time))
|
|
|
tcp_send_dupack(sk, skb);
|
|
|
+ } else if (tcp_reset_check(sk, skb)) {
|
|
|
+ tcp_reset(sk);
|
|
|
}
|
|
|
goto discard;
|
|
|
}
|
|
|
|
|
|
/* Step 2: check RST bit */
|
|
|
if (th->rst) {
|
|
|
- /* RFC 5961 3.2 (extend to match against SACK too if available):
|
|
|
- * If seq num matches RCV.NXT or the right-most SACK block,
|
|
|
+ /* RFC 5961 3.2 (extend to match against (RCV.NXT - 1) after a
|
|
|
+ * FIN and SACK too if available):
|
|
|
+ * If seq num matches RCV.NXT or (RCV.NXT - 1) after a FIN, or
|
|
|
+ * the right-most SACK block,
|
|
|
* then
|
|
|
* RESET the connection
|
|
|
* else
|
|
|
* Send a challenge ACK
|
|
|
*/
|
|
|
- if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
|
|
|
+ if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt ||
|
|
|
+ tcp_reset_check(sk, skb)) {
|
|
|
rst_seq_match = true;
|
|
|
} else if (tcp_is_sack(tp) && tp->rx_opt.num_sacks > 0) {
|
|
|
struct tcp_sack_block *sp = &tp->selective_acks[0];
|