mmc: s3c6410: enable ADMA feature in 6410 sdhci controller
[safe/jmp/linux-2.6] / net / sctp / outqueue.c
index fd4deef..c04b2eb 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/list.h>   /* For struct list_head */
 #include <linux/socket.h>
 #include <linux/ip.h>
+#include <linux/slab.h>
 #include <net/sock.h>    /* For skb_set_owner_w */
 
 #include <net/sctp/sctp.h>
@@ -61,7 +62,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
                                   struct sctp_sackhdr *sack,
-                                  __u32 highest_new_tsn);
+                                  __u32 *highest_new_tsn);
 
 static void sctp_mark_missing(struct sctp_outq *q,
                              struct list_head *transmitted_queue,
@@ -71,13 +72,14 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
 static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
 
+static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout);
+
 /* Add data to the front of the queue. */
 static inline void sctp_outq_head_data(struct sctp_outq *q,
                                        struct sctp_chunk *ch)
 {
        list_add(&ch->list, &q->out_chunk_list);
        q->out_qlen += ch->skb->len;
-       return;
 }
 
 /* Take data from the front of the queue. */
@@ -100,7 +102,6 @@ static inline void sctp_outq_tail_data(struct sctp_outq *q,
 {
        list_add_tail(&ch->list, &q->out_chunk_list);
        q->out_qlen += ch->skb->len;
-       return;
 }
 
 /*
@@ -189,8 +190,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;
 }
@@ -208,6 +209,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
        INIT_LIST_HEAD(&q->sacked);
        INIT_LIST_HEAD(&q->abandoned);
 
+       q->fast_rtx = 0;
        q->outstanding_bytes = 0;
        q->empty = 1;
        q->cork  = 0;
@@ -221,12 +223,12 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
 void sctp_outq_teardown(struct sctp_outq *q)
 {
        struct sctp_transport *transport;
-       struct list_head *lchunk, *pos, *temp;
+       struct list_head *lchunk, *temp;
        struct sctp_chunk *chunk, *tmp;
 
        /* Throw away unacknowledged chunks. */
-       list_for_each(pos, &q->asoc->peer.transport_addr_list) {
-               transport = list_entry(pos, struct sctp_transport, transports);
+       list_for_each_entry(transport, &q->asoc->peer.transport_addr_list,
+                       transports) {
                while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) {
                        chunk = list_entry(lchunk, struct sctp_chunk,
                                           transmitted_list);
@@ -304,7 +306,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
        /* If it is data, queue it up, otherwise, send it
         * immediately.
         */
-       if (SCTP_CID_DATA == chunk->chunk_hdr->type) {
+       if (sctp_chunk_is_data(chunk)) {
                /* Is it OK to queue data chunks?  */
                /* From 9. Termination of Association
                 *
@@ -403,8 +405,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));
@@ -417,17 +420,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                 * be added to the retransmit queue.
                 */
                if ((reason == SCTP_RTXR_FAST_RTX  &&
-                           (chunk->fast_retransmit > 0)) ||
+                           (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 &&
-                           (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
@@ -439,7 +433,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
@@ -469,7 +464,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
 
        SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
                          "cwnd: %d, ssthresh: %d, flight_size: %d, "
-                         "pba: %d\n", __FUNCTION__,
+                         "pba: %d\n", __func__,
                          transport, reason,
                          transport->cwnd, transport->ssthresh,
                          transport->flight_size,
@@ -500,6 +495,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
        case SCTP_RTXR_FAST_RTX:
                SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
+               q->fast_rtx = 1;
                break;
        case SCTP_RTXR_PMTUD:
                SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
@@ -518,9 +514,15 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
         * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
         * following the procedures outlined in C1 - C5.
         */
-       sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
+       if (reason == SCTP_RTXR_T3_RTX)
+               sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
 
-       error = sctp_outq_flush(q, /* rtx_timeout */ 1);
+       /* Flush the queues only on timeout, since fast_rtx is only
+        * triggered during sack processing and the queue
+        * will be flushed at the end.
+        */
+       if (reason != SCTP_RTXR_FAST_RTX)
+               error = sctp_outq_flush(q, /* rtx_timeout */ 1);
 
        if (error)
                q->asoc->base.sk->sk_err = -error;
@@ -538,17 +540,23 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                               int rtx_timeout, int *start_timer)
 {
        struct list_head *lqueue;
-       struct list_head *lchunk, *lchunk1;
        struct sctp_transport *transport = pkt->transport;
        sctp_xmit_t status;
        struct sctp_chunk *chunk, *chunk1;
        struct sctp_association *asoc;
+       int fast_rtx;
        int error = 0;
+       int timer = 0;
+       int done = 0;
 
        asoc = q->asoc;
        lqueue = &q->retransmit;
+       fast_rtx = q->fast_rtx;
 
-       /* RFC 2960 6.3.3 Handle T3-rtx Expiration
+       /* This loop handles time-out retransmissions, fast retransmissions,
+        * and retransmissions due to opening of whindow.
+        *
+        * RFC 2960 6.3.3 Handle T3-rtx Expiration
         *
         * E3) Determine how many of the earliest (i.e., lowest TSN)
         * outstanding DATA chunks for the address for which the
@@ -563,12 +571,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
         * [Just to be painfully clear, if we are retransmitting
         * because a timeout just happened, we should send only ONE
         * packet of retransmitted data.]
+        *
+        * For fast retransmissions we also send only ONE packet.  However,
+        * if we are just flushing the queue due to open window, we'll
+        * try to send as much as possible.
         */
-       lchunk = sctp_list_dequeue(lqueue);
-
-       while (lchunk) {
-               chunk = list_entry(lchunk, struct sctp_chunk,
-                                  transmitted_list);
+       list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) {
 
                /* Make sure that Gap Acked TSNs are not retransmitted.  A
                 * simple approach is just to move such TSNs out of the
@@ -576,88 +584,109 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                 * next chunk.
                 */
                if (chunk->tsn_gap_acked) {
-                       list_add_tail(lchunk, &transport->transmitted);
-                       lchunk = sctp_list_dequeue(lqueue);
+                       list_del(&chunk->transmitted_list);
+                       list_add_tail(&chunk->transmitted_list,
+                                       &transport->transmitted);
                        continue;
                }
 
+               /* If we are doing fast retransmit, ignore non-fast_rtransmit
+                * chunks
+                */
+               if (fast_rtx && !chunk->fast_retransmit)
+                       continue;
+
+redo:
                /* Attempt to append this chunk to the packet. */
                status = sctp_packet_append_chunk(pkt, chunk);
 
                switch (status) {
                case SCTP_XMIT_PMTU_FULL:
+                       if (!pkt->has_data && !pkt->has_cookie_echo) {
+                               /* If this packet did not contain DATA then
+                                * retransmission did not happen, so do it
+                                * again.  We'll ignore the error here since
+                                * control chunks are already freed so there
+                                * is nothing we can do.
+                                */
+                               sctp_packet_transmit(pkt);
+                               goto redo;
+                       }
+
                        /* Send this packet.  */
-                       if ((error = sctp_packet_transmit(pkt)) == 0)
-                               *start_timer = 1;
+                       error = sctp_packet_transmit(pkt);
 
                        /* If we are retransmitting, we should only
                         * send a single packet.
                         */
-                       if (rtx_timeout) {
-                               list_add(lchunk, lqueue);
-                               lchunk = NULL;
-                       }
+                       if (rtx_timeout || fast_rtx)
+                               done = 1;
 
-                       /* Bundle lchunk in the next round.  */
+                       /* Bundle next chunk in the next round.  */
                        break;
 
                case SCTP_XMIT_RWND_FULL:
                        /* Send this packet. */
-                       if ((error = sctp_packet_transmit(pkt)) == 0)
-                               *start_timer = 1;
+                       error = sctp_packet_transmit(pkt);
 
                        /* Stop sending DATA as there is no more room
                         * at the receiver.
                         */
-                       list_add(lchunk, lqueue);
-                       lchunk = NULL;
+                       done = 1;
                        break;
 
                case SCTP_XMIT_NAGLE_DELAY:
                        /* Send this packet. */
-                       if ((error = sctp_packet_transmit(pkt)) == 0)
-                               *start_timer = 1;
+                       error = sctp_packet_transmit(pkt);
 
                        /* Stop sending DATA because of nagle delay. */
-                       list_add(lchunk, lqueue);
-                       lchunk = NULL;
+                       done = 1;
                        break;
 
                default:
                        /* The append was successful, so add this chunk to
                         * the transmitted list.
                         */
-                       list_add_tail(lchunk, &transport->transmitted);
+                       list_del(&chunk->transmitted_list);
+                       list_add_tail(&chunk->transmitted_list,
+                                       &transport->transmitted);
 
                        /* Mark the chunk as ineligible for fast retransmit
                         * after it is retransmitted.
                         */
-                       if (chunk->fast_retransmit > 0)
-                               chunk->fast_retransmit = -1;
+                       if (chunk->fast_retransmit == SCTP_NEED_FRTX)
+                               chunk->fast_retransmit = SCTP_DONT_FRTX;
 
-                       *start_timer = 1;
                        q->empty = 0;
-
-                       /* Retrieve a new chunk to bundle. */
-                       lchunk = sctp_list_dequeue(lqueue);
                        break;
                }
 
-               /* If we are here due to a retransmit timeout or a fast
-                * retransmit and if there are any chunks left in the retransmit
-                * queue that could not fit in the PMTU sized packet, they need
-                * to be marked as ineligible for a subsequent fast retransmit.
-                */
-               if (rtx_timeout && !lchunk) {
-                       list_for_each(lchunk1, lqueue) {
-                               chunk1 = list_entry(lchunk1, struct sctp_chunk,
-                                                   transmitted_list);
-                               if (chunk1->fast_retransmit > 0)
-                                       chunk1->fast_retransmit = -1;
-                       }
+               /* Set the timer if there were no errors */
+               if (!error && !timer)
+                       timer = 1;
+
+               if (done)
+                       break;
+       }
+
+       /* If we are here due to a retransmit timeout or a fast
+        * retransmit and if there are any chunks left in the retransmit
+        * queue that could not fit in the PMTU sized packet, they need
+        * to be marked as ineligible for a subsequent fast retransmit.
+        */
+       if (rtx_timeout || fast_rtx) {
+               list_for_each_entry(chunk1, lqueue, transmitted_list) {
+                       if (chunk1->fast_retransmit == SCTP_NEED_FRTX)
+                               chunk1->fast_retransmit = SCTP_DONT_FRTX;
                }
        }
 
+       *start_timer = timer;
+
+       /* Clear fast retransmit hint */
+       if (fast_rtx)
+               q->fast_rtx = 0;
+
        return error;
 }
 
@@ -671,6 +700,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
        return error;
 }
 
+
 /*
  * Try to flush an outqueue.
  *
@@ -680,7 +710,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
  * locking concerns must be made.  Today we use the sock lock to protect
  * this function.
  */
-int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
+static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
 {
        struct sctp_packet *packet;
        struct sctp_packet singleton;
@@ -694,6 +724,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
        sctp_xmit_t status;
        int error = 0;
        int start_timer = 0;
+       int one_packet = 0;
 
        /* These transports have chunks to send. */
        struct list_head transport_list;
@@ -796,20 +827,42 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                        break;
 
                case SCTP_CID_ABORT:
-               case SCTP_CID_SACK:
-               case SCTP_CID_HEARTBEAT:
+                       if (sctp_test_T_bit(chunk)) {
+                               packet->vtag = asoc->c.my_vtag;
+                       }
+               /* The following chunks are "response" chunks, i.e.
+                * they are generated in response to something we
+                * received.  If we are sending these, then we can
+                * send only 1 packet containing these chunks.
+                */
                case SCTP_CID_HEARTBEAT_ACK:
-               case SCTP_CID_SHUTDOWN:
                case SCTP_CID_SHUTDOWN_ACK:
-               case SCTP_CID_ERROR:
-               case SCTP_CID_COOKIE_ECHO:
                case SCTP_CID_COOKIE_ACK:
-               case SCTP_CID_ECN_ECNE:
+               case SCTP_CID_COOKIE_ECHO:
+               case SCTP_CID_ERROR:
                case SCTP_CID_ECN_CWR:
-               case SCTP_CID_ASCONF:
                case SCTP_CID_ASCONF_ACK:
+                       one_packet = 1;
+                       /* Fall throught */
+
+               case SCTP_CID_SACK:
+               case SCTP_CID_HEARTBEAT:
+               case SCTP_CID_SHUTDOWN:
+               case SCTP_CID_ECN_ECNE:
+               case SCTP_CID_ASCONF:
                case SCTP_CID_FWD_TSN:
-                       sctp_packet_transmit_chunk(packet, chunk);
+                       status = sctp_packet_transmit_chunk(packet, chunk,
+                                                           one_packet);
+                       if (status  != SCTP_XMIT_OK) {
+                               /* put the chunk back */
+                               list_add(&chunk->list, &q->control_chunk_list);
+                       } else if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
+                               /* PR-SCTP C5) If a FORWARD TSN is sent, the
+                                * sender MUST assure that at least one T3-rtx
+                                * timer is running.
+                                */
+                               sctp_transport_reset_timers(transport);
+                       }
                        break;
 
                default:
@@ -876,8 +929,15 @@ 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.  */
-               start_timer = 0;
                while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
                        /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
                         * stream identifier.
@@ -922,6 +982,10 @@ 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]), ",
@@ -939,7 +1003,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                                        atomic_read(&chunk->skb->users) : -1);
 
                        /* Add the chunk to the packet.  */
-                       status = sctp_packet_transmit_chunk(packet, chunk);
+                       status = sctp_packet_transmit_chunk(packet, chunk, 0);
 
                        switch (status) {
                        case SCTP_XMIT_PMTU_FULL:
@@ -957,6 +1021,13 @@ 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:
@@ -1009,6 +1080,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;
@@ -1033,36 +1107,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
        assoc->unack_data = unack_data;
 }
 
-/* Return the highest new tsn that is acknowledged by the given SACK chunk. */
-static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
-                                 struct sctp_association *asoc)
-{
-       struct list_head *ltransport, *lchunk;
-       struct sctp_transport *transport;
-       struct sctp_chunk *chunk;
-       __u32 highest_new_tsn, tsn;
-       struct list_head *transport_list = &asoc->peer.transport_addr_list;
-
-       highest_new_tsn = ntohl(sack->cum_tsn_ack);
-
-       list_for_each(ltransport, transport_list) {
-               transport = list_entry(ltransport, struct sctp_transport,
-                                      transports);
-               list_for_each(lchunk, &transport->transmitted) {
-                       chunk = list_entry(lchunk, struct sctp_chunk,
-                                          transmitted_list);
-                       tsn = ntohl(chunk->subh.data_hdr->tsn);
-
-                       if (!chunk->tsn_gap_acked &&
-                           TSN_lt(highest_new_tsn, tsn) &&
-                           sctp_acked(sack, tsn))
-                               highest_new_tsn = tsn;
-               }
-       }
-
-       return highest_new_tsn;
-}
-
 /* This is where we REALLY process a SACK.
  *
  * Process the SACK against the outqueue.  Mostly, this just frees
@@ -1073,7 +1117,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        struct sctp_association *asoc = q->asoc;
        struct sctp_transport *transport;
        struct sctp_chunk *tchunk = NULL;
-       struct list_head *lchunk, *transport_list, *pos, *temp;
+       struct list_head *lchunk, *transport_list, *temp;
        sctp_sack_variable_t *frags = sack->variable;
        __u32 sack_ctsn, ctsn, tsn;
        __u32 highest_tsn, highest_new_tsn;
@@ -1081,12 +1125,14 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        unsigned outstanding;
        struct sctp_transport *primary = asoc->peer.primary_path;
        int count_of_newacks = 0;
+       int gap_ack_blocks;
+       u8 accum_moved = 0;
 
        /* Grab the association's destination address list. */
        transport_list = &asoc->peer.transport_addr_list;
 
        sack_ctsn = ntohl(sack->cum_tsn_ack);
-
+       gap_ack_blocks = ntohs(sack->num_gap_ack_blocks);
        /*
         * SFR-CACC algorithm:
         * On receipt of a SACK the sender SHOULD execute the
@@ -1096,62 +1142,57 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be
         * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for
         * all destinations.
-        */
-       if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
-               primary->cacc.changeover_active = 0;
-               list_for_each(pos, transport_list) {
-                       transport = list_entry(pos, struct sctp_transport,
-                                       transports);
-                       transport->cacc.cycling_changeover = 0;
-               }
-       }
-
-       /*
-        * SFR-CACC algorithm:
         * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE
         * is set the receiver of the SACK MUST take the following actions:
         *
         * A) Initialize the cacc_saw_newack to 0 for all destination
         * addresses.
+        *
+        * Only bother if changeover_active is set. Otherwise, this is
+        * totally suboptimal to do on every SACK.
         */
-       if (sack->num_gap_ack_blocks &&
-           primary->cacc.changeover_active) {
-               list_for_each(pos, transport_list) {
-                       transport = list_entry(pos, struct sctp_transport,
-                                       transports);
-                       transport->cacc.cacc_saw_newack = 0;
+       if (primary->cacc.changeover_active) {
+               u8 clear_cycling = 0;
+
+               if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
+                       primary->cacc.changeover_active = 0;
+                       clear_cycling = 1;
+               }
+
+               if (clear_cycling || gap_ack_blocks) {
+                       list_for_each_entry(transport, transport_list,
+                                       transports) {
+                               if (clear_cycling)
+                                       transport->cacc.cycling_changeover = 0;
+                               if (gap_ack_blocks)
+                                       transport->cacc.cacc_saw_newack = 0;
+                       }
                }
        }
 
        /* Get the highest TSN in the sack. */
        highest_tsn = sack_ctsn;
-       if (sack->num_gap_ack_blocks)
-               highest_tsn +=
-                   ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);
+       if (gap_ack_blocks)
+               highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end);
 
-       if (TSN_lt(asoc->highest_sacked, highest_tsn)) {
-               highest_new_tsn = highest_tsn;
+       if (TSN_lt(asoc->highest_sacked, highest_tsn))
                asoc->highest_sacked = highest_tsn;
-       } else {
-               highest_new_tsn = sctp_highest_new_tsn(sack, asoc);
-       }
+
+       highest_new_tsn = sack_ctsn;
 
        /* Run through the retransmit queue.  Credit bytes received
         * and free those chunks that we can.
         */
-       sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);
-       sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0);
+       sctp_check_transmitted(q, &q->retransmit, NULL, sack, &highest_new_tsn);
 
        /* Run through the transmitted queue.
         * Credit bytes received and free those chunks which we can.
         *
         * This is a MASSIVE candidate for optimization.
         */
