[SCTP]: Correctly handle AUTH parameters in unexpected INIT
[platform/kernel/linux-rpi.git] / net / sctp / ulpqueue.c
index 4be92d0..1733fa2 100644 (file)
@@ -53,6 +53,7 @@ static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
                                              struct sctp_ulpevent *);
 static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *,
                                              struct sctp_ulpevent *);
+static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq);
 
 /* 1st Level Abstractions */
 
@@ -190,6 +191,7 @@ static void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq)
 static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
 {
        ulpq->pd_mode = 0;
+       sctp_ulpq_reasm_drain(ulpq);
        return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc);
 }
 
@@ -699,6 +701,37 @@ void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn)
        }
 }
 
+/*
+ * Drain the reassembly queue.  If we just cleared parted delivery, it
+ * is possible that the reassembly queue will contain already reassembled
+ * messages.  Retrieve any such messages and give them to the user.
+ */
+static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq)
+{
+       struct sctp_ulpevent *event = NULL;
+       struct sk_buff_head temp;
+
+       if (skb_queue_empty(&ulpq->reasm))
+               return;
+
+       while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) {
+               /* Do ordering if needed.  */
+               if ((event) && (event->msg_flags & MSG_EOR)){
+                       skb_queue_head_init(&temp);
+                       __skb_queue_tail(&temp, sctp_event2skb(event));
+
+                       event = sctp_ulpq_order(ulpq, event);
+               }
+
+               /* Send event to the ULP.  'event' is the
+                * sctp_ulpevent for  very first SKB on the  temp' list.
+                */
+               if (event)
+                       sctp_ulpq_tail_event(ulpq, event);
+       }
+}
+
+
 /* Helper function to gather skbs that have possibly become
  * ordered by an an incoming chunk.
  */
@@ -862,7 +895,7 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
                        continue;
 
                /* see if this ssn has been marked by skipping */
-               if (!SSN_lt(cssn, sctp_ssn_peek(in, csid)))
+               if (!SSN_lte(cssn, sctp_ssn_peek(in, csid)))
                        break;
 
                __skb_unlink(pos, &ulpq->lobby);