summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:56 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2009-09-04 18:20:56 -0400
commit3e62abf92f34d75fe22352d8d102e3cd2755804d (patch)
treee8e175b95bdf137565a301e382d6f7c22e4a417e
parentbec9640bb0d451813b1bb1f2cc13a5bfb17c3e48 (diff)
sctp: Fix data segmentation with small frag_size
Since an application may specify the maximum SCTP fragment size that all data should be fragmented to, we need to fix how we do segmentation. Right now, if a user specifies a small fragment size, the segment size can go negative in the presence of AUTH or COOKIE_ECHO bundling. What we need to do is track the largest possbile DATA chunk that can fit into the mtu. Then if the fragment size specified is bigger then this maximum length, we'll shrink it down. Otherwise, we just use the smaller segment size without changing it further. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
-rw-r--r--net/sctp/chunk.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef90950c..9292294dbc12 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -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? */