Author: tuexen
Date: Sun May 13 16:07:53 2012
New Revision: 235402
URL: http://svn.freebsd.org/changeset/base/235402

Log:
  Ensure the user can read COMM_LOST notifications on 1-to-1 style sockets.
  
  MFC after: 3 days

Modified:
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c Sun May 13 14:28:00 2012        (r235401)
+++ head/sys/netinet/sctputil.c Sun May 13 16:07:53 2012        (r235402)
@@ -2609,10 +2609,82 @@ sctp_notify_assoc_change(uint16_t state,
 
 #endif
 
+       if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, 
SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
+               notif_len = sizeof(struct sctp_assoc_change);
+               if (abort != NULL) {
+                       abort_len = htons(abort->ch.chunk_length);
+               } else {
+                       abort_len = 0;
+               }
+               if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
+                       notif_len += SCTP_ASSOC_SUPPORTS_MAX;
+               } else if ((state == SCTP_COMM_LOST) || (state == 
SCTP_CANT_STR_ASSOC)) {
+                       notif_len += abort_len;
+               }
+               m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, 
MT_DATA);
+               if (m_notify == NULL) {
+                       /* Retry with smaller value. */
+                       notif_len = sizeof(struct sctp_assoc_change);
+                       m_notify = sctp_get_mbuf_for_msg(notif_len, 0, 
M_DONTWAIT, 1, MT_DATA);
+                       if (m_notify == NULL) {
+                               goto set_error;
+                       }
+               }
+               SCTP_BUF_NEXT(m_notify) = NULL;
+               sac = mtod(m_notify, struct sctp_assoc_change *);
+               sac->sac_type = SCTP_ASSOC_CHANGE;
+               sac->sac_flags = 0;
+               sac->sac_length = sizeof(struct sctp_assoc_change);
+               sac->sac_state = state;
+               sac->sac_error = error;
+               /* XXX verify these stream counts */
+               sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
+               sac->sac_inbound_streams = stcb->asoc.streamincnt;
+               sac->sac_assoc_id = sctp_get_associd(stcb);
+               if (notif_len > sizeof(struct sctp_assoc_change)) {
+                       if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) 
{
+                               i = 0;
+                               if (stcb->asoc.peer_supports_prsctp) {
+                                       sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_PR;
+                               }
+                               if (stcb->asoc.peer_supports_auth) {
+                                       sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_AUTH;
+                               }
+                               if (stcb->asoc.peer_supports_asconf) {
+                                       sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_ASCONF;
+                               }
+                               sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_MULTIBUF;
+                               if (stcb->asoc.peer_supports_strreset) {
+                                       sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_RE_CONFIG;
+                               }
+                               sac->sac_length += i;
+                       } else if ((state == SCTP_COMM_LOST) || (state == 
SCTP_CANT_STR_ASSOC)) {
+                               memcpy(sac->sac_info, abort, abort_len);
+                               sac->sac_length += abort_len;
+                       }
+               }
+               SCTP_BUF_LEN(m_notify) = sac->sac_length;
+               control = sctp_build_readq_entry(stcb, 
stcb->asoc.primary_destination,
+                   0, 0, stcb->asoc.context, 0, 0, 0,
+                   m_notify);
+               if (control != NULL) {
+                       control->length = SCTP_BUF_LEN(m_notify);
+                       /* not that we need this */
+                       control->tail_mbuf = m_notify;
+                       control->spec_flags = M_NOTIFICATION;
+                       sctp_add_to_readq(stcb->sctp_ep, stcb,
+                           control,
+                           &stcb->sctp_socket->so_rcv, 1, 
SCTP_READ_LOCK_NOT_HELD,
+                           so_locked);
+               } else {
+                       sctp_m_freem(m_notify);
+               }
+       }
        /*
-        * For TCP model AND UDP connected sockets we will send an error up
-        * when an ABORT comes in.
+        * For 1-to-1 style sockets, we send up and error when an ABORT
+        * comes in.
         */
+set_error:
        if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
            (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
            ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
@@ -2623,127 +2695,34 @@ sctp_notify_assoc_change(uint16_t state,
                        SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, 
SCTP_FROM_SCTPUTIL, ECONNRESET);
                        stcb->sctp_socket->so_error = ECONNRESET;
                }
