Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / net / sctp / outqueue.c
index e5faa35..a7ba9e1 100644 (file)
@@ -1,21 +1,21 @@
-/* SCTP kernel reference Implementation
+/* SCTP kernel implementation
  * (C) Copyright IBM Corp. 2001, 2004
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001-2003 Intel Corp.
  *
- * This file is part of the SCTP kernel reference Implementation
+ * This file is part of the SCTP kernel implementation
  *
  * These functions implement the sctp_outq class.   The outqueue handles
  * bundling and queueing of outgoing SCTP chunks.
  *
- * The SCTP reference implementation is free software;
+ * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
- * The SCTP reference implementation is distributed in the hope that it
+ * This SCTP implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -221,12 +221,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);
@@ -338,7 +338,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
                                SCTP_INC_STATS(SCTP_MIB_OUTORDERCHUNKS);
                        q->empty = 0;
                        break;
-               };
+               }
        } else {
                list_add_tail(&chunk->list, &q->control_chunk_list);
                SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
@@ -376,13 +376,13 @@ static void sctp_insert_list(struct list_head *head, struct list_head *new)
                }
        }
        if (!done)
-               list_add_tail(new, head); 
+               list_add_tail(new, head);
 }
 
 /* Mark all the eligible packets on a transport for retransmission.  */
 void sctp_retransmit_mark(struct sctp_outq *q,
                          struct sctp_transport *transport,
-                         __u8 fast_retransmit)
+                         __u8 reason)
 {
        struct list_head *lchunk, *ltemp;
        struct sctp_chunk *chunk;
@@ -396,18 +396,38 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                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;
                }
 
-               /* If we are doing retransmission due to a fast retransmit,
-                * only the chunk's that are marked for fast retransmit
-                * should be added to the retransmit queue.  If we are doing
-                * retransmission due to a timeout or pmtu discovery, only the
-                * chunks that are not yet acked should be added to the
-                * retransmit queue.
+               /* If we are doing  retransmission due to a timeout or pmtu
+                * discovery, only the  chunks that are not yet acked should
+                * be added to the retransmit queue.
                 */
-               if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
-                  (!fast_retransmit && !chunk->tsn_gap_acked)) {
+               if ((reason == SCTP_RTXR_FAST_RTX  &&
+                           (chunk->fast_retransmit > 0)) ||
+                   (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
@@ -416,7 +436,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                         * (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);
 
@@ -446,10 +467,10 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                }
        }
 
-       SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, "
+       SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
                          "cwnd: %d, ssthresh: %d, flight_size: %d, "
-                         "pba: %d\n", __FUNCTION__,
-                         transport, fast_retransmit,
+                         "pba: %d\n", __func__,
+                         transport, reason,
                          transport->cwnd, transport->ssthresh,
                          transport->flight_size,
                          transport->partial_bytes_acked);
