sctp: check src addr when processing SACK to update transport state
[pandora-kernel.git] / net / sctp / outqueue.c
index 072bf6a..1b4a7f8 100644 (file)
@@ -63,6 +63,7 @@ static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);
 static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
+                                  union sctp_addr *saddr,
                                   struct sctp_sackhdr *sack,
                                   __u32 *highest_new_tsn);
 
@@ -591,9 +592,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                 * next chunk.
                 */
                if (chunk->tsn_gap_acked) {
-                       list_del(&chunk->transmitted_list);
-                       list_add_tail(&chunk->transmitted_list,
-                                       &transport->transmitted);
+                       list_move_tail(&chunk->transmitted_list,
+                                      &transport->transmitted);
                        continue;
                }
 
@@ -657,9 +657,8 @@ redo:
                        /* The append was successful, so add this chunk to
                         * the transmitted list.
                         */
-                       list_del(&chunk->transmitted_list);
-                       list_add_tail(&chunk->transmitted_list,
-                                       &transport->transmitted);
+                       list_move_tail(&chunk->transmitted_list,
+                                      &transport->transmitted);
 
                        /* Mark the chunk as ineligible for fast retransmit
                         * after it is retransmitted.
@@ -1141,9 +1140,10 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
  * Process the SACK against the outqueue.  Mostly, this just frees
  * things off the transmitted queue.
  */
-int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
+int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
 {
        struct sctp_association *asoc = q->asoc;
+       struct sctp_sackhdr *sack = chunk->subh.sack_hdr;
        struct sctp_transport *transport;
        struct sctp_chunk *tchunk = NULL;
        struct list_head *lchunk, *transport_list, *temp;
@@ -1212,7 +1212,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        /* 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_check_transmitted(q, &q->retransmit, NULL, NULL, sack, &highest_new_tsn);
 
        /* Run through the transmitted queue.
         * Credit bytes received and free those chunks which we can.
@@ -1221,7 +1221,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         */
        list_for_each_entry(transport, transport_list, transports) {
                sctp_check_transmitted(q, &transport->transmitted,
-                                      transport, sack, &highest_new_tsn);
+                                      transport, &chunk->source, sack,
+                                      &highest_new_tsn);
                /*
                 * SFR-CACC algorithm:
                 * C) Let count_of_newacks be the number of
@@ -1328,6 +1329,7 @@ int sctp_outq_is_empty(const struct sctp_outq *q)
 static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
+                                  union sctp_addr *saddr,
                                   struct sctp_sackhdr *sack,
                                   __u32 *highest_new_tsn_in_sack)
 {
@@ -1635,8 +1637,9 @@ 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) ||
-                           (transport->state == SCTP_UNCONFIRMED)) {
+                       if ((transport->state == SCTP_INACTIVE ||
+                            transport->state == SCTP_UNCONFIRMED) &&
+                           sctp_cmp_addr_exact(&transport->ipaddr, saddr)) {
                                sctp_assoc_control_transport(
                                        transport->asoc,
                                        transport,