List Info

Thread: : Basic support for passive-close




: Basic support for passive-close
country flaguser name
United Kingdom
2007-07-12 09:26:31
[DCCP]: Basic support for passive-close

This implements necessary state transitions for the two
forms of passive-close

 * PASSIVE_1, which is entered when a host receives Close;
 * PASSIVE_2, which is entered when a client receives
CloseReq.

The handling is such that these passive
connection-termination requests are
enqueued as `fin' packets so that dccp_recvmsg() can later
detect them. The
only thing I am not entirely sure about is the wake_async in
dccp_rcv_closereq();
this has been copied from dccp_rcv_close() (but looks ok
from the principle).

The completed state transition diagram is on 
http://www.erg.abdn.ac.uk/users/gerrit/dccp/not
es/closing_states/

NB: Regrettably, it is no longer easily possible to use a
table-based transition as
    before. The reason is that the role of the host (server
or client) also plays a
    `role' in the state transition. Therefore
DCCP_ACTION_FIN has also been removed.
    Another difference is that the transition into
DCCP_CLOSED is now after sending
    the Close/CloseReq.

Signed-off-by: Gerrit Renker <gerriterg.abdn.ac.uk>
---
 include/linux/dccp.h |    1 
 net/dccp/input.c     |   34 +++++++++++-----
 net/dccp/proto.c     |  108
++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 102 insertions(+), 41 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
 -55,6
+55,9  EXPORT_SYMBOL_GPL(dccp_hashinfo);
 /* the maximum queue length for tx in packets. 0 is no
limit */
 int sysctl_dccp_tx_qlen __read_mostly = 5;
 
