From 3e62abf92f34d75fe22352d8d102e3cd2755804d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 4 Sep 2009 18:20:56 -0400 Subject: 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 --- net/sctp/chunk.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'net/sctp/chunk.c') diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 1748ef90950..9292294dbc1 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? */ -- cgit v1.2.3