aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2009-11-23 15:54:00 -0500
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-11-23 15:54:00 -0500
commitd8dd15781dd621c5ceab79083f4c5112787863f5 (patch)
tree49ee8bfc01d2ded7130a0c17298ca7a9db998fa4 /net
parent46d5a808558181e03a4760d2188cc9879445738a (diff)
sctp: Fix mis-ordering of user space data when multihoming in use
Recently had a bug reported to me, in which the user was sending packets with a payload containing a sequence number. The packets were getting delivered in order according the chunk TSN values, but the sequence values in the payload were arriving out of order. At first I thought it must be an application error, but we eventually found it to be a problem on the transmit side in the sctp stack. The conditions for the error are that multihoming must be in use, and it helps if each transport has a different pmtu. The problem occurs in sctp_outq_flush. Basically we dequeue packets from the data queue, and attempt to append them to the orrered packet for a given transport. After we append a data chunk we add the trasport to the end of a list of transports to have their packets sent at the end of sctp_outq_flush. The problem occurs when a data chunks fills up a offered packet on a transport. The function that does the appending (sctp_packet_transmit_chunk), will try to call sctp_packet_transmit on the full packet, and then append the chunk to a new packet. This call to sctp_packet_transmit, sends that packet ahead of the others that may be queued in the transport_list in sctp_outq_flush. The result is that frames that were sent in one order from the user space sending application get re-ordered prior to tsn assignment in sctp_packet_transmit, resulting in mis-sequencing of data payloads, even though tsn ordering is correct. The fix is to change where we assign a tsn. By doing this earlier, we are then free to place chunks in packets, whatever way we see fit and the protocol will make sure to do all the appropriate re-ordering on receive as is needed. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Reported-by: William Reich <reich@ulticom.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/output.c25
1 files changed, 13 insertions, 12 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c
index b210d2077e28..7c5589363433 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -429,23 +429,22 @@ int sctp_packet_transmit(struct sctp_packet *packet)
429 list_del_init(&chunk->list); 429 list_del_init(&chunk->list);
430 if (sctp_chunk_is_data(chunk)) { 430 if (sctp_chunk_is_data(chunk)) {
431 431
432 if (!chunk->has_tsn) { 432 if (!chunk->resent) {
433 sctp_chunk_assign_ssn(chunk); 433
434 sctp_chunk_assign_tsn(chunk); 434 /* 6.3.1 C4) When data is in flight and when allowed
435 435 * by rule C5, a new RTT measurement MUST be made each
436 /* 6.3.1 C4) When data is in flight and when allowed 436 * round trip. Furthermore, new RTT measurements
437 * by rule C5, a new RTT measurement MUST be made each 437 * SHOULD be made no more than once per round-trip
438 * round trip. Furthermore, new RTT measurements 438 * for a given destination transport address.
439 * SHOULD be made no more than once per round-trip 439 */
440 * for a given destination transport address.
441 */
442 440
443 if (!tp->rto_pending) { 441 if (!tp->rto_pending) {
444 chunk->rtt_in_progress = 1; 442 chunk->rtt_in_progress = 1;
445 tp->rto_pending = 1; 443 tp->rto_pending = 1;
446 } 444 }
447 } else 445 }
448 chunk->resent = 1; 446
447 chunk->resent = 1;
449 448
450 has_data = 1; 449 has_data = 1;
451 } 450 }
@@ -722,6 +721,8 @@ static void sctp_packet_append_data(struct sctp_packet *packet,
722 /* Has been accepted for transmission. */ 721 /* Has been accepted for transmission. */
723 if (!asoc->peer.prsctp_capable) 722 if (!asoc->peer.prsctp_capable)
724 chunk->msg->can_abandon = 0; 723 chunk->msg->can_abandon = 0;
724 sctp_chunk_assign_tsn(chunk);
725 sctp_chunk_assign_ssn(chunk);
725} 726}
726 727
727static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, 728static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet,