]> xenbits.xensource.com Git - people/royger/freebsd.git/commitdiff
Don't send multiple SHUTDOWN chunks in a single packet.
authortuexen <tuexen@FreeBSD.org>
Fri, 9 Dec 2016 17:57:17 +0000 (17:57 +0000)
committertuexen <tuexen@FreeBSD.org>
Fri, 9 Dec 2016 17:57:17 +0000 (17:57 +0000)
Thanks to Felix Weinrank for making me aware of this issue.

MFC after: 1 week

sys/netinet/sctp_output.c

index 33f02d43980cd15faf0a2e60fe7304d8db53b2ab..3f86e0145d9917d298d0140061c476ccc93d4eee 100644 (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;
-       }
-       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);
+               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);
        }
-       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;
 }