aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-12-13 09:37:19 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:57:51 -0500
commitb4d4f7c70fd3361c6c889752e08ea9be304cf5f4 (patch)
treeb84c712184dfcdde4b68980f4eff21bcaefbfcf3
parent8109616e2ef978d142ea45850efd4f102b9bdce4 (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>
-rw-r--r--include/linux/dccp.h16
-rw-r--r--net/dccp/minisocks.c21
-rw-r--r--net/dccp/options.c56
3 files changed, 63 insertions, 30 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 7214031461d3..484e45c7c89a 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -407,11 +407,23 @@ struct dccp_opt_pend {
407 407
408extern void dccp_minisock_init(struct dccp_minisock *dmsk); 408extern void dccp_minisock_init(struct dccp_minisock *dmsk);
409 409
410/**
411 * struct dccp_request_sock - represent DCCP-specific connection request
412 * @dreq_inet_rsk: structure inherited from
413 * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
414 * @dreq_isr: initial sequence number received on the Request
415 * @dreq_service: service code present on the Request (there is just one)
416 * The following two fields are analogous to the ones in dccp_sock:
417 * @dreq_timestamp_echo: last received timestamp to echo (13.1)
418 * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
419 */
410struct dccp_request_sock { 420struct dccp_request_sock {
411 struct inet_request_sock dreq_inet_rsk; 421 struct inet_request_sock dreq_inet_rsk;
412 __u64 dreq_iss; 422 __u64 dreq_iss;
413 __u64 dreq_isr; 423 __u64 dreq_isr;
414 __be32 dreq_service; 424 __be32 dreq_service;
425 __u32 dreq_timestamp_echo;
426 __u32 dreq_timestamp_time;
415}; 427};
416 428
417static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req) 429static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req)
@@ -477,8 +489,8 @@ struct dccp_ackvec;
477 * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss 489 * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss
478 * @dccps_service - first (passive sock) or unique (active sock) service code 490 * @dccps_service - first (passive sock) or unique (active sock) service code
479 * @dccps_service_list - second .. last service code on passive socket 491 * @dccps_service_list - second .. last service code on passive socket
480 * @dccps_timestamp_time - time of latest TIMESTAMP option
481 * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option 492 * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option
493 * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo
482 * @dccps_l_ack_ratio - feature-local Ack Ratio 494 * @dccps_l_ack_ratio - feature-local Ack Ratio
483 * @dccps_r_ack_ratio - feature-remote Ack Ratio 495 * @dccps_r_ack_ratio - feature-remote Ack Ratio
484 * @dccps_pcslen - sender partial checksum coverage (via sockopt) 496 * @dccps_pcslen - sender partial checksum coverage (via sockopt)
@@ -514,8 +526,8 @@ struct dccp_sock {
514 __u64 dccps_gar; 526 __u64 dccps_gar;
515 __be32 dccps_service; 527 __be32 dccps_service;
516 struct dccp_service_list *dccps_service_list; 528 struct dccp_service_list *dccps_service_list;
517 ktime_t dccps_timestamp_time;
518 __u32 dccps_timestamp_echo; 529 __u32 dccps_timestamp_echo;
530 __u32 dccps_timestamp_time;
519 __u16 dccps_l_ack_ratio; 531 __u16 dccps_l_ack_ratio;
520 __u16 dccps_r_ack_ratio; 532 __u16 dccps_r_ack_ratio;
521 __u16 dccps_pcslen; 533 __u16 dccps_pcslen;
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
304void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) 306void 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
311EXPORT_SYMBOL_GPL(dccp_reqsk_init); 316EXPORT_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
394EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); 405EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
395 406
396static int dccp_insert_option_timestamp_echo(struct sock *sk, 407static 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) {