aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:37 -0400
commitc8bf462bc567c3dcb083ff95cc13060dd06f138c (patch)
treec612129b23db7bb8613fff4c6e2d51301bc77f65
parent5a577b488f687f339dea62e7bb4f4c5793ad523f (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. The patch provides a new data structure and associated list housekeeping. Only small changes were necessary to integrate with CCID-2: data structure initialisation, adapt list traversal routine, and add call to the provided cleanup routine. The latter also lead to fixing the following BUG: CCID-2 so far ignored Ack Vectors on all packets other than Ack/DataAck, which is incorrect, since Ack Vectors can be present on any packet that has an Ack field. Details: -------- * received Ack Vectors are parsed by dccp_parse_options() alone, which passes the result on to the CCID-specific routine ccid_hc_tx_parse_options(); * CCIDs interested in using/decoding Ack Vector information will add code to fetch parsed Ack Vectors via this interface; * a data structure, `struct dccp_ackvec_parsed' is provided as interface; * this structure arranges Ack Vectors of the same skb into a FIFO order; * a doubly-linked list is used to keep the required FIFO code small. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
-rw-r--r--net/dccp/ackvec.c28
-rw-r--r--net/dccp/ackvec.h19
-rw-r--r--net/dccp/ccids/ccid2.c135
-rw-r--r--net/dccp/ccids/ccid2.h2
-rw-r--r--net/dccp/options.c17
5 files changed, 101 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 */
349int 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}
362EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_add);
363
364void 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}
372EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup);
373
346int __init dccp_ackvec_init(void) 374int __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 db447503b636..6cdca79a99f7 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 */
126struct dccp_ackvec_parsed {
127 u8 *vec,
128 len,
129 nonce:1;
130 struct list_head node;
131};
132
133extern int dccp_ackvec_parsed_add(struct list_head *head,
134 u8 *vec, u8 len, u8 nonce);
135extern 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 813d5cd40e8b..bbf16b35734d 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -317,68 +317,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
317#endif 317#endif
318} 318}
319 319
320/* XXX Lame code duplication!
321 * returns -1 if none was found.
322 * else returns the next offset to use in the function call.
323 */
324static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
325 unsigned char **vec, unsigned char *veclen)
326{
327 const struct dccp_hdr *dh = dccp_hdr(skb);
328 unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
329 unsigned char *opt_ptr;
330 const unsigned char *opt_end = (unsigned char *)dh +
331 (dh->dccph_doff * 4);
332 unsigned char opt, len;
333 unsigned char *value;
334
335 BUG_ON(offset < 0);
336 options += offset;
337 opt_ptr = options;
338 if (opt_ptr >= opt_end)
339 return -1;
340
341 while (opt_ptr != opt_end) {
342 opt = *opt_ptr++;
343 len = 0;
344 value = NULL;
345
346 /* Check if this isn't a single byte option */
347 if (opt > DCCPO_MAX_RESERVED) {
348 if (opt_ptr == opt_end)
349 goto out_invalid_option;
350
351 len = *opt_ptr++;
352 if (len < 3)
353 goto out_invalid_option;
354 /*
355 * Remove the type and len fields, leaving
356 * just the value size
357 */
358 len -= 2;
359 value = opt_ptr;
360 opt_ptr += len;
361
362 if (opt_ptr > opt_end)
363 goto out_invalid_option;
364 }
365
366 switch (opt) {
367 case DCCPO_ACK_VECTOR_0:
368 case DCCPO_ACK_VECTOR_1:
369 *vec = value;
370 *veclen = len;
371 return offset + (opt_ptr - options);
372 }
373 }
374
375 return -1;
376
377out_invalid_option:
378 DCCP_BUG("Invalid option - this should not happen (previous parsing)!");
379 return -1;
380}
381
382static void ccid2_hc_tx_kill_rto_timer(struct sock *sk) 320static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
383{ 321{
384 struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); 322 struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
@@ -499,15 +437,27 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
499 ccid2_change_l_ack_ratio(sk, hctx->cwnd); 437 ccid2_change_l_ack_ratio(sk, hctx->cwnd);
500} 438}
501 439
440static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type,
441 u8 option, u8 *optval, u8 optlen)
442{
443 struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
444
445 switch (option) {
446 case DCCPO_ACK_VECTOR_0:
447 case DCCPO_ACK_VECTOR_1:
448 return dccp_ackvec_parsed_add(&hctx->av_chunks, optval, optlen,
449 option - DCCPO_ACK_VECTOR_0);
450 }
451 return 0;
452}
453
502static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) 454static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
503{ 455{
504 struct dccp_sock *dp = dccp_sk(sk); 456 struct dccp_sock *dp = dccp_sk(sk);
505 struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); 457 struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
458 struct dccp_ackvec_parsed *avp;
506 u64 ackno, seqno; 459 u64 ackno, seqno;
507 struct ccid2_seq *seqp; 460 struct ccid2_seq *seqp;
508 unsigned char *vector;
509 unsigned char veclen;
510 int offset = 0;
511 int done = 0; 461 int done = 0;
512 unsigned int maxincr = 0; 462 unsigned int maxincr = 0;
513 463
@@ -542,17 +492,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
542 } 492 }
543 493
544 /* check forward path congestion */ 494 /* check forward path congestion */
545 /* still didn't send out new data packets */ 495 if (dccp_packet_without_ack(skb))
546 if (hctx->seqh == hctx->seqt)
547 return; 496 return;
548 497
549 switch (DCCP_SKB_CB(skb)->dccpd_type) { 498 /* still didn't send out new data packets */
550 case DCCP_PKT_ACK: 499 if (hctx->seqh == hctx->seqt)
551 case DCCP_PKT_DATAACK: 500 goto done;
552 break;
553 default:
554 return;
555 }
556 501
557 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; 502 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
558 if (after48(ackno, hctx->high_ack)) 503 if (after48(ackno, hctx->high_ack))
@@ -576,15 +521,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
576 maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); 521 maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2);
577 522
578 /* go through all ack vectors */ 523 /* go through all ack vectors */
579 while ((offset = ccid2_ackvector(sk, skb, offset, 524 list_for_each_entry(avp, &hctx->av_chunks, node) {
580 &vector, &veclen)) != -1) {
581 /* go through this ack vector */ 525 /* go through this ack vector */
582 while (veclen--) { 526 for (; avp->len--; avp->vec++) {
583 u64 ackno_end_rl = SUB48(ackno, dccp_ackvec_runlen(vector)); 527 u64 ackno_end_rl = SUB48(ackno,
528 dccp_ackvec_runlen(avp->vec));
584 529
585 ccid2_pr_debug("ackvec start:%llu end:%llu\n", 530 ccid2_pr_debug("ackvec %llu |%u,%u|\n",
586 (unsigned long long)ackno, 531 (unsigned long long)ackno,
587 (unsigned long long)ackno_end_rl); 532 dccp_ackvec_state(avp->vec) >> 6,
533 dccp_ackvec_runlen(avp->vec));
588 /* if the seqno we are analyzing is larger than the 534 /* if the seqno we are analyzing is larger than the
589 * current ackno, then move towards the tail of our 535 * current ackno, then move towards the tail of our
590 * seqnos. 536 * seqnos.
@@ -603,7 +549,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
603 * run length 549 * run length
604 */ 550 */
605 while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { 551 while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
606 const u8 state = dccp_ackvec_state(vector); 552 const u8 state = dccp_ackvec_state(avp->vec);
607 553
608 /* new packet received or marked */ 554 /* new packet received or marked */
609 if (state != DCCPAV_NOT_RECEIVED && 555 if (state != DCCPAV_NOT_RECEIVED &&
@@ -630,7 +576,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
630 break; 576 break;
631 577
632 ackno = SUB48(ackno_end_rl, 1); 578 ackno = SUB48(ackno_end_rl, 1);
633 vector++;
634 } 579 }
635 if (done) 580 if (done)
636 break; 581 break;
@@ -694,6 +639,8 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
694 } 639 }
695 640
696 ccid2_hc_tx_check_sanity(hctx); 641 ccid2_hc_tx_check_sanity(hctx);
642done:
643 dccp_ackvec_parsed_cleanup(&hctx->av_chunks);
697} 644}
698 645
699static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) 646static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
@@ -727,6 +674,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
727 hctx->rpdupack = -1; 674 hctx->rpdupack = -1;
728 hctx->last_cong = jiffies; 675 hctx->last_cong = jiffies;
729 setup_timer(&hctx->rtotimer, ccid2_hc_tx_rto_expire, (unsigned long)sk); 676 setup_timer(&hctx->rtotimer, ccid2_hc_tx_rto_expire, (unsigned long)sk);
677 INIT_LIST_HEAD(&hctx->av_chunks);
730 678
731 ccid2_hc_tx_check_sanity(hctx); 679 ccid2_hc_tx_check_sanity(hctx);
732 return 0; 680 return 0;
@@ -762,17 +710,18 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
762} 710}
763 711
764static struct ccid_operations ccid2 = { 712static struct ccid_operations ccid2 = {
765 .ccid_id = DCCPC_CCID2, 713 .ccid_id = DCCPC_CCID2,
766 .ccid_name = "TCP-like", 714 .ccid_name = "TCP-like",
767 .ccid_owner = THIS_MODULE, 715 .ccid_owner = THIS_MODULE,
768 .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), 716 .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
769 .ccid_hc_tx_init = ccid2_hc_tx_init, 717 .ccid_hc_tx_init = ccid2_hc_tx_init,
770 .ccid_hc_tx_exit = ccid2_hc_tx_exit, 718 .ccid_hc_tx_exit = ccid2_hc_tx_exit,
771 .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, 719 .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet,
772 .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, 720 .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent,
773 .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, 721 .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options,
774 .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), 722 .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv,
775 .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, 723 .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock),
724 .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv,
776}; 725};
777 726
778#ifdef CONFIG_IP_DCCP_CCID2_DEBUG 727#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index d7815804bceb..907deed255b4 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -47,6 +47,7 @@ struct ccid2_seq {
47 * @lastrtt: time RTT was last measured 47 * @lastrtt: time RTT was last measured
48 * @rpseq: last consecutive seqno 48 * @rpseq: last consecutive seqno
49 * @rpdupack: dupacks since rpseq 49 * @rpdupack: dupacks since rpseq
50 * @av_chunks: list of Ack Vectors received on current skb
50 */ 51 */
51struct ccid2_hc_tx_sock { 52struct ccid2_hc_tx_sock {
52 u32 cwnd; 53 u32 cwnd;
@@ -66,6 +67,7 @@ struct ccid2_hc_tx_sock {
66 int rpdupack; 67 int rpdupack;
67 unsigned long last_cong; 68 unsigned long last_cong;
68 u64 high_ack; 69 u64 high_ack;
70 struct list_head av_chunks;
69}; 71};
70 72
71struct ccid2_hc_rx_sock { 73struct ccid2_hc_rx_sock {
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 791e07853a79..e5a32979d7d7 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))