Author: tuexen
Date: Sat Jul 15 19:54:03 2017
New Revision: 321034
URL: https://svnweb.freebsd.org/changeset/base/321034

Log:
  Fix the handling of Explicit EOR mode.
  
  While there, appropriately handle the overhead depending on
  the usage of DATA or I-DATA chunks. Take the overhead only
  into account, when required.
  
  Joint work with rrs@
  MFC after:    1 week

Modified:
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_output.h

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Sat Jul 15 19:52:59 2017        
(r321033)
+++ head/sys/netinet/sctp_output.c      Sat Jul 15 19:54:03 2017        
(r321034)
@@ -6250,11 +6250,7 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
        } else {
                ovh = SCTP_MIN_V4_OVERHEAD;
        }
-       if (stcb->asoc.idata_supported) {
-               ovh += sizeof(struct sctp_idata_chunk);
-       } else {
-               ovh += sizeof(struct sctp_data_chunk);
-       }
+       ovh += SCTP_DATA_CHUNK_OVERHEAD(stcb);
        if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
                siz = asoc->smallest_mtu - ovh;
        else
@@ -6759,7 +6755,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct s
                }
        }
        un_sent = ((stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight) +
-           (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+           (stcb->asoc.stream_queue_cnt * SCTP_DATA_CHUNK_OVERHEAD(stcb)));
 
        if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
            (stcb->asoc.total_flight > 0) &&
@@ -7459,11 +7455,7 @@ dont_do_it:
        } else {
                atomic_subtract_int(&sp->length, to_move);
        }
-       if (stcb->asoc.idata_supported == 0) {
-               leading = sizeof(struct sctp_data_chunk);
-       } else {
-               leading = sizeof(struct sctp_idata_chunk);
-       }
+       leading = SCTP_DATA_CHUNK_OVERHEAD(stcb);
        if (M_LEADINGSPACE(chk->data) < leading) {
                /* Not enough room for a chunk header, get some */
                struct mbuf *m;
@@ -7505,11 +7497,7 @@ dont_do_it:
                        M_ALIGN(chk->data, 4);
                }
        }
-       if (stcb->asoc.idata_supported == 0) {
-               SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), 
M_NOWAIT);
-       } else {
-               SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_idata_chunk), 
M_NOWAIT);
-       }
+       SCTP_BUF_PREPEND(chk->data, SCTP_DATA_CHUNK_OVERHEAD(stcb), M_NOWAIT);
        if (chk->data == NULL) {
                /* HELP, TSNH since we assured it would not above? */
 #ifdef INVARIANTS
@@ -7522,13 +7510,8 @@ dont_do_it:
                to_move = 0;
                goto out_of;
        }
-       if (stcb->asoc.idata_supported == 0) {
-               sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
-               chk->book_size = chk->send_size = (uint16_t)(to_move + 
sizeof(struct sctp_data_chunk));
-       } else {
-               sctp_snd_sb_alloc(stcb, sizeof(struct sctp_idata_chunk));
-               chk->book_size = chk->send_size = (uint16_t)(to_move + 
sizeof(struct sctp_idata_chunk));
-       }
+       sctp_snd_sb_alloc(stcb, SCTP_DATA_CHUNK_OVERHEAD(stcb));
+       chk->book_size = chk->send_size = (uint16_t)(to_move + 
SCTP_DATA_CHUNK_OVERHEAD(stcb));
        chk->book_size_scale = 0;
        chk->sent = SCTP_DATAGRAM_UNSENT;
 
@@ -7728,11 +7711,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
                break;
        }
        /* Need an allowance for the data chunk header too */
-       if (stcb->asoc.idata_supported == 0) {
-               space_left -= sizeof(struct sctp_data_chunk);
-       } else {
-               space_left -= sizeof(struct sctp_idata_chunk);
-       }
+       space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
 
        /* must make even word boundary */
        space_left &= 0xfffffffc;
@@ -7749,18 +7728,10 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
                strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, 
asoc);
                total_moved += moved;
                space_left -= moved;
-               if (stcb->asoc.idata_supported == 0) {
-                       if (space_left >= sizeof(struct sctp_data_chunk)) {
-                               space_left -= sizeof(struct sctp_data_chunk);
-                       } else {
-                               space_left = 0;
-                       }
+               if (space_left >= SCTP_DATA_CHUNK_OVERHEAD(stcb)) {
+                       space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
                } else {
-                       if (space_left >= sizeof(struct sctp_idata_chunk)) {
-                               space_left -= sizeof(struct sctp_idata_chunk);
-                       } else {
-                               space_left = 0;
-                       }
+                       space_left = 0;
                }
                space_left &= 0xfffffffc;
        }
@@ -10209,8 +10180,7 @@ do_it_again:
                         * and we have data in flight we stop, except if we
                         * are handling a fragmented user message.
                         */
