Ensure the user can read COMM_LOST notifications on 1-to-1 style sockets.

MFC after: 3 days
This commit is contained in:
Michael Tuexen 2012-05-13 16:07:53 +00:00
parent 67783ce453
commit 58411b0821

View File

@ -2609,48 +2609,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
#endif
/*
* For TCP model AND UDP connected sockets we will send an error up
* when an ABORT comes in.
*/
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))) {
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
stcb->sctp_socket->so_error = ECONNREFUSED;
} else {
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);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
if (!so_locked) {
SCTP_SOCKET_UNLOCK(so, 1);
}
#endif
}
if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
/* event not enabled */
return;
}
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);
@ -2668,7 +2627,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
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;
goto set_error;
}
}
SCTP_BUF_NEXT(m_notify) = NULL;
@ -2708,11 +2667,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
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;
}
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
/* not that we need this */
control->tail_mbuf = m_notify;
@ -2721,8 +2676,27 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
so_locked);
if (state == SCTP_COMM_LOST) {
/* Wake up any sleeper */
} else {
sctp_m_freem(m_notify);
}
}
/*
* 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))) {
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED);
stcb->sctp_socket->so_error = ECONNREFUSED;
} else {
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) {
@ -2737,13 +2711,18 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
}
}
#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
}
}
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;