summaryrefslogtreecommitdiffstats
path: root/net/rxrpc
diff options
context:
space:
mode:
authorJeffrey Altman <jaltman@auristor.com>2019-04-12 11:34:16 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-12 19:57:23 -0400
commit1a2391c30c0b9d041bc340f68df81d49c53546cc (patch)
treeadec0da77205b01e590914e28aca0930926f9949 /net/rxrpc
parent39ce67557568962fa9d1593741f76c4cc6762469 (diff)
rxrpc: Fix detection of out of order acks
The rxrpc packet serial number cannot be safely used to compute out of order ack packets for several reasons: 1. The allocation of serial numbers cannot be assumed to imply the order by which acks are populated and transmitted. In some rxrpc implementations, delayed acks and ping acks are transmitted asynchronously to the receipt of data packets and so may be transmitted out of order. As a result, they can race with idle acks. 2. Serial numbers are allocated by the rxrpc connection and not the call and as such may wrap independently if multiple channels are in use. In any case, what matters is whether the ack packet provides new information relating to the bounds of the window (the firstPacket and previousPacket in the ACK data). Fix this by discarding packets that appear to wind back the window bounds rather than on serial number procession. Fixes: 298bc15b2079 ("rxrpc: Only take the rwind and mtu values from latest ACK") Signed-off-by: Jeffrey Altman <jaltman@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Marc Dionne <marc.dionne@auristor.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc')
-rw-r--r--net/rxrpc/ar-internal.h1
-rw-r--r--net/rxrpc/input.c18
2 files changed, 13 insertions, 6 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 4b1a534d290a..062ca9dc29b8 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -654,6 +654,7 @@ struct rxrpc_call {
654 u8 ackr_reason; /* reason to ACK */ 654 u8 ackr_reason; /* reason to ACK */
655 u16 ackr_skew; /* skew on packet being ACK'd */ 655 u16 ackr_skew; /* skew on packet being ACK'd */
656 rxrpc_serial_t ackr_serial; /* serial of packet being ACK'd */ 656 rxrpc_serial_t ackr_serial; /* serial of packet being ACK'd */
657 rxrpc_serial_t ackr_first_seq; /* first sequence number received */
657 rxrpc_seq_t ackr_prev_seq; /* previous sequence number received */ 658 rxrpc_seq_t ackr_prev_seq; /* previous sequence number received */
658 rxrpc_seq_t ackr_consumed; /* Highest packet shown consumed */ 659 rxrpc_seq_t ackr_consumed; /* Highest packet shown consumed */
659 rxrpc_seq_t ackr_seen; /* Highest packet shown seen */ 660 rxrpc_seq_t ackr_seen; /* Highest packet shown seen */
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index 9128aa0e40aa..4c6f9d0a00e7 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -837,7 +837,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
837 u8 acks[RXRPC_MAXACKS]; 837 u8 acks[RXRPC_MAXACKS];
838 } buf; 838 } buf;
839 rxrpc_serial_t acked_serial; 839 rxrpc_serial_t acked_serial;
840 rxrpc_seq_t first_soft_ack, hard_ack; 840 rxrpc_seq_t first_soft_ack, hard_ack, prev_pkt;
841 int nr_acks, offset, ioffset; 841 int nr_acks, offset, ioffset;
842 842
843 _enter(""); 843 _enter("");
@@ -851,13 +851,14 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
851 851
852 acked_serial = ntohl(buf.ack.serial); 852 acked_serial = ntohl(buf.ack.serial);
853 first_soft_ack = ntohl(buf.ack.firstPacket); 853 first_soft_ack = ntohl(buf.ack.firstPacket);
854 prev_pkt = ntohl(buf.ack.previousPacket);
854 hard_ack = first_soft_ack - 1; 855 hard_ack = first_soft_ack - 1;
855 nr_acks = buf.ack.nAcks; 856 nr_acks = buf.ack.nAcks;
856 summary.ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ? 857 summary.ack_reason = (buf.ack.reason < RXRPC_ACK__INVALID ?
857 buf.ack.reason : RXRPC_ACK__INVALID); 858 buf.ack.reason : RXRPC_ACK__INVALID);
858 859
859 trace_rxrpc_rx_ack(call, sp->hdr.serial, acked_serial, 860 trace_rxrpc_rx_ack(call, sp->hdr.serial, acked_serial,
860 first_soft_ack, ntohl(buf.ack.previousPacket), 861 first_soft_ack, prev_pkt,
861 summary.ack_reason, nr_acks); 862 summary.ack_reason, nr_acks);
862 863
863 if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE) 864 if (buf.ack.reason == RXRPC_ACK_PING_RESPONSE)
@@ -878,8 +879,9 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
878 rxrpc_propose_ack_respond_to_ack); 879 rxrpc_propose_ack_respond_to_ack);
879 } 880 }
880 881
881 /* Discard any out-of-order or duplicate ACKs. */ 882 /* Discard any out-of-order or duplicate ACKs (outside lock). */
882 if (before_eq(sp->hdr.serial, call->acks_latest)) 883 if (before(first_soft_ack, call->ackr_first_seq) ||
884 before(prev_pkt, call->ackr_prev_seq))
883 return; 885 return;
884 886
885 buf.info.rxMTU = 0; 887 buf.info.rxMTU = 0;
@@ -890,12 +892,16 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,
890 892
891 spin_lock(&call->input_lock); 893 spin_lock(&call->input_lock);
892 894
893 /* Discard any out-of-order or duplicate ACKs. */ 895 /* Discard any out-of-order or duplicate ACKs (inside lock). */
894 if (before_eq(sp->hdr.serial, call->acks_latest)) 896 if (before(first_soft_ack, call->ackr_first_seq) ||
897 before(prev_pkt, call->ackr_prev_seq))
895 goto out; 898 goto out;
896 call->acks_latest_ts = skb->tstamp; 899 call->acks_latest_ts = skb->tstamp;
897 call->acks_latest = sp->hdr.serial; 900 call->acks_latest = sp->hdr.serial;
898 901
902 call->ackr_first_seq = first_soft_ack;
903 call->ackr_prev_seq = prev_pkt;
904
899 /* Parse rwind and mtu sizes if provided. */ 905 /* Parse rwind and mtu sizes if provided. */
900 if (buf.info.rxMTU) 906 if (buf.info.rxMTU)
901 rxrpc_input_ackinfo(call, skb, &buf.info); 907 rxrpc_input_ackinfo(call, skb, &buf.info);