aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2011-07-24 22:22:29 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2011-08-01 09:52:34 -0400
commitd6916f87ca5e566786f1a935a7cabba54774bbda (patch)
tree5420a242fe5f7aacf08e941a96cff8b173eec9aa
parent3da3f872aa175f59e20766ed30aaea67fd4fa7d1 (diff)
dccp: support for the exchange of NN options in established state 1/2
In contrast to static feature negotiation at the begin of a connection, this patch introduces support for exchange of dynamically changing options. Such an update/exchange is necessary in at least two cases: * CCID-2's Ack Ratio (RFC 4341, 6.1.2) which changes during the connection; * Sequence Window values that, as per RFC 4340, 7.5.2, should be sent "as the connection progresses". Both are non-negotiable (NN) features, which means that no new capabilities are negotiated, but rather that changes in known parameters are brought up-to-date at either end. Thse characteristics are reflected by the implementation: * only NN options can be exchanged after connection setup; * an ack is scheduled directly after activation to speed up the update; * CCIDs may request changes to an NN feature even if a negotiation for that feature is already underway: this is required by CCID-2, where changes in cwnd necessitate Ack Ratio changes, such that the previous Ack Ratio (which is still being negotiated) would cause irrecoverable RTO timeouts (thanks to work by Samuel Jero). Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Samuel Jero <sj323707@ohio.edu> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.uk>
-rw-r--r--net/dccp/dccp.h1
-rw-r--r--net/dccp/feat.c65
-rw-r--r--net/dccp/feat.h1
3 files changed, 67 insertions, 0 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 5fdb07229017..583490aaf56f 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -474,6 +474,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
474 return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk); 474 return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
475} 475}
476 476
477extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
477extern int dccp_feat_finalise_settings(struct dccp_sock *dp); 478extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
478extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); 479extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
479extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, 480extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 568def952722..8bd28f244fef 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -12,6 +12,7 @@
12 * ----------- 12 * -----------
13 * o Feature negotiation is coordinated with connection setup (as in TCP), wild 13 * o Feature negotiation is coordinated with connection setup (as in TCP), wild
14 * changes of parameters of an established connection are not supported. 14 * changes of parameters of an established connection are not supported.
15 * o Changing non-negotiable (NN) values is supported in state OPEN/PARTOPEN.
15 * o All currently known SP features have 1-byte quantities. If in the future 16 * o All currently known SP features have 1-byte quantities. If in the future
16 * extensions of RFCs 4340..42 define features with item lengths larger than 17 * extensions of RFCs 4340..42 define features with item lengths larger than
17 * one byte, a feature-specific extension of the code will be required. 18 * one byte, a feature-specific extension of the code will be required.
@@ -730,6 +731,70 @@ int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
730 0, list, len); 731 0, list, len);
731} 732}
732 733
734/**
735 * dccp_feat_nn_get - Query current/pending value of NN feature
736 * @sk: DCCP socket of an established connection
737 * @feat: NN feature number from %dccp_feature_numbers
738 * For a known NN feature, returns value currently being negotiated, or
739 * current (confirmed) value if no negotiation is going on.
740 */
741u64 dccp_feat_nn_get(struct sock *sk, u8 feat)
742{
743 if (dccp_feat_type(feat) == FEAT_NN) {
744 struct dccp_sock *dp = dccp_sk(sk);
745 struct dccp_feat_entry *entry;
746
747 entry = dccp_feat_list_lookup(&dp->dccps_featneg, feat, 1);
748 if (entry != NULL)
749 return entry->val.nn;
750
751 switch (feat) {
752 case DCCPF_ACK_RATIO:
753 return dp->dccps_l_ack_ratio;
754 case DCCPF_SEQUENCE_WINDOW:
755 return dp->dccps_l_seq_win;
756 }
757 }
758 DCCP_BUG("attempt to look up unsupported feature %u", feat);
759 return 0;
760}
761EXPORT_SYMBOL_GPL(dccp_feat_nn_get);
762
763/**
764 * dccp_feat_signal_nn_change - Update NN values for an established connection
765 * @sk: DCCP socket of an established connection
766 * @feat: NN feature number from %dccp_feature_numbers
767 * @nn_val: the new value to use
768 * This function is used to communicate NN updates out-of-band.
769 */
770int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val)
771{
772 struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
773 dccp_feat_val fval = { .nn = nn_val };
774 struct dccp_feat_entry *entry;
775
776 if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN)
777 return 0;
778
779 if (dccp_feat_type(feat) != FEAT_NN ||
780 !dccp_feat_is_valid_nn_val(feat, nn_val))
781 return -EINVAL;
782
783 if (nn_val == dccp_feat_nn_get(sk, feat))
784 return 0; /* already set or negotiation under way */
785
786 entry = dccp_feat_list_lookup(fn, feat, 1);
787 if (entry != NULL) {
788 dccp_pr_debug("Clobbering existing NN entry %llu -> %llu\n",
789 (unsigned long long)entry->val.nn,
790 (unsigned long long)nn_val);
791 dccp_feat_list_pop(entry);
792 }
793
794 inet_csk_schedule_ack(sk);
795 return dccp_feat_push_change(fn, feat, 1, 0, &fval);
796}
797EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change);
733 798
734/* 799/*
735 * Tracking features whose value depend on the choice of CCID 800 * Tracking features whose value depend on the choice of CCID
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index e56a4e5e634e..90b957d34d26 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -129,6 +129,7 @@ extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
129 129
130extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); 130extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
131extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); 131extern u64 dccp_decode_value_var(const u8 *bf, const u8 len);
132extern u64 dccp_feat_nn_get(struct sock *sk, u8 feat);
132 133
133extern int dccp_insert_option_mandatory(struct sk_buff *skb); 134extern int dccp_insert_option_mandatory(struct sk_buff *skb);
134extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, 135extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,