aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,