}
}
if (!done)
- list_add_tail(new, head);
+ list_add_tail(new, head);
}
/* Mark all the eligible packets on a transport for retransmission. */
if (sctp_chunk_abandoned(chunk)) {
list_del_init(lchunk);
sctp_insert_list(&q->abandoned, lchunk);
+
+ /* If this chunk has not been previousely acked,
+ * stop considering it 'outstanding'. Our peer
+ * will most likely never see it since it will
+ * not be retransmitted
+ */
+ if (!chunk->tsn_gap_acked) {
+ 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));
+ }
continue;
}
* (Section 7.2.4)), add the data size of those
* chunks to the rwnd.
*/
- q->asoc->peer.rwnd += sctp_data_size(chunk);
+ 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);
break;
case SCTP_XMIT_RWND_FULL:
- /* Send this packet. */
+ /* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
break;
case SCTP_XMIT_NAGLE_DELAY:
- /* Send this packet. */
+ /* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
*/
list_add_tail(lchunk, &transport->transmitted);
- /* Mark the chunk as ineligible for fast retransmit
+ /* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
*/
if (chunk->fast_retransmit > 0)
* inactive.
*
* 3.3.6 Heartbeat Acknowledgement:
- * ...
+ * ...
* A HEARTBEAT ACK is always sent to the source IP
* address of the IP datagram containing the
* HEARTBEAT chunk to which this ack is responding.
- * ...
+ * ...
*/
if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT &&
chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK)
BUG();
}
- /* BUG: We assume that the sctp_packet_transmit()
+ /* BUG: We assume that the sctp_packet_transmit()
* call below will succeed all the time and add the
* chunk to the transmitted list and restart the
* timers.
* A) Initialize the cacc_saw_newack to 0 for all destination
* addresses.
*/
- if (sack->num_gap_ack_blocks > 0 &&
+ if (sack->num_gap_ack_blocks &&
primary->cacc.changeover_active) {
list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport,
if (sctp_chunk_abandoned(tchunk)) {
/* Move the chunk to abandoned list. */
sctp_insert_list(&q->abandoned, lchunk);
+
+ /* If this chunk has not been acked, stop
+ * considering it as 'outstanding'.
+ */
+ if (!tchunk->tsn_gap_acked) {
+ tchunk->transport->flight_size -=
+ sctp_data_size(tchunk);
+ q->outstanding_bytes -= sctp_data_size(tchunk);
+ }
continue;
}
* first instance of the packet or a later
* instance).
*/
- if (!tchunk->tsn_gap_acked &&
+ if (!tchunk->tsn_gap_acked &&
!tchunk->resent &&
tchunk->rtt_in_progress) {
tchunk->rtt_in_progress = 0;
rtt);
}
}
- if (TSN_lte(tsn, sack_ctsn)) {
+ if (TSN_lte(tsn, sack_ctsn)) {
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
* R3) Whenever a SACK is received
SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n",
__FUNCTION__, transport, transport->cwnd,
- transport->ssthresh, transport->flight_size,
+ transport->ssthresh, transport->flight_size,
transport->partial_bytes_acked);
}
}
__u16 gap;
__u32 ctsn = ntohl(sack->cum_tsn_ack);
- if (TSN_lte(tsn, ctsn))
+ if (TSN_lte(tsn, ctsn))
goto pass;
/* 3.3.4 Selective Acknowledgement (SACK) (3):
}
static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist,
- int nskips, __u16 stream)
+ int nskips, __be16 stream)
{
int i;
/* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the
* received SACK.
- *
+ *
* If (Advanced.Peer.Ack.Point < SackCumAck), then update
* Advanced.Peer.Ack.Point to be equal to SackCumAck.
*/
*
* Assuming that a SACK arrived with the Cumulative TSN ACK 102
* and the Advanced.Peer.Ack.Point is updated to this value:
- *
+ *
* out-queue at the end of ==> out-queue after Adv.Ack.Point
* normal SACK processing local advancement
* ... ...
/* Remove any chunks in the abandoned queue that are acked by
* the ctsn.
- */
+ */
if (TSN_lte(tsn, ctsn)) {
list_del_init(lchunk);
- if (!chunk->tsn_gap_acked) {
- chunk->transport->flight_size -=
- sctp_data_size(chunk);
- q->outstanding_bytes -= sctp_data_size(chunk);
- }
sctp_chunk_free(chunk);
} else {
if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {
*/
if (asoc->adv_peer_ack_point > ctsn)
ftsn_chunk = sctp_make_fwdtsn(asoc, asoc->adv_peer_ack_point,
- nskips, &ftsn_skip_arr[0]);
+ nskips, &ftsn_skip_arr[0]);
if (ftsn_chunk) {
list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);