@@ -463,27 +484,35 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
                     sctp_retransmit_reason_t reason)
 {
        int error = 0;
-       __u8 fast_retransmit = 0;
 
        switch(reason) {
        case SCTP_RTXR_T3_RTX:
+               SCTP_INC_STATS(SCTP_MIB_T3_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
                /* Update the retran path if the T3-rtx timer has expired for
                 * the current retran path.
                 */
                if (transport == transport->asoc->peer.retran_path)
                        sctp_assoc_update_retran_path(transport->asoc);
+               transport->asoc->rtx_data_chunks +=
+                       transport->asoc->unack_data;
                break;
        case SCTP_RTXR_FAST_RTX:
+               SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
-               fast_retransmit = 1;
                break;
        case SCTP_RTXR_PMTUD:
-       default:
+               SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
+               break;
+       case SCTP_RTXR_T1_RTX:
+               SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+               transport->asoc->init_retries++;
                break;
+       default:
+               BUG();
        }
 
-       sctp_retransmit_mark(q, transport, fast_retransmit);
+       sctp_retransmit_mark(q, transport, reason);
 
        /* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination,
         * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
@@ -509,7 +538,7 @@ 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 list_head *lchunk;
        struct sctp_transport *transport = pkt->transport;
        sctp_xmit_t status;
        struct sctp_chunk *chunk, *chunk1;
@@ -573,7 +602,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        break;
 
                case SCTP_XMIT_RWND_FULL:
-                       /* Send this packet. */
+                       /* Send this packet. */
                        if ((error = sctp_packet_transmit(pkt)) == 0)
                                *start_timer = 1;
 
@@ -585,7 +614,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        break;
 
                case SCTP_XMIT_NAGLE_DELAY:
-                       /* Send this packet. */
+                       /* Send this packet. */
                        if ((error = sctp_packet_transmit(pkt)) == 0)
                                *start_timer = 1;
 
@@ -600,7 +629,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                         */
                        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)
@@ -612,16 +641,15 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        /* 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.
+                * 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);
+                       list_for_each_entry(chunk1, lqueue, transmitted_list) {
                                if (chunk1->fast_retransmit > 0)
                                        chunk1->fast_retransmit = -1;
                        }
@@ -635,10 +663,9 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
 int sctp_outq_uncork(struct sctp_outq *q)
 {
        int error = 0;
-       if (q->cork) {
+       if (q->cork)
                q->cork = 0;
-               error = sctp_outq_flush(q, 0);
-       }
+       error = sctp_outq_flush(q, 0);
        return error;
 }
 
@@ -690,21 +717,47 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                new_transport = chunk->transport;
 
                if (!new_transport) {
-                       new_transport = asoc->peer.active_path;
-               } else if (new_transport->state == SCTP_INACTIVE) {
+                       /*
+                        * If we have a prior transport pointer, see if
+                        * the destination address of the chunk
+                        * matches the destination address of the
+                        * current transport.  If not a match, then
+                        * try to look up the transport with a given
+                        * destination address.  We do this because
+                        * after processing ASCONFs, we may have new
+                        * transports created.
+                        */
+                       if (transport &&
+                           sctp_cmp_addr_exact(&chunk->dest,
+                                               &transport->ipaddr))
+                                       new_transport = transport;
+                       else
+                               new_transport = sctp_assoc_lookup_paddr(asoc,
+                                                               &chunk->dest);
+
+                       /* if we still don't have a new transport, then
+                        * use the current active path.
+                        */
+                       if (!new_transport)
+                               new_transport = asoc->peer.active_path;
+               } else if ((new_transport->state == SCTP_INACTIVE) ||
+                          (new_transport->state == SCTP_UNCONFIRMED)) {
                        /* If the chunk is Heartbeat or Heartbeat Ack,
                         * send it to chunk->transport, even if it's
                         * 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.
-                        * ...  
+                        * ...
+                        *
+                        * ASCONF_ACKs also must be sent to the source.
                         */
                        if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT &&
-                           chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK)
+                           chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT_ACK &&
+                           chunk->chunk_hdr->type != SCTP_CID_ASCONF_ACK)
                                new_transport = asoc->peer.active_path;
                }
 
@@ -741,6 +794,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                        break;
 
                case SCTP_CID_ABORT:
+                       if (sctp_test_T_bit(chunk)) {
+                               packet->vtag = asoc->c.my_vtag;
+                       }
                case SCTP_CID_SACK:
                case SCTP_CID_HEARTBEAT:
                case SCTP_CID_HEARTBEAT_ACK:
@@ -760,7 +816,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                default:
                        /* We built a chunk with an illegal type! */
                        BUG();
-               };
+               }
        }
 
        /* Is it OK to send data chunks?  */
@@ -848,7 +904,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                         */
                        new_transport = chunk->transport;
                        if (!new_transport ||
-                           new_transport->state == SCTP_INACTIVE)
+                           ((new_transport->state == SCTP_INACTIVE) ||
+                            (new_transport->state == SCTP_UNCONFIRMED)))
                                new_transport = asoc->peer.active_path;
 
                        /* Change packets if necessary.  */
@@ -907,7 +964,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                                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.
@@ -981,7 +1038,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
 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;
@@ -989,12 +1045,9 @@ static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
 
        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);
