sctp: Fix data segmentation with small frag_size
[pandora-kernel.git] / net / sctp / chunk.c
index 1748ef9..9292294 100644 (file)
@@ -158,6 +158,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;
@@ -179,8 +180,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.
@@ -189,23 +196,30 @@ 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;
 
        /* Encourage Cookie-ECHO bundling. */
        if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
-               whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
+               max_data -= 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;
-               }
+               /* This is the biggesr first_len we can have */
+               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? */