-       list_for_each(pos, transport_list) {
-               transport  = list_entry(pos, struct sctp_transport,
-                                       transports);
+       list_for_each_entry(transport, transport_list, transports) {
                sctp_check_transmitted(q, &transport->transmitted,
-                                      transport, sack, highest_new_tsn);
+                                      transport, sack, &highest_new_tsn);
                /*
                 * SFR-CACC algorithm:
                 * C) Let count_of_newacks be the number of
@@ -1161,16 +1202,21 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
                        count_of_newacks ++;
        }
 
-       list_for_each(pos, transport_list) {
-               transport  = list_entry(pos, struct sctp_transport,
-                                       transports);
-               sctp_mark_missing(q, &transport->transmitted, transport,
-                                 highest_new_tsn, count_of_newacks);
-       }
-
        /* Move the Cumulative TSN Ack Point if appropriate.  */
-       if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn))
+       if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn)) {
                asoc->ctsn_ack_point = sack_ctsn;
+               accum_moved = 1;
+       }
+
+       if (gap_ack_blocks) {
+
+               if (asoc->fast_recovery && accum_moved)
+                       highest_new_tsn = highest_tsn;
+
+               list_for_each_entry(transport, transport_list, transports)
+                       sctp_mark_missing(q, &transport->transmitted, transport,
+                                         highest_new_tsn, count_of_newacks);
+       }
 
        /* Update unack_data field in the assoc. */
        sctp_sack_update_unack_data(asoc, sack);
