udp: fix for unicast RX path optimization
[safe/jmp/linux-2.6] / net / sctp / transport.c
index e745c11..b827d21 100644 (file)
@@ -74,15 +74,15 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
         * given destination transport address, set RTO to the protocol
         * parameter 'RTO.Initial'.
         */
-       peer->last_rto = peer->rto = msecs_to_jiffies(sctp_rto_initial);
+       peer->rto = msecs_to_jiffies(sctp_rto_initial);
        peer->rtt = 0;
        peer->rttvar = 0;
        peer->srtt = 0;
        peer->rto_pending = 0;
+       peer->hb_sent = 0;
        peer->fast_recovery = 0;
 
        peer->last_time_heard = jiffies;
-       peer->last_time_used = jiffies;
        peer->last_time_ecne_reduced = jiffies;
 
        peer->init_sent_count = 0;
@@ -307,7 +307,8 @@ void sctp_transport_route(struct sctp_transport *transport,
                /* Initialize sk->sk_rcv_saddr, if the transport is the
                 * association's active path for getsockname().
                 */
-               if (asoc && (transport == asoc->peer.active_path))
+               if (asoc && (!asoc->peer.primary_path ||
+                               (transport == asoc->peer.active_path)))
                        opt->pf->af->to_sk_saddr(&transport->saddr,
                                                 asoc->base.sk);
        } else
@@ -384,7 +385,6 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
                tp->rto = tp->asoc->rto_max;
 
        tp->rtt = rtt;
-       tp->last_rto = tp->rto;
 
        /* Reset rto_pending so that a new RTT measurement is started when a
         * new data chunk is sent.
@@ -502,6 +502,9 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                transport->ssthresh = max(transport->cwnd/2,
                                          4*transport->asoc->pathmtu);
                transport->cwnd = transport->asoc->pathmtu;
+
+               /* T3-rtx also clears fast recovery on the transport */
+               transport->fast_recovery = 0;
                break;
 
        case SCTP_LOWER_CWND_FAST_RTX:
@@ -542,8 +545,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * congestion indications more than once every window of
                 * data (or more loosely more than once every round-trip time).
                 */
-               if ((jiffies - transport->last_time_ecne_reduced) >
-                   transport->rtt) {
+               if (time_after(jiffies, transport->last_time_ecne_reduced +
+                                       transport->rtt)) {
                        transport->ssthresh = max(transport->cwnd/2,
                                                  4*transport->asoc->pathmtu);
                        transport->cwnd = transport->ssthresh;
@@ -560,9 +563,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * to be done every RTO interval, we do it every hearbeat
                 * interval.
                 */
-               if ((jiffies - transport->last_time_used) > transport->rto)
-                       transport->cwnd = max(transport->cwnd/2,
-                                                4*transport->asoc->pathmtu);
+               transport->cwnd = max(transport->cwnd/2,
+                                        4*transport->asoc->pathmtu);
                break;
        }
 
@@ -573,6 +575,43 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                          transport->cwnd, transport->ssthresh);
 }
 
+/* Apply Max.Burst limit to the congestion window:
+ * sctpimpguide-05 2.14.2
+ * D) When the time comes for the sender to
+ * transmit new DATA chunks, the protocol parameter Max.Burst MUST
+ * first be applied to limit how many new DATA chunks may be sent.
+ * The limit is applied by adjusting cwnd as follows:
+ *     if ((flightsize+ Max.Burst * MTU) < cwnd)
+ *             cwnd = flightsize + Max.Burst * MTU
+ */
+
+void sctp_transport_burst_limited(struct sctp_transport *t)
+{
+       struct sctp_association *asoc = t->asoc;
+       u32 old_cwnd = t->cwnd;
+       u32 max_burst_bytes;
+
+       if (t->burst_limited)
+               return;
+
+       max_burst_bytes = t->flight_size + (asoc->max_burst * asoc->pathmtu);
+       if (max_burst_bytes < old_cwnd) {
+               t->cwnd = max_burst_bytes;
+               t->burst_limited = old_cwnd;
+       }
+}
+
+/* Restore the old cwnd congestion window, after the burst had it's
+ * desired effect.
+ */
+void sctp_transport_burst_reset(struct sctp_transport *t)
+{
+       if (t->burst_limited) {
+               t->cwnd = t->burst_limited;
+               t->burst_limited = 0;
+       }
+}
+
 /* What is the next timeout value for this transport? */
 unsigned long sctp_transport_timeout(struct sctp_transport *t)
 {
@@ -595,8 +634,9 @@ void sctp_transport_reset(struct sctp_transport *t)
         * (see Section 6.2.1)
         */
        t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
+       t->burst_limited = 0;
        t->ssthresh = asoc->peer.i.a_rwnd;
-       t->last_rto = t->rto = asoc->rto_initial;
+       t->rto = asoc->rto_initial;
        t->rtt = 0;
        t->srtt = 0;
        t->rttvar = 0;
@@ -608,6 +648,7 @@ void sctp_transport_reset(struct sctp_transport *t)
        t->flight_size = 0;
        t->error_count = 0;
        t->rto_pending = 0;
+       t->hb_sent = 0;
        t->fast_recovery = 0;
 
        /* Initialize the state information for SFR-CACC */