Author: tuexen
Date: Fri Jun 18 09:01:44 2010
New Revision: 209289
URL: http://svn.freebsd.org/changeset/base/209289

Log:
  Fix a rece condition in the shutdown handling.
  The race condition resulted in a panic.
  
  MFC after: 3 days

Modified:
  head/sys/netinet/sctp.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp.h
==============================================================================
--- head/sys/netinet/sctp.h     Fri Jun 18 08:51:20 2010        (r209288)
+++ head/sys/netinet/sctp.h     Fri Jun 18 09:01:44 2010        (r209289)
@@ -442,6 +442,7 @@ struct sctp_error_unrecognized_chunk {
 #define SCTP_PCB_FLAGS_BLOCKING_IO     0x08000000
 #define SCTP_PCB_FLAGS_SOCKET_GONE     0x10000000
 #define SCTP_PCB_FLAGS_SOCKET_ALLGONE  0x20000000
+#define SCTP_PCB_FLAGS_SOCKET_CANT_READ        0x40000000
 /* flags to copy to new PCB */
 #define SCTP_PCB_COPY_FLAGS            (SCTP_PCB_FLAGS_BOUNDALL|\
                                         SCTP_PCB_FLAGS_WAKEINPUT|\

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Fri Jun 18 08:51:20 2010        
(r209288)
+++ head/sys/netinet/sctp_usrreq.c      Fri Jun 18 09:01:44 2010        
(r209289)
@@ -947,11 +947,30 @@ sctp_flush(struct socket *so, int how)
         * they will not be able to read the data, the socket will block
         * that from happening.
         */
+       struct sctp_inpcb *inp;
+
+       inp = (struct sctp_inpcb *)so->so_pcb;
+       if (inp == NULL) {
+               SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, 
EINVAL);
+               return EINVAL;
+       }
+       SCTP_INP_RLOCK(inp);
+       /* For the 1 to many model this does nothing */
+       if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
+               SCTP_INP_RUNLOCK(inp);
+               return (0);
+       }
+       SCTP_INP_RUNLOCK(inp);
        if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
                /*
                 * First make sure the sb will be happy, we don't use these
                 * except maybe the count
                 */
+               SCTP_INP_WLOCK(inp);
+               SCTP_INP_READ_LOCK(inp);
+               inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
+               SCTP_INP_READ_UNLOCK(inp);
+               SCTP_INP_WUNLOCK(inp);
                so->so_rcv.sb_cc = 0;
                so->so_rcv.sb_mbcnt = 0;
                so->so_rcv.sb_mb = NULL;

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c Fri Jun 18 08:51:20 2010        (r209288)
+++ head/sys/netinet/sctputil.c Fri Jun 18 09:01:44 2010        (r209289)
@@ -3185,6 +3185,9 @@ sctp_notify_partial_delivery_indication(
                /* event not enabled */
                return;
        }
+       if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
+               return;
+       }
        m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, 
M_DONTWAIT, 1, MT_DATA);
        if (m_notify == NULL)
                /* no space left */
@@ -4365,6 +4368,17 @@ sctp_add_to_readq(struct sctp_inpcb *inp
        }
        if (inp_read_lock_held == 0)
                SCTP_INP_READ_LOCK(inp);
+       if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) {
+               sctp_free_remote_addr(control->whoFrom);
+               if (control->data) {
+                       sctp_m_freem(control->data);
+                       control->data = NULL;
+               }
+               SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
+               if (inp_read_lock_held == 0)
+                       SCTP_INP_READ_UNLOCK(inp);
+               return;
+       }
        if (!(control->spec_flags & M_NOTIFICATION)) {
                atomic_add_int(&inp->total_recvs, 1);
                if (!control->do_not_ref_stcb) {
@@ -4405,6 +4419,8 @@ sctp_add_to_readq(struct sctp_inpcb *inp
                control->tail_mbuf = prev;
        } else {
                /* Everything got collapsed out?? */
+               sctp_free_remote_addr(control->whoFrom);
+               SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control);
                if (inp_read_lock_held == 0)
                        SCTP_INP_READ_UNLOCK(inp);
                return;
@@ -4477,6 +4493,10 @@ get_out:
                }
                return (-1);
        }
+       if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) {
+               SCTP_INP_READ_UNLOCK(inp);
+               return 0;
+       }
        if (control->end_added) {
                /* huh this one is complete? */
                goto get_out;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to