vserver 1.9.5.x5
[linux-2.6.git] / net / sctp / inqueue.c
index 2e83405..cedf435 100644 (file)
@@ -59,19 +59,6 @@ void sctp_inq_init(struct sctp_inq *queue)
        queue->malloced = 0;
 }
 
-/* Create an initialized sctp_inq.  */
-struct sctp_inq *sctp_inq_new(void)
-{
-       struct sctp_inq *retval;
-
-       retval = t_new(struct sctp_inq, GFP_ATOMIC);
-       if (retval) {
-               sctp_inq_init(retval);
-               retval->malloced = 1;
-       }
-        return retval;
-}
-
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
@@ -157,14 +144,36 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
        }
 
         chunk->chunk_hdr = ch;
-        chunk->chunk_end = ((__u8 *) ch)
-               + WORD_ROUND(ntohs(ch->length));
+        chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+       /* In the unlikely case of an IP reassembly, the skb could be
+        * non-linear. If so, update chunk_end so that it doesn't go past
+        * the skb->tail.
+        */
+       if (unlikely(skb_is_nonlinear(chunk->skb))) {
+               if (chunk->chunk_end > chunk->skb->tail)
+                       chunk->chunk_end = chunk->skb->tail;
+       }
        skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
        chunk->subh.v = NULL; /* Subheader is no longer valid.  */
 
        if (chunk->chunk_end < chunk->skb->tail) {
                /* This is not a singleton */
                chunk->singleton = 0;
+       } else if (chunk->chunk_end > chunk->skb->tail) {
+                /* RFC 2960, Section 6.10  Bundling
+                *
+                * Partial chunks MUST NOT be placed in an SCTP packet.
+                * If the receiver detects a partial chunk, it MUST drop
+                * the chunk.  
+                *
+                * Since the end of the chunk is past the end of our buffer
+                * (which contains the whole packet, we can freely discard
+                * the whole packet.
+                */
+               sctp_chunk_free(chunk);
+               chunk = queue->in_progress = NULL;
+
+               return NULL;
        } else {
                /* We are at the end of the packet, so mark the chunk
                 * in case we need to send a SACK.