Code refactoring: 1. Move the common code of inet_listen() and inet_dccp_listen() to sock_common_listen(). 2. Modify and rename inet_listen() to tcp_listen(). 3. Modify and rename inet_dccp_listen() to dccp_listen(). 4. Add new callback pointer listen in struct proto for tcp_listen() and dccp_listen(). This patch makes codes more modularized and removes redudant codes. Signed-off-by: Firo Yang <firogm@xxxxxxxxx> --- v2: In according to the advices of Eric Dumazet, sock_common_listen() keep using TCP_xxx state instead of introducing new aliases. Test info: I test it on my x86 PC. include/net/sock.h | 3 +++ include/net/tcp.h | 1 + net/core/sock.c | 39 +++++++++++++++++++++++++++++++++ net/dccp/dccp.h | 2 +- net/dccp/ipv4.c | 4 ++-- net/dccp/ipv6.c | 3 ++- net/dccp/proto.c | 62 ++++++++++++++++------------------------------------- net/ipv4/af_inet.c | 58 +------------------------------------------------ net/ipv4/tcp.c | 35 ++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv6/af_inet6.c | 2 +- net/ipv6/tcp_ipv6.c | 1 + 12 files changed, 106 insertions(+), 105 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 26c1c31..8066a4c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -934,6 +934,7 @@ struct proto { int (*connect)(struct sock *sk, struct sockaddr *uaddr, int addr_len); + int (*listen)(struct sock *sk, int backlog); int (*disconnect)(struct sock *sk, int flags); struct sock * (*accept)(struct sock *sk, int flags, int *err); @@ -1587,6 +1588,8 @@ int compat_sock_common_setsockopt(struct socket *sock, int level, void sk_common_release(struct sock *sk); +int sock_common_listen(struct socket *sock, int backlog); + /* * Default socket callbacks and setup code */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 978cebe..70d3f64 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -434,6 +434,7 @@ int compat_tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen); void tcp_set_keepalive(struct sock *sk, int val); void tcp_syn_ack_timeout(const struct request_sock *req); +int tcp_listen(struct sock *sk, int backlog); int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len); void tcp_parse_options(const struct sk_buff *skb, diff --git a/net/core/sock.c b/net/core/sock.c index e72633c..e839721 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2559,6 +2559,45 @@ int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, EXPORT_SYMBOL(sock_common_recvmsg); /* + * Move a socket into listening state. + */ +int sock_common_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + unsigned char old_state; + int err; + + lock_sock(sk); + + err = -EINVAL; + if (sock->state != SS_UNCONNECTED) + goto out; + + old_state = sk->sk_state; + /* Since DCCP used the same state value as TCP, here we + * just check the TCP version state. + */ + if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) + goto out; + + /* Really, if the socket is already in listen state + * we can only allow the backlog to be adjusted. + */ + if (old_state != TCP_LISTEN) { + err = sk->sk_prot->listen(sk, backlog); + if (err) + goto out; + } + sk->sk_max_ack_backlog = backlog; + err = 0; + +out: + release_sock(sk); + return err; +} +EXPORT_SYMBOL(sock_common_listen); + +/* * Set socket options on an inet socket. */ int sock_common_setsockopt(struct socket *sock, int level, int optname, diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index bebc735..5a5acbb 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -313,7 +313,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len); void dccp_shutdown(struct sock *sk, int how); -int inet_dccp_listen(struct socket *sock, int backlog); +int dccp_listen(struct sock *sk, int backlog); unsigned int dccp_poll(struct file *file, struct socket *sock, poll_table *wait); int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ccf4c56..339f253 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -952,6 +952,7 @@ static struct proto dccp_v4_prot = { .name = "DCCP", .owner = THIS_MODULE, .close = dccp_close, + .listen = dccp_listen, .connect = dccp_v4_connect, .disconnect = dccp_disconnect, .ioctl = dccp_ioctl, @@ -1000,8 +1001,7 @@ static const struct proto_ops inet_dccp_ops = { /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ .poll = dccp_poll, .ioctl = inet_ioctl, - /* FIXME: work on inet_listen to rename it to sock_common_listen */ - .listen = inet_dccp_listen, + .listen = sock_common_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 5165571..1a96194 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1011,6 +1011,7 @@ static struct proto dccp_v6_prot = { .name = "DCCPv6", .owner = THIS_MODULE, .close = dccp_close, + .listen = dccp_listen, .connect = dccp_v6_connect, .disconnect = dccp_disconnect, .ioctl = dccp_ioctl, @@ -1056,7 +1057,7 @@ static const struct proto_ops inet6_dccp_ops = { .getname = inet6_getname, .poll = dccp_poll, .ioctl = inet6_ioctl, - .listen = inet_dccp_listen, + .listen = sock_common_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 52a9401..097edab 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -231,17 +231,31 @@ void dccp_destroy_sock(struct sock *sk) EXPORT_SYMBOL_GPL(dccp_destroy_sock); -static inline int dccp_listen_start(struct sock *sk, int backlog) +int dccp_listen(struct sock *sk, int backlog) { - struct dccp_sock *dp = dccp_sk(sk); + struct socket *sock = sk->sk_socket; + struct dccp_sock *dp; + int err; + err = -EINVAL; + if (sock->type != SOCK_DCCP) + goto out; + + dp = dccp_sk(sk); dp->dccps_role = DCCP_ROLE_LISTEN; /* do not start to listen if feature negotiation setup fails */ - if (dccp_feat_finalise_settings(dp)) - return -EPROTO; - return inet_csk_listen_start(sk, backlog); + if (dccp_feat_finalise_settings(dp)) { + err = -EPROTO; + goto out; + } + err = inet_csk_listen_start(sk, backlog); + +out: + return err; } +EXPORT_SYMBOL_GPL(dccp_listen); + static inline int dccp_need_reset(int state) { return state != DCCP_CLOSED && state != DCCP_LISTEN && @@ -913,44 +927,6 @@ out: EXPORT_SYMBOL_GPL(dccp_recvmsg); -int inet_dccp_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - unsigned char old_state; - int err; - - lock_sock(sk); - - err = -EINVAL; - if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP) - goto out; - - old_state = sk->sk_state; - if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) - goto out; - - /* Really, if the socket is already in listen state - * we can only allow the backlog to be adjusted. - */ - if (old_state != DCCP_LISTEN) { - /* - * FIXME: here it probably should be sk->sk_prot->listen_start - * see tcp_listen_start - */ - err = dccp_listen_start(sk, backlog); - if (err) - goto out; - } - sk->sk_max_ack_backlog = backlog; - err = 0; - -out: - release_sock(sk); - return err; -} - -EXPORT_SYMBOL_GPL(inet_dccp_listen); - static void dccp_terminate_connection(struct sock *sk) { u8 next_state = DCCP_CLOSED; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index cc858ef..e2e2b19 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -187,62 +187,6 @@ static int inet_autobind(struct sock *sk) } /* - * Move a socket into listening state. - */ -int inet_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - unsigned char old_state; - int err; - - lock_sock(sk); - - err = -EINVAL; - if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) - goto out; - - old_state = sk->sk_state; - if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) - goto out; - - /* Really, if the socket is already in listen state - * we can only allow the backlog to be adjusted. - */ - if (old_state != TCP_LISTEN) { - /* Check special setups for testing purpose to enable TFO w/o - * requiring TCP_FASTOPEN sockopt. - * Note that only TCP sockets (SOCK_STREAM) will reach here. - * Also fastopenq may already been allocated because this - * socket was in TCP_LISTEN state previously but was - * shutdown() (rather than close()). - */ - if ((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) != 0 && - !inet_csk(sk)->icsk_accept_queue.fastopenq) { - if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) != 0) - err = fastopen_init_queue(sk, backlog); - else if ((sysctl_tcp_fastopen & - TFO_SERVER_WO_SOCKOPT2) != 0) - err = fastopen_init_queue(sk, - ((uint)sysctl_tcp_fastopen) >> 16); - else - err = 0; - if (err) - goto out; - } - err = inet_csk_listen_start(sk, backlog); - if (err) - goto out; - } - sk->sk_max_ack_backlog = backlog; - err = 0; - -out: - release_sock(sk); - return err; -} -EXPORT_SYMBOL(inet_listen); - -/* * Create an inet socket. */ @@ -903,7 +847,7 @@ const struct proto_ops inet_stream_ops = { .getname = inet_getname, .poll = tcp_poll, .ioctl = inet_ioctl, - .listen = inet_listen, + .listen = sock_common_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 65f791f..3aa185b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1301,6 +1301,41 @@ out_err: } EXPORT_SYMBOL(tcp_sendmsg); +int tcp_listen(struct sock *sk, int backlog) +{ + struct socket *sock = sk->sk_socket; + int err; + + err = -EINVAL; + if (sock->type != SOCK_STREAM) + goto out; + /* Check special setups for testing purpose to enable TFO w/o + * requiring TCP_FASTOPEN sockopt. + * Note that only TCP sockets (SOCK_STREAM) will reach here. + * Also fastopenq may already been allocated because this + * socket was in TCP_LISTEN state previously but was + * shutdown() (rather than close()). + */ + if ((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) != 0 && + !inet_csk(sk)->icsk_accept_queue.fastopenq) { + if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) != 0) + err = fastopen_init_queue(sk, backlog); + else if ((sysctl_tcp_fastopen & + TFO_SERVER_WO_SOCKOPT2) != 0) + err = fastopen_init_queue(sk, + ((uint)sysctl_tcp_fastopen) >> 16); + else + err = 0; + if (err) + goto out; + } + err = inet_csk_listen_start(sk, backlog); + +out: + return err; +} +EXPORT_SYMBOL(tcp_listen); + /* * Handle reading urgent data. BSD has very simple semantics for * this, no blocking and very strange errors 8) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d7d4c2b..0dff9dc 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2337,6 +2337,7 @@ struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, .close = tcp_close, + .listen = tcp_listen, .connect = tcp_v4_connect, .disconnect = tcp_disconnect, .accept = inet_csk_accept, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 7de52b6..8fd9c77 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -516,7 +516,7 @@ const struct proto_ops inet6_stream_ops = { .getname = inet6_getname, .poll = tcp_poll, /* ok */ .ioctl = inet6_ioctl, /* must change */ - .listen = inet_listen, /* ok */ + .listen = sock_common_listen, /* ok */ .shutdown = inet_shutdown, /* ok */ .setsockopt = sock_common_setsockopt, /* ok */ .getsockopt = sock_common_getsockopt, /* ok */ diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 45a7176..80cecc6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1822,6 +1822,7 @@ struct proto tcpv6_prot = { .name = "TCPv6", .owner = THIS_MODULE, .close = tcp_close, + .listen = tcp_listen, .connect = tcp_v6_connect, .disconnect = tcp_disconnect, .accept = inet_csk_accept, -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html