sctp: simplify sctp listening code
sctp_inet_listen() call is split between UDP and TCP style. Looking at the code, the two functions are almost the same and can be merged into a single helper. This also fixes a bug that was fixed in the UDP function, but missed in the TCP function. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3bcb1255ba
commit
5e8f3f703a
|
@ -5842,128 +5842,14 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
|
|||
return (ret ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3.1.3 listen() - UDP Style Syntax
|
||||
*
|
||||
* By default, new associations are not accepted for UDP style sockets.
|
||||
* An application uses listen() to mark a socket as being able to
|
||||
* accept new associations.
|
||||
*/
|
||||
SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
|
||||
{
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
|
||||
/* Only UDP style sockets that are not peeled off are allowed to
|
||||
* listen().
|
||||
*/
|
||||
if (!sctp_style(sk, UDP))
|
||||
return -EINVAL;
|
||||
|
||||
/* If backlog is zero, disable listening. */
|
||||
if (!backlog) {
|
||||
if (sctp_sstate(sk, CLOSED))
|
||||
return 0;
|
||||
|
||||
sctp_unhash_endpoint(ep);
|
||||
sk->sk_state = SCTP_SS_CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return if we are already listening. */
|
||||
if (sctp_sstate(sk, LISTENING))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If a bind() or sctp_bindx() is not called prior to a listen()
|
||||
* call that allows new associations to be accepted, the system
|
||||
* picks an ephemeral port and will choose an address set equivalent
|
||||
* to binding with a wildcard address.
|
||||
*
|
||||
* This is not currently spelled out in the SCTP sockets
|
||||
* extensions draft, but follows the practice as seen in TCP
|
||||
* sockets.
|
||||
*
|
||||
* Additionally, turn off fastreuse flag since we are not listening
|
||||
*/
|
||||
sk->sk_state = SCTP_SS_LISTENING;
|
||||
if (!ep->base.bind_addr.port) {
|
||||
if (sctp_autobind(sk))
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
if (sctp_get_port(sk, inet_sk(sk)->num)) {
|
||||
sk->sk_state = SCTP_SS_CLOSED;
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
sctp_sk(sk)->bind_hash->fastreuse = 0;
|
||||
}
|
||||
|
||||
sctp_hash_endpoint(ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4.1.3 listen() - TCP Style Syntax
|
||||
*
|
||||
* Applications uses listen() to ready the SCTP endpoint for accepting
|
||||
* inbound associations.
|
||||
*/
|
||||
SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
|
||||
{
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
|
||||
/* If backlog is zero, disable listening. */
|
||||
if (!backlog) {
|
||||
if (sctp_sstate(sk, CLOSED))
|
||||
return 0;
|
||||
|
||||
sctp_unhash_endpoint(ep);
|
||||
sk->sk_state = SCTP_SS_CLOSED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sctp_sstate(sk, LISTENING))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If a bind() or sctp_bindx() is not called prior to a listen()
|
||||
* call that allows new associations to be accepted, the system
|
||||
* picks an ephemeral port and will choose an address set equivalent
|
||||
* to binding with a wildcard address.
|
||||
*
|
||||
* This is not currently spelled out in the SCTP sockets
|
||||
* extensions draft, but follows the practice as seen in TCP
|
||||
* sockets.
|
||||
*/
|
||||
sk->sk_state = SCTP_SS_LISTENING;
|
||||
if (!ep->base.bind_addr.port) {
|
||||
if (sctp_autobind(sk))
|
||||
return -EAGAIN;
|
||||
} else
|
||||
sctp_sk(sk)->bind_hash->fastreuse = 0;
|
||||
|
||||
sk->sk_max_ack_backlog = backlog;
|
||||
sctp_hash_endpoint(ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move a socket to LISTENING state.
|
||||
*/
|
||||
int sctp_inet_listen(struct socket *sock, int backlog)
|
||||
SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
struct crypto_hash *tfm = NULL;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (unlikely(backlog < 0))
|
||||
goto out;
|
||||
|
||||
sctp_lock_sock(sk);
|
||||
|
||||
if (sock->state != SS_UNCONNECTED)
|
||||
goto out;
|
||||
|
||||
/* Allocate HMAC for generating cookie. */
|
||||
if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
|
||||
|
@ -5974,34 +5860,96 @@ int sctp_inet_listen(struct socket *sock, int backlog)
|
|||
"SCTP: failed to load transform for %s: %ld\n",
|
||||
sctp_hmac_alg, PTR_ERR(tfm));
|
||||
}
|
||||
err = -ENOSYS;
|
||||
goto out;
|
||||
return -ENOSYS;
|
||||
}
|
||||
sctp_sk(sk)->hmac = tfm;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a bind() or sctp_bindx() is not called prior to a listen()
|
||||
* call that allows new associations to be accepted, the system
|
||||
* picks an ephemeral port and will choose an address set equivalent
|
||||
* to binding with a wildcard address.
|
||||
*
|
||||
* This is not currently spelled out in the SCTP sockets
|
||||
* extensions draft, but follows the practice as seen in TCP
|
||||
* sockets.
|
||||
*
|
||||
*/
|
||||
sk->sk_state = SCTP_SS_LISTENING;
|
||||
if (!ep->base.bind_addr.port) {
|
||||
if (sctp_autobind(sk))
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
if (sctp_get_port(sk, inet_sk(sk)->num)) {
|
||||
sk->sk_state = SCTP_SS_CLOSED;
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (sock->type) {
|
||||
case SOCK_SEQPACKET:
|
||||
err = sctp_seqpacket_listen(sk, backlog);
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
err = sctp_stream_listen(sk, backlog);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
sk->sk_max_ack_backlog = backlog;
|
||||
sctp_hash_endpoint(ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4.1.3 / 5.1.3 listen()
|
||||
*
|
||||
* By default, new associations are not accepted for UDP style sockets.
|
||||
* An application uses listen() to mark a socket as being able to
|
||||
* accept new associations.
|
||||
*
|
||||
* On TCP style sockets, applications use listen() to ready the SCTP
|
||||
* endpoint for accepting inbound associations.
|
||||
*
|
||||
* On both types of endpoints a backlog of '0' disables listening.
|
||||
*
|
||||
* Move a socket to LISTENING state.
|
||||
*/
|
||||
int sctp_inet_listen(struct socket *sock, int backlog)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (unlikely(backlog < 0))
|
||||
return err;
|
||||
|
||||
sctp_lock_sock(sk);
|
||||
|
||||
/* Peeled-off sockets are not allowed to listen(). */
|
||||
if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
|
||||
goto out;
|
||||
|
||||
if (sock->state != SS_UNCONNECTED)
|
||||
goto out;
|
||||
|
||||
/* If backlog is zero, disable listening. */
|
||||
if (!backlog) {
|
||||
if (sctp_sstate(sk, CLOSED))
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
sctp_unhash_endpoint(ep);
|
||||
sk->sk_state = SCTP_SS_CLOSED;
|
||||
if (sk->sk_reuse)
|
||||
sctp_sk(sk)->bind_hash->fastreuse = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto cleanup;
|
||||
/* If we are already listening, just update the backlog */
|
||||
if (sctp_sstate(sk, LISTENING))
|
||||
sk->sk_max_ack_backlog = backlog;
|
||||
else {
|
||||
err = sctp_listen_start(sk, backlog);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Store away the transform reference. */
|
||||
if (!sctp_sk(sk)->hmac)
|
||||
sctp_sk(sk)->hmac = tfm;
|
||||
err = 0;
|
||||
out:
|
||||
sctp_release_sock(sk);
|
||||
return err;
|
||||
cleanup:
|
||||
crypto_free_hash(tfm);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue