Commit 6a4e04fb authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] listen() backlog support for TCP-style sockets.

parent 89f0091e
...@@ -290,14 +290,18 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -290,14 +290,18 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
*/ */
void sctp_association_free(sctp_association_t *asoc) void sctp_association_free(sctp_association_t *asoc)
{ {
struct sock *sk = asoc->base.sk;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_endpoint_t *ep;
struct list_head *pos, *temp; struct list_head *pos, *temp;
int i; int i;
ep = asoc->ep;
list_del(&asoc->asocs); list_del(&asoc->asocs);
/* Decrement the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog--;
/* Mark as dead, so other users can know this structure is /* Mark as dead, so other users can know this structure is
* going away. * going away.
*/ */
...@@ -818,12 +822,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -818,12 +822,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
{ {
struct sctp_opt *newsp = sctp_sk(newsk); struct sctp_opt *newsp = sctp_sk(newsk);
struct sock *oldsk = assoc->base.sk;
/* Delete the association from the old endpoint's list of /* Delete the association from the old endpoint's list of
* associations. * associations.
*/ */
list_del(&assoc->asocs); list_del(&assoc->asocs);
/* Decrement the backlog value for a TCP-style socket. */
if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type)
oldsk->ack_backlog--;
/* Release references to the old endpoint and the sock. */ /* Release references to the old endpoint and the sock. */
sctp_endpoint_put(assoc->ep); sctp_endpoint_put(assoc->ep);
sock_put(assoc->base.sk); sock_put(assoc->base.sk);
......
...@@ -177,8 +177,15 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ...@@ -177,8 +177,15 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
/* Add an association to an endpoint. */ /* Add an association to an endpoint. */
void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc)
{ {
struct sock *sk = ep->base.sk;
/* Now just add it to our list of asocs */ /* Now just add it to our list of asocs */
list_add_tail(&asoc->asocs, &ep->asocs); list_add_tail(&asoc->asocs, &ep->asocs);
/* Increment the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog++;
} }
/* Free the endpoint structure. Delay cleanup until /* Free the endpoint structure. Delay cleanup until
......
...@@ -191,14 +191,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -191,14 +191,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_chunk_t *err_chunk; sctp_chunk_t *err_chunk;
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param; sctp_unrecognized_param_t *unk_param;
struct sock *sk;
int len; int len;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands);
/* 6.10 Bundling /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
...@@ -206,6 +201,22 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -206,6 +201,22 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if (!chunk->singleton) if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION; return SCTP_DISPOSITION_VIOLATION;
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
*/
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
sk = ep->base.sk;
/* If the endpoint is not listening or if the number of associations
* on the TCP-style socket exceed the max backlog, respond with an
* ABORT.
*/
if ((SCTP_SS_LISTENING != sk->state) ||
((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
(sk->ack_backlog >= sk->max_ack_backlog)))
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* Verify the INIT chunk before processing it. */ /* Verify the INIT chunk before processing it. */
err_chunk = NULL; err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
......
...@@ -2746,6 +2746,9 @@ int sctp_inet_listen(struct socket *sock, int backlog) ...@@ -2746,6 +2746,9 @@ int sctp_inet_listen(struct socket *sock, int backlog)
err = -EINVAL; err = -EINVAL;
if (sock->state != SS_UNCONNECTED) if (sock->state != SS_UNCONNECTED)
goto out; goto out;
if (unlikely(backlog < 0))
goto out;
switch (sock->type) { switch (sock->type) {
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
err = sctp_seqpacket_listen(sk, backlog); err = sctp_seqpacket_listen(sk, backlog);
......
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