diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2007-12-13 09:37:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:57:51 -0500 |
commit | b4d4f7c70fd3361c6c889752e08ea9be304cf5f4 (patch) | |
tree | b84c712184dfcdde4b68980f4eff21bcaefbfcf3 /net/dccp | |
parent | 8109616e2ef978d142ea45850efd4f102b9bdce4 (diff) |
[DCCP]: Handle timestamps on Request/Response exchange separately
In DCCP, timestamps can occur on packets anytime, CCID3 uses a timestamp(/echo) on the Request/Response
exchange. This patch addresses the following situation:
* timestamps are recorded on the listening socket;
* Responses are sent from dccp_request_sockets;
* suppose two connections reach the listening socket with very small time in between:
* the first timestamp value gets overwritten by the second connection request.
This is not really good, so this patch separates timestamps into
* those which are received by the server during the initial handshake (on dccp_request_sock);
* those which are received by the client or the client after connection establishment.
As before, a timestamp of 0 is regarded as indicating that no (meaningful) timestamp has been
received (in addition, a warning message is printed if hosts send 0-valued timestamps).
The timestamp-echoing now works as follows:
* when a timestamp is present on the initial Request, it is placed into dreq, due to the
call to dccp_parse_options in dccp_v{4,6}_conn_request;
* when a timestamp is present on the Ack leading from RESPOND => OPEN, it is copied over
from the request_sock into the child cocket in dccp_create_openreq_child;
* timestamps received on an (established) dccp_sock are treated as before.
Since Elapsed Time is measured in hundredths of milliseconds (13.2), the new dccp_timestamp()
function is used, as it is expected that the time between receiving the timestamp and
sending the timestamp echo will be very small against the wrap-around time. As a byproduct,
this allows smaller timestamping-time fields.
Furthermore, inserting the Timestamp Echo option has been taken out of the block starting with
'!dccp_packet_without_ack()', since Timestamp Echo can be carried on any packet (5.8 and 13.3).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-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/minisocks.c | 21 | ||||
-rw-r--r-- | net/dccp/options.c | 56 |
2 files changed, 49 insertions, 28 deletions
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index b1d5da61f6af..027d1814e1ab 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -117,11 +117,13 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
117 | struct dccp_sock *newdp = dccp_sk(newsk); | 117 | struct dccp_sock *newdp = dccp_sk(newsk); |
118 | struct dccp_minisock *newdmsk = dccp_msk(newsk); | 118 | struct dccp_minisock *newdmsk = dccp_msk(newsk); |
119 | 119 | ||
120 | newdp->dccps_role = DCCP_ROLE_SERVER; | 120 | newdp->dccps_role = DCCP_ROLE_SERVER; |
121 | newdp->dccps_hc_rx_ackvec = NULL; | 121 | newdp->dccps_hc_rx_ackvec = NULL; |
122 | newdp->dccps_service_list = NULL; | 122 | newdp->dccps_service_list = NULL; |
123 | newdp->dccps_service = dreq->dreq_service; | 123 | newdp->dccps_service = dreq->dreq_service; |
124 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | 124 | newdp->dccps_timestamp_echo = dreq->dreq_timestamp_echo; |
125 | newdp->dccps_timestamp_time = dreq->dreq_timestamp_time; | ||
126 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
125 | 127 | ||
126 | if (dccp_feat_clone(sk, newsk)) | 128 | if (dccp_feat_clone(sk, newsk)) |
127 | goto out_free; | 129 | goto out_free; |
@@ -303,9 +305,12 @@ EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack); | |||
303 | 305 | ||
304 | void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) | 306 | void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) |
305 | { | 307 | { |
306 | inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport; | 308 | struct dccp_request_sock *dreq = dccp_rsk(req); |
307 | inet_rsk(req)->acked = 0; | 309 | |
308 | req->rcv_wnd = sysctl_dccp_feat_sequence_window; | 310 | inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport; |
311 | inet_rsk(req)->acked = 0; | ||
312 | req->rcv_wnd = sysctl_dccp_feat_sequence_window; | ||
313 | dreq->dreq_timestamp_echo = 0; | ||
309 | } | 314 | } |
310 | 315 | ||
311 | EXPORT_SYMBOL_GPL(dccp_reqsk_init); | 316 | EXPORT_SYMBOL_GPL(dccp_reqsk_init); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index f496d4dc7efc..0c996d8c79a3 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -166,16 +166,27 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
166 | case DCCPO_TIMESTAMP: | 166 | case DCCPO_TIMESTAMP: |
167 | if (len != 4) | 167 | if (len != 4) |
168 | goto out_invalid_option; | 168 | goto out_invalid_option; |
169 | 169 | /* | |
170 | * RFC 4340 13.1: "The precise time corresponding to | ||
171 | * Timestamp Value zero is not specified". We use | ||
172 | * zero to indicate absence of a meaningful timestamp. | ||
173 | */ | ||
170 | opt_val = get_unaligned((__be32 *)value); | 174 | opt_val = get_unaligned((__be32 *)value); |
171 | opt_recv->dccpor_timestamp = ntohl(opt_val); | 175 | if (unlikely(opt_val == 0)) { |
172 | 176 | DCCP_WARN("Timestamp with zero value\n"); | |
173 | /* FIXME: if dreq != NULL, don't store this on listening socket */ | 177 | break; |
174 | dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; | 178 | } |
175 | dp->dccps_timestamp_time = ktime_get_real(); | ||
176 | 179 | ||
180 | if (dreq != NULL) { | ||
181 | dreq->dreq_timestamp_echo = ntohl(opt_val); | ||
182 | dreq->dreq_timestamp_time = dccp_timestamp(); | ||
183 | } else { | ||
184 | opt_recv->dccpor_timestamp = | ||
185 | dp->dccps_timestamp_echo = ntohl(opt_val); | ||
186 | dp->dccps_timestamp_time = dccp_timestamp(); | ||
187 | } | ||
177 | dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n", | 188 | dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n", |
178 | dccp_role(sk), opt_recv->dccpor_timestamp, | 189 | dccp_role(sk), ntohl(opt_val), |
179 | (unsigned long long) | 190 | (unsigned long long) |
180 | DCCP_SKB_CB(skb)->dccpd_ack_seq); | 191 | DCCP_SKB_CB(skb)->dccpd_ack_seq); |
181 | break; | 192 | break; |
@@ -393,16 +404,24 @@ int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) | |||
393 | 404 | ||
394 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); | 405 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); |
395 | 406 | ||
396 | static int dccp_insert_option_timestamp_echo(struct sock *sk, | 407 | static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, |
408 | struct dccp_request_sock *dreq, | ||
397 | struct sk_buff *skb) | 409 | struct sk_buff *skb) |
398 | { | 410 | { |
399 | struct dccp_sock *dp = dccp_sk(sk); | ||
400 | __be32 tstamp_echo; | 411 | __be32 tstamp_echo; |
401 | int len, elapsed_time_len; | ||
402 | unsigned char *to; | 412 | unsigned char *to; |
403 | const suseconds_t delta = ktime_us_delta(ktime_get_real(), | 413 | u32 elapsed_time, elapsed_time_len, len; |
404 | dp->dccps_timestamp_time); | 414 | |
405 | u32 elapsed_time = delta / 10; | 415 | if (dreq != NULL) { |
416 | elapsed_time = dccp_timestamp() - dreq->dreq_timestamp_time; | ||
417 | tstamp_echo = htonl(dreq->dreq_timestamp_echo); | ||
418 | dreq->dreq_timestamp_echo = 0; | ||
419 | } else { | ||
420 | elapsed_time = dccp_timestamp() - dp->dccps_timestamp_time; | ||
421 | tstamp_echo = htonl(dp->dccps_timestamp_echo); | ||
422 | dp->dccps_timestamp_echo = 0; | ||
423 | } | ||
424 | |||
406 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 425 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
407 | len = 6 + elapsed_time_len; | 426 | len = 6 + elapsed_time_len; |
408 | 427 | ||
@@ -415,7 +434,6 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, | |||
415 | *to++ = DCCPO_TIMESTAMP_ECHO; | 434 | *to++ = DCCPO_TIMESTAMP_ECHO; |
416 | *to++ = len; | 435 | *to++ = len; |
417 | 436 | ||
418 | tstamp_echo = htonl(dp->dccps_timestamp_echo); | ||
419 | memcpy(to, &tstamp_echo, 4); | 437 | memcpy(to, &tstamp_echo, 4); |
420 | to += 4; | 438 | to += 4; |
421 | 439 | ||
@@ -427,8 +445,6 @@ static int dccp_insert_option_timestamp_echo(struct sock *sk, | |||
427 | memcpy(to, &var32, 4); | 445 | memcpy(to, &var32, 4); |
428 | } | 446 | } |
429 | 447 | ||
430 | dp->dccps_timestamp_echo = 0; | ||
431 | dp->dccps_timestamp_time = ktime_set(0, 0); | ||
432 | return 0; | 448 | return 0; |
433 | } | 449 | } |
434 | 450 | ||
@@ -537,10 +553,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
537 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && | 553 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && |
538 | dccp_insert_option_ackvec(sk, skb)) | 554 | dccp_insert_option_ackvec(sk, skb)) |
539 | return -1; | 555 | return -1; |
540 | |||
541 | if (dp->dccps_timestamp_echo != 0 && | ||
542 | dccp_insert_option_timestamp_echo(sk, skb)) | ||
543 | return -1; | ||
544 | } | 556 | } |
545 | 557 | ||
546 | if (dp->dccps_hc_rx_insert_options) { | 558 | if (dp->dccps_hc_rx_insert_options) { |
@@ -564,6 +576,10 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
564 | dccp_insert_option_timestamp(sk, skb)) | 576 | dccp_insert_option_timestamp(sk, skb)) |
565 | return -1; | 577 | return -1; |
566 | 578 | ||
579 | if (dp->dccps_timestamp_echo != 0 && | ||
580 | dccp_insert_option_timestamp_echo(dp, NULL, skb)) | ||
581 | return -1; | ||
582 | |||
567 | /* XXX: insert other options when appropriate */ | 583 | /* XXX: insert other options when appropriate */ |
568 | 584 | ||
569 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { | 585 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { |