diff options
Diffstat (limited to 'net/dccp/options.c')
-rw-r--r-- | net/dccp/options.c | 91 |
1 files changed, 31 insertions, 60 deletions
diff --git a/net/dccp/options.c b/net/dccp/options.c index 676d53065de9..bfa1cb8f3ef1 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb) | |||
482 | return 0; | 482 | return 0; |
483 | } | 483 | } |
484 | 484 | ||
485 | static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, | 485 | /** |
486 | u8 *val, u8 len) | 486 | * dccp_insert_fn_opt - Insert single Feature-Negotiation option into @skb |
487 | * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R | ||
488 | * @feat: one out of %dccp_feature_numbers | ||
489 | * @val: NN value or SP array (preferred element first) to copy | ||
490 | * @len: true length of @val in bytes (excluding first element repetition) | ||
491 | * @repeat_first: whether to copy the first element of @val twice | ||
492 | * The last argument is used to construct Confirm options, where the preferred | ||
493 | * value and the preference list appear separately (RFC 4340, 6.3.1). Preference | ||
494 | * lists are kept such that the preferred entry is always first, so we only need | ||
495 | * to copy twice, and avoid the overhead of cloning into a bigger array. | ||
496 | */ | ||
497 | int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, | ||
498 | u8 *val, u8 len, bool repeat_first) | ||
487 | { | 499 | { |
488 | u8 *to; | 500 | u8 tot_len, *to; |
489 | 501 | ||
490 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { | 502 | /* take the `Feature' field and possible repetition into account */ |
491 | DCCP_WARN("packet too small for feature %d option!\n", feat); | 503 | if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) { |
504 | DCCP_WARN("length %u for feature %u too large\n", len, feat); | ||
492 | return -1; | 505 | return -1; |
493 | } | 506 | } |
494 | 507 | ||
495 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3; | 508 | if (unlikely(val == NULL || len == 0)) |
509 | len = repeat_first = 0; | ||
510 | tot_len = 3 + repeat_first + len; | ||
511 | |||
512 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) { | ||
513 | DCCP_WARN("packet too small for feature %d option!\n", feat); | ||
514 | return -1; | ||
515 | } | ||
516 | DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len; | ||
496 | 517 | ||
497 | to = skb_push(skb, len + 3); | 518 | to = skb_push(skb, tot_len); |
498 | *to++ = type; | 519 | *to++ = type; |
499 | *to++ = len + 3; | 520 | *to++ = tot_len; |
500 | *to++ = feat; | 521 | *to++ = feat; |
501 | 522 | ||
523 | if (repeat_first) | ||
524 | *to++ = *val; | ||
502 | if (len) | 525 | if (len) |
503 | memcpy(to, val, len); | 526 | memcpy(to, val, len); |
504 | 527 | ||
@@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, | |||
508 | return 0; | 531 | return 0; |
509 | } | 532 | } |
510 | 533 | ||
511 | static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) | ||
512 | { | ||
513 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
514 | struct dccp_opt_pend *opt, *next; | ||
515 | int change = 0; | ||
516 | |||
517 | /* confirm any options [NN opts] */ | ||
518 | list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { | ||
519 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
520 | opt->dccpop_feat, opt->dccpop_val, | ||
521 | opt->dccpop_len); | ||
522 | /* fear empty confirms */ | ||
523 | if (opt->dccpop_val) | ||
524 | kfree(opt->dccpop_val); | ||
525 | kfree(opt); | ||
526 | } | ||
527 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
528 | |||
529 | /* see which features we need to send */ | ||
530 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
531 | /* see if we need to send any confirm */ | ||
532 | if (opt->dccpop_sc) { | ||
533 | dccp_insert_feat_opt(skb, opt->dccpop_type + 1, | ||
534 | opt->dccpop_feat, | ||
535 | opt->dccpop_sc->dccpoc_val, | ||
536 | opt->dccpop_sc->dccpoc_len); | ||
537 | |||
538 | BUG_ON(!opt->dccpop_sc->dccpoc_val); | ||
539 | kfree(opt->dccpop_sc->dccpoc_val); | ||
540 | kfree(opt->dccpop_sc); | ||
541 | opt->dccpop_sc = NULL; | ||
542 | } | ||
543 | |||
544 | /* any option not confirmed, re-send it */ | ||
545 | if (!opt->dccpop_conf) { | ||
546 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
547 | opt->dccpop_feat, opt->dccpop_val, | ||
548 | opt->dccpop_len); | ||
549 | change++; | ||
550 | } | ||
551 | } | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | /* The length of all options needs to be a multiple of 4 (5.8) */ | 534 | /* The length of all options needs to be a multiple of 4 (5.8) */ |
557 | static void dccp_insert_option_padding(struct sk_buff *skb) | 535 | static void dccp_insert_option_padding(struct sk_buff *skb) |
558 | { | 536 | { |
@@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
589 | dp->dccps_hc_rx_insert_options = 0; | 567 | dp->dccps_hc_rx_insert_options = 0; |
590 | } | 568 | } |
591 | 569 | ||
592 | /* Feature negotiation */ | ||
593 | /* Data packets can't do feat negotiation */ | ||
594 | if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA && | ||
595 | DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK && | ||
596 | dccp_insert_options_feat(sk, skb)) | ||
597 | return -1; | ||
598 | |||
599 | /* | 570 | /* |
600 | * Obtain RTT sample from Request/Response exchange. | 571 | * Obtain RTT sample from Request/Response exchange. |
601 | * This is currently used in CCID 3 initialisation. | 572 | * This is currently used in CCID 3 initialisation. |