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 { ...@@ -216,7 +216,7 @@ typedef enum {
* - A socket in SCTP_SS_LISTENING state indicates that it is willing to * - A socket in SCTP_SS_LISTENING state indicates that it is willing to
* accept new associations, but cannot initiate the creation of new ones. * accept new associations, but cannot initiate the creation of new ones.
* - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single
* association in ESTABLISHED state. * association.
*/ */
typedef enum { typedef enum {
SCTP_SS_CLOSED = TCP_CLOSE, SCTP_SS_CLOSED = TCP_CLOSE,
......
...@@ -1545,6 +1545,9 @@ struct sctp_association { ...@@ -1545,6 +1545,9 @@ struct sctp_association {
* after reaching 4294967295. * after reaching 4294967295.
*/ */
__u32 addip_serial; __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, ...@@ -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); asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
if (!asoc) if (!asoc)
goto nodata; goto nodata;
asoc->temp = 1;
skb = chunk->skb; skb = chunk->skb;
/* Create an entry for the source address of the packet. */ /* Create an entry for the source address of the packet. */
/* FIXME: Use the af specific helpers. */ /* 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 ...@@ -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 /* 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 * main flow of sctp_do_sm() to keep attention focused on the real
* functionality there. * functionality there.
...@@ -861,8 +879,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -861,8 +879,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_DELETE_TCB: case SCTP_CMD_DELETE_TCB:
/* Delete the current association. */ /* Delete the current association. */
sctp_unhash_established(asoc); sctp_cmd_delete_tcb(commands, asoc);
sctp_association_free(asoc);
asoc = NULL; asoc = NULL;
break; break;
......
...@@ -688,7 +688,17 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -688,7 +688,17 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Walk all associations on a socket, not on an endpoint. */ /* Walk all associations on a socket, not on an endpoint. */
list_for_each_safe(pos, temp, &ep->asocs) { list_for_each_safe(pos, temp, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, 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. */ /* Clean up any skbs sitting on the receive queue. */
...@@ -718,6 +728,16 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -718,6 +728,16 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
SCTP_DBG_OBJCNT_DEC(sock); 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 /* API 3.1.3 sendmsg() - UDP Style Syntax
* *
* An application uses sendmsg() and recvmsg() calls to transmit data to * 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, ...@@ -763,6 +783,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
long timeo; long timeo;
__u16 sinfo_flags = 0; __u16 sinfo_flags = 0;
struct sk_buff_head chunks; struct sk_buff_head chunks;
int msg_flags = msg->msg_flags;
SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n",
sk, msg, msg_len); sk, msg, msg_len);
...@@ -773,6 +794,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -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); 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. */ /* Parse out the SCTP CMSGs. */
err = sctp_msghdr_parse(msg, &cmsgs); err = sctp_msghdr_parse(msg, &cmsgs);
...@@ -859,6 +886,18 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -859,6 +886,18 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
if (asoc) { if (asoc) {
SCTP_DEBUG_PRINTK("Just looked up association: " SCTP_DEBUG_PRINTK("Just looked up association: "
"%s. \n", asoc->debug_name); "%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) { if (sinfo_flags & MSG_EOF) {
SCTP_DEBUG_PRINTK("Shutting down association: %p\n", SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
asoc); asoc);
...@@ -1067,7 +1106,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1067,7 +1106,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_release_sock(sk); sctp_release_sock(sk);
out_nounlock: out_nounlock:
return err; return sctp_error(sk, msg_flags, err);
#if 0 #if 0
do_sock_err: 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