summaryrefslogtreecommitdiffstats
path: root/net/sctp/associola.c
diff options
context:
space:
mode:
authorVlad Yasevich2009-09-05 00:21:00 +0200
committerVlad Yasevich2009-09-05 00:21:00 +0200
commit31b02e1549406efa346534acad956a42bc3f28c4 (patch)
tree3acc807275810eb2efdc5fc2744bdfc3528488c2 /net/sctp/associola.c
parentsctp: Fix SCTP_MAXSEG socket option to comply to spec. (diff)
downloadkernel-qcow2-linux-31b02e1549406efa346534acad956a42bc3f28c4.tar.gz
kernel-qcow2-linux-31b02e1549406efa346534acad956a42bc3f28c4.tar.xz
kernel-qcow2-linux-31b02e1549406efa346534acad956a42bc3f28c4.zip
sctp: Failover transmitted list on transport delete
Add-IP feature allows users to delete an active transport. If that transport has chunks in flight, those chunks need to be moved to another transport or association may get into unrecoverable state. Reported-by: Rafael Laufer <rlaufer@cisco.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp/associola.c')
-rw-r--r--net/sctp/associola.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 1f05b942564e..caba989f4e76 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -584,6 +584,33 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
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);