@@ -1206,23 +1252,20 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        sctp_generate_fwdtsn(q, sack_ctsn);
 
        SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
-                         __FUNCTION__, sack_ctsn);
+                         __func__, sack_ctsn);
        SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "
                          "%p is 0x%x. Adv peer ack point: 0x%x\n",
-                         __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);
+                         __func__, asoc, ctsn, asoc->adv_peer_ack_point);
 
        /* See if all chunks are acked.
         * Make sure the empty queue handler will get run later.
         */
        q->empty = (list_empty(&q->out_chunk_list) &&
-                   list_empty(&q->control_chunk_list) &&
                    list_empty(&q->retransmit));
        if (!q->empty)
                goto finish;
 
-       list_for_each(pos, transport_list) {
-               transport  = list_entry(pos, struct sctp_transport,
-                                       transports);
+       list_for_each_entry(transport, transport_list, transports) {
                q->empty = q->empty && list_empty(&transport->transmitted);
                if (!q->empty)
                        goto finish;
@@ -1257,7 +1300,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
                                   struct sctp_sackhdr *sack,
-                                  __u32 highest_new_tsn_in_sack)
+                                  __u32 *highest_new_tsn_in_sack)
 {
        struct list_head *lchunk;
        struct sctp_chunk *tchunk;
@@ -1267,6 +1310,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 */
 
@@ -1300,8 +1344,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;
@@ -1327,7 +1372,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                 * instance).
                                 */
                                if (!tchunk->tsn_gap_acked &&
-                                   !tchunk->resent &&
                                    tchunk->rtt_in_progress) {
                                        tchunk->rtt_in_progress = 0;
                                        rtt = jiffies - tchunk->sent_at;
@@ -1335,6 +1379,21 @@ 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;
+                               *highest_new_tsn_in_sack = tsn;
+                               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
                                 *
@@ -1348,8 +1407,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
@@ -1389,10 +1446,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);
                        }
 
