msg->can_abandon = 0;
msg->expires_at = 0;
INIT_LIST_HEAD(&msg->chunks);
+ msg->msg_size = 0;
}
/* Allocate and initialize datamsg. */
{
struct sctp_datamsg *msg;
msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
- if (msg)
+ if (msg) {
sctp_datamsg_init(msg);
- SCTP_DBG_OBJCNT_INC(datamsg);
+ SCTP_DBG_OBJCNT_INC(datamsg);
+ }
return msg;
}
+void sctp_datamsg_free(struct sctp_datamsg *msg)
+{
+ struct sctp_chunk *chunk;
+
+ /* This doesn't have to be a _safe vairant because
+ * sctp_chunk_free() only drops the refs.
+ */
+ list_for_each_entry(chunk, &msg->chunks, frag_list)
+ sctp_chunk_free(chunk);
+
+ sctp_datamsg_put(msg);
+}
+
/* Final destructruction of datamsg memory. */
static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
{
{
sctp_datamsg_hold(msg);
chunk->msg = msg;
+ msg->msg_size += chunk->skb->len;
}
{
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;
__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.
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;
+ /* 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.
+ * To check that, look at out_qlen and retransmit list.
+ * NOTE: we will not reduce to account for SACK, if the message would
+ * not have been fragmented.
+ */
+ if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) &&
+ asoc->outqueue.out_qlen == 0 &&
+ list_empty(&asoc->outqueue.retransmit) &&
+ msg_len > max)
+ max_data -= WORD_ROUND(sizeof(sctp_sack_chunk_t));
+
/* Encourage Cookie-ECHO bundling. */
- if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
- whole = msg_len / (max - 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;
- }
+ 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;
+
+ /* 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? */