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/ccids/ccid2.c | |
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/ccids/ccid2.c')
-rw-r--r-- | net/dccp/ccids/ccid2.c | 134 |
1 files changed, 41 insertions, 93 deletions
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index cb1b4a0d187..e96d5e81003 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 |