summaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-12-13 15:25:01 +0100
committerDavid S. Miller <davem@davemloft.net>2008-01-28 23:57:48 +0100
commitb8599d20708fa3bde1e414689f3474560c2d990b (patch)
treeadeb51da63a75b03fa55ddbc4712c8359240a3bf /net/dccp
parent[DCCP]: Use maximum-RTO backoff from DCCP spec (diff)
downloadlinux-b8599d20708fa3bde1e414689f3474560c2d990b.tar.xz
linux-b8599d20708fa3bde1e414689f3474560c2d990b.zip
[DCCP]: Support for server holding timewait state
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>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/output.c6
-rw-r--r--net/dccp/proto.c13
2 files changed, 16 insertions, 3 deletions
diff --git a/net/dccp/output.c b/net/dccp/output.c
index e97584aa4898..b2e17910930d 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -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);
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 8a73c8f98d76..cc87c500bfb8 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -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;