aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/feat.h2
-rw-r--r--net/dccp/options.c91
2 files changed, 33 insertions, 60 deletions
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index f8e4878dfc28..7efb2025f6bf 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -141,4 +141,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
141extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); 141extern u64 dccp_decode_value_var(const u8 *bf, const u8 len);
142 142
143extern int dccp_insert_option_mandatory(struct sk_buff *skb); 143extern int dccp_insert_option_mandatory(struct sk_buff *skb);
144extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
145 u8 *val, u8 len, bool repeat_first);
144#endif /* _DCCP_FEAT_H */ 146#endif /* _DCCP_FEAT_H */
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
485static 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 */
497int 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
511static 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) */
557static void dccp_insert_option_padding(struct sk_buff *skb) 535static 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.