-                       un_sent = ((stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight) +
-                           (stcb->asoc.stream_queue_cnt * sizeof(struct 
sctp_data_chunk)));
+                       un_sent = stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight;
                        if ((un_sent < (int)(stcb->asoc.smallest_mtu - 
SCTP_MIN_OVERHEAD)) &&
                            (stcb->asoc.total_flight > 0)) {
 /*     &&                   sctp_is_feature_on(inp, 
SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
@@ -12448,7 +12418,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
        sp->sender_all_done = 0;
        sp->some_taken = 0;
        sp->put_last_out = 0;
-       resv_in_first = sizeof(struct sctp_data_chunk);
+       resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb);
        sp->data = sp->tail_mbuf = NULL;
        if (sp->length == 0) {
                *error = 0;
@@ -12865,12 +12835,19 @@ sctp_lower_sosend(struct socket *so,
        }
        /* would we block? */
        if (non_blocking) {
+               uint32_t amount;
+
                if (hold_tcblock == 0) {
                        SCTP_TCB_LOCK(stcb);
                        hold_tcblock = 1;
                }
-               inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
-               if ((SCTP_SB_LIMIT_SND(so) < (sndlen + inqueue_bytes + 
stcb->asoc.sb_send_resv)) ||
+               inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+               if (user_marks_eor == 0) {
+                       amount = sndlen;
+               } else {
+                       amount = 1;
+               }
+               if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + 
stcb->asoc.sb_send_resv)) ||
                    (stcb->asoc.chunks_on_out_queue >= 
SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
                        SCTP_LTRACE_ERR_RET(inp, stcb, net, 
SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
                        if (sndlen > SCTP_SB_LIMIT_SND(so))
@@ -13036,7 +13013,7 @@ sctp_lower_sosend(struct socket *so,
                goto out_unlocked;
        }
        /* Calculate the maximum we can send */
-       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
        if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
                if (non_blocking) {
                        /* we already checked for non-blocking above. */
@@ -13093,7 +13070,7 @@ sctp_lower_sosend(struct socket *so,
            ((stcb->asoc.chunks_on_out_queue + stcb->asoc.stream_queue_cnt) >= 
SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
                /* No room right now ! */
                SOCKBUF_LOCK(&so->so_snd);
-               inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+               inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
                while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + 
local_add_more)) ||
                    ((stcb->asoc.stream_queue_cnt + 
stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) 
{
                        SCTPDBG(SCTP_DEBUG_OUTPUT1, "pre_block limit:%u 
<(inq:%d + %d) || (%d+%d > %d)\n",
@@ -13129,7 +13106,7 @@ sctp_lower_sosend(struct socket *so,
                                SOCKBUF_UNLOCK(&so->so_snd);
                                goto out_unlocked;
                        }
-                       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+                       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
                }
                if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
                        max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
@@ -13222,8 +13199,9 @@ skip_preblock:
                        /* How much room do we have? */
                        struct mbuf *new_tail, *mm;
 
-                       if (SCTP_SB_LIMIT_SND(so) > 
stcb->asoc.total_output_queue_size)
-                               max_len = SCTP_SB_LIMIT_SND(so) - 
stcb->asoc.total_output_queue_size;
+                       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+                       if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
+                               max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
                        else
                                max_len = 0;
 
@@ -13299,8 +13277,8 @@ skip_preblock:
                                        hold_tcblock = 1;
                                }
                                sctp_prune_prsctp(stcb, asoc, srcv, sndlen);
-                               inqueue_bytes = 
stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * 
sizeof(struct sctp_data_chunk));
-                               if (SCTP_SB_LIMIT_SND(so) > 
stcb->asoc.total_output_queue_size)
+                               inqueue_bytes = 
stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * 
SCTP_DATA_CHUNK_OVERHEAD(stcb));
+                               if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
                                        max_len = SCTP_SB_LIMIT_SND(so) - 
inqueue_bytes;
                                else
                                        max_len = 0;
@@ -13341,8 +13319,7 @@ skip_preblock:
                                }
                                asoc->ifp_had_enobuf = 0;
                        }
-                       un_sent = ((stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight) +
-                           (stcb->asoc.stream_queue_cnt * sizeof(struct 
sctp_data_chunk)));
+                       un_sent = stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight;
                        if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) 
&&
                            (stcb->asoc.total_flight > 0) &&
                            (stcb->asoc.stream_queue_cnt < 
SCTP_MAX_DATA_BUNDLING) &&
@@ -13416,7 +13393,8 @@ skip_preblock:
                         * size we KNOW we will get to sleep safely with the
                         * wakeup flag in place.
                         */
-                       if (SCTP_SB_LIMIT_SND(so) <= 
(stcb->asoc.total_output_queue_size +
+                       inqueue_bytes = stcb->asoc.total_output_queue_size - 
(stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+                       if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes +
                            min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), 
SCTP_SB_LIMIT_SND(so)))) {
                                if (SCTP_BASE_SYSCTL(sctp_logging_level) & 
SCTP_BLK_LOGGING_ENABLE) {
                                        sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
@@ -13613,8 +13591,7 @@ skip_out_eof:
                }
                asoc->ifp_had_enobuf = 0;
        }
-       un_sent = ((stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight) +
-           (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+       un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
        if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
            (stcb->asoc.total_flight > 0) &&
            (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&

Modified: head/sys/netinet/sctp_output.h
==============================================================================
--- head/sys/netinet/sctp_output.h      Sat Jul 15 19:52:59 2017        
(r321033)
+++ head/sys/netinet/sctp_output.h      Sat Jul 15 19:54:03 2017        
(r321034)
@@ -135,6 +135,11 @@ void sctp_fix_ecn_echo(struct sctp_association *);
 
 void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net);
 
+
+#define SCTP_DATA_CHUNK_OVERHEAD(stcb) ((stcb)->asoc.idata_supported ? \
+                                       sizeof(struct sctp_idata_chunk) : \
+                                       sizeof(struct sctp_data_chunk))
+
 int
 sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
     struct mbuf *, struct thread *, int);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to