It should be possible to send a message and set the SCTP_EOF flag
at the same time, but we don't support it yet. This patch fix the
sendmsg() flag SCTP_EOF to comply to spec.
Signed-off-by: Wei Yongjun <yjwei@xxxxxxxxxxxxxx>
---
include/net/sctp/structs.h | 3 ++-
net/sctp/socket.c | 40 ++++++++++++++++++++++++++++++++--------
2 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 828185c..dc894e0 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1924,7 +1924,8 @@ struct sctp_association {
__u16 active_key_id;
__u8 need_ecne:1, /* Need to send an ECNE Chunk? */
- temp:1; /* Is it a temporary association? */
+ temp:1, /* Is it a temporary association? */
+ eof_pending:1; /* SCTP_EOF flag is indicated in send() */
};
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 0af3a8c..44c1773 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1555,13 +1555,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_nounlock;
}
- /* If SCTP_EOF is set, no data can be sent. Disallow sending zero
- * length messages when SCTP_EOF|SCTP_ABORT is not set.
- * If SCTP_ABORT is set, the message length could be non zero with
- * the msg_iov set to the user abort reason.
+ /* Disallow sending zero length messages when SCTP_EOF|SCTP_ABORT
+ * is not set. If SCTP_ABORT is set, the message length could be
+ * non zero with the msg_iov set to the user abort reason.
*/
- if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) ||
- (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) {
+ if (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0)) {
err = -EINVAL;
goto out_nounlock;
}
@@ -1608,6 +1606,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
if (asoc) {
SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);
+ /* Previous send() is called with SCTP_EOF flag */
+ if (asoc->eof_pending) {
+ err = -ESHUTDOWN;
+ goto out_unlock;
+ }
+
/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED
* socket that has an association in CLOSED state. This can
* happen when an accepted socket has an association that is
@@ -1618,13 +1622,24 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_unlock;
}
- if (sinfo_flags & SCTP_EOF) {
+ /* Forbid SCTP_EOF and send a message combination
+ * on non-blocking sockets.
+ */
+ if ((sinfo_flags & SCTP_EOF) && msg_len != 0 &&
+ sk->sk_socket->file &&
+ (sk->sk_socket->file->f_flags & O_NONBLOCK)) {
+ err = -EWOULDBLOCK;
+ goto out_nounlock;
+ }
+
+ if (sinfo_flags & SCTP_EOF && msg_len == 0) {
SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
asoc);
sctp_primitive_SHUTDOWN(asoc, NULL);
err = 0;
goto out_unlock;
}
+
if (sinfo_flags & SCTP_ABORT) {
chunk = sctp_make_abort_user(asoc, msg, msg_len);
@@ -1644,7 +1659,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
if (!asoc) {
SCTP_DEBUG_PRINTK("There is no association yet.\n");
- if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) {
+ if (sinfo_flags & SCTP_ABORT) {
err = -EINVAL;
goto out_unlock;
}
@@ -1850,6 +1865,15 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
else
err = msg_len;
+ if (sinfo_flags & SCTP_EOF) {
+ SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
+ asoc);
+ if (sctp_state(asoc, ESTABLISHED))
+ sctp_primitive_SHUTDOWN(asoc, NULL);
+ else
+ asoc->eof_pending = 1;
+ }
+
/* If we are already past ASSOCIATE, the lower
* layers are responsible for association cleanup.
*/
--
1.6.5.2
--
To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
[Linux OMAP]
[Linux USB Devel]
[Video for Linux]
[Linux Audio Users]
[Photo]
[Yosemite News]
[Yosemite Photos]
[Free Online Dating]
[Linux Kernel]
[Linux SCSI]
[XFree86]