-               /* Wake ANY sleepers */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-               so = SCTP_INP_SO(stcb->sctp_ep);
-               if (!so_locked) {
-                       atomic_add_int(&stcb->asoc.refcnt, 1);
-                       SCTP_TCB_UNLOCK(stcb);
-                       SCTP_SOCKET_LOCK(so, 1);
-                       SCTP_TCB_LOCK(stcb);
-                       atomic_subtract_int(&stcb->asoc.refcnt, 1);
-                       if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
-                               SCTP_SOCKET_UNLOCK(so, 1);
-                               return;
-                       }
-               }
-#endif
-               socantrcvmore(stcb->sctp_socket);
-               sorwakeup(stcb->sctp_socket);
-               sowwakeup(stcb->sctp_socket);
+       }
+       /* Wake ANY sleepers */
 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-               if (!so_locked) {
+       so = SCTP_INP_SO(stcb->sctp_ep);
+       if (!so_locked) {
+               atomic_add_int(&stcb->asoc.refcnt, 1);
+               SCTP_TCB_UNLOCK(stcb);
+               SCTP_SOCKET_LOCK(so, 1);
+               SCTP_TCB_LOCK(stcb);
+               atomic_subtract_int(&stcb->asoc.refcnt, 1);
+               if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
                        SCTP_SOCKET_UNLOCK(so, 1);
-               }
-#endif
-       }
-       if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, 
SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
-               /* event not enabled */
-               return;
-       }
-       notif_len = sizeof(struct sctp_assoc_change);
-       if (abort != NULL) {
-               abort_len = htons(abort->ch.chunk_length);
-       } else {
-               abort_len = 0;
-       }
-       if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
-               notif_len += SCTP_ASSOC_SUPPORTS_MAX;
-       } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) 
{
-               notif_len += abort_len;
-       }
-       m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA);
-       if (m_notify == NULL) {
-               /* Retry with smaller value. */
-               notif_len = sizeof(struct sctp_assoc_change);
-               m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, 
MT_DATA);
-               if (m_notify == NULL) {
                        return;
                }
        }
-       SCTP_BUF_NEXT(m_notify) = NULL;
-       sac = mtod(m_notify, struct sctp_assoc_change *);
-       sac->sac_type = SCTP_ASSOC_CHANGE;
-       sac->sac_flags = 0;
-       sac->sac_length = sizeof(struct sctp_assoc_change);
-       sac->sac_state = state;
-       sac->sac_error = error;
-       /* XXX verify these stream counts */
-       sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
-       sac->sac_inbound_streams = stcb->asoc.streamincnt;
-       sac->sac_assoc_id = sctp_get_associd(stcb);
-       if (notif_len > sizeof(struct sctp_assoc_change)) {
-               if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) {
-                       i = 0;
-                       if (stcb->asoc.peer_supports_prsctp) {
-                               sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR;
-                       }
-                       if (stcb->asoc.peer_supports_auth) {
-                               sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH;
-                       }
-                       if (stcb->asoc.peer_supports_asconf) {
-                               sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF;
-                       }
-                       sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF;
-                       if (stcb->asoc.peer_supports_strreset) {
-                               sac->sac_info[i++] = 
SCTP_ASSOC_SUPPORTS_RE_CONFIG;
-                       }
-                       sac->sac_length += i;
-               } else if ((state == SCTP_COMM_LOST) || (state == 
SCTP_CANT_STR_ASSOC)) {
-                       memcpy(sac->sac_info, abort, abort_len);
-                       sac->sac_length += abort_len;
-               }
-       }
-       SCTP_BUF_LEN(m_notify) = sac->sac_length;
-       control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
-           0, 0, stcb->asoc.context, 0, 0, 0,
-           m_notify);
-       if (control == NULL) {
-               /* no memory */
-               sctp_m_freem(m_notify);
-               return;
-       }
-       control->length = SCTP_BUF_LEN(m_notify);
-       /* not that we need this */
-       control->tail_mbuf = m_notify;
-       control->spec_flags = M_NOTIFICATION;
-       sctp_add_to_readq(stcb->sctp_ep, stcb,
-           control,
-           &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
-           so_locked);
-       if (state == SCTP_COMM_LOST) {
-               /* Wake up any sleeper */
-#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-               so = SCTP_INP_SO(stcb->sctp_ep);
-               if (!so_locked) {
-                       atomic_add_int(&stcb->asoc.refcnt, 1);
-                       SCTP_TCB_UNLOCK(stcb);
-                       SCTP_SOCKET_LOCK(so, 1);
-                       SCTP_TCB_LOCK(stcb);
-                       atomic_subtract_int(&stcb->asoc.refcnt, 1);
-                       if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
-                               SCTP_SOCKET_UNLOCK(so, 1);
-                               return;
-                       }
-               }
 #endif
-               sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+       if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+           (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
+           ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
+               socantrcvmore(stcb->sctp_socket);
+       }
+       sorwakeup(stcb->sctp_socket);
+       sowwakeup(stcb->sctp_socket);
 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
-               if (!so_locked) {
-                       SCTP_SOCKET_UNLOCK(so, 1);
-               }
-#endif
+       if (!so_locked) {
+               SCTP_SOCKET_UNLOCK(so, 1);
        }
+#endif
 }
 
 static void
@@ -5220,7 +5199,7 @@ restart_nosblocks:
            (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
                goto out;
        }
-       if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
+       if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) 
{
                if (so->so_error) {
                        error = so->so_error;
                        if ((in_flags & MSG_PEEK) == 0)
@@ -5228,7 +5207,6 @@ restart_nosblocks:
                        goto out;
                } else {
                        if (so->so_rcv.sb_cc == 0) {
-                               SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTPUTIL, ENOTCONN);
                                /* indicate EOF */
                                error = 0;
                                goto out;
_______________________________________________
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