Commit e21eb45a authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] Handle accept() of a CLOSED association.

parent 984c6c43
......@@ -216,7 +216,7 @@ typedef enum {
* - A socket in SCTP_SS_LISTENING state indicates that it is willing to
* accept new associations, but cannot initiate the creation of new ones.
* - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single
* association in ESTABLISHED state.
* association.
*/
typedef enum {
SCTP_SS_CLOSED = TCP_CLOSE,
......
......@@ -1545,6 +1545,9 @@ struct sctp_association {
* after reaching 4294967295.
*/
__u32 addip_serial;
/* Is it a temporary association? */
__u8 temp;
};
......
......@@ -1308,6 +1308,7 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
if (!asoc)
goto nodata;
asoc->temp = 1;
skb = chunk->skb;
/* Create an entry for the source address of the packet. */
/* FIXME: Use the af specific helpers. */
......
......@@ -651,6 +651,24 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *as
}
}
/* Helper function to delete an association. */
static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
struct sctp_association *asoc)
{
struct sock *sk = asoc->base.sk;
/* If it is a non-temporary association belonging to a TCP-style
* listening socket, do not free it so that accept() can pick it
* up later.
*/
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
(SCTP_SS_LISTENING == sk->state) && (!asoc->temp))
return;
sctp_unhash_established(asoc);
sctp_association_free(asoc);
}
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
......@@ -861,8 +879,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_DELETE_TCB:
/* Delete the current association. */
sctp_unhash_established(asoc);
sctp_association_free(asoc);
sctp_cmd_delete_tcb(commands, asoc);
asoc = NULL;
break;
......
......@@ -688,7 +688,17 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Walk all associations on a socket, not on an endpoint. */
list_for_each_safe(pos, temp, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
sctp_primitive_SHUTDOWN(asoc, NULL);
/* A closed association can still be in the list if it
* belongs to a TCP-style listening socket that is not
* yet accepted.
*/
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
(SCTP_STATE_CLOSED == asoc->state)) {
sctp_unhash_established(asoc);
sctp_association_free(asoc);
} else
sctp_primitive_SHUTDOWN(asoc, NULL);
}
/* Clean up any skbs sitting on the receive queue. */
......@@ -718,6 +728,16 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
SCTP_DBG_OBJCNT_DEC(sock);
}
/* Handle EPIPE error. */
static int sctp_error(struct sock *sk, int flags, int err)
{
if (err == -EPIPE)
err = sock_error(sk) ? : -EPIPE;
if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
send_sig(SIGPIPE, current, 0);
return err;
}
/* API 3.1.3 sendmsg() - UDP Style Syntax
*
* An application uses sendmsg() and recvmsg() calls to transmit data to
......@@ -763,6 +783,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
long timeo;
__u16 sinfo_flags = 0;
struct sk_buff_head chunks;
int msg_flags = msg->msg_flags;
SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n",
sk, msg, msg_len);
......@@ -773,6 +794,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);
if ((SCTP_SOCKET_TCP == sp->type) &&
(SCTP_SS_ESTABLISHED != sk->state)) {
err = -EPIPE;
goto out_nounlock;
}
/* Parse out the SCTP CMSGs. */
err = sctp_msghdr_parse(msg, &cmsgs);
......@@ -859,6 +886,18 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
if (asoc) {
SCTP_DEBUG_PRINTK("Just looked up association: "
"%s. \n", asoc->debug_name);
/* 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
* already CLOSED.
*/
if ((SCTP_STATE_CLOSED == asoc->state) &&
(SCTP_SOCKET_TCP == sp->type)) {
err = -EPIPE;
goto out_unlock;
}
if (sinfo_flags & MSG_EOF) {
SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
asoc);
......@@ -1067,7 +1106,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_release_sock(sk);
out_nounlock:
return err;
return sctp_error(sk, msg_flags, err);
#if 0
do_sock_err:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment