aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-23 19:10:23 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-23 19:10:23 -0500
commit8c862c23e2563e6aedfc6c4aa6827cadb83f2414 (patch)
tree55550ae7c2b62e5b93a09487278db91c334d615a /net
parentd371056695ef993d36c57b73d654e66080377a9c (diff)
dccp: Header option insertion routine for feature-negotiation
The patch extends existing code: * Confirm options divide into the confirmed value plus an optional preference list for SP values. Previously only the preference list was echoed for SP values, now the confirmed value is added as per RFC 4340, 6.1; * length and sanity checks are added to avoid illegal memory (or NULL) access. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-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.