+       list_for_each_entry(transport, transport_list, transports) {
+               list_for_each_entry(chunk, &transport->transmitted,
+                               transmitted_list) {
                        tsn = ntohl(chunk->subh.data_hdr->tsn);
 
                        if (!chunk->tsn_gap_acked &&
@@ -1017,7 +1070,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;
@@ -1043,9 +1096,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         */
        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);
+               list_for_each_entry(transport, transport_list,
+                               transports) {
                        transport->cacc.cycling_changeover = 0;
                }
        }
@@ -1058,11 +1110,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         * 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,
-                                       transports);
+               list_for_each_entry(transport, transport_list, transports) {
                        transport->cacc.cacc_saw_newack = 0;
                }
        }
@@ -1091,9 +1141,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         *
         * 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);
                /*
@@ -1105,9 +1153,7 @@ 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);
+       list_for_each_entry(transport, transport_list, transports) {
                sctp_mark_missing(q, &transport->transmitted, transport,
                                  highest_new_tsn, count_of_newacks);
        }
@@ -1126,8 +1172,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
                tchunk = list_entry(lchunk, struct sctp_chunk,
                                    transmitted_list);
                tsn = ntohl(tchunk->subh.data_hdr->tsn);
-               if (TSN_lte(tsn, ctsn))
+               if (TSN_lte(tsn, ctsn)) {
+                       list_del_init(&tchunk->transmitted_list);
                        sctp_chunk_free(tchunk);
+               }
        }
 
        /* ii) Set rwnd equal to the newly received a_rwnd minus the
@@ -1148,10 +1196,10 @@ 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.
@@ -1162,9 +1210,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        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;
@@ -1237,6 +1283,15 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                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;
                }
 
@@ -1259,7 +1314,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                 * 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;
@@ -1268,7 +1323,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                                                  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
@@ -1368,7 +1423,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                SCTP_DEBUG_PRINTK("ACKed: %08x", tsn);
                                dbg_prt_state = 0;
                                dbg_ack_tsn = tsn;
-                       };
+                       }
 
                        dbg_last_ack_tsn = tsn;
 #endif /* SCTP_DEBUG */
@@ -1377,7 +1432,7 @@ 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;
 
@@ -1423,7 +1478,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                SCTP_DEBUG_PRINTK("KEPT: %08x",tsn);
                                dbg_prt_state = 1;
                                dbg_kept_tsn = tsn;
-                       };
+                       }
 
                        dbg_last_kept_tsn = tsn;
 #endif /* SCTP_DEBUG */
@@ -1447,7 +1502,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                } else {
                        SCTP_DEBUG_PRINTK("\n");
                }
-       };
+       }
 #endif /* SCTP_DEBUG */
        if (transport) {
                if (bytes_acked) {
@@ -1464,7 +1519,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                        /* Mark the destination transport address as
                         * active if it is not so marked.
                         */
-                       if (transport->state == SCTP_INACTIVE) {
+                       if ((transport->state == SCTP_INACTIVE) ||
+                           (transport->state == SCTP_UNCONFIRMED)) {
                                sctp_assoc_control_transport(
                                        transport->asoc,
                                        transport,
@@ -1493,7 +1549,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;
                        }
@@ -1528,14 +1584,12 @@ 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;
 
-       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
@@ -1558,7 +1612,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);
                        }
                }
@@ -1581,8 +1635,8 @@ 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,
-                                 transport->ssthresh, transport->flight_size,
+                                 __func__, transport, transport->cwnd,
+                                 transport->ssthresh, transport->flight_size,
                                  transport->partial_bytes_acked);
        }
 }
@@ -1595,7 +1649,7 @@ static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn)
        __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):
@@ -1624,7 +1678,7 @@ pass:
 }
 
 static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist,
-                                   int nskips, __u16 stream)
+                                   int nskips, __be16 stream)
 {
        int i;
 
@@ -1649,7 +1703,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
 
        /* 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.
         */
@@ -1663,7 +1717,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
         *
         * 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
         *                ...                           ...
@@ -1684,14 +1738,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
 
                /* 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)) {
@@ -1735,7 +1784,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
         */
        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);