asoc->addip_last_asconf->transport == peer)
asoc->addip_last_asconf->transport = NULL;
+ /* If we have something on the transmitted list, we have to
+ * save it off. The best place is the active path.
+ */
+ if (!list_empty(&peer->transmitted)) {
+ struct sctp_transport *active = asoc->peer.active_path;
+ struct sctp_chunk *ch;
+
+ /* Reset the transport of each chunk on this list */
+ list_for_each_entry(ch, &peer->transmitted,
+ transmitted_list) {
+ ch->transport = NULL;
+ ch->rtt_in_progress = 0;
+ }
+
+ list_splice_tail_init(&peer->transmitted,
+ &active->transmitted);
+
+ /* Start a T3 timer here in case it wasn't running so
+ * that these migrated packets have a chance to get
+ * retrnasmitted.
+ */
+ if (!timer_pending(&active->T3_rtx_timer))
+ if (!mod_timer(&active->T3_rtx_timer,
+ jiffies + active->rto))
+ sctp_transport_hold(active);
+ }
+
asoc->peer.transport_count--;
sctp_transport_free(peer);
* 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));
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
__u32 rtt;
__u8 restart_timer = 0;
int bytes_acked = 0;
+ int migrate_bytes = 0;
/* These state variables are for coherent debug output. --xguo */
* 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;
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
*
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
* 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);
}
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
*
#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
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