diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-28 15:49:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-28 15:49:40 -0500 |
commit | 0191b625ca5a46206d2fb862bb08f36f2fcb3b31 (patch) | |
tree | 454d1842b1833d976da62abcbd5c47521ebe9bd7 /net/dccp/options.c | |
parent | 54a696bd07c14d3b1192d03ce7269bc59b45209a (diff) | |
parent | eb56092fc168bf5af199d47af50c0d84a96db898 (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.c | 229 |
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 @@ | |||
26 | int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; | 26 | int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; |
27 | int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID; | 27 | int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID; |
28 | int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID; | 28 | int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID; |
29 | int sysctl_dccp_feat_ack_ratio = DCCPF_INITIAL_ACK_RATIO; | ||
30 | int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; | ||
31 | int sysctl_dccp_feat_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; | ||
32 | 29 | ||
33 | static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) | 30 | u64 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 | ||
290 | out_invalid_option: | 269 | out_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); | 272 | out_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 | ||
300 | EXPORT_SYMBOL_GPL(dccp_parse_options); | 281 | EXPORT_SYMBOL_GPL(dccp_parse_options); |
301 | 282 | ||
302 | static void dccp_encode_value_var(const u32 value, unsigned char *to, | 283 | void 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 | ||
464 | static 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 | */ | ||
453 | int 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 | */ | ||
475 | int 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 | ||
490 | static 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) */ |
554 | static void dccp_insert_option_padding(struct sk_buff *skb) | 513 | static 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) | |||
565 | int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | 524 | int 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; |