summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2016-06-23 19:27:29 +0000
committertuexen <tuexen@FreeBSD.org>2016-06-23 19:27:29 +0000
commitab637d3a1788cce5e0bf602613954661ed38f99e (patch)
tree33676b01ce7c22bd782b677e0eef9c3552a4f301 /sys/netinet/sctputil.c
parent8ac07d0f7954b3cb4b8df478294c9110dab312d8 (diff)
downloadFreeBSD-src-ab637d3a1788cce5e0bf602613954661ed38f99e.zip
FreeBSD-src-ab637d3a1788cce5e0bf602613954661ed38f99e.tar.gz
Fix a bug in the handling of non-blocking SCTP 1-to-1 sockets. When using
this code in the userland stack, it could result in a loop. This happened on iOS. However, I was not able to reproduce this when using the code in the kernel. Thanks to Eugen-Andrei Gavriloaie for reporting the issue and proving detailed information to find the root of the problem. Approved by: re (gjb) MFC after: 1 week
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c59
1 files changed, 16 insertions, 43 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index ffb58ed..5dbd741 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -5274,8 +5274,14 @@ restart_nosblocks:
}
}
}
- if ((so->so_rcv.sb_cc <= held_length) && block_allowed) {
- /* we need to wait for data */
+ if (so->so_rcv.sb_cc <= held_length) {
+ if (so->so_error) {
+ error = so->so_error;
+ if ((in_flags & MSG_PEEK) == 0) {
+ so->so_error = 0;
+ }
+ goto out;
+ }
if ((so->so_rcv.sb_cc == 0) &&
((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
@@ -5306,51 +5312,18 @@ restart_nosblocks:
goto out;
}
}
- error = sbwait(&so->so_rcv);
- if (error) {
- goto out;
- }
- held_length = 0;
- goto restart_nosblocks;
- } else if (so->so_rcv.sb_cc == 0) {
- if (so->so_error) {
- error = so->so_error;
- if ((in_flags & MSG_PEEK) == 0)
- so->so_error = 0;
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
- /*
- * For active open side clear flags
- * for re-use passive open is
- * blocked by connect.
- */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) {
- /*
- * You were aborted, passive
- * side always hits here
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET);
- error = ECONNRESET;
- }
- so->so_state &= ~(SS_ISCONNECTING |
- SS_ISDISCONNECTING |
- SS_ISCONFIRMING |
- SS_ISCONNECTED);
- if (error == 0) {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN);
- error = ENOTCONN;
- }
- }
- goto out;
- }
+ if (block_allowed) {
+ error = sbwait(&so->so_rcv);
+ if (error) {
+ goto out;
}
+ held_length = 0;
+ goto restart_nosblocks;
+ } else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK);
error = EWOULDBLOCK;
+ goto out;
}
- goto out;
}
if (hold_sblock == 1) {
SOCKBUF_UNLOCK(&so->so_rcv);
OpenPOWER on IntegriCloud