]> err.no Git - linux-2.6/commitdiff
[DCCP]: Support for server holding timewait state
authorGerrit Renker <gerrit@erg.abdn.ac.uk>
Thu, 13 Dec 2007 14:25:01 +0000 (12:25 -0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 22:57:48 +0000 (14:57 -0800)
This adds a socket option and signalling support for the case where the server
holds timewait state on closing the connection, as described in RFC 4340, 8.3.

Since holding timewait state at the server is the non-usual case, it is enabled
via a socket option. Documentation for this socket option has been added.

The setsockopt statement has been made resilient against different possible cases
of expressing boolean `true' values using a suggestion by Ian McDonald.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/dccp.txt
include/linux/dccp.h
net/dccp/output.c
net/dccp/proto.c

index d76905a5a08712c811571bfd0aae5f080a86faa9..39131a3c78f8826bb9949ddf25ff50e591904028 100644 (file)
@@ -57,6 +57,12 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
+timewait state when closing the connection (RFC 4340, 8.3). The usual case is
+that the closing server sends a CloseReq, whereupon the client holds timewait
+state. When this boolean socket option is on, the server sends a Close instead
+and will enter TIMEWAIT. This option must be set after accept() returns.
+
 DCCP_SOCKOPT_SEND_CSCOV and DCCP_SOCKOPT_RECV_CSCOV are used for setting the
 partial checksum coverage (RFC 4340, sec. 9.2). The default is that checksums
 always cover the entire packet and that only fully covered application data is
index 312b989c7edb5ae103782b2a3036d5b92d72939c..c676021603f55b8914c09fd6af67547172e0a411 100644 (file)
@@ -205,6 +205,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_CHANGE_L          3
 #define DCCP_SOCKOPT_CHANGE_R          4
 #define DCCP_SOCKOPT_GET_CUR_MPS       5
+#define DCCP_SOCKOPT_SERVER_TIMEWAIT   6
 #define DCCP_SOCKOPT_SEND_CSCOV                10
 #define DCCP_SOCKOPT_RECV_CSCOV                11
 #define DCCP_SOCKOPT_CCID_RX_INFO      128
@@ -492,6 +493,7 @@ struct dccp_ackvec;
  * @dccps_role - role of this sock, one of %dccp_role
  * @dccps_hc_rx_insert_options - receiver wants to add options when acking
  * @dccps_hc_tx_insert_options - sender wants to add options when sending
+ * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3)
  * @dccps_xmit_timer - timer for when CCID is not ready to send
  * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs)
  */
@@ -528,6 +530,7 @@ struct dccp_sock {
        enum dccp_role                  dccps_role:2;
        __u8                            dccps_hc_rx_insert_options:1;
        __u8                            dccps_hc_tx_insert_options:1;
+       __u8                            dccps_server_timewait:1;
        struct timer_list               dccps_xmit_timer;
 };
 
index e97584aa489881b33881e4e7da78441ab4634ad7..b2e17910930dab5b5b0d8e327322551e75635f32 100644 (file)
@@ -567,8 +567,10 @@ void dccp_send_close(struct sock *sk, const int active)
 
        /* Reserve space for headers and prepare control bits. */
        skb_reserve(skb, sk->sk_prot->max_header);
-       DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ?
-                                       DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
+       if (dp->dccps_role == DCCP_ROLE_SERVER && !dp->dccps_server_timewait)
+               DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSEREQ;
+       else
+               DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_CLOSE;
 
        if (active) {
                dccp_write_xmit(sk, 1);
index 8a73c8f98d763c8c8b56f7165a6278198db94d88..cc87c500bfb8c004c5563303f219f49e68c0d8e2 100644 (file)
@@ -551,6 +551,12 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
                                                     (struct dccp_so_feat __user *)
                                                     optval);
                break;
+       case DCCP_SOCKOPT_SERVER_TIMEWAIT:
+               if (dp->dccps_role != DCCP_ROLE_SERVER)
+                       err = -EOPNOTSUPP;
+               else
+                       dp->dccps_server_timewait = (val != 0);
+               break;
        case DCCP_SOCKOPT_SEND_CSCOV:   /* sender side, RFC 4340, sec. 9.2 */
                if (val < 0 || val > 15)
                        err = -EINVAL;
@@ -653,6 +659,10 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
                val = dp->dccps_mss_cache;
                len = sizeof(val);
                break;
+       case DCCP_SOCKOPT_SERVER_TIMEWAIT:
+               val = dp->dccps_server_timewait;
+               len = sizeof(val);
+               break;
        case DCCP_SOCKOPT_SEND_CSCOV:
                val = dp->dccps_pcslen;
                len = sizeof(val);
@@ -918,7 +928,8 @@ static void dccp_terminate_connection(struct sock *sk)
        case DCCP_OPEN:
                dccp_send_close(sk, 1);
 
-               if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
+               if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER &&
+                   !dccp_sk(sk)->dccps_server_timewait)
                        next_state = DCCP_ACTIVE_CLOSEREQ;
                else
                        next_state = DCCP_CLOSING;