diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:32 -0400 |
commit | 624a965a93610152b10c73d050ed44812efa8abe (patch) | |
tree | 50ad65253183b9140ff6f8a3ef43cdeb1b8feb9f /net/dccp | |
parent | 76f738a7950b559a23ab3c692c99a02f35a54f7f (diff) |
dccp: Support for the exchange of NN options in established state
In contrast to static feature negotiation at the begin of a connection, which
establishes the capabilities of both endpoints, this patch introduces support
for dynamic exchange of feature negotiation options.
Such a dynamic 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
as the connection progresses".
Both are NN (non-negotiable) features. Hence dynamic feature "negotiation" is
distinguished from static/pre-connection negotiation by the following:
* no new capabilities are negotiated (those that matter for the connection
are negotiated prior to setting up the connection, comparable to SIP);
* features must be understood by each endpoint: as per RFC 4340, 6.4,
Sequence Window is "Req'd" and Ack Ratio must be understood when CCID-2
is used as per the note underneath Table 4.
These characteristics are reflected in the implementation:
* only NN options can be exchanged after connection setup;
* NN options are activated directly after validating them. The rationale is
that a peer must accept every valid NN value (RFC 4340, 6.3.2), hence it
will either accept the value and send a "Confirm R", or it will send an
empty Confirm (which will reset the connection according to FN rules).
* An Ack is scheduled directly after activation to accelerate communicating
the update to the peer.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/feat.c | 57 |
2 files changed, 58 insertions, 0 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 94ae6d41d724..0a07b2e24e62 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -436,6 +436,7 @@ static inline int dccp_ack_pending(const struct sock *sk) | |||
436 | inet_csk_ack_scheduled(sk); | 436 | inet_csk_ack_scheduled(sk); |
437 | } | 437 | } |
438 | 438 | ||
439 | extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val); | ||
439 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 440 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
440 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); | 441 | extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); |
441 | extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, | 442 | 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 3abacad0b224..5be8b85ac74b 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * ----------- | 13 | * ----------- |
14 | * o Feature negotiation is coordinated with connection setup (as in TCP), wild | 14 | * o Feature negotiation is coordinated with connection setup (as in TCP), wild |
15 | * changes of parameters of an established connection are not supported. | 15 | * changes of parameters of an established connection are not supported. |
16 | * o Changing NN values (Ack Ratio only) is supported in state OPEN/PARTOPEN. | ||
16 | * o All currently known SP features have 1-byte quantities. If in the future | 17 | * o All currently known SP features have 1-byte quantities. If in the future |
17 | * extensions of RFCs 4340..42 define features with item lengths larger than | 18 | * extensions of RFCs 4340..42 define features with item lengths larger than |
18 | * one byte, a feature-specific extension of the code will be required. | 19 | * one byte, a feature-specific extension of the code will be required. |
@@ -337,6 +338,20 @@ static int __dccp_feat_activate(struct sock *sk, const int idx, | |||
337 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); | 338 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); |
338 | } | 339 | } |
339 | 340 | ||
341 | /** | ||
342 | * dccp_feat_activate - Activate feature value on socket | ||
343 | * @sk: fully connected DCCP socket (after handshake is complete) | ||
344 | * @feat_num: feature to activate, one of %dccp_feature_numbers | ||
345 | * @local: whether local (1) or remote (0) @feat_num is meant | ||
346 | * @fval: the value (SP or NN) to activate, or NULL to use the default value | ||
347 | * For general use this function is preferable over __dccp_feat_activate(). | ||
348 | */ | ||
349 | static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local, | ||
350 | dccp_feat_val const *fval) | ||
351 | { | ||
352 | return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval); | ||
353 | } | ||
354 | |||
340 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ | 355 | /* Test for "Req'd" feature (RFC 4340, 6.4) */ |
341 | static inline int dccp_feat_must_be_understood(u8 feat_num) | 356 | static inline int dccp_feat_must_be_understood(u8 feat_num) |
342 | { | 357 | { |
@@ -734,6 +749,48 @@ int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val) | |||
734 | return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val); | 749 | return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val); |
735 | } | 750 | } |
736 | 751 | ||
752 | /** | ||
753 | * dccp_feat_signal_nn_change - Update NN values for an established connection | ||
754 | * @sk: DCCP socket of an established connection | ||
755 | * @feat: NN feature number from %dccp_feature_numbers | ||
756 | * @nn_val: the new value to use | ||
757 | * This function is used to communicate NN updates out-of-band. The difference | ||
758 | * to feature negotiation during connection setup is that values are activated | ||
759 | * immediately after validation, i.e. we don't wait for the Confirm: either the | ||
760 | * value is accepted by the peer (and then the waiting is futile), or it is not | ||
761 | * (Reset or empty Confirm). We don't accept empty Confirms - transmitted values | ||
762 | * are validated, and the peer "MUST accept any valid value" (RFC 4340, 6.3.2). | ||
763 | */ | ||
764 | int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val) | ||
765 | { | ||
766 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; | ||
767 | dccp_feat_val fval = { .nn = nn_val }; | ||
768 | struct dccp_feat_entry *entry; | ||
769 | |||
770 | if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN) | ||
771 | return 0; | ||
772 | |||
773 | if (dccp_feat_type(feat) != FEAT_NN || | ||
774 | !dccp_feat_is_valid_nn_val(feat, nn_val)) | ||
775 | return -EINVAL; | ||
776 | |||
777 | entry = dccp_feat_list_lookup(fn, feat, 1); | ||
778 | if (entry != NULL) { | ||
779 | dccp_pr_debug("Ignoring %llu, entry %llu exists in state %s\n", | ||
780 | (unsigned long long)nn_val, | ||
781 | (unsigned long long)entry->val.nn, | ||
782 | dccp_feat_sname[entry->state]); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | if (dccp_feat_activate(sk, feat, 1, &fval)) | ||
787 | return -EADV; | ||
788 | |||
789 | inet_csk_schedule_ack(sk); | ||
790 | return dccp_feat_push_change(fn, feat, 1, 0, &fval); | ||
791 | } | ||
792 | EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change); | ||
793 | |||
737 | /* | 794 | /* |
738 | * Tracking features whose value depend on the choice of CCID | 795 | * Tracking features whose value depend on the choice of CCID |
739 | * | 796 | * |