summaryrefslogtreecommitdiffstats
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c83
1 files changed, 58 insertions, 25 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index d765fc53e74..229690f02a1 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -191,8 +191,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary,
__u32 tsn)
{
if (primary->cacc.changeover_active &&
- (sctp_cacc_skip_3_1(primary, transport, count_of_newacks)
- || sctp_cacc_skip_3_2(primary, tsn)))
+ (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) ||
+ sctp_cacc_skip_3_2(primary, tsn)))
return 1;
return 0;
}
@@ -406,8 +406,9 @@ void sctp_retransmit_mark(struct sctp_outq *q,
* not be retransmitted
*/
if (!chunk->tsn_gap_acked) {
- chunk->transport->flight_size -=
- sctp_data_size(chunk);
+ if (chunk->transport)
+ chunk->transport->flight_size -=
+ sctp_data_size(chunk);
q->outstanding_bytes -= sctp_data_size(chunk);
q->asoc->peer.rwnd += (sctp_data_size(chunk) +
sizeof(struct sk_buff));
@@ -422,16 +423,6 @@ void sctp_retransmit_mark(struct sctp_outq *q,
if ((reason == SCTP_RTXR_FAST_RTX &&
(chunk->fast_retransmit == SCTP_NEED_FRTX)) ||
(reason != SCTP_RTXR_FAST_RTX && !chunk->tsn_gap_acked)) {
- /* If this chunk was sent less then 1 rto ago, do not
- * retransmit this chunk, but give the peer time
- * to acknowlege it. Do this only when
- * retransmitting due to T3 timeout.
- */
- if (reason == SCTP_RTXR_T3_RTX &&
- time_before(jiffies, chunk->sent_at +
- transport->last_rto))
- continue;
-
/* RFC 2960 6.2.1 Processing a Received SACK
*
* C) Any time a DATA chunk is marked for
@@ -443,7 +434,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
q->asoc->peer.rwnd += (sctp_data_size(chunk) +
sizeof(struct sk_buff));
q->outstanding_bytes -= sctp_data_size(chunk);
- transport->flight_size -= sctp_data_size(chunk);
+ if (chunk->transport)
+ transport->flight_size -= sctp_data_size(chunk);
/* sctpimpguide-05 Section 2.8.2
* M5) If a T3-rtx timer expires, the
@@ -929,6 +921,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
goto sctp_flush_out;
}
+ /* Apply Max.Burst limitation to the current transport in
+ * case it will be used for new data. We are going to
+ * rest it before we return, but we want to apply the limit
+ * to the currently queued data.
+ */
+ if (transport)
+ sctp_transport_burst_limited(transport);
+
/* Finally, transmit new packets. */
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
@@ -974,6 +974,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
packet = &transport->packet;
sctp_packet_config(packet, vtag,
asoc->peer.ecn_capable);
+ /* We've switched transports, so apply the
+ * Burst limit to the new transport.
+ */
+ sctp_transport_burst_limited(transport);
}
SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",
@@ -1009,6 +1013,13 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
break;
case SCTP_XMIT_OK:
+ /* The sender is in the SHUTDOWN-PENDING state,
+ * The sender MAY set the I-bit in the DATA
+ * chunk header.
+ */
+ if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING)
+ chunk->chunk_hdr->flags |= SCTP_DATA_SACK_IMM;
+
break;
default:
@@ -1061,6 +1072,9 @@ sctp_flush_out:
packet = &t->packet;
if (!sctp_packet_empty(packet))
error = sctp_packet_transmit(packet);
+
+ /* Clear the burst limited state, if any */
+ sctp_transport_burst_reset(t);
}
return error;
@@ -1310,6 +1324,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
__u32 rtt;
__u8 restart_timer = 0;
int bytes_acked = 0;
+ int migrate_bytes = 0;
/* These state variables are for coherent debug output. --xguo */
@@ -1343,8 +1358,9 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* considering it as 'outstanding'.
*/
if (!tchunk->tsn_gap_acked) {
- tchunk->transport->flight_size -=
- sctp_data_size(tchunk);
+ if (tchunk->transport)
+ tchunk->transport->flight_size -=
+ sctp_data_size(tchunk);
q->outstanding_bytes -= sctp_data_size(tchunk);
}
continue;
@@ -1378,6 +1394,20 @@ static void sctp_check_transmitted(struct sctp_outq *q,
rtt);
}
}
+
+ /* If the chunk hasn't been marked as ACKED,
+ * mark it and account bytes_acked if the
+ * chunk had a valid transport (it will not
+ * have a transport if ASCONF had deleted it
+ * while DATA was outstanding).
+ */
+ if (!tchunk->tsn_gap_acked) {
+ tchunk->tsn_gap_acked = 1;
+ bytes_acked += sctp_data_size(tchunk);
+ if (!tchunk->transport)
+ migrate_bytes += sctp_data_size(tchunk);
+ }
+
if (TSN_lte(tsn, sack_ctsn)) {
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
@@ -1391,8 +1421,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
restart_timer = 1;
if (!tchunk->tsn_gap_acked) {
- tchunk->tsn_gap_acked = 1;
- bytes_acked += sctp_data_size(tchunk);
/*
* SFR-CACC algorithm:
* 2) If the SACK contains gap acks
@@ -1432,10 +1460,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* older than that newly acknowledged DATA
* chunk, are qualified as 'Stray DATA chunks'.
*/
- if (!tchunk->tsn_gap_acked) {
- tchunk->tsn_gap_acked = 1;
- bytes_acked += sctp_data_size(tchunk);
- }
list_add_tail(lchunk, &tlist);
}
@@ -1491,7 +1515,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
tsn);
tchunk->tsn_gap_acked = 0;
- bytes_acked -= sctp_data_size(tchunk);
+ if (tchunk->transport)
+ bytes_acked -= sctp_data_size(tchunk);
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
@@ -1561,6 +1586,14 @@ static void sctp_check_transmitted(struct sctp_outq *q,
#endif /* SCTP_DEBUG */
if (transport) {
if (bytes_acked) {
+ /* We may have counted DATA that was migrated
+ * to this transport due to DEL-IP operation.
+ * Subtract those bytes, since the were never
+ * send on this transport and shouldn't be
+ * credited to this transport.
+ */
+ bytes_acked -= migrate_bytes;
+
/* 8.2. When an outstanding TSN is acknowledged,
* the endpoint shall clear the error counter of
* the destination transport address to which the
@@ -1589,7 +1622,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
transport->flight_size -= bytes_acked;
if (transport->flight_size == 0)
transport->partial_bytes_acked = 0;
- q->outstanding_bytes -= bytes_acked;
+ q->outstanding_bytes -= bytes_acked + migrate_bytes;
} else {
/* RFC 2960 6.1, sctpimpguide-06 2.15.2
* When a sender is doing zero window probing, it