]> git.ipfire.org Git - people/ms/linux.git/blobdiff - net/rxrpc/input.c
afs: Adjust ACK interpretation to try and cope with NAT
[people/ms/linux.git] / net / rxrpc / input.c
index 853b869b026a7786c7e0436dca35cb723ba6e2be..16c0af41c202ae2c7b6c53299b712ceb2585788a 100644 (file)
@@ -903,6 +903,33 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
                                  rxrpc_propose_ack_respond_to_ack);
        }
 
+       /* If we get an EXCEEDS_WINDOW ACK from the server, it probably
+        * indicates that the client address changed due to NAT.  The server
+        * lost the call because it switched to a different peer.
+        */
+       if (unlikely(buf.ack.reason == RXRPC_ACK_EXCEEDS_WINDOW) &&
+           first_soft_ack == 1 &&
+           prev_pkt == 0 &&
+           rxrpc_is_client_call(call)) {
+               rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
+                                         0, -ENETRESET);
+               return;
+       }
+
+       /* If we get an OUT_OF_SEQUENCE ACK from the server, that can also
+        * indicate a change of address.  However, we can retransmit the call
+        * if we still have it buffered to the beginning.
+        */
+       if (unlikely(buf.ack.reason == RXRPC_ACK_OUT_OF_SEQUENCE) &&
+           first_soft_ack == 1 &&
+           prev_pkt == 0 &&
+           call->tx_hard_ack == 0 &&
+           rxrpc_is_client_call(call)) {
+               rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
+                                         0, -ENETRESET);
+               return;
+       }
+
        /* Discard any out-of-order or duplicate ACKs (outside lock). */
        if (!rxrpc_is_ack_valid(call, first_soft_ack, prev_pkt)) {
                trace_rxrpc_rx_discard_ack(call->debug_id, ack_serial,