Author: tuexen
Date: Thu May 28 18:34:02 2015
New Revision: 283662
URL: https://svnweb.freebsd.org/changeset/base/283662

Log:
  Fix a bug where messages would not be sent in SHUTDOWN_RECEIVED state.
  This problem was reported by Mark Bonnekessel and Markus Boese.
  Thanks to Irene Ruengeler for helping me to fix the cause of
  the problem. It can be tested with the following packetdrill script:
  
  +0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
  +0.0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
  +0.0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
  // Check the handshake with an empty(!) cookie
  +0.1 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress)
  +0.0 > sctp: INIT[flgs=0, tag=1, a_rwnd=..., os=..., is=..., tsn=0, ...]
  +0.1 < sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=10000, os=1, is=1, tsn=0, 
STATE_COOKIE[len=4, val=...]]
  +0.0 > sctp: COOKIE_ECHO[flgs=0, len=4, val=...]
  +0.1 < sctp: COOKIE_ACK[flgs=0]
  +0.0 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
  +0.0 write(3, ..., 1024) = 1024
  +0.0 > sctp: DATA[flgs=BE, len=1040, tsn=0, sid=0, ssn=0, ppid=0]
  +0.0 write(3, ..., 1024) = 1024 // Pending due to Nagle
  +0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
  +0.0 > sctp: DATA[flgs=BE, len=1040, tsn=1, sid=0, ssn=1, ppid=0]
  +0.0 < sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=10000, gaps=[], dups=[]] // Do we 
need another SHUTDOWN here?
  +0.0 > sctp: SHUTDOWN_ACK[flgs=0]
  +0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
  +0.0 close(3) = 0
  
  MFC after: 3 days

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

Modified: head/sys/netinet/sctp_asconf.c
==============================================================================
--- head/sys/netinet/sctp_asconf.c      Thu May 28 18:24:22 2015        
(r283661)
+++ head/sys/netinet/sctp_asconf.c      Thu May 28 18:34:02 2015        
(r283662)
@@ -1977,7 +1977,8 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *
                         * sent when the state goes open.
                         */
                        if (status == 0 &&
-                           SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+                           ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
+                           (SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_SHUTDOWN_RECEIVED))) {
 #ifdef SCTP_TIMER_BASED_ASCONF
                                sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
                                    stcb, stcb->asoc.primary_destination);
@@ -2225,7 +2226,8 @@ sctp_asconf_iterator_stcb(struct sctp_in
                         * count of queued params.  If in the non-open
                         * state, these get sent when the assoc goes open.
                         */
-                       if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+                       if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
+                           (SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_SHUTDOWN_RECEIVED)) {
                                if (status >= 0) {
                                        num_queued++;
                                }
@@ -2285,7 +2287,8 @@ sctp_set_primary_ip_address_sa(struct sc
                    "set_primary_ip_address_sa: queued on tcb=%p, ",
                    (void *)stcb);
                SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
-               if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
+               if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
+                   (SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_SHUTDOWN_RECEIVED)) {
 #ifdef SCTP_TIMER_BASED_ASCONF
                        sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
                            stcb->sctp_ep, stcb,
@@ -2321,7 +2324,8 @@ sctp_set_primary_ip_address(struct sctp_
                                SCTPDBG(SCTP_DEBUG_ASCONF1, 
"set_primary_ip_address: queued on stcb=%p, ",
                                    (void *)stcb);
                                SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, 
&ifa->address.sa);
-                               if (SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_OPEN) {
+                               if ((SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_OPEN) ||
+                                   (SCTP_GET_STATE(&stcb->asoc) == 
SCTP_STATE_SHUTDOWN_RECEIVED)) {
 #ifdef SCTP_TIMER_BASED_ASCONF
                                        sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
                                            stcb->sctp_ep, stcb,

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Thu May 28 18:24:22 2015        
(r283661)
+++ head/sys/netinet/sctp_output.c      Thu May 28 18:34:02 2015        
(r283662)
@@ -8535,7 +8535,8 @@ again_one_more_time:
                        omtu = 0;
                        break;
                }
-               if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) &&
+               if ((((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+                   (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
                    (skip_data_for_this_net == 0)) ||
                    (cookie)) {
                        TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, 
nchk) {
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to