Commit 3e62abf9 authored by Vlad Yasevich's avatar Vlad Yasevich

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: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent bec9640b
...@@ -158,6 +158,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -158,6 +158,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
{ {
int max, whole, i, offset, over, err; int max, whole, i, offset, over, err;
int len, first_len; int len, first_len;
int max_data;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
struct sctp_datamsg *msg; struct sctp_datamsg *msg;
struct list_head *pos, *temp; struct list_head *pos, *temp;
...@@ -179,8 +180,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -179,8 +180,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
__func__, msg, msg->expires_at, jiffies); __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 /* If the the peer requested that we authenticate DATA chunks
* we need to accound for bundling of the AUTH chunks along with * we need to accound for bundling of the AUTH chunks along with
* DATA. * DATA.
...@@ -189,24 +196,31 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -189,24 +196,31 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc); struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
if (hmac_desc) if (hmac_desc)
max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) + max_data -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
hmac_desc->hmac_len); hmac_desc->hmac_len);
} }
/* Now, check if we need to reduce our max */
if (max > max_data)
max = max_data;
whole = 0; whole = 0;
first_len = max; first_len = max;
/* Encourage Cookie-ECHO bundling. */ /* Encourage Cookie-ECHO bundling. */
if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { 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. */ /* This is the biggesr first_len we can have */
if (whole) { if (first_len > max_data)
first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; first_len = max_data;
}
/* Account for a different sized first fragment */
if (msg_len >= first_len) {
msg_len -= first_len; msg_len -= first_len;
whole = 1; whole = 1;
} }
}
/* How many full sized? How many bytes leftover? */ /* How many full sized? How many bytes leftover? */
whole += msg_len / max; whole += msg_len / max;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment