Commit bfd2e4b8 authored by Marcelo Ricardo Leitner's avatar Marcelo Ricardo Leitner Committed by David S. Miller

sctp: refactor sctp_datamsg_from_user

This patch refactors sctp_datamsg_from_user() in an attempt to make it
better to read and avoid code duplication for handling the last
fragment.

It also avoids doing division and remaining operations. Even though, it
should still operate similarly as before this patch.
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5e458531
...@@ -165,14 +165,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -165,14 +165,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct sctp_sndrcvinfo *sinfo, struct sctp_sndrcvinfo *sinfo,
struct iov_iter *from) struct iov_iter *from)
{ {
int max, whole, i, offset, over, err; size_t len, first_len, max_data, remaining;
int len, first_len; size_t msg_len = iov_iter_count(from);
int max_data; struct list_head *pos, *temp;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
struct sctp_datamsg *msg; struct sctp_datamsg *msg;
struct list_head *pos, *temp; int err;
size_t msg_len = iov_iter_count(from);
__u8 frag;
msg = sctp_datamsg_new(GFP_KERNEL); msg = sctp_datamsg_new(GFP_KERNEL);
if (!msg) if (!msg)
...@@ -195,7 +193,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -195,7 +193,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk); sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk);
max_data = SCTP_TRUNC4(max_data); max_data = SCTP_TRUNC4(max_data);
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 account for bundling of the AUTH chunks along with * we need to account for bundling of the AUTH chunks along with
* DATA. * DATA.
...@@ -208,12 +205,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -208,12 +205,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
hmac_desc->hmac_len); hmac_desc->hmac_len);
} }
/* Now, check if we need to reduce our max */ /* Check what's our max considering the above */
if (max > max_data) max_data = min_t(size_t, max_data, asoc->frag_point);
max = max_data;
whole = 0; /* Set first_len and then account for possible bundles on first frag */
first_len = max; first_len = max_data;
/* Check to see if we have a pending SACK and try to let it be bundled /* 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. * with this message. Do this if we don't have any data queued already.
...@@ -224,40 +220,38 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -224,40 +220,38 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) && if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) &&
asoc->outqueue.out_qlen == 0 && asoc->outqueue.out_qlen == 0 &&
list_empty(&asoc->outqueue.retransmit) && list_empty(&asoc->outqueue.retransmit) &&
msg_len > max) msg_len > max_data)
max_data -= SCTP_PAD4(sizeof(sctp_sack_chunk_t)); first_len -= SCTP_PAD4(sizeof(sctp_sack_chunk_t));
/* Encourage Cookie-ECHO bundling. */ /* Encourage Cookie-ECHO bundling. */
if (asoc->state < SCTP_STATE_COOKIE_ECHOED) if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN; first_len -= 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 */ /* Account for a different sized first fragment */
if (msg_len >= first_len) { if (msg_len >= first_len) {
msg_len -= first_len;
whole = 1;
msg->can_delay = 0; msg->can_delay = 0;
}
/* How many full sized? How many bytes leftover? */
whole += msg_len / max;
over = msg_len % max;
offset = 0;
if ((whole > 1) || (whole && over))
SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS); SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS);
} else {
/* Which may be the only one... */
first_len = msg_len;
}
/* Create chunks for all the full sized DATA chunks. */ /* Create chunks for all DATA chunks. */
for (i = 0, len = first_len; i < whole; i++) { for (remaining = msg_len; remaining; remaining -= len) {
frag = SCTP_DATA_MIDDLE_FRAG; u8 frag = SCTP_DATA_MIDDLE_FRAG;
if (0 == i) if (remaining == msg_len) {
/* First frag, which may also be the last */
frag |= SCTP_DATA_FIRST_FRAG; frag |= SCTP_DATA_FIRST_FRAG;
len = first_len;
} else {
/* Middle frags */
len = max_data;
}
if ((i == (whole - 1)) && !over) { if (len >= remaining) {
/* Last frag, which may also be the first */
len = remaining;
frag |= SCTP_DATA_LAST_FRAG; frag |= SCTP_DATA_LAST_FRAG;
/* The application requests to set the I-bit of the /* The application requests to set the I-bit of the
...@@ -271,7 +265,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -271,7 +265,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag,
0, GFP_KERNEL); 0, GFP_KERNEL);
if (!chunk) { if (!chunk) {
err = -ENOMEM; err = -ENOMEM;
goto errout; goto errout;
...@@ -282,45 +275,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -282,45 +275,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
goto errout_chunk_free; goto errout_chunk_free;
/* Put the chunk->skb back into the form expected by send. */ /* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr -
- (__u8 *)chunk->skb->data); chunk->skb->data);
sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks);
/* The first chunk, the first chunk was likely short
* to allow bundling, so reset to full size.
*/
if (0 == i)
len = max;
}
/* .. now the leftover bytes. */
if (over) {
if (!whole)
frag = SCTP_DATA_NOT_FRAG;
else
frag = SCTP_DATA_LAST_FRAG;
if ((sinfo->sinfo_flags & SCTP_EOF) ||
(sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
frag |= SCTP_DATA_SACK_IMM;
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag,
0, GFP_KERNEL);
if (!chunk) {
err = -ENOMEM;
goto errout;
}
err = sctp_user_addto_chunk(chunk, over, from);
/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
if (err < 0)
goto errout_chunk_free;
sctp_datamsg_assign(msg, chunk); sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks); list_add_tail(&chunk->frag_list, &msg->chunks);
...@@ -338,6 +294,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -338,6 +294,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
sctp_datamsg_put(msg); sctp_datamsg_put(msg);
return ERR_PTR(err); return ERR_PTR(err);
} }
......
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