Skip to content

Commit

Permalink
dccp: Support for the exchange of NN options in established state
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gerrit Renker committed Sep 4, 2008
1 parent 76f738a commit 624a965
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
1 change: 1 addition & 0 deletions net/dccp/dccp.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
inet_csk_ack_scheduled(sk);
}

extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*,
Expand Down
57 changes: 57 additions & 0 deletions net/dccp/feat.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* -----------
* o Feature negotiation is coordinated with connection setup (as in TCP), wild
* changes of parameters of an established connection are not supported.
* o Changing NN values (Ack Ratio only) is supported in state OPEN/PARTOPEN.
* o All currently known SP features have 1-byte quantities. If in the future
* extensions of RFCs 4340..42 define features with item lengths larger than
* one byte, a feature-specific extension of the code will be required.
Expand Down Expand Up @@ -337,6 +338,20 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
}

/**
* dccp_feat_activate - Activate feature value on socket
* @sk: fully connected DCCP socket (after handshake is complete)
* @feat_num: feature to activate, one of %dccp_feature_numbers
* @local: whether local (1) or remote (0) @feat_num is meant
* @fval: the value (SP or NN) to activate, or NULL to use the default value
* For general use this function is preferable over __dccp_feat_activate().
*/
static int dccp_feat_activate(struct sock *sk, u8 feat_num, bool local,
dccp_feat_val const *fval)
{
return __dccp_feat_activate(sk, dccp_feat_index(feat_num), local, fval);
}

/* Test for "Req'd" feature (RFC 4340, 6.4) */
static inline int dccp_feat_must_be_understood(u8 feat_num)
{
Expand Down Expand Up @@ -734,6 +749,48 @@ int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
}

/**
* dccp_feat_signal_nn_change - Update NN values for an established connection
* @sk: DCCP socket of an established connection
* @feat: NN feature number from %dccp_feature_numbers
* @nn_val: the new value to use
* This function is used to communicate NN updates out-of-band. The difference
* to feature negotiation during connection setup is that values are activated
* immediately after validation, i.e. we don't wait for the Confirm: either the
* value is accepted by the peer (and then the waiting is futile), or it is not
* (Reset or empty Confirm). We don't accept empty Confirms - transmitted values
* are validated, and the peer "MUST accept any valid value" (RFC 4340, 6.3.2).
*/
int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val)
{
struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
dccp_feat_val fval = { .nn = nn_val };
struct dccp_feat_entry *entry;

if (sk->sk_state != DCCP_OPEN && sk->sk_state != DCCP_PARTOPEN)
return 0;

if (dccp_feat_type(feat) != FEAT_NN ||
!dccp_feat_is_valid_nn_val(feat, nn_val))
return -EINVAL;

entry = dccp_feat_list_lookup(fn, feat, 1);
if (entry != NULL) {
dccp_pr_debug("Ignoring %llu, entry %llu exists in state %s\n",
(unsigned long long)nn_val,
(unsigned long long)entry->val.nn,
dccp_feat_sname[entry->state]);
return 0;
}

if (dccp_feat_activate(sk, feat, 1, &fval))
return -EADV;

inet_csk_schedule_ack(sk);
return dccp_feat_push_change(fn, feat, 1, 0, &fval);
}
EXPORT_SYMBOL_GPL(dccp_feat_signal_nn_change);

/*
* Tracking features whose value depend on the choice of CCID
*
Expand Down

0 comments on commit 624a965

Please sign in to comment.