diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2010-11-14 11:26:13 -0500 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2010-11-15 01:12:01 -0500 |
commit | 7e87fe84303cc54ecf3c7b688cb08ca24322a41d (patch) | |
tree | df764cbfefe19e628e92a8353d331d91c33212b6 /net/dccp | |
parent | 52394eecec4e6fa677a61af26f0bd35de665344e (diff) |
dccp ccid-2: Separate option parsing from CCID processing
This patch replaces an almost identical replication of code: large parts
of dccp_parse_options() re-appeared as ccid2_ackvector() in ccid2.c.
Apart from the duplication, this caused two more problems:
1. CCIDs should not need to be concerned with parsing header options;
2. one can not assume that Ack Vectors appear as a contiguous area within an
skb, it is legal to insert other options and/or padding in between. The
current code would throw an error and stop reading in such a case.
Since Ack Vectors provide CCID-specific information, they are now processed
by the CCID directly, separating this functionality from the main DCCP code.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ackvec.c | 28 | ||||
-rw-r--r-- | net/dccp/ackvec.h | 19 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.c | 134 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.h | 2 | ||||
-rw-r--r-- | net/dccp/options.c | 17 |
5 files changed, 100 insertions, 100 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 66b8a51300c0..41819848bdda 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -343,6 +343,34 @@ free_records: | |||
343 | } | 343 | } |
344 | } | 344 | } |
345 | 345 | ||
346 | /* | ||
347 | * Routines to keep track of Ack Vectors received in an skb | ||
348 | */ | ||
349 | int dccp_ackvec_parsed_add(struct list_head *head, u8 *vec, u8 len, u8 nonce) | ||
350 | { | ||
351 | struct dccp_ackvec_parsed *new = kmalloc(sizeof(*new), GFP_ATOMIC); | ||
352 | |||
353 | if (new == NULL) | ||
354 | return -ENOBUFS; | ||
355 | new->vec = vec; | ||
356 | new->len = len; | ||
357 | new->nonce = nonce; | ||
358 | |||
359 | list_add_tail(&new->node, head); | ||
360 | return 0; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_add); | ||
363 | |||
364 | void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks) | ||
365 | { | ||
366 | struct dccp_ackvec_parsed *cur, *next; | ||
367 | |||
368 | list_for_each_entry_safe(cur, next, parsed_chunks, node) | ||
369 | kfree(cur); | ||
370 | INIT_LIST_HEAD(parsed_chunks); | ||
371 | } | ||
372 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup); | ||
373 | |||
346 | int __init dccp_ackvec_init(void) | 374 | int __init dccp_ackvec_init(void) |
347 | { | 375 | { |
348 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", | 376 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", |
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index e19b8d5ee05f..e2ab0627a5ff 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -114,4 +114,23 @@ static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) | |||
114 | { | 114 | { |
115 | return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; | 115 | return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; |
116 | } | 116 | } |
117 | |||
118 | /** | ||
119 | * struct dccp_ackvec_parsed - Record offsets of Ack Vectors in skb | ||
120 | * @vec: start of vector (offset into skb) | ||
121 | * @len: length of @vec | ||
122 | * @nonce: whether @vec had an ECN nonce of 0 or 1 | ||
123 | * @node: FIFO - arranged in descending order of ack_ackno | ||
124 | * This structure is used by CCIDs to access Ack Vectors in a received skb. | ||
125 | */ | ||
126 | struct dccp_ackvec_parsed { | ||
127 | u8 *vec, | ||
128 | len, | ||
129 | nonce:1; | ||
130 | struct list_head node; | ||
131 | }; | ||
132 | |||
133 | extern int dccp_ackvec_parsed_add(struct list_head *head, | ||
134 | u8 *vec, u8 len, u8 nonce); | ||
135 | extern void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks); | ||
117 | #endif /* _ACKVEC_H */ | 136 | #endif /* _ACKVEC_H */ |
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index cb1b4a0d1877..e96d5e810039 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -246,68 +246,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) | |||
246 | #endif | 246 | #endif |
247 | } | 247 | } |
248 | 248 | ||
249 | /* XXX Lame code duplication! | ||
250 | * returns -1 if none was found. | ||
251 | * else returns the next offset to use in the function call. | ||
252 | */ | ||
253 | static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset, | ||
254 | unsigned char **vec, unsigned char *veclen) | ||
255 | { | ||
256 | const struct dccp_hdr *dh = dccp_hdr(skb); | ||
257 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | ||
258 | unsigned char *opt_ptr; | ||
259 | const unsigned char *opt_end = (unsigned char *)dh + | ||
260 | (dh->dccph_doff * 4); | ||
261 | unsigned char opt, len; | ||
262 | unsigned char *value; | ||
263 | |||
264 | BUG_ON(offset < 0); | ||
265 | options += offset; | ||
266 | opt_ptr = options; | ||
267 | if (opt_ptr >= opt_end) | ||
268 | return -1; | ||
269 | |||
270 | while (opt_ptr != opt_end) { | ||
271 | opt = *opt_ptr++; | ||
272 | len = 0; | ||
273 | value = NULL; | ||
274 | |||
275 | /* Check if this isn't a single byte option */ | ||
276 | if (opt > DCCPO_MAX_RESERVED) { | ||
277 | if (opt_ptr == opt_end) | ||
278 | goto out_invalid_option; | ||
279 | |||
280 | len = *opt_ptr++; | ||
281 | if (len < 3) | ||
282 | goto out_invalid_option; | ||
283 | /* | ||
284 | * Remove the type and len fields, leaving | ||
285 | * just the value size | ||
286 | */ | ||
287 | len -= 2; | ||
288 | value = opt_ptr; | ||
289 | opt_ptr += len; | ||
290 | |||
291 | if (opt_ptr > opt_end) | ||
292 | goto out_invalid_option; | ||
293 | } | ||
294 | |||
295 | switch (opt) { | ||
296 | case DCCPO_ACK_VECTOR_0: | ||
297 | case DCCPO_ACK_VECTOR_1: | ||
298 | *vec = value; | ||
299 | *veclen = len; | ||
300 | return offset + (opt_ptr - options); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | return -1; | ||
305 | |||
306 | out_invalid_option: | ||
307 | DCCP_BUG("Invalid option - this should not happen (previous parsing)!"); | ||
308 | return -1; | ||
309 | } | ||
310 | |||
311 | /** | 249 | /** |
312 | * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm | 250 | * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm |
313 | * This code is almost identical with TCP's tcp_rtt_estimator(), since | 251 | * This code is almost identical with TCP's tcp_rtt_estimator(), since |
@@ -432,16 +370,28 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) | |||
432 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); | 370 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); |
433 | } | 371 | } |
434 | 372 | ||
373 | static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, | ||
374 | u8 option, u8 *optval, u8 optlen) | ||
375 | { | ||
376 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | ||
377 | |||
378 | switch (option) { | ||
379 | case DCCPO_ACK_VECTOR_0: | ||
380 | case DCCPO_ACK_VECTOR_1: | ||
381 | return dccp_ackvec_parsed_add(&hc->tx_av_chunks, optval, optlen, | ||
382 | option - DCCPO_ACK_VECTOR_0); | ||
383 | } | ||
384 | return 0; | ||
385 | } | ||
386 | |||
435 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | 387 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) |
436 | { | 388 | { |
437 | struct dccp_sock *dp = dccp_sk(sk); | 389 | struct dccp_sock *dp = dccp_sk(sk); |
438 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | 390 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); |
439 | const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); | 391 | const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); |
392 | struct dccp_ackvec_parsed *avp; | ||
440 | u64 ackno, seqno; | 393 | u64 ackno, seqno; |
441 | struct ccid2_seq *seqp; | 394 | struct ccid2_seq *seqp; |
442 | unsigned char *vector; | ||
443 | unsigned char veclen; | ||
444 | int offset = 0; | ||
445 | int done = 0; | 395 | int done = 0; |
446 | unsigned int maxincr = 0; | 396 | unsigned int maxincr = 0; |
447 | 397 | ||
@@ -475,17 +425,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
475 | } | 425 | } |
476 | 426 | ||
477 | /* check forward path congestion */ | 427 | /* check forward path congestion */ |
478 | /* still didn't send out new data packets */ | 428 | if (dccp_packet_without_ack(skb)) |
479 | if (hc->tx_seqh == hc->tx_seqt) | ||
480 | return; | 429 | return; |
481 | 430 | ||
482 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | 431 | /* still didn't send out new data packets */ |
483 | case DCCP_PKT_ACK: | 432 | if (hc->tx_seqh == hc->tx_seqt) |
484 | case DCCP_PKT_DATAACK: | 433 | goto done; |
485 | break; | ||
486 | default: | ||
487 | return; | ||
488 | } | ||
489 | 434 | ||
490 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | 435 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; |
491 | if (after48(ackno, hc->tx_high_ack)) | 436 | if (after48(ackno, hc->tx_high_ack)) |
@@ -509,15 +454,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
509 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); | 454 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); |
510 | 455 | ||
511 | /* go through all ack vectors */ | 456 | /* go through all ack vectors */ |
512 | while ((offset = ccid2_ackvector(sk, skb, offset, | 457 | list_for_each_entry(avp, &hc->tx_av_chunks, node) { |
513 | &vector, &veclen)) != -1) { | ||
514 | /* go through this ack vector */ | 458 | /* go through this ack vector */ |
515 | while (veclen--) { | 459 | for (; avp->len--; avp->vec++) { |
516 | u64 ackno_end_rl = SUB48(ackno, dccp_ackvec_runlen(vector)); | 460 | u64 ackno_end_rl = SUB48(ackno, |
461 | dccp_ackvec_runlen(avp->vec)); | ||
517 | 462 | ||
518 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", | 463 | ccid2_pr_debug("ackvec %llu |%u,%u|\n", |
519 | (unsigned long long)ackno, | 464 | (unsigned long long)ackno, |
520 | (unsigned long long)ackno_end_rl); | 465 | dccp_ackvec_state(avp->vec) >> 6, |
466 | dccp_ackvec_runlen(avp->vec)); | ||
521 | /* if the seqno we are analyzing is larger than the | 467 | /* if the seqno we are analyzing is larger than the |
522 | * current ackno, then move towards the tail of our | 468 | * current ackno, then move towards the tail of our |
523 | * seqnos. | 469 | * seqnos. |
@@ -536,7 +482,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
536 | * run length | 482 | * run length |
537 | */ | 483 | */ |
538 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { | 484 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { |
539 | const u8 state = dccp_ackvec_state(vector); | 485 | const u8 state = dccp_ackvec_state(avp->vec); |
540 | 486 | ||
541 | /* new packet received or marked */ | 487 | /* new packet received or marked */ |
542 | if (state != DCCPAV_NOT_RECEIVED && | 488 | if (state != DCCPAV_NOT_RECEIVED && |
@@ -563,7 +509,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
563 | break; | 509 | break; |
564 | 510 | ||
565 | ackno = SUB48(ackno_end_rl, 1); | 511 | ackno = SUB48(ackno_end_rl, 1); |
566 | vector++; | ||
567 | } | 512 | } |
568 | if (done) | 513 | if (done) |
569 | break; | 514 | break; |
@@ -631,10 +576,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
631 | sk_stop_timer(sk, &hc->tx_rtotimer); | 576 | sk_stop_timer(sk, &hc->tx_rtotimer); |
632 | else | 577 | else |
633 | sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); | 578 | sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); |
634 | 579 | done: | |
635 | /* check if incoming Acks allow pending packets to be sent */ | 580 | /* check if incoming Acks allow pending packets to be sent */ |
636 | if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) | 581 | if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) |
637 | tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); | 582 | tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); |
583 | dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks); | ||
638 | } | 584 | } |
639 | 585 | ||
640 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | 586 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) |
@@ -663,6 +609,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | |||
663 | hc->tx_last_cong = ccid2_time_stamp; | 609 | hc->tx_last_cong = ccid2_time_stamp; |
664 | setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, | 610 | setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, |
665 | (unsigned long)sk); | 611 | (unsigned long)sk); |
612 | INIT_LIST_HEAD(&hc->tx_av_chunks); | ||
666 | return 0; | 613 | return 0; |
667 | } | 614 | } |
668 | 615 | ||
@@ -696,16 +643,17 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
696 | } | 643 | } |
697 | 644 | ||
698 | struct ccid_operations ccid2_ops = { | 645 | struct ccid_operations ccid2_ops = { |
699 | .ccid_id = DCCPC_CCID2, | 646 | .ccid_id = DCCPC_CCID2, |
700 | .ccid_name = "TCP-like", | 647 | .ccid_name = "TCP-like", |
701 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), | 648 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), |
702 | .ccid_hc_tx_init = ccid2_hc_tx_init, | 649 | .ccid_hc_tx_init = ccid2_hc_tx_init, |
703 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, | 650 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, |
704 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, | 651 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, |
705 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, | 652 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, |
706 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, | 653 | .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options, |
707 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), | 654 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, |
708 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | 655 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), |
656 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | ||
709 | }; | 657 | }; |
710 | 658 | ||
711 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG | 659 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index 25cb6b216eda..e9985dafc2c7 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h | |||
@@ -55,6 +55,7 @@ struct ccid2_seq { | |||
55 | * @tx_rtt_seq: to decay RTTVAR at most once per flight | 55 | * @tx_rtt_seq: to decay RTTVAR at most once per flight |
56 | * @tx_rpseq: last consecutive seqno | 56 | * @tx_rpseq: last consecutive seqno |
57 | * @tx_rpdupack: dupacks since rpseq | 57 | * @tx_rpdupack: dupacks since rpseq |
58 | * @tx_av_chunks: list of Ack Vectors received on current skb | ||
58 | */ | 59 | */ |
59 | struct ccid2_hc_tx_sock { | 60 | struct ccid2_hc_tx_sock { |
60 | u32 tx_cwnd; | 61 | u32 tx_cwnd; |
@@ -79,6 +80,7 @@ struct ccid2_hc_tx_sock { | |||
79 | int tx_rpdupack; | 80 | int tx_rpdupack; |
80 | u32 tx_last_cong; | 81 | u32 tx_last_cong; |
81 | u64 tx_high_ack; | 82 | u64 tx_high_ack; |
83 | struct list_head tx_av_chunks; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) | 86 | static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) |
diff --git a/net/dccp/options.c b/net/dccp/options.c index dabd6ee34d45..f06ffcfc8d71 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -128,13 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
128 | if (rc) | 128 | if (rc) |
129 | goto out_featneg_failed; | 129 | goto out_featneg_failed; |
130 | break; | 130 | break; |
131 | case DCCPO_ACK_VECTOR_0: | ||
132 | case DCCPO_ACK_VECTOR_1: | ||
133 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
134 | break; | ||
135 | dccp_pr_debug("%s Ack Vector (len=%u)\n", dccp_role(sk), | ||
136 | len); | ||
137 | break; | ||
138 | case DCCPO_TIMESTAMP: | 131 | case DCCPO_TIMESTAMP: |
139 | if (len != 4) | 132 | if (len != 4) |
140 | goto out_invalid_option; | 133 | goto out_invalid_option; |
@@ -224,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
224 | pkt_type, opt, value, len)) | 217 | pkt_type, opt, value, len)) |
225 | goto out_invalid_option; | 218 | goto out_invalid_option; |
226 | break; | 219 | break; |
220 | case DCCPO_ACK_VECTOR_0: | ||
221 | case DCCPO_ACK_VECTOR_1: | ||
222 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
223 | break; | ||
224 | /* | ||
225 | * Ack vectors are processed by the TX CCID if it is | ||
226 | * interested. The RX CCID need not parse Ack Vectors, | ||
227 | * since it is only interested in clearing old state. | ||
228 | * Fall through. | ||
229 | */ | ||
227 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: | 230 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: |
228 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, | 231 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, |
229 | pkt_type, opt, value, len)) | 232 | pkt_type, opt, value, len)) |