diff options
| author | Sridhar Samudrala <sri@us.ibm.com> | 2003-04-17 20:09:15 -0700 |
|---|---|---|
| committer | Sridhar Samudrala <sri@us.ibm.com> | 2003-04-17 20:09:15 -0700 |
| commit | e21eb45a4841b24713cb131da9dad787a9871267 (patch) | |
| tree | 243297c0db0b2bde80a8450e89073950f91a413a | |
| parent | 984c6c43dc97db6f8d7da55cc8b14681754b2094 (diff) | |
[SCTP] Handle accept() of a CLOSED association.
| -rw-r--r-- | include/net/sctp/constants.h | 2 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 3 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 1 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 21 | ||||
| -rw-r--r-- | net/sctp/socket.c | 43 |
5 files changed, 65 insertions, 5 deletions
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 60fe2147486f..9cdd0e551c19 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -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, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 719aa2cbb28c..a4fcb9e14d01 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1545,6 +1545,9 @@ struct sctp_association { * after reaching 4294967295. */ __u32 addip_serial; + + /* Is it a temporary association? */ + __u8 temp; }; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 861f4f9da48d..5770f34706ae 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -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. */ diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 46c50dbab871..821b8fd3dc67 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -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; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 446cd9c23658..01e8a1e4ce75 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -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 @@ out_unlock: sctp_release_sock(sk); out_nounlock: - return err; + return sctp_error(sk, msg_flags, err); #if 0 do_sock_err: |
