Merge branch 'sii-m15w' into upstream
[pandora-kernel.git] / net / sctp / sm_statefuns.c
index 8bc2792..ead3f1b 100644 (file)
@@ -846,6 +846,7 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
        hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
        hbinfo.daddr = transport->ipaddr;
        hbinfo.sent_at = jiffies;
+       hbinfo.hb_nonce = transport->hb_nonce;
 
        /* Send a heartbeat to our peer.  */
        paylen = sizeof(sctp_sender_hb_info_t);
@@ -1048,6 +1049,10 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
                return SCTP_DISPOSITION_DISCARD;
        }
 
+       /* Validate the 64-bit random nonce. */
+       if (hbinfo->hb_nonce != link->hb_nonce)
+               return SCTP_DISPOSITION_DISCARD;
+
        max_interval = link->hbinterval + link->rto;
 
        /* Check if the timestamp looks valid.  */
@@ -5278,7 +5283,6 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        datalen -= sizeof(sctp_data_chunk_t);
 
        deliver = SCTP_CMD_CHUNK_ULP;
-       chunk->data_accepted = 1;
 
        /* Think about partial delivery. */
        if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
@@ -5293,10 +5297,18 @@ static int sctp_eat_data(const struct sctp_association *asoc,
         * seems a bit troublesome in that frag_point varies based on
         * PMTU.  In cases, such as loopback, this might be a rather
         * large spill over.
+        * NOTE: If we have a full receive buffer here, we only renege if
+        * our receiver can still make progress without the tsn being
+        * received. We do this because in the event that the associations
+        * receive queue is empty we are filling a leading gap, and since
+        * reneging moves the gap to the end of the tsn stream, we are likely
+        * to stall again very shortly. Avoiding the renege when we fill a
+        * leading gap is a good heuristic for avoiding such steady state
+        * stalls.
         */
        if (!asoc->rwnd || asoc->rwnd_over ||
            (datalen > asoc->rwnd + asoc->frag_point) ||
-           rcvbuf_over) {
+           (rcvbuf_over && (!skb_queue_len(&sk->sk_receive_queue)))) {
 
                /* If this is the next TSN, consider reneging to make
                 * room.   Note: Playing nice with a confused sender.  A
@@ -5349,6 +5361,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        if (SCTP_CMD_CHUNK_ULP == deliver)
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
 
+       chunk->data_accepted = 1;
+
        /* Note: Some chunks may get overcounted (if we drop) or overcounted
         * if we renege and the chunk arrives again.
         */