Commit bfdc85be authored by Jon Grimm's avatar Jon Grimm

sctp: Fix small data can bypass pending rtx data bug. (jgrimm)

parent 125903c5
...@@ -3,45 +3,45 @@ ...@@ -3,45 +3,45 @@
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* These functions implement the outqueue class. The outqueue handles * These functions implement the outqueue class. The outqueue handles
* bundling and queueing of outgoing SCTP chunks. * bundling and queueing of outgoing SCTP chunks.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Perry Melange <pmelange@null.cc.uic.edu> * Perry Melange <pmelange@null.cc.uic.edu>
* Xingang Guo <xingang.guo@intel.com> * Xingang Guo <xingang.guo@intel.com>
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -163,7 +163,7 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) ...@@ -163,7 +163,7 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
if (SCTP_CID_DATA == chunk->chunk_hdr->type) { if (SCTP_CID_DATA == chunk->chunk_hdr->type) {
/* Is it OK to queue data chunks? */ /* Is it OK to queue data chunks? */
/* From 9. Termination of Association /* From 9. Termination of Association
* *
* When either endpoint performs a shutdown, the * When either endpoint performs a shutdown, the
* association on each peer will stop accepting new * association on each peer will stop accepting new
* data from its user and only deliver data in queue * data from its user and only deliver data in queue
...@@ -276,10 +276,10 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport, ...@@ -276,10 +276,10 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
} }
/* Mark all the eligible packets on a transport for retransmission and force /* Mark all the eligible packets on a transport for retransmission and force
* one packet out. * one packet out.
*/ */
void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
int error = 0; int error = 0;
...@@ -514,7 +514,7 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, ...@@ -514,7 +514,7 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet,
* fragments. It returns the first fragment with the frag_list field holding * fragments. It returns the first fragment with the frag_list field holding
* the remaining fragments. * the remaining fragments.
*/ */
sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
size_t max_frag_data_len) size_t max_frag_data_len)
{ {
sctp_association_t *asoc = chunk->asoc; sctp_association_t *asoc = chunk->asoc;
...@@ -549,12 +549,12 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, ...@@ -549,12 +549,12 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
/* Make the middle fragments. */ /* Make the middle fragments. */
while (chunk_data_len > max_frag_data_len) { while (chunk_data_len > max_frag_data_len) {
frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
data_ptr, SCTP_DATA_MIDDLE_FRAG, data_ptr, SCTP_DATA_MIDDLE_FRAG,
ssn); ssn);
if (!frag) if (!frag)
goto err; goto err;
/* Add the middle fragment to the first fragment's /* Add the middle fragment to the first fragment's
* frag_list. * frag_list.
*/ */
list_add_tail(&frag->frag_list, frag_list); list_add_tail(&frag->frag_list, frag_list);
...@@ -773,6 +773,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -773,6 +773,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/ */
if (packet->has_cookie_echo) if (packet->has_cookie_echo)
goto sctp_flush_out; goto sctp_flush_out;
/* Don't send new data if there is still data
* waiting to retransmit.
*/
if (!list_empty(&q->retransmit))
goto sctp_flush_out;
} }
/* Finally, transmit new packets. */ /* Finally, transmit new packets. */
...@@ -849,9 +855,9 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -849,9 +855,9 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
/* We could not append this chunk, so put /* We could not append this chunk, so put
* the chunk back on the output queue. * the chunk back on the output queue.
*/ */
SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could" SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could "
"not transmit TSN: 0x%x, status: %d\n", "not transmit TSN: 0x%x, status: %d\n",
ntohl(chunk->subh.data_hdr->tsn), ntohl(chunk->subh.data_hdr->tsn),
status); status);
skb_queue_head(queue, (struct sk_buff *)chunk); skb_queue_head(queue, (struct sk_buff *)chunk);
goto sctp_flush_out; goto sctp_flush_out;
...@@ -911,7 +917,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -911,7 +917,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
default: default:
/* Do nothing. */ /* Do nothing. */
break; break;
} }
sctp_flush_out: sctp_flush_out:
...@@ -932,7 +938,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -932,7 +938,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if (packet->size != SCTP_IP_OVERHEAD) if (packet->size != SCTP_IP_OVERHEAD)
error = (*q->force_output)(packet); error = (*q->force_output)(packet);
} }
return error; return error;
} }
...@@ -1054,14 +1060,14 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) ...@@ -1054,14 +1060,14 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
if (!q->empty) if (!q->empty)
goto finish; goto finish;
list_for_each(pos, transport_list) { list_for_each(pos, transport_list) {
transport = list_entry(pos, sctp_transport_t, transports); transport = list_entry(pos, sctp_transport_t, transports);
q->empty = q->empty && list_empty(&transport->transmitted); q->empty = q->empty && list_empty(&transport->transmitted);
if (!q->empty) if (!q->empty)
goto finish; goto finish;
} }
SCTP_DEBUG_PRINTK("sack queue is empty.\n"); SCTP_DEBUG_PRINTK("sack queue is empty.\n");
finish: finish:
return q->empty; return q->empty;
} }
...@@ -1144,8 +1150,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1144,8 +1150,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 6.3.1 C5) Karn's algorithm: RTT measurements * 6.3.1 C5) Karn's algorithm: RTT measurements
* MUST NOT be made using packets that were * MUST NOT be made using packets that were
* retransmitted (and thus for which it is * retransmitted (and thus for which it is
* ambiguous whether the reply was for the * ambiguous whether the reply was for the
* first instance of the packet or a later * first instance of the packet or a later
* instance). * instance).
*/ */
if ((!tchunk->tsn_gap_acked) && if ((!tchunk->tsn_gap_acked) &&
...@@ -1181,14 +1187,14 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1181,14 +1187,14 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 'Stray DATA chunk(s)' record the highest TSN * 'Stray DATA chunk(s)' record the highest TSN
* reported as newly acknowledged, call this * reported as newly acknowledged, call this
* value 'HighestTSNinSack'. A newly * value 'HighestTSNinSack'. A newly
* acknowledged DATA chunk is one not * acknowledged DATA chunk is one not
* previously acknowledged in a SACK. * previously acknowledged in a SACK.
* *
* When the SCTP sender of data receives a SACK * When the SCTP sender of data receives a SACK
* chunk that acknowledges, for the first time, * chunk that acknowledges, for the first time,
* the receipt of a DATA chunk, all the still * the receipt of a DATA chunk, all the still
* unacknowledged DATA chunks whose TSN is * unacknowledged DATA chunks whose TSN is
* older than that newly acknowledged DATA * older than that newly acknowledged DATA
* chunk, are qualified as 'Stray DATA chunks'. * chunk, are qualified as 'Stray DATA chunks'.
*/ */
if (!tchunk->tsn_gap_acked) { if (!tchunk->tsn_gap_acked) {
...@@ -1258,10 +1264,10 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1258,10 +1264,10 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* RFC 2960 6.3.2 Retransmission Timer Rules /* RFC 2960 6.3.2 Retransmission Timer Rules
* *
* R4) Whenever a SACK is received missing a * R4) Whenever a SACK is received missing a
* TSN that was previously acknowledged via a * TSN that was previously acknowledged via a
* Gap Ack Block, start T3-rtx for the * Gap Ack Block, start T3-rtx for the
* destination address to which the DATA * destination address to which the DATA
* chunk was originally * chunk was originally
* transmitted if it is not already running. * transmitted if it is not already running.
*/ */
......
...@@ -1118,7 +1118,8 @@ void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, ...@@ -1118,7 +1118,8 @@ void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
} }
/* Helper function to handle the reception of an HEARTBEAT ACK. */ /* Helper function to handle the reception of an HEARTBEAT ACK. */
static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc,
sctp_transport_t *t, sctp_chunk_t *chunk) sctp_transport_t *t, sctp_chunk_t *chunk)
{ {
sctp_sender_hb_info_t *hbinfo; sctp_sender_hb_info_t *hbinfo;
...@@ -1164,7 +1165,8 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, ...@@ -1164,7 +1165,8 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
} }
/* Helper function to process the process SACK command. */ /* Helper function to process the process SACK command. */
static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc,
sctp_sackhdr_t *sackh) sctp_sackhdr_t *sackh)
{ {
int err; int err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment