Ensure the user can read COMM_LOST notifications on 1-to-1 style sockets.
MFC after: 3 days
This commit is contained in:
parent
67783ce453
commit
58411b0821
@ -2609,10 +2609,82 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
|
||||
|
||||
#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, struct sctp_tcb *stcb,
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
|
||||
stcb->sctp_socket->so_error = ECONNRESET;
|
||||
}
|
||||
/* Wake ANY sleepers */
|
||||
}
|
||||
/* 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) {
|
||||
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 defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
if (!so_locked) {
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
}
|
||||
#endif
|
||||
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 @@ sctp_sorecvmsg(struct socket *so,
|
||||
(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 @@ sctp_sorecvmsg(struct socket *so,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user