[DCCP]: Implement the CLOSING timer

So that we retransmit CLOSE/CLOSEREQ packets till they elicit an
answer or we hit a timeout.

Most of the machinery uses TCP approaches, this code has to be
polished & audited, but this is better than we had before.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 8540253..02af05e 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -31,14 +31,9 @@
 
 static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
 {
-	switch (sk->sk_state) {
-	case DCCP_PARTOPEN:
-	case DCCP_OPEN:
-		dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED);
-		dccp_fin(sk, skb);
-		dccp_set_state(sk, DCCP_CLOSED);
-		break;
-	}
+	dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED);
+	dccp_fin(sk, skb);
+	dccp_set_state(sk, DCCP_CLOSED);
 }
 
 static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
@@ -54,13 +49,8 @@
 		return;
 	}
 
-	switch (sk->sk_state) {
-	case DCCP_PARTOPEN:
-	case DCCP_OPEN:
-		dccp_set_state(sk, DCCP_CLOSING);
-		dccp_send_close(sk);
-		break;
-	}
+	dccp_set_state(sk, DCCP_CLOSING);
+	dccp_send_close(sk, 0);
 }
 
 static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
@@ -562,6 +552,12 @@
 		dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
 			       DCCP_PKT_SYNC);
 		goto discard;
+	} else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
+		dccp_rcv_closereq(sk, skb);
+		goto discard;
+	} else if (dh->dccph_type == DCCP_PKT_CLOSE) {
+		dccp_rcv_close(sk, skb);
+		return 0;
 	}
 
 	switch (sk->sk_state) {