[DCCP]: Dedicated auxiliary states to support passive-close
This adds two auxiliary states to deal with passive closes: * PASSIVE_CLOSE (reached from OPEN via reception of Close) and * PASSIVE_CLOSEREQ (reached from OPEN via reception of CloseReq) as internal intermediate states. These states are used to allow a receiver to process unread data before acknowledging the received connection-termination-request (the Close/CloseReq). Without such support, it will happen that passively-closed sockets enter CLOSED state while there is still unprocessed data in the queue; leading to unexpected and erratic API behaviour. PASSIVE_CLOSE has been mapped into TCPF_CLOSE_WAIT, so that the code will seamlessly work with inet_accept() (which tests for this state). The state names are thanks to Arnaldo, who suggested this naming scheme following an earlier revision of this patch. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f53dc67c5e
commit
f11135a344
2 changed files with 51 additions and 27 deletions
|
@ -227,29 +227,51 @@ struct dccp_so_feat {
|
|||
#include <net/tcp_states.h>
|
||||
|
||||
enum dccp_state {
|
||||
DCCP_OPEN = TCP_ESTABLISHED,
|
||||
DCCP_REQUESTING = TCP_SYN_SENT,
|
||||
DCCP_LISTEN = TCP_LISTEN,
|
||||
DCCP_RESPOND = TCP_SYN_RECV,
|
||||
DCCP_CLOSING = TCP_CLOSING,
|
||||
DCCP_TIME_WAIT = TCP_TIME_WAIT,
|
||||
DCCP_CLOSED = TCP_CLOSE,
|
||||
DCCP_PARTOPEN = TCP_MAX_STATES,
|
||||
DCCP_OPEN = TCP_ESTABLISHED,
|
||||
DCCP_REQUESTING = TCP_SYN_SENT,
|
||||
DCCP_LISTEN = TCP_LISTEN,
|
||||
DCCP_RESPOND = TCP_SYN_RECV,
|
||||
/*
|
||||
* States involved in closing a DCCP connection:
|
||||
* 1) ACTIVE_CLOSEREQ is entered by a server sending a CloseReq.
|
||||
*
|
||||
* 2) CLOSING can have three different meanings (RFC 4340, 8.3):
|
||||
* a. Client has performed active-close, has sent a Close to the server
|
||||
* from state OPEN or PARTOPEN, and is waiting for the final Reset
|
||||
* (in this case, SOCK_DONE == 1).
|
||||
* b. Client is asked to perform passive-close, by receiving a CloseReq
|
||||
* in (PART)OPEN state. It sends a Close and waits for final Reset
|
||||
* (in this case, SOCK_DONE == 0).
|
||||
* c. Server performs an active-close as in (a), keeps TIMEWAIT state.
|
||||
*
|
||||
* 3) The following intermediate states are employed to give passively
|
||||
* closing nodes a chance to process their unread data:
|
||||
* - PASSIVE_CLOSE (from OPEN => CLOSED) and
|
||||
* - PASSIVE_CLOSEREQ (from (PART)OPEN to CLOSING; case (b) above).
|
||||
*/
|
||||
DCCP_ACTIVE_CLOSEREQ = TCP_FIN_WAIT1,
|
||||
DCCP_PASSIVE_CLOSE = TCP_CLOSE_WAIT, /* any node receiving a Close */
|
||||
DCCP_CLOSING = TCP_CLOSING,
|
||||
DCCP_TIME_WAIT = TCP_TIME_WAIT,
|
||||
DCCP_CLOSED = TCP_CLOSE,
|
||||
DCCP_PARTOPEN = TCP_MAX_STATES,
|
||||
DCCP_PASSIVE_CLOSEREQ, /* clients receiving CloseReq */
|
||||
DCCP_MAX_STATES
|
||||
};
|
||||
|
||||
#define DCCP_STATE_MASK 0xf
|
||||
#define DCCP_STATE_MASK 0x1f
|
||||
#define DCCP_ACTION_FIN (1<<7)
|
||||
|
||||
enum {
|
||||
DCCPF_OPEN = TCPF_ESTABLISHED,
|
||||
DCCPF_REQUESTING = TCPF_SYN_SENT,
|
||||
DCCPF_LISTEN = TCPF_LISTEN,
|
||||
DCCPF_RESPOND = TCPF_SYN_RECV,
|
||||
DCCPF_CLOSING = TCPF_CLOSING,
|
||||
DCCPF_TIME_WAIT = TCPF_TIME_WAIT,
|
||||
DCCPF_CLOSED = TCPF_CLOSE,
|
||||
DCCPF_PARTOPEN = 1 << DCCP_PARTOPEN,
|
||||
DCCPF_OPEN = TCPF_ESTABLISHED,
|
||||
DCCPF_REQUESTING = TCPF_SYN_SENT,
|
||||
DCCPF_LISTEN = TCPF_LISTEN,
|
||||
DCCPF_RESPOND = TCPF_SYN_RECV,
|
||||
DCCPF_ACTIVE_CLOSEREQ = TCPF_FIN_WAIT1,
|
||||
DCCPF_CLOSING = TCPF_CLOSING,
|
||||
DCCPF_TIME_WAIT = TCPF_TIME_WAIT,
|
||||
DCCPF_CLOSED = TCPF_CLOSE,
|
||||
DCCPF_PARTOPEN = (1 << DCCP_PARTOPEN),
|
||||
};
|
||||
|
||||
static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb)
|
||||
|
|
|
@ -60,8 +60,7 @@ void dccp_set_state(struct sock *sk, const int state)
|
|||
{
|
||||
const int oldstate = sk->sk_state;
|
||||
|
||||
dccp_pr_debug("%s(%p) %-10.10s -> %s\n",
|
||||
dccp_role(sk), sk,
|
||||
dccp_pr_debug("%s(%p) %s --> %s\n", dccp_role(sk), sk,
|
||||
dccp_state_name(oldstate), dccp_state_name(state));
|
||||
WARN_ON(state == oldstate);
|
||||
|
||||
|
@ -134,14 +133,17 @@ EXPORT_SYMBOL_GPL(dccp_packet_name);
|
|||
const char *dccp_state_name(const int state)
|
||||
{
|
||||
static char *dccp_state_names[] = {
|
||||
[DCCP_OPEN] = "OPEN",
|
||||
[DCCP_REQUESTING] = "REQUESTING",
|
||||
[DCCP_PARTOPEN] = "PARTOPEN",
|
||||
[DCCP_LISTEN] = "LISTEN",
|
||||
[DCCP_RESPOND] = "RESPOND",
|
||||
[DCCP_CLOSING] = "CLOSING",
|
||||
[DCCP_TIME_WAIT] = "TIME_WAIT",
|
||||
[DCCP_CLOSED] = "CLOSED",
|
||||
[DCCP_OPEN] = "OPEN",
|
||||
[DCCP_REQUESTING] = "REQUESTING",
|
||||
[DCCP_PARTOPEN] = "PARTOPEN",
|
||||
[DCCP_LISTEN] = "LISTEN",
|
||||
[DCCP_RESPOND] = "RESPOND",
|
||||
[DCCP_CLOSING] = "CLOSING",
|
||||
[DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
|
||||
[DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
|
||||
[DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
|
||||
[DCCP_TIME_WAIT] = "TIME_WAIT",
|
||||
[DCCP_CLOSED] = "CLOSED",
|
||||
};
|
||||
|
||||
if (state >= DCCP_MAX_STATES)
|
||||
|
|
Loading…
Reference in a new issue