nfsd: simplify fh_verify access checks
[safe/jmp/linux-2.6] / net / sctp / chunk.c
index ed85764..acf7c4d 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. */
@@ -66,12 +67,26 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
 {
        struct sctp_datamsg *msg;
        msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
-       if (msg)
+       if (msg) {
                sctp_datamsg_init(msg);
-       SCTP_DBG_OBJCNT_INC(datamsg);
+               SCTP_DBG_OBJCNT_INC(datamsg);
+       }
        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)
 {
@@ -141,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;
 }
 
 
@@ -157,6 +173,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
 {
        int max, whole, i, offset, over, err;
        int len, first_len;
+       int max_data;
        struct sctp_chunk *chunk;
        struct sctp_datamsg *msg;
        struct list_head *pos, *temp;
@@ -178,8 +195,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                                  __func__, msg, msg->expires_at, jiffies);
        }
 
-       max = asoc->frag_point;
+       /* This is the biggest possible DATA chunk that can fit into
+        * the packet
+        */
+       max_data = asoc->pathmtu -
+               sctp_sk(asoc->base.sk)->pf->af->net_header_len -
+               sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk);
 
+       max = asoc->frag_point;
        /* If the the peer requested that we authenticate DATA chunks
         * we need to accound for bundling of the AUTH chunks along with
         * DATA.
@@ -188,23 +211,41 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
 
                if (hmac_desc)
-                       max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
+                       max_data -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
                                            hmac_desc->hmac_len);
        }
 
+       /* Now, check if we need to reduce our max */
+       if (max > max_data)
+               max = max_data;
+
        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) {
-               whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
-
-               /* Account for the DATA to be bundled with the COOKIE-ECHO. */
-               if (whole) {
-                       first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
-                       msg_len -= first_len;
-                       whole = 1;
-               }
+       if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
+               max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;
+
+       /* 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) {
+               msg_len -= first_len;
+               whole = 1;
        }
 
        /* How many full sized?  How many bytes leftover? */