summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2012-05-13 16:07:53 +0000
committertuexen <tuexen@FreeBSD.org>2012-05-13 16:07:53 +0000
commit3a7a58a884dbe40a6ccd2e5168783c13fad81e93 (patch)
treefacdb921caf44a0e54447dfe3e4e2ca9bf2d865f /sys/netinet/sctputil.c
parent7404b21e2daab075c921b26bf1d709d70531e1cf (diff)
downloadFreeBSD-src-3a7a58a884dbe40a6ccd2e5168783c13fad81e93.zip
FreeBSD-src-3a7a58a884dbe40a6ccd2e5168783c13fad81e93.tar.gz
Ensure the user can read COMM_LOST notifications on 1-to-1 style sockets.
MFC after: 3 days
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c212
1 files changed, 95 insertions, 117 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 5380848..91c1180 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -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 */
-#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;
OpenPOWER on IntegriCloud