net: CONFIG_COMPAT redux
[safe/jmp/linux-2.6] / net / sctp / chunk.c
index 9292294..8e43200 100644 (file)
@@ -59,6 +59,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
        msg->can_abandon = 0;
        msg->expires_at = 0;
        INIT_LIST_HEAD(&msg->chunks);
+       msg->msg_size = 0;
 }
 
 /* Allocate and initialize datamsg. */
@@ -73,6 +74,19 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
        return msg;
 }
 
+void sctp_datamsg_free(struct sctp_datamsg *msg)
+{
+       struct sctp_chunk *chunk;
+
+       /* This doesn't have to be a _safe vairant because
+        * sctp_chunk_free() only drops the refs.
+        */
+       list_for_each_entry(chunk, &msg->chunks, frag_list)
+               sctp_chunk_free(chunk);
+
+       sctp_datamsg_put(msg);
+}
+
 /* Final destructruction of datamsg memory. */
 static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
 {
@@ -142,6 +156,7 @@ static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chu
 {
        sctp_datamsg_hold(msg);
        chunk->msg = msg;
+       msg->msg_size += chunk->skb->len;
 }
 
 
@@ -207,14 +222,25 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
        whole = 0;
        first_len = max;
 
+       /* Check to see if we have a pending SACK and try to let it be bundled
+        * with this message.  Do this if we don't have any data queued already.
+        * To check that, look at out_qlen and retransmit list.
+        * NOTE: we will not reduce to account for SACK, if the message would
+        * not have been fragmented.
+        */
+       if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) &&
+           asoc->outqueue.out_qlen == 0 &&
+           list_empty(&asoc->outqueue.retransmit) &&
+           msg_len > max)
+               max_data -= WORD_ROUND(sizeof(sctp_sack_chunk_t));
+
        /* Encourage Cookie-ECHO bundling. */
-       if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
+       if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
                max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;
 
-               /* This is the biggesr first_len we can have */
-               if (first_len > max_data)
-                       first_len = max_data;
-       }
+       /* Now that we adjusted completely, reset first_len */
+       if (first_len > max_data)
+               first_len = max_data;
 
        /* Account for a different sized first fragment */
        if (msg_len >= first_len) {
@@ -237,9 +263,18 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                if (0 == i)
                        frag |= SCTP_DATA_FIRST_FRAG;
 
-               if ((i == (whole - 1)) && !over)
+               if ((i == (whole - 1)) && !over) {
                        frag |= SCTP_DATA_LAST_FRAG;
 
+                       /* The application requests to set the I-bit of the
+                        * last DATA chunk of a user message when providing
+                        * the user message to the SCTP implementation.
+                        */
+                       if ((sinfo->sinfo_flags & SCTP_EOF) ||
+                           (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
+                               frag |= SCTP_DATA_SACK_IMM;
+               }
+
                chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
 
                if (!chunk)
@@ -271,6 +306,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                else
                        frag = SCTP_DATA_LAST_FRAG;
 
+               if ((sinfo->sinfo_flags & SCTP_EOF) ||
+                   (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
+                       frag |= SCTP_DATA_SACK_IMM;
+
                chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
 
                if (!chunk)