@@ -1444,11 +1497,12 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                        if (tchunk->tsn_gap_acked) {
                                SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
                                                  "data TSN: 0x%x\n",
-                                                 __FUNCTION__,
+                                                 __func__,
                                                  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
                                 *
@@ -1518,6 +1572,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
@@ -1544,7 +1606,9 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                                  bytes_acked);
 
                        transport->flight_size -= bytes_acked;
-                       q->outstanding_bytes -= bytes_acked;
+                       if (transport->flight_size == 0)
+                               transport->partial_bytes_acked = 0;
+                       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
@@ -1561,7 +1625,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                            (sack_ctsn+2 == q->asoc->next_tsn)) {
                                SCTP_DEBUG_PRINTK("%s: SACK received for zero "
                                                  "window probe: %u\n",
-                                                 __FUNCTION__, sack_ctsn);
+                                                 __func__, sack_ctsn);
                                q->asoc->overall_error_count = 0;
                                transport->error_count = 0;
                        }
@@ -1596,14 +1660,13 @@ static void sctp_mark_missing(struct sctp_outq *q,
                              int count_of_newacks)
 {
        struct sctp_chunk *chunk;
-       struct list_head *pos;
        __u32 tsn;
        char do_fast_retransmit = 0;
-       struct sctp_transport *primary = q->asoc->peer.primary_path;
+       struct sctp_association *asoc = q->asoc;
+       struct sctp_transport *primary = asoc->peer.primary_path;
 
-       list_for_each(pos, transmitted_queue) {
+       list_for_each_entry(chunk, transmitted_queue, transmitted_list) {
 
-               chunk = list_entry(pos, struct sctp_chunk, transmitted_list);
                tsn = ntohl(chunk->subh.data_hdr->tsn);
 
                /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all
@@ -1613,7 +1676,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
                 * chunk if it has NOT been fast retransmitted or marked for
                 * fast retransmit already.
                 */
-               if (!chunk->fast_retransmit &&
+               if (chunk->fast_retransmit == SCTP_CAN_FRTX &&
                    !chunk->tsn_gap_acked &&
                    TSN_lt(tsn, highest_new_tsn_in_sack)) {
 
@@ -1626,7 +1689,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
                                SCTP_DEBUG_PRINTK(
                                        "%s: TSN 0x%x missing counter: %d\n",
-                                       __FUNCTION__, tsn,
+                                       __func__, tsn,
                                        chunk->tsn_missing_report);
                        }
                }
@@ -1638,7 +1701,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
                 */
 
                if (chunk->tsn_missing_report >= 3) {
-                       chunk->fast_retransmit = 1;
+                       chunk->fast_retransmit = SCTP_NEED_FRTX;
                        do_fast_retransmit = 1;
                }
        }
@@ -1649,7 +1712,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
                SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
                                  "ssthresh: %d, flight_size: %d, pba: %d\n",
-                                 __FUNCTION__, transport, transport->cwnd,
+                                 __func__, transport, transport->cwnd,
                                  transport->ssthresh, transport->flight_size,
                                  transport->partial_bytes_acked);
        }
@@ -1715,6 +1778,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
        struct sctp_chunk *chunk;
        struct list_head *lchunk, *temp;
 
+       if (!asoc->peer.prsctp_capable)
+               return;
+
        /* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the
         * received SACK.
         *