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