diff options
-rw-r--r-- | net/dccp/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/feat.c | 65 | ||||
-rw-r--r-- | net/dccp/feat.h | 1 |
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 | ||
477 | extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val); | ||
477 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 478 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
478 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); | 479 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); |
479 | extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, | 480 | extern 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 | */ | ||
741 | u64 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 | } | ||
761 | EXPORT_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 | */ | ||
770 | int 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 | } | ||
797 | EXPORT_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 | ||
130 | extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); | 130 | extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); |
131 | extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); | 131 | extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); |
132 | extern u64 dccp_feat_nn_get(struct sock *sk, u8 feat); | ||
132 | 133 | ||
133 | extern int dccp_insert_option_mandatory(struct sk_buff *skb); | 134 | extern int dccp_insert_option_mandatory(struct sk_buff *skb); |
134 | extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, | 135 | extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, |