Don't send multiple SHUTDOWN chunks in a single packet.

Thanks to Felix Weinrank for making me aware of this issue.

MFC after:	1 week
This commit is contained in:
Michael Tuexen 2016-12-09 17:57:17 +00:00
parent d9121bf564
commit 8d0a31e19c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=309743

View File

@ -9164,40 +9164,61 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net)
struct sctp_shutdown_chunk *shutdown_cp;
struct sctp_tmit_chunk *chk;
m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER);
if (m_shutdown == NULL) {
/* no mbuf's */
return;
TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
if (chk->rec.chunk_id.id == SCTP_SHUTDOWN) {
/* We already have a SHUTDOWN queued. Reuse it. */
if (chk->whoTo) {
sctp_free_remote_addr(chk->whoTo);
chk->whoTo = NULL;
}
break;
}
}
SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD);
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* no memory */
sctp_m_freem(m_shutdown);
return;
m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER);
if (m_shutdown == NULL) {
/* no mbuf's */
return;
}
SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD);
sctp_alloc_a_chunk(stcb, chk);
if (chk == NULL) {
/* no memory */
sctp_m_freem(m_shutdown);
return;
}
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_SHUTDOWN;
chk->rec.chunk_id.can_take_data = 1;
chk->flags = 0;
chk->send_size = sizeof(struct sctp_shutdown_chunk);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = m_shutdown;
chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
shutdown_cp->ch.chunk_flags = 0;
shutdown_cp->ch.chunk_length = htons(chk->send_size);
shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
SCTP_BUF_LEN(m_shutdown) = chk->send_size;
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
} else {
TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, sctp_next);
chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
shutdown_cp = mtod(chk->data, struct sctp_shutdown_chunk *);
shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next);
}
chk->copy_by_ref = 0;
chk->rec.chunk_id.id = SCTP_SHUTDOWN;
chk->rec.chunk_id.can_take_data = 1;
chk->flags = 0;
chk->send_size = sizeof(struct sctp_shutdown_chunk);
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
chk->flags = 0;
chk->asoc = &stcb->asoc;
chk->data = m_shutdown;
chk->whoTo = net;
if (chk->whoTo) {
atomic_add_int(&chk->whoTo->ref_count, 1);
}
shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *);
shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN;
shutdown_cp->ch.chunk_flags = 0;
shutdown_cp->ch.chunk_length = htons(chk->send_size);
shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn);
SCTP_BUF_LEN(m_shutdown) = chk->send_size;
TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next);
chk->asoc->ctrl_queue_cnt++;
return;
}