aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/options.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 15:49:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 15:49:40 -0500
commit0191b625ca5a46206d2fb862bb08f36f2fcb3b31 (patch)
tree454d1842b1833d976da62abcbd5c47521ebe9bd7 /net/dccp/options.c
parent54a696bd07c14d3b1192d03ce7269bc59b45209a (diff)
parenteb56092fc168bf5af199d47af50c0d84a96db898 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1429 commits) net: Allow dependancies of FDDI & Tokenring to be modular. igb: Fix build warning when DCA is disabled. net: Fix warning fallout from recent NAPI interface changes. gro: Fix potential use after free sfc: If AN is enabled, always read speed/duplex from the AN advertising bits sfc: When disabling the NIC, close the device rather than unregistering it sfc: SFT9001: Add cable diagnostics sfc: Add support for multiple PHY self-tests sfc: Merge top-level functions for self-tests sfc: Clean up PHY mode management in loopback self-test sfc: Fix unreliable link detection in some loopback modes sfc: Generate unique names for per-NIC workqueues 802.3ad: use standard ethhdr instead of ad_header 802.3ad: generalize out mac address initializer 802.3ad: initialize ports LACPDU from const initializer 802.3ad: remove typedef around ad_system 802.3ad: turn ports is_individual into a bool 802.3ad: turn ports is_enabled into a bool 802.3ad: make ntt bool ixgbe: Fix set_ringparam in ixgbe to use the same memory pools. ... Fixed trivial IPv4/6 address printing conflicts in fs/cifs/connect.c due to the conversion to %pI (in this networking merge) and the addition of doing IPv6 addresses (from the earlier merge of CIFS).
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r--net/dccp/options.c229
1 files changed, 94 insertions, 135 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 0809b63cb055..7b1165c21f51 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,20 +26,21 @@
26int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; 26int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
27int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID; 27int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID;
28int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID; 28int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID;
29int sysctl_dccp_feat_ack_ratio = DCCPF_INITIAL_ACK_RATIO;
30int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
31int sysctl_dccp_feat_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT;
32 29
33static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) 30u64 dccp_decode_value_var(const u8 *bf, const u8 len)
34{ 31{
35 u32 value = 0; 32 u64 value = 0;
36 33
34 if (len >= DCCP_OPTVAL_MAXLEN)
35 value += ((u64)*bf++) << 40;
36 if (len > 4)
37 value += ((u64)*bf++) << 32;
37 if (len > 3) 38 if (len > 3)
38 value += *bf++ << 24; 39 value += ((u64)*bf++) << 24;
39 if (len > 2) 40 if (len > 2)
40 value += *bf++ << 16; 41 value += ((u64)*bf++) << 16;
41 if (len > 1) 42 if (len > 1)
42 value += *bf++ << 8; 43 value += ((u64)*bf++) << 8;
43 if (len > 0) 44 if (len > 0)
44 value += *bf; 45 value += *bf;
45 46
@@ -64,7 +65,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
64 (dh->dccph_doff * 4); 65 (dh->dccph_doff * 4);
65 struct dccp_options_received *opt_recv = &dp->dccps_options_received; 66 struct dccp_options_received *opt_recv = &dp->dccps_options_received;
66 unsigned char opt, len; 67 unsigned char opt, len;
67 unsigned char *value; 68 unsigned char *uninitialized_var(value);
68 u32 elapsed_time; 69 u32 elapsed_time;
69 __be32 opt_val; 70 __be32 opt_val;
70 int rc; 71 int rc;
@@ -131,41 +132,19 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
131 dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk), 132 dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
132 (unsigned long long)opt_recv->dccpor_ndp); 133 (unsigned long long)opt_recv->dccpor_ndp);
133 break; 134 break;
134 case DCCPO_CHANGE_L: 135 case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
135 /* fall through */ 136 if (pkt_type == DCCP_PKT_DATA) /* RFC 4340, 6 */
136 case DCCPO_CHANGE_R:
137 if (pkt_type == DCCP_PKT_DATA)
138 break; 137 break;
139 if (len < 2) 138 rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
140 goto out_invalid_option; 139 *value, value + 1, len - 1);
141 rc = dccp_feat_change_recv(sk, opt, *value, value + 1, 140 if (rc)
142 len - 1); 141 goto out_featneg_failed;
143 /*
144 * When there is a change error, change_recv is
145 * responsible for dealing with it. i.e. reply with an
146 * empty confirm.
147 * If the change was mandatory, then we need to die.
148 */
149 if (rc && mandatory)
150 goto out_invalid_option;
151 break;
152 case DCCPO_CONFIRM_L:
153 /* fall through */
154 case DCCPO_CONFIRM_R:
155 if (pkt_type == DCCP_PKT_DATA)
156 break;
157 if (len < 2) /* FIXME this disallows empty confirm */
158 goto out_invalid_option;
159 if (dccp_feat_confirm_recv(sk, opt, *value,
160 value + 1, len - 1))
161 goto out_invalid_option;
162 break; 142 break;
163 case DCCPO_ACK_VECTOR_0: 143 case DCCPO_ACK_VECTOR_0:
164 case DCCPO_ACK_VECTOR_1: 144 case DCCPO_ACK_VECTOR_1:
165 if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ 145 if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */
166 break; 146 break;
167 147 if (dp->dccps_hc_rx_ackvec != NULL &&
168 if (dccp_msk(sk)->dccpms_send_ack_vector &&
169 dccp_ackvec_parse(sk, skb, &ackno, opt, value, len)) 148 dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
170 goto out_invalid_option; 149 goto out_invalid_option;
171 break; 150 break;
@@ -289,8 +268,10 @@ out_nonsensical_length:
289 268
290out_invalid_option: 269out_invalid_option:
291 DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); 270 DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
292 DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; 271 rc = DCCP_RESET_CODE_OPTION_ERROR;
293 DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len); 272out_featneg_failed:
273 DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
274 DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
294 DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt; 275 DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
295 DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0; 276 DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
296 DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0; 277 DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
@@ -299,9 +280,12 @@ out_invalid_option:
299 280
300EXPORT_SYMBOL_GPL(dccp_parse_options); 281EXPORT_SYMBOL_GPL(dccp_parse_options);
301 282
302static void dccp_encode_value_var(const u32 value, unsigned char *to, 283void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
303 const unsigned int len)
304{ 284{
285 if (len >= DCCP_OPTVAL_MAXLEN)
286 *to++ = (value & 0xFF0000000000ull) >> 40;
287 if (len > 4)
288 *to++ = (value & 0xFF00000000ull) >> 32;
305 if (len > 3) 289 if (len > 3)
306 *to++ = (value & 0xFF000000) >> 24; 290 *to++ = (value & 0xFF000000) >> 24;
307 if (len > 2) 291 if (len > 2)
@@ -461,23 +445,61 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
461 return 0; 445 return 0;
462} 446}
463 447
464static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, 448/**
465 u8 *val, u8 len) 449 * dccp_insert_option_mandatory - Mandatory option (5.8.2)
450 * Note that since we are using skb_push, this function needs to be called
451 * _after_ inserting the option it is supposed to influence (stack order).
452 */
453int dccp_insert_option_mandatory(struct sk_buff *skb)
454{
455 if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
456 return -1;
457
458 DCCP_SKB_CB(skb)->dccpd_opt_len++;
459 *skb_push(skb, 1) = DCCPO_MANDATORY;
460 return 0;
461}
462
463/**
464 * dccp_insert_fn_opt - Insert single Feature-Negotiation option into @skb
465 * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
466 * @feat: one out of %dccp_feature_numbers
467 * @val: NN value or SP array (preferred element first) to copy
468 * @len: true length of @val in bytes (excluding first element repetition)
469 * @repeat_first: whether to copy the first element of @val twice
470 * The last argument is used to construct Confirm options, where the preferred
471 * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
472 * lists are kept such that the preferred entry is always first, so we only need
473 * to copy twice, and avoid the overhead of cloning into a bigger array.
474 */
475int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
476 u8 *val, u8 len, bool repeat_first)
466{ 477{
467 u8 *to; 478 u8 tot_len, *to;
468 479
469 if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { 480 /* take the `Feature' field and possible repetition into account */
470 DCCP_WARN("packet too small for feature %d option!\n", feat); 481 if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
482 DCCP_WARN("length %u for feature %u too large\n", len, feat);
471 return -1; 483 return -1;
472 } 484 }
473 485
474 DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3; 486 if (unlikely(val == NULL || len == 0))
487 len = repeat_first = 0;
488 tot_len = 3 + repeat_first + len;
489
490 if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
491 DCCP_WARN("packet too small for feature %d option!\n", feat);
492 return -1;
493 }
494 DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
475 495
476 to = skb_push(skb, len + 3); 496 to = skb_push(skb, tot_len);
477 *to++ = type; 497 *to++ = type;
478 *to++ = len + 3; 498 *to++ = tot_len;
479 *to++ = feat; 499 *to++ = feat;
480 500
501 if (repeat_first)
502 *to++ = *val;
481 if (len) 503 if (len)
482 memcpy(to, val, len); 504 memcpy(to, val, len);
483 505
@@ -487,69 +509,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
487 return 0; 509 return 0;
488} 510}
489 511
490static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
491{
492 struct dccp_sock *dp = dccp_sk(sk);
493 struct dccp_minisock *dmsk = dccp_msk(sk);
494 struct dccp_opt_pend *opt, *next;
495 int change = 0;
496
497 /* confirm any options [NN opts] */
498 list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
499 dccp_insert_feat_opt(skb, opt->dccpop_type,
500 opt->dccpop_feat, opt->dccpop_val,
501 opt->dccpop_len);
502 /* fear empty confirms */
503 if (opt->dccpop_val)
504 kfree(opt->dccpop_val);
505 kfree(opt);
506 }
507 INIT_LIST_HEAD(&dmsk->dccpms_conf);
508
509 /* see which features we need to send */
510 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
511 /* see if we need to send any confirm */
512 if (opt->dccpop_sc) {
513 dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
514 opt->dccpop_feat,
515 opt->dccpop_sc->dccpoc_val,
516 opt->dccpop_sc->dccpoc_len);
517
518 BUG_ON(!opt->dccpop_sc->dccpoc_val);
519 kfree(opt->dccpop_sc->dccpoc_val);
520 kfree(opt->dccpop_sc);
521 opt->dccpop_sc = NULL;
522 }
523
524 /* any option not confirmed, re-send it */
525 if (!opt->dccpop_conf) {
526 dccp_insert_feat_opt(skb, opt->dccpop_type,
527 opt->dccpop_feat, opt->dccpop_val,
528 opt->dccpop_len);
529 change++;
530 }
531 }
532
533 /* Retransmit timer.
534 * If this is the master listening sock, we don't set a timer on it. It
535 * should be fine because if the dude doesn't receive our RESPONSE
536 * [which will contain the CHANGE] he will send another REQUEST which
537 * will "retrnasmit" the change.
538 */
539 if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
540 dccp_pr_debug("reset feat negotiation timer %p\n", sk);
541
542 /* XXX don't reset the timer on re-transmissions. I.e. reset it
543 * only when sending new stuff i guess. Currently the timer
544 * never backs off because on re-transmission it just resets it!
545 */
546 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
547 inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
548 }
549
550 return 0;
551}
552
553/* The length of all options needs to be a multiple of 4 (5.8) */ 512/* The length of all options needs to be a multiple of 4 (5.8) */
554static void dccp_insert_option_padding(struct sk_buff *skb) 513static void dccp_insert_option_padding(struct sk_buff *skb)
555{ 514{
@@ -565,19 +524,31 @@ static void dccp_insert_option_padding(struct sk_buff *skb)
565int dccp_insert_options(struct sock *sk, struct sk_buff *skb) 524int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
566{ 525{
567 struct dccp_sock *dp = dccp_sk(sk); 526 struct dccp_sock *dp = dccp_sk(sk);
568 struct dccp_minisock *dmsk = dccp_msk(sk);
569 527
570 DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 528 DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
571 529
572 if (dmsk->dccpms_send_ndp_count && 530 if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
573 dccp_insert_option_ndp(sk, skb))
574 return -1; 531 return -1;
575 532
576 if (!dccp_packet_without_ack(skb)) { 533 if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
577 if (dmsk->dccpms_send_ack_vector && 534
578 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && 535 /* Feature Negotiation */
579 dccp_insert_option_ackvec(sk, skb)) 536 if (dccp_feat_insert_opts(dp, NULL, skb))
580 return -1; 537 return -1;
538
539 if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
540 /*
541 * Obtain RTT sample from Request/Response exchange.
542 * This is currently used in CCID 3 initialisation.
543 */
544 if (dccp_insert_option_timestamp(sk, skb))
545 return -1;
546
547 } else if (dp->dccps_hc_rx_ackvec != NULL &&
548 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
549 dccp_insert_option_ackvec(sk, skb)) {
550 return -1;
551 }
581 } 552 }
582 553
583 if (dp->dccps_hc_rx_insert_options) { 554 if (dp->dccps_hc_rx_insert_options) {
@@ -586,21 +557,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
586 dp->dccps_hc_rx_insert_options = 0; 557 dp->dccps_hc_rx_insert_options = 0;
587 } 558 }
588 559
589 /* Feature negotiation */
590 /* Data packets can't do feat negotiation */
591 if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
592 DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
593 dccp_insert_options_feat(sk, skb))
594 return -1;
595
596 /*
597 * Obtain RTT sample from Request/Response exchange.
598 * This is currently used in CCID 3 initialisation.
599 */
600 if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
601 dccp_insert_option_timestamp(sk, skb))
602 return -1;
603
604 if (dp->dccps_timestamp_echo != 0 && 560 if (dp->dccps_timestamp_echo != 0 &&
605 dccp_insert_option_timestamp_echo(dp, NULL, skb)) 561 dccp_insert_option_timestamp_echo(dp, NULL, skb))
606 return -1; 562 return -1;
@@ -613,6 +569,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
613{ 569{
614 DCCP_SKB_CB(skb)->dccpd_opt_len = 0; 570 DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
615 571
572 if (dccp_feat_insert_opts(NULL, dreq, skb))
573 return -1;
574
616 if (dreq->dreq_timestamp_echo != 0 && 575 if (dreq->dreq_timestamp_echo != 0 &&
617 dccp_insert_option_timestamp_echo(NULL, dreq, skb)) 576 dccp_insert_option_timestamp_echo(NULL, dreq, skb))
618 return -1; 577 return -1;