Skip to content

Commit

Permalink
sctp: refactor sctp_datamsg_from_user
Browse files Browse the repository at this point in the history
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: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Marcelo Ricardo Leitner authored and David S. Miller committed Dec 29, 2016
1 parent 5e45853 commit bfd2e4b
Showing 1 changed file with 32 additions and 75 deletions.
107 changes: 32 additions & 75 deletions net/sctp/chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,12 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct sctp_sndrcvinfo *sinfo,
struct iov_iter *from)
{
int max, whole, i, offset, over, err;
int len, first_len;
int max_data;
size_t len, first_len, max_data, remaining;
size_t msg_len = iov_iter_count(from);
struct list_head *pos, *temp;
struct sctp_chunk *chunk;
struct sctp_datamsg *msg;
struct list_head *pos, *temp;
size_t msg_len = iov_iter_count(from);
__u8 frag;
int err;

msg = sctp_datamsg_new(GFP_KERNEL);
if (!msg)
Expand All @@ -185,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
(SCTP_PR_TTL_ENABLED(sinfo->sinfo_flags) ||
!SCTP_PR_POLICY(sinfo->sinfo_flags)))
msg->expires_at = jiffies +
msecs_to_jiffies(sinfo->sinfo_timetolive);
msecs_to_jiffies(sinfo->sinfo_timetolive);

/* This is the biggest possible DATA chunk that can fit into
* the packet
Expand All @@ -195,7 +193,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
sizeof(struct sctphdr) - sizeof(struct sctp_data_chunk);
max_data = SCTP_TRUNC4(max_data);

max = asoc->frag_point;
/* If the the peer requested that we authenticate DATA chunks
* we need to account for bundling of the AUTH chunks along with
* DATA.
Expand All @@ -208,12 +205,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
hmac_desc->hmac_len);
}

/* Now, check if we need to reduce our max */
if (max > max_data)
max = max_data;
/* Check what's our max considering the above */
max_data = min_t(size_t, max_data, asoc->frag_point);

whole = 0;
first_len = max;
/* Set first_len and then account for possible bundles on first frag */
first_len = max_data;

/* 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.
Expand All @@ -224,40 +220,38 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) &&
asoc->outqueue.out_qlen == 0 &&
list_empty(&asoc->outqueue.retransmit) &&
msg_len > max)
max_data -= SCTP_PAD4(sizeof(sctp_sack_chunk_t));
msg_len > max_data)
first_len -= SCTP_PAD4(sizeof(sctp_sack_chunk_t));

/* Encourage Cookie-ECHO bundling. */
if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
max_data -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;

/* Now that we adjusted completely, reset first_len */
if (first_len > max_data)
first_len = max_data;
first_len -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;

/* Account for a different sized first fragment */
if (msg_len >= first_len) {
msg_len -= first_len;
whole = 1;
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);
} else {
/* Which may be the only one... */
first_len = msg_len;
}

/* Create chunks for all the full sized DATA chunks. */
for (i = 0, len = first_len; i < whole; i++) {
frag = SCTP_DATA_MIDDLE_FRAG;
/* Create chunks for all DATA chunks. */
for (remaining = msg_len; remaining; remaining -= len) {
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;
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;

/* The application requests to set the I-bit of the
Expand All @@ -271,7 +265,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,

chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag,
0, GFP_KERNEL);

if (!chunk) {
err = -ENOMEM;
goto errout;
Expand All @@ -282,45 +275,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
goto errout_chunk_free;

/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)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;
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr -
chunk->skb->data);

sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks);
Expand All @@ -338,6 +294,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
sctp_chunk_free(chunk);
}
sctp_datamsg_put(msg);

return ERR_PTR(err);
}

Expand Down

0 comments on commit bfd2e4b

Please sign in to comment.