+/* Forward Declarations. */
+static void dccp_handle_passive_close(struct sock *sk);
+
 void dccp_set_state(struct sock *sk, const int state)
 {
 	const int oldstate = sk->sk_state;
 -71,7
+74,8  void dccp_set_state(struct sock *sk, con
 		break;
 
 	case DCCP_CLOSED:
-		if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN)
+		if (oldstate == DCCP_CLOSING  ||
+		    oldstate == DCCP_CLOSEREQ || oldstate == DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
 
 		sk->sk_prot->unhash(sk);
 -723,19
+727,26  int dccp_recvmsg(struct kiocb *iocb, str
 
 		dh = dccp_hdr(skb);
 
-		if (dh->dccph_type == DCCP_PKT_DATA ||
-		    dh->dccph_type == DCCP_PKT_DATAACK)
+		switch (dh->dccph_type) {
+		case DCCP_PKT_DATA:
+		case DCCP_PKT_DATAACK:
 			goto found_ok_skb;
 
-		if (dh->dccph_type == DCCP_PKT_RESET ||
-		    dh->dccph_type == DCCP_PKT_CLOSE) {
-			dccp_pr_debug("found fin ok!n");
+		case DCCP_PKT_CLOSE:
+		case DCCP_PKT_CLOSEREQ:
+			if (!(flags & MSG_PEEK))
+				dccp_handle_passive_close(sk);
+			/* fall through */
+		case DCCP_PKT_RESET:
+			dccp_pr_debug("found fin (%s) ok!n",
+				      dccp_packet_name(dh->dccph_type));
 			len = 0;
 			goto found_fin_ok;
+		default:
+			dccp_pr_debug("packet_type=%sn",
+				      dccp_packet_name(dh->dccph_type));
+			sk_eat_skb(sk, skb, 0);
 		}
-		dccp_pr_debug("packet_type=%sn",
-			      dccp_packet_name(dh->dccph_type));
-		sk_eat_skb(sk, skb, 0);
 verify_sock_status:
 		if (sock_flag(sk, SOCK_DONE)) {
 			len = 0;
 -837,28
+848,64  out:
 
 EXPORT_SYMBOL_GPL(inet_dccp_listen);
 
-static const unsigned char dccp_new_state[] = {
-	/* current state:   new state:      action:	*/
-	[0]		  = DCCP_CLOSED,
-	[DCCP_OPEN]	  = DCCP_CLOSING | DCCP_ACTION_FIN,
-	[DCCP_REQUESTING] = DCCP_CLOSED,
-	[DCCP_PARTOPEN]	  = DCCP_CLOSING | DCCP_ACTION_FIN,
-	[DCCP_LISTEN]	  = DCCP_CLOSED,
-	[DCCP_RESPOND]	  = DCCP_CLOSED,
-	[DCCP_CLOSING]	  = DCCP_CLOSED,
-	[DCCP_TIME_WAIT]  = DCCP_CLOSED,
-	[DCCP_CLOSED]	  = DCCP_CLOSED,
-};
-
-static int dccp_close_state(struct sock *sk)
+void dccp_handle_passive_close(struct sock *sk)
 {
-	const int next = dccp_new_state[sk->sk_state];
-	const int ns = next & DCCP_STATE_MASK;
+	switch (sk->sk_state) {
+	case DCCP_PASSIVE_1:
+		/* Node (client or server) has received Close packet. */
+		dccp_set_state(sk, DCCP_CLOSED);
+		dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+		break;
+	case DCCP_PASSIVE_2:
+		/*
+		 * Client passive-close by receiving a CloseReq packet.
+		 * We need to set `active' when sending the Close, since
8.3 in
+		 * RFC 4340 requires nodes in the CLOSING state to
retransmit
+		 * the Close/CloseReq packets. A conforming peer
implementation
+		 * will in turn retransmit its CloseReq packets as well.
+		 */
+		dccp_set_state(sk, DCCP_CLOSING);
+		dccp_send_close(sk, 1);
+		break;
+	default:
+		return;
+	}
+}
 
-	if (ns != sk->sk_state)
-		dccp_set_state(sk, ns);
+static void dccp_handle_close(struct sock *sk)
+{
+	u8 next_state = DCCP_CLOSED;
 
-	return next & DCCP_ACTION_FIN;
+	switch (sk->sk_state) {
+	case DCCP_CLOSED:
+		return;
+	case DCCP_PASSIVE_1:
+	case DCCP_PASSIVE_2:
+		dccp_handle_passive_close(sk);
+		break;
+	case DCCP_PARTOPEN:
+		/*
+		 * Clear PARTOPEN timer [RFC 4340, 8.1.5]; we will be
sending a
+		 * Close presently, which will be (re-)transmitted anyhow
(8.3).
+		 */
+		dccp_pr_debug("Stop PARTOPEN timer (%p)n",
sk);
+		inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
+		/* fall through */
+	case DCCP_OPEN:
+		/*
+		 * An active close need only be sent in these two states
+		 */
+		dccp_send_close(sk, 1);
+
+		if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+			next_state = DCCP_CLOSEREQ;
+		else
+			next_state = DCCP_CLOSING;
+		/* fall through */
+	default:
+		dccp_set_state(sk, next_state);
+		break;
+	}
 }
 
 void dccp_close(struct sock *sk, long timeout)
 -895,9
+942,8  void dccp_close(struct sock *sk, long ti
 	if (sock_flag(sk, SOCK_LINGER) &&
!sk->sk_lingertime) {
 		/* Check zero linger _after_ checking for unread data.
*/
 		sk->sk_prot->disconnect(sk, 0);
-	} else if (dccp_close_state(sk)) {
-		dccp_send_close(sk, 1);
-	}
+	} else	/* Passive/active close after all data has been
read. */
+		dccp_handle_close(sk);
 
 	sk_stream_wait_close(sk, timeout);
 
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
 -31,10
+31,23  static void dccp_fin(struct sock *sk, st
 
 static void dccp_rcv_close(struct sock *sk, struct sk_buff
*skb)
 {
-	dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
-	dccp_fin(sk, skb);
-	dccp_set_state(sk, DCCP_CLOSED);
-	sk_wake_async(sk, 1, POLL_HUP);
+	if (sk->sk_state == DCCP_CLOSEREQ) {
+		/* Server performed active close */
+		dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+		dccp_done(sk);
+	} else {
+		/*
+		 * Passive-close: only the first Close is enqueued. There
is no
+		 * point in putting several Closes on the queue - in case
of an
+		 * application bug, the input queue may not be emptied at
all.
+		 * In this case we wait until the peer sends the terminal
Reset.
+		 */
+		if (sk->sk_state != DCCP_PASSIVE_1) {
+			dccp_fin(sk, skb);
+			dccp_set_state(sk, DCCP_PASSIVE_1);
+		}
+		sk_wake_async(sk, 1, POLL_HUP);
+	}
 }
 
 static void dccp_rcv_closereq(struct sock *sk, struct
sk_buff *skb)
 -50,9
+63,12  static void dccp_rcv_closereq(struct soc
 		return;
 	}
 
-	if (sk->sk_state != DCCP_CLOSING)
-		dccp_set_state(sk, DCCP_CLOSING);
-	dccp_send_close(sk, 0);
+	/* Do not enqueue CloseReq twice: see comments above for
PASSIVE_1 */
+	if (sk->sk_state != DCCP_PASSIVE_2) {
+		dccp_fin(sk, skb);
+		dccp_set_state(sk, DCCP_PASSIVE_2);
+	}
+	sk_wake_async(sk, 1, POLL_HUP);
 }
 
 static void dccp_event_ack_recv(struct sock *sk, struct
sk_buff *skb)
 -192,7
+208,7  static int __dccp_rcv_established(struct
 		return 0;
 	case DCCP_PKT_CLOSEREQ:
 		dccp_rcv_closereq(sk, skb);
-		goto discard;
+		return 0;
 	case DCCP_PKT_CLOSE:
 		dccp_rcv_close(sk, skb);
 		return 0;
 -548,7
+564,7  int dccp_rcv_state_process(struct sock *
 		goto discard;
 	} else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
 		dccp_rcv_closereq(sk, skb);
-		goto discard;
+		return 0;
 	} else if (dh->dccph_type == DCCP_PKT_CLOSE) {
 		dccp_rcv_close(sk, skb);
 		return 0;
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
 -259,7
+259,6  enum dccp_state {
 };
 
 #define DCCP_STATE_MASK 0x1f
-#define DCCP_ACTION_FIN (1<<7)
 
 enum {
 	DCCPF_OPEN	 = TCPF_ESTABLISHED,
-
To unsubscribe from this list: send the line
"unsubscribe dccp" in
the body of a message to majordomovger.kernel.org
More majordomo info at  http://vge
r.kernel.org/majordomo-info.html

[1]

about | contact  Other archives ( Real Estate discussion Medical topics )