aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-11-28 08:34:53 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:12 -0500
commitf11135a3442996d78dad99933bfdb90d1f6588d3 (patch)
tree6b10cea26f0551b769097296b7e41f25d6b44f08
parentf53dc67c5e7babafe239b93a11678b0e05bead51 (diff)
[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>
-rw-r--r--include/linux/dccp.h56
-rw-r--r--net/dccp/proto.c22
2 files changed, 51 insertions, 27 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index a0073268808f..8b3f9ad3cf04 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -227,29 +227,51 @@ struct dccp_so_feat {
227#include <net/tcp_states.h> 227#include <net/tcp_states.h>
228 228
229enum dccp_state { 229enum dccp_state {
230 DCCP_OPEN = TCP_ESTABLISHED, 230 DCCP_OPEN = TCP_ESTABLISHED,
231 DCCP_REQUESTING = TCP_SYN_SENT, 231 DCCP_REQUESTING = TCP_SYN_SENT,
232 DCCP_LISTEN = TCP_LISTEN, 232 DCCP_LISTEN = TCP_LISTEN,
233 DCCP_RESPOND = TCP_SYN_RECV, 233 DCCP_RESPOND = TCP_SYN_RECV,
234 DCCP_CLOSING = TCP_CLOSING, 234 /*
235 DCCP_TIME_WAIT = TCP_TIME_WAIT, 235 * States involved in closing a DCCP connection:
236 DCCP_CLOSED = TCP_CLOSE, 236 * 1) ACTIVE_CLOSEREQ is entered by a server sending a CloseReq.
237 DCCP_PARTOPEN = TCP_MAX_STATES, 237 *
238 * 2) CLOSING can have three different meanings (RFC 4340, 8.3):
239 * a. Client has performed active-close, has sent a Close to the server
240 * from state OPEN or PARTOPEN, and is waiting for the final Reset
241 * (in this case, SOCK_DONE == 1).
242 * b. Client is asked to perform passive-close, by receiving a CloseReq
243 * in (PART)OPEN state. It sends a Close and waits for final Reset
244 * (in this case, SOCK_DONE == 0).
245 * c. Server performs an active-close as in (a), keeps TIMEWAIT state.
246 *
247 * 3) The following intermediate states are employed to give passively
248 * closing nodes a chance to process their unread data:
249 * - PASSIVE_CLOSE (from OPEN => CLOSED) and
250 * - PASSIVE_CLOSEREQ (from (PART)OPEN to CLOSING; case (b) above).
251 */
252 DCCP_ACTIVE_CLOSEREQ = TCP_FIN_WAIT1,
253 DCCP_PASSIVE_CLOSE = TCP_CLOSE_WAIT, /* any node receiving a Close */
254 DCCP_CLOSING = TCP_CLOSING,
255 DCCP_TIME_WAIT = TCP_TIME_WAIT,
256 DCCP_CLOSED = TCP_CLOSE,
257 DCCP_PARTOPEN = TCP_MAX_STATES,
258 DCCP_PASSIVE_CLOSEREQ, /* clients receiving CloseReq */
238 DCCP_MAX_STATES 259 DCCP_MAX_STATES
239}; 260};
240 261
241#define DCCP_STATE_MASK 0xf 262#define DCCP_STATE_MASK 0x1f
242#define DCCP_ACTION_FIN (1<<7) 263#define DCCP_ACTION_FIN (1<<7)
243 264
244enum { 265enum {
245 DCCPF_OPEN = TCPF_ESTABLISHED, 266 DCCPF_OPEN = TCPF_ESTABLISHED,
246 DCCPF_REQUESTING = TCPF_SYN_SENT, 267 DCCPF_REQUESTING = TCPF_SYN_SENT,
247 DCCPF_LISTEN = TCPF_LISTEN, 268 DCCPF_LISTEN = TCPF_LISTEN,
248 DCCPF_RESPOND = TCPF_SYN_RECV, 269 DCCPF_RESPOND = TCPF_SYN_RECV,
249 DCCPF_CLOSING = TCPF_CLOSING, 270 DCCPF_ACTIVE_CLOSEREQ = TCPF_FIN_WAIT1,
250 DCCPF_TIME_WAIT = TCPF_TIME_WAIT, 271 DCCPF_CLOSING = TCPF_CLOSING,
251 DCCPF_CLOSED = TCPF_CLOSE, 272 DCCPF_TIME_WAIT = TCPF_TIME_WAIT,
252 DCCPF_PARTOPEN = 1 << DCCP_PARTOPEN, 273 DCCPF_CLOSED = TCPF_CLOSE,
274 DCCPF_PARTOPEN = (1 << DCCP_PARTOPEN),
253}; 275};
254 276
255static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb) 277static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 73006b747678..3489d3f21f50 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -60,8 +60,7 @@ void dccp_set_state(struct sock *sk, const int state)
60{ 60{
61 const int oldstate = sk->sk_state; 61 const int oldstate = sk->sk_state;
62 62
63 dccp_pr_debug("%s(%p) %-10.10s -> %s\n", 63 dccp_pr_debug("%s(%p) %s --> %s\n", dccp_role(sk), sk,
64 dccp_role(sk), sk,
65 dccp_state_name(oldstate), dccp_state_name(state)); 64 dccp_state_name(oldstate), dccp_state_name(state));
66 WARN_ON(state == oldstate); 65 WARN_ON(state == oldstate);
67 66
@@ -134,14 +133,17 @@ EXPORT_SYMBOL_GPL(dccp_packet_name);
134const char *dccp_state_name(const int state) 133const char *dccp_state_name(const int state)
135{ 134{
136 static char *dccp_state_names[] = { 135 static char *dccp_state_names[] = {
137 [DCCP_OPEN] = "OPEN", 136 [DCCP_OPEN] = "OPEN",
138 [DCCP_REQUESTING] = "REQUESTING", 137 [DCCP_REQUESTING] = "REQUESTING",
139 [DCCP_PARTOPEN] = "PARTOPEN", 138 [DCCP_PARTOPEN] = "PARTOPEN",
140 [DCCP_LISTEN] = "LISTEN", 139 [DCCP_LISTEN] = "LISTEN",
141 [DCCP_RESPOND] = "RESPOND", 140 [DCCP_RESPOND] = "RESPOND",
142 [DCCP_CLOSING] = "CLOSING", 141 [DCCP_CLOSING] = "CLOSING",
143 [DCCP_TIME_WAIT] = "TIME_WAIT", 142 [DCCP_ACTIVE_CLOSEREQ] = "CLOSEREQ",
144 [DCCP_CLOSED] = "CLOSED", 143 [DCCP_PASSIVE_CLOSE] = "PASSIVE_CLOSE",
144 [DCCP_PASSIVE_CLOSEREQ] = "PASSIVE_CLOSEREQ",
145 [DCCP_TIME_WAIT] = "TIME_WAIT",
146 [DCCP_CLOSED] = "CLOSED",
145 }; 147 };
146 148
147 if (state >= DCCP_MAX_STATES) 149 if (state >= DCCP_